diff --git a/BUILD.gn b/BUILD.gn new file mode 100644 index 00000000..f58353d7 --- /dev/null +++ b/BUILD.gn @@ -0,0 +1,30 @@ +# Copyright (C) 2021 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. + +import("//build/ohos.gni") + +################################################################################ + +group("inputmethod_native_packages") { + if (is_standard_system) { + deps = [ + "etc/init:inputmethodservice.rc", + "services:inputmethod_service", + "frameworks/inputmethod_controller:inputmethod_client", + "frameworks/inputmethod_ability:inputmethod_ability", + "interfaces/kits/js/declaration:inputmethod", + "interfaces/kits/js/napi:inputmethodability", + "profile:miscservices_inputmethod_sa_profiles", + ] + } +} diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..4947287f --- /dev/null +++ b/LICENSE @@ -0,0 +1,177 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/etc/init/BUILD.gn b/etc/init/BUILD.gn new file mode 100644 index 00000000..09f7e627 --- /dev/null +++ b/etc/init/BUILD.gn @@ -0,0 +1,27 @@ +# Copyright (C) 2021 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. + +import("//build/ohos.gni") + +################################################################################ + +ohos_prebuilt_etc("inputmethodservice.rc") { + if (use_musl) { + source = "inputmethodservice.cfg" + } else { + source = "inputmethodservice.rc" + } + relative_install_dir = "init" + part_name = "inputmethod_native" + subsystem_name = "miscservices" +} \ No newline at end of file diff --git a/etc/init/inputmethodservice.cfg b/etc/init/inputmethodservice.cfg new file mode 100644 index 00000000..9f9a783e --- /dev/null +++ b/etc/init/inputmethodservice.cfg @@ -0,0 +1,17 @@ +{ + "jobs" : [{ + "name" : "boot", + "cmds" : [ + "start inputmethod_service" + ] + } + ], + "services" : [{ + "name" : "inputmethod_service", + "path" : ["/system/bin/sa_main", "/system/profile/inputmethod_service.xml"], + "uid" : "system", + "gid" : ["system", "shell"], + "caps" : ["SYS_TIME"] + } + ] +} diff --git a/etc/init/inputmethodservice.rc b/etc/init/inputmethodservice.rc new file mode 100644 index 00000000..fbfbcc44 --- /dev/null +++ b/etc/init/inputmethodservice.rc @@ -0,0 +1,21 @@ +# Copyright (C) 2021 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. + +on boot + start inputmethod_service +service inputmethod_service /system/bin/sa_main /system/profile/inputmethod_service.xml + class z_core + user system + group system shell + capabilities SYS_TIME + seclabel u:r:time_service:s0 diff --git a/frameworks/inputmethod_ability/BUILD.gn b/frameworks/inputmethod_ability/BUILD.gn new file mode 100644 index 00000000..bbfa1736 --- /dev/null +++ b/frameworks/inputmethod_ability/BUILD.gn @@ -0,0 +1,74 @@ +# Copyright (c) 2021 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. +import("//base/miscservices/inputmethod/inputmethod.gni") +import("//build/ohos.gni") + +config("inputmethod_ability_native_config") { + visibility = [ ":*" ] + include_dirs = [ + "include", + "${inputmethod_path}/frameworks/inputmethod_controller/include", + ] + +} +config("inputmethod_ability_native_public_config") { + visibility = [] + include_dirs = [ "include" ] +} + +ohos_shared_library("inputmethod_ability") { + sources = [ + "src/input_method_ability.cpp", + "src/input_method_agent_proxy.cpp", + "src/input_method_agent_stub.cpp", + "src/input_method_core_stub.cpp", + "src/input_method_core_proxy.cpp", + "src/event_target.cpp", + "../inputmethod_controller/src/input_method_system_ability_proxy.cpp", + ] + + configs = [ ":inputmethod_ability_native_config" ] + + deps = [ + "//utils/native/base:utils", + "//base/global/resmgr_standard/frameworks/resmgr:global_resmgr", + "//foundation/aafwk/standard/frameworks/kits/ability/native:abilitykit_native", + "//foundation/aafwk/standard/interfaces/innerkits/ability_manager:ability_manager", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/intent:intent", + "//foundation/ace/napi/:ace_napi", + "//foundation/multimodalinput/input/interfaces/native/innerkits/event:mmi_event", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler:libeventhandler", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//foundation/communication/ipc/interfaces/innerkits/ipc_core:ipc_core", + "//foundation/communication/ipc/interfaces/innerkits/ipc_single:ipc_single", + "//foundation/multimodalinput/input/interfaces/native/innerkits/event:mmi_event", + "//foundation/distributedschedule/dmsfwk/interfaces/innerkits/uri:zuri", + "//base/miscservices/inputmethod/services:inputmethod_service", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + ] + + public_configs = [ + ":inputmethod_ability_native_config", + "//utils/native/base:utils_config", + ] + + subsystem_name = "miscservices" + part_name = "inputmethod_native" +} diff --git a/frameworks/inputmethod_ability/include/event_target.h b/frameworks/inputmethod_ability/include/event_target.h new file mode 100644 index 00000000..5ff610cb --- /dev/null +++ b/frameworks/inputmethod_ability/include/event_target.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2021 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 FOUNDATION_ACE_NAPI_TEST_NATIVE_MODULE_NETSERVER_EVENT_TARGET_H +#define FOUNDATION_ACE_NAPI_TEST_NATIVE_MODULE_NETSERVER_EVENT_TARGET_H + +#include "napi/native_api.h" +#include "global.h" +#include "input_method_ability.h" + +namespace OHOS { +namespace MiscServices { +struct EventListener; + +class Event { +public: + virtual napi_value ToJsObject() = 0; +}; + +class EventTarget : public RefBase { +public: + EventTarget(napi_env env, napi_value thisVar); + virtual ~EventTarget(); + + virtual void On(const char* type, napi_value handler); + virtual void Once(const char* type, napi_value handler); + virtual void Off(const char* type, napi_value handler); + virtual void Off(const char* type); + virtual void Emit(const char* type, Event* event); + +protected: + napi_env env_; + napi_ref thisVarRef_; + EventListener* first_; + EventListener* last_; +}; +} +} +#endif /* FOUNDATION_ACE_NAPI_TEST_NATIVE_MODULE_NETSERVER_EVENT_TARGET_H */ \ No newline at end of file diff --git a/frameworks/inputmethod_ability/include/i_input_method_agent.h b/frameworks/inputmethod_ability/include/i_input_method_agent.h new file mode 100644 index 00000000..e9eb80a8 --- /dev/null +++ b/frameworks/inputmethod_ability/include/i_input_method_agent.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2021 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 FM_IMMS_PROJECT_IINPUTMETHODAGENT_H +#define FM_IMMS_PROJECT_IINPUTMETHODAGENT_H + +#include "iremote_broker.h" +#include "global.h" + +/** + * brief Definition of interface IInputMethodAgent + * It defines the remote calls from input client to input method service + */ +namespace OHOS { +namespace MiscServices { + class IInputMethodAgent : public IRemoteBroker { + public: + enum { + DISPATCH_KEY = FIRST_CALL_TRANSACTION, + }; + + DECLARE_INTERFACE_DESCRIPTOR(u"ohos.miscservices.inputmethod.IInputMethodAgent"); + + virtual int32_t DispatchKey(int32_t key, int32_t status) = 0; + }; +} +} +#endif // FM_IMMS_PROJECT_IINPUTMETHODAGENT_H diff --git a/frameworks/inputmethod_ability/include/i_input_method_core.h b/frameworks/inputmethod_ability/include/i_input_method_core.h new file mode 100644 index 00000000..50ecf881 --- /dev/null +++ b/frameworks/inputmethod_ability/include/i_input_method_core.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2021 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 FM_IMMS_PROJECT_IINPUTMETHODCORE_H +#define FM_IMMS_PROJECT_IINPUTMETHODCORE_H +#include "iremote_broker.h" +#include "i_input_data_channel.h" +#include "i_input_control_channel.h" +#include "ipc_types.h" +#include "input_attribute.h" +#include "keyboard_type.h" +#include "input_channel.h" +#include "global.h" + +/** + * brief Definition of interface IInputMethodCore + * It defines the remote calls from input method management service to input method service + */ +namespace OHOS { +namespace MiscServices { + class IInputMethodCore : public IRemoteBroker { + public: + enum { + INITIALIZE_INPUT = FIRST_CALL_TRANSACTION, + START_INPUT, + STOP_INPUT, + SHOW_KEYBOARD, + HIDE_KEYBOARD, + SET_KEYBOARD_TYPE, + GET_KEYBOARD_WINDOW_HEIGHT, + }; + + DECLARE_INTERFACE_DESCRIPTOR(u"ohos.miscservices.inputmethod.IInputMethodCore"); + + virtual int32_t initializeInput(sptr& startInputToken, int32_t displayId, + sptr& inputControlChannel) = 0; + virtual bool startInput(const sptr& startInputToken, + const InputAttribute& editorAttribute, + bool supportPhysicalKbd) = 0; + virtual int32_t stopInput() = 0; + virtual bool showKeyboard(int32_t flags) = 0; + virtual bool hideKeyboard(int32_t flags) = 0; + virtual int32_t setKeyboardType(const KeyboardType& type) = 0; + virtual int32_t getKeyboardWindowHeight(int32_t* retHeight) = 0; + }; +} +} +#endif // FM_IMMS_PROJECT_IINPUTMETHODCORE_H diff --git a/frameworks/inputmethod_ability/include/input_method_ability.h b/frameworks/inputmethod_ability/include/input_method_ability.h new file mode 100644 index 00000000..e4340329 --- /dev/null +++ b/frameworks/inputmethod_ability/include/input_method_ability.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2021 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 FM_IMMS_PROJECT_INPUTMETHODABILITY_H +#define FM_IMMS_PROJECT_INPUTMETHODABILITY_H + +#include +#include "iremote_object.h" +#include "i_input_control_channel.h" +#include "i_input_method_core.h" +#include "i_input_data_channel.h" +#include "i_input_method_agent.h" +#include "input_method_core_stub.h" +#include "input_control_channel_proxy.h" +#include "input_attribute.h" +#include "message_handler.h" +#include "input_channel.h" +#include "message.h" +#include "utils.h" +#include "input_method_system_ability_proxy.h" + +namespace OHOS { +namespace MiscServices { + class EventTarget; + class InputMethodAbility : public RefBase { + public: + InputMethodAbility(); + ~InputMethodAbility(); + static sptr GetInstance(); + sptr OnConnect(); + bool InsertText(const std::string text); + void setEventTarget(sptr &eventTarget); + void DeleteBackward(int32_t length); + void HideKeyboardSelf(); + + private: + std::thread workThreadHandler; + MessageHandler* msgHandler; + bool mSupportPhysicalKbd = false; + InputAttribute* editorAttribute; + int32_t displyId = 0; + sptr startInputToken; + InputChannel* writeInputChannel; + + // communicating with IMSA + sptr inputControlChannel; + + // communicating with IMC + sptr inputDataChannel; + sptr inputMethodAgent; + sptr eventTarget_; + static std::mutex instanceLock_; + static sptr instance_; + sptr mImms; + sptr GetImsaProxy(); + + + void Initialize(); + void WorkThread(); + void CreateInputMethodAgent(bool supportPhysicalKbd); + + // the message from IMSA + void OnInitialInput(Message* msg); + void OnStartInput(Message* msg); + void OnStopInput(Message* msg); + void OnSetKeyboardType(Message* msg); + void OnShowKeyboard(Message* msg); + void OnHideKeyboard(Message* msg); + + // the message from IMC + bool DispatchKey(Message* msg); + + // control inputwindow + void InitialInputWindow(); + void ShowInputWindow(); + void DissmissInputWindow(); + }; +} +} +#endif // FM_IMMS_PROJECT_INPUTMETHODABILITY_H \ No newline at end of file diff --git a/frameworks/inputmethod_ability/include/input_method_agent_proxy.h b/frameworks/inputmethod_ability/include/input_method_agent_proxy.h new file mode 100644 index 00000000..038f3aba --- /dev/null +++ b/frameworks/inputmethod_ability/include/input_method_agent_proxy.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2021 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 FM_IMC_PROJECT_INPUTMETHODAGENTPROXY_H +#define FM_IMC_PROJECT_INPUTMETHODAGENTPROXY_H + +#include "iremote_proxy.h" +#include "i_input_method_agent.h" + +namespace OHOS { +namespace MiscServices { + class InputMethodAgentProxy : public IRemoteProxy { + public: + explicit InputMethodAgentProxy(const sptr &object); + ~InputMethodAgentProxy() = default; + DISALLOW_COPY_AND_MOVE(InputMethodAgentProxy); + + int32_t DispatchKey(int32_t key, int32_t status) override; + private: + static inline BrokerDelegator delegator_; + }; +} +} +#endif // FM_IMC_PROJECT_INPUTMETHODAGENTPROXY_H \ No newline at end of file diff --git a/frameworks/inputmethod_ability/include/input_method_agent_stub.h b/frameworks/inputmethod_ability/include/input_method_agent_stub.h new file mode 100644 index 00000000..b477e82f --- /dev/null +++ b/frameworks/inputmethod_ability/include/input_method_agent_stub.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2021 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 FM_IMC_PROJECT_INPUTMETHODAGENTSTUB_H +#define FM_IMC_PROJECT_INPUTMETHODAGENTSTUB_H + +#include "iremote_stub.h" +#include "message_parcel.h" +#include "message_option.h" +#include "i_input_method_agent.h" +#include "message_handler.h" + +namespace OHOS { +namespace MiscServices { + class InputMethodAgentStub : public IRemoteStub { + public: + explicit InputMethodAgentStub(); + virtual ~InputMethodAgentStub(); + virtual int32_t OnRemoteRequest(uint32_t code, + MessageParcel &data, + MessageParcel &reply, + MessageOption &option) override; + virtual int32_t DispatchKey(int32_t key, int32_t status) override; + void SetMessageHandler(MessageHandler* msgHandler); + private: + MessageHandler* msgHandler_; + }; +} +} +#endif // FM_IMC_PROJECT_INPUTMETHODAGENTSTUB_H \ No newline at end of file diff --git a/frameworks/inputmethod_ability/include/input_method_core_proxy.h b/frameworks/inputmethod_ability/include/input_method_core_proxy.h new file mode 100644 index 00000000..63db0e0f --- /dev/null +++ b/frameworks/inputmethod_ability/include/input_method_core_proxy.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2021 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 FM_IMC_PROJECT_INPUTMETHODCOREPROXY_H +#define FM_IMC_PROJECT_INPUTMETHODCOREPROXY_H + +#include "iremote_proxy.h" +#include "iremote_object.h" +#include "message_parcel.h" +#include "message_option.h" +#include "i_input_method_core.h" +#include "i_input_control_channel.h" +#include "i_input_data_channel.h" +#include "input_attribute.h" + +namespace OHOS { +namespace MiscServices { + class InputMethodCoreProxy : public IRemoteProxy { + public: + explicit InputMethodCoreProxy(const sptr& object); + ~InputMethodCoreProxy(); + + DISALLOW_COPY_AND_MOVE(InputMethodCoreProxy); + + virtual int32_t initializeInput(sptr& startInputToken, int32_t displayId, + sptr& inputControlChannel) override; + virtual bool startInput(const sptr& inputDataChannel, + const InputAttribute& editorAttribute, + bool supportPhysicalKbd) override; + virtual int32_t stopInput() override; + virtual bool showKeyboard(int32_t flags) override; + virtual bool hideKeyboard(int32_t flags) override; + virtual int32_t setKeyboardType(const KeyboardType& type) override; + virtual int32_t getKeyboardWindowHeight(int32_t * retHeight) override; + + private: + static inline BrokerDelegator delegator_; + }; +} +} +#endif // FM_IMC_PROJECT_INPUTMETHODCOREPROXY_H \ No newline at end of file diff --git a/frameworks/inputmethod_ability/include/input_method_core_stub.h b/frameworks/inputmethod_ability/include/input_method_core_stub.h new file mode 100644 index 00000000..acb47cd8 --- /dev/null +++ b/frameworks/inputmethod_ability/include/input_method_core_stub.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2021 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 FM_IMMS_PROJECT_INPUTCONTROLCHANNEL_SK_H +#define FM_IMMS_PROJECT_INPUTCONTROLCHANNEL_SK_H + +#include "iremote_broker.h" +#include "iremote_stub.h" +#include "i_input_method_agent.h" +#include "input_channel.h" +#include +#include +#include +#include "message_parcel.h" +#include "input_attribute.h" +#include "i_input_data_channel.h" +#include "i_input_method_core.h" +#include "i_input_control_channel.h" +#include "keyboard_type.h" +#include "message_handler.h" + +namespace OHOS { +namespace MiscServices { + class InputMethodCoreStub : public IRemoteStub { + public: + DISALLOW_COPY_AND_MOVE(InputMethodCoreStub); + explicit InputMethodCoreStub(int userId); + virtual ~InputMethodCoreStub(); + virtual int OnRemoteRequest(uint32_t code, + MessageParcel &data, + MessageParcel &reply, + MessageOption &option) override; + + virtual int32_t initializeInput(sptr& startInputToken, int32_t displayId, + sptr& inputControlChannel) override; + virtual bool startInput(const sptr& inputDataChannel, + const InputAttribute& editorAttribute, + bool supportPhysicalKbd) override; + virtual int32_t stopInput() override; + virtual bool showKeyboard(int32_t flags) override; + virtual bool hideKeyboard(int32_t flags)override; + virtual int32_t setKeyboardType(const KeyboardType& type) override; + virtual int32_t getKeyboardWindowHeight(int32_t * retHeight) override; + void SetMessageHandler(MessageHandler* msgHandler); + + private: + int userId_; + MessageHandler* msgHandler_; + }; +} +} +#endif // FM_IMMS_PROJECT_INPUTCONTROLCHANNEL_SK_H diff --git a/frameworks/inputmethod_ability/src/event_target.cpp b/frameworks/inputmethod_ability/src/event_target.cpp new file mode 100644 index 00000000..e0f89960 --- /dev/null +++ b/frameworks/inputmethod_ability/src/event_target.cpp @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2021 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 "event_target.h" + +#include "securec.h" + +#include "utils/log.h" +#include "input_method_ability.h" +#define LISTENER_TYPTE_MAX_LENGTH 64 +namespace OHOS { +namespace MiscServices { + struct EventListener { + char type[LISTENER_TYPTE_MAX_LENGTH] = { 0 }; + bool isOnce = false; + napi_ref handlerRef = nullptr; + EventListener* back = nullptr; + EventListener* next = nullptr; + }; + EventTarget::EventTarget(napi_env env, napi_value thisVar) { + IMSA_HILOGI("EventTarget::EventTarget"); + env_ = env; + first_ = last_ = nullptr; + thisVarRef_ = nullptr; + napi_create_reference(env, thisVar, 1, &thisVarRef_); + } + + EventTarget::~EventTarget() { + EventListener* temp = nullptr; + for (EventListener* i = first_; i != nullptr; i = temp) { + temp = i->next; + if (i == first_) { + first_ = first_->next; + } else if (i == last_) { + last_ = last_->back; + } else { + i->next->back = i->back; + i->back->next = i->next; + } + napi_delete_reference(env_, i->handlerRef); + delete i; + } + napi_delete_reference(env_, thisVarRef_); + } + + void EventTarget::On(const char* type, napi_value handler) + { + IMSA_HILOGI("EventTarget::On"); + auto tmp = new EventListener(); + + if (strncpy_s(tmp->type, LISTENER_TYPTE_MAX_LENGTH, type, strlen(type)) == -1) { + delete tmp; + tmp = nullptr; + return; + } + + if (first_ == nullptr) { + first_ = last_ = tmp; + } else { + last_->next = tmp; + last_->next->back = last_; + last_ = last_->next; + } + last_->isOnce = false; + napi_create_reference(env_, handler, 1, &last_->handlerRef); + } + + void EventTarget::Once(const char* type, napi_value handler) + { + IMSA_HILOGI("EventTarget::Once"); + auto tmp = new EventListener(); + + if (strncpy_s(tmp->type, LISTENER_TYPTE_MAX_LENGTH, type, strlen(type)) == -1) { + delete tmp; + tmp = nullptr; + return; + } + + if (first_ == nullptr) { + first_ = last_ = tmp; + } else { + last_->next = tmp; + last_->next->back = last_; + last_ = last_->next; + } + last_->isOnce = true; + napi_create_reference(env_, handler, 1, &last_->handlerRef); + } + + void EventTarget::Off(const char* type, napi_value handler) + { + IMSA_HILOGI("EventTarget::Off"); + napi_handle_scope scope = nullptr; + napi_open_handle_scope(env_, &scope); + if (scope == nullptr) { + HILOG_ERROR("scope is nullptr"); + return; + } + + EventListener* temp = nullptr; + for (EventListener* eventListener = first_; eventListener != nullptr; eventListener = temp) { + temp = eventListener->next; + bool isEquals = false; + napi_value handlerTemp = nullptr; + napi_get_reference_value(env_, eventListener->handlerRef, &handlerTemp); + napi_strict_equals(env_, handlerTemp, handler, &isEquals); + if (strcmp(eventListener->type, type) == 0 && isEquals) { + if (eventListener == first_) { + first_ = first_->next; + } else if (eventListener == last_) { + last_ = last_->back; + } else { + eventListener->next->back = eventListener->back; + eventListener->back->next = eventListener->next; + } + napi_delete_reference(env_, eventListener->handlerRef); + delete eventListener; + eventListener = nullptr; + break; + } + } + napi_close_handle_scope(env_, scope); + } + + void EventTarget::Off(const char* type) + { + IMSA_HILOGI("EventTarget::Off"); + EventListener* temp = nullptr; + for (EventListener* eventListener = first_; eventListener != nullptr; eventListener = temp) { + temp = eventListener->next; + if (strcmp(eventListener->type, type) == 0) { + if (eventListener == first_) { + first_ = first_->next; + } else if (eventListener == last_) { + last_ = last_->back; + } else { + eventListener->next->back = eventListener->back; + eventListener->back->next = eventListener->next; + } + napi_delete_reference(env_, eventListener->handlerRef); + delete eventListener; + eventListener = nullptr; + } + } + } + + void EventTarget::Emit(const char* type, Event* event) + { + IMSA_HILOGI("EventTarget::Emit"); + napi_handle_scope scope = nullptr; + napi_open_handle_scope(env_, &scope); + + napi_value thisVar = nullptr; + napi_get_reference_value(env_, thisVarRef_, &thisVar); + for (EventListener* eventListener = first_; eventListener != nullptr; eventListener = eventListener->next) { + if (strcmp(eventListener->type, type) == 0) { + napi_value jsEvent = event ? event->ToJsObject() : nullptr; + napi_value handler = nullptr; + napi_value result = nullptr; + napi_get_reference_value(env_, eventListener->handlerRef, &handler); + napi_call_function(env_, thisVar, handler, jsEvent ? 1 : 0, jsEvent ? &jsEvent : nullptr, &result); + if (eventListener->isOnce) { + Off(type, handler); + } + } + } + napi_close_handle_scope(env_, scope); + } +} +} \ No newline at end of file diff --git a/frameworks/inputmethod_ability/src/input_method_ability.cpp b/frameworks/inputmethod_ability/src/input_method_ability.cpp new file mode 100644 index 00000000..6c144ca3 --- /dev/null +++ b/frameworks/inputmethod_ability/src/input_method_ability.cpp @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2021 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 "input_method_ability.h" +#include "input_method_core_proxy.h" +#include "input_method_core_stub.h" +#include "input_method_agent_proxy.h" +#include "input_method_agent_stub.h" +#include "message_parcel.h" +#include "event_target.h" +#include "iservice_registry.h" +#include "system_ability_definition.h" +#include "input_data_channel_proxy.h" + +namespace OHOS { +namespace MiscServices { + using namespace MessageID; + sptr InputMethodAbility::instance_; + std::mutex InputMethodAbility::instanceLock_; + + InputMethodAbility::InputMethodAbility() { + Initialize(); + OnConnect(); + } + + InputMethodAbility::~InputMethodAbility() { + if (msgHandler != nullptr) { + delete msgHandler; + } + } + + sptr InputMethodAbility::GetInstance() { + IMSA_HILOGI("InputMethodAbility::GetInstance"); + if (instance_ == nullptr) { + std::lock_guard autoLock(instanceLock_); + if (instance_ == nullptr) { + IMSA_HILOGI("InputMethodAbility::GetInstance need new IMA"); + instance_ = new InputMethodAbility(); + } + } + return instance_; + } + + sptr InputMethodAbility::GetImsaProxy() { + IMSA_HILOGI("InputMethodAbility::GetImsaProxy"); + sptr systemAbilityManager = + SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (systemAbilityManager == nullptr) { + IMSA_HILOGI("InputMethodAbility::GetImsaProxy systemAbilityManager is nullptr"); + return nullptr; + } + + auto systemAbility = systemAbilityManager->GetSystemAbility(INPUT_METHOD_SYSTEM_ABILITY_ID, ""); + if (systemAbility == nullptr) { + IMSA_HILOGI("InputMethodAbility::GetImsaProxy systemAbility is nullptr"); + return nullptr; + } + + sptr iface = new InputMethodSystemAbilityProxy(systemAbility); + return iface; + } + + sptr InputMethodAbility::OnConnect() { + IMSA_HILOGI("InputMethodAbility::OnConnect"); + mImms = GetImsaProxy(); + sptr stub = new InputMethodCoreStub(0); + stub->SetMessageHandler(msgHandler); + sptr stub2=stub; + if (mImms != nullptr) { + mImms->setInputMethodCore(stub2); + } + IMSA_HILOGI("InputMethodAbility::OnConnect() mImms is nullptr"); + return nullptr; + } + + void InputMethodAbility::Initialize() { + IMSA_HILOGI("InputMethodAbility::Initialize"); + InitialInputWindow(); + msgHandler = new MessageHandler(); + workThreadHandler = std::thread([this]{WorkThread();}); + } + + void InputMethodAbility::setEventTarget(sptr &eventTarget) { + IMSA_HILOGI("InputMethodAbility::setEventTarget"); + eventTarget_ = eventTarget; + } + + void InputMethodAbility::WorkThread() { + while(1){ + Message* msg = msgHandler->GetMessage(); + switch(msg->msgId_) { + case MSG_ID_INITIALIZE_INPUT: { + OnInitialInput(msg); + break; + } + + case MSG_ID_START_INPUT: { + OnStartInput(msg); + break; + } + + case MSG_ID_STOP_INPUT: { + OnStopInput(msg); + break; + } + + case MSG_ID_SHOW_KEYBOARD: { + OnShowKeyboard(msg); + break; + } + + case MSG_ID_HIDE_KEYBOARD: { + OnHideKeyboard(msg); + break; + } + + case MSG_ID_DISPATCH_KEY : { + DispatchKey(msg); + break; + } + + default:{ + break; + } + } + delete msg; + } + } + + void InputMethodAbility::OnInitialInput(Message* msg) { + IMSA_HILOGI("InputMethodAbility::OnInitialInput"); + MessageParcel* data = msg->msgContent_; + displyId = data->ReadInt32(); + sptr channelObject = data->ReadRemoteObject(); + if (channelObject == nullptr) { + IMSA_HILOGI("InputMethodAbility::OnInitialInput channelObject is nullptr"); + return; + } + sptr channelProxy=new InputControlChannelProxy(channelObject); + inputControlChannel = channelProxy; + if(inputControlChannel == nullptr) { + IMSA_HILOGI("InputMethodAbility::OnInitialInput inputControlChannel is nullptr"); + return; + } + InitialInputWindow(); + } + + void InputMethodAbility::OnStartInput(Message* msg) { + IMSA_HILOGI("InputMethodAbility::OnStartInput"); + MessageParcel* data = msg->msgContent_; + sptr channalProxy = new InputDataChannelProxy(data->ReadRemoteObject()); + inputDataChannel = channalProxy; + if(inputDataChannel == nullptr) { + IMSA_HILOGI("InputMethodAbility::OnStartInput inputDataChannel is nullptr"); + } + editorAttribute = data->ReadParcelable(); + if(editorAttribute == nullptr) { + IMSA_HILOGI("InputMethodAbility::OnStartInput editorAttribute is nullptr"); + } + mSupportPhysicalKbd = data->ReadBool(); + + CreateInputMethodAgent(mSupportPhysicalKbd); + if (inputControlChannel != nullptr) { + IMSA_HILOGI("InputMethodAbility::OnStartInput inputControlChannel is not nullptr"); + inputControlChannel->onAgentCreated(inputMethodAgent, nullptr); + } + } + + void InputMethodAbility::OnShowKeyboard(Message* msg) { + IMSA_HILOGI("InputMethodAbility::OnShowKeyboard"); + ShowInputWindow(); + } + + void InputMethodAbility::OnHideKeyboard(Message* msg) { + IMSA_HILOGI("InputMethodAbility::OnHideKeyboard"); + DissmissInputWindow(); + } + + void InputMethodAbility::OnStopInput(Message* msg) { + IMSA_HILOGI("InputMethodAbility::OnStopInput"); + if (writeInputChannel != nullptr) { + delete writeInputChannel; + } + } + + bool InputMethodAbility::DispatchKey(Message* msg) { + IMSA_HILOGI("InputMethodAbility::DispatchKey"); + MessageParcel* data = msg->msgContent_; + int32_t key = data->ReadInt32(); + int32_t status = data->ReadInt32(); + IMSA_HILOGI("InputMethodAbility::DispatchKey: key = %{public}d, status = %{public}d", key, status); + return true; + } + + void InputMethodAbility::CreateInputMethodAgent(bool supportPhysicalKbd) { + IMSA_HILOGI("InputMethodAbility::CreateInputMethodAgent"); + sptr inputMethodAgentStub(new InputMethodAgentStub()); + inputMethodAgentStub->SetMessageHandler(msgHandler); + inputMethodAgent = sptr(new InputMethodAgentProxy(inputMethodAgentStub)); + } + + void InputMethodAbility::InitialInputWindow() { + IMSA_HILOGI("InputMethodAbility::InitialInputWindow"); + } + + void InputMethodAbility::ShowInputWindow() { + IMSA_HILOGI("InputMethodAbility::ShowInputWindow"); + eventTarget_->Emit("keyboardShow",nullptr); + } + + void InputMethodAbility::DissmissInputWindow() { + IMSA_HILOGI("InputMethodAbility::DissmissInputWindow"); + eventTarget_->Emit("keyboardHide",nullptr); + } + + bool InputMethodAbility::InsertText(const std::string text) { + IMSA_HILOGI("InputMethodAbility::InsertText"); + if (inputDataChannel == nullptr){ + IMSA_HILOGI("InputMethodAbility::InsertText inputDataChanel is nullptr"); + return false; + } + + return inputDataChannel->InsertText(Utils::to_utf16(text)); + } + + void InputMethodAbility::DeleteBackward(int32_t length) { + IMSA_HILOGI("InputMethodAbility::DeleteBackward"); + if (inputDataChannel == nullptr){ + IMSA_HILOGI("InputMethodAbility::DeleteBackward inputDataChanel is nullptr"); + return; + } + inputDataChannel->DeleteBackward(length); + } + + void InputMethodAbility::HideKeyboardSelf() { + IMSA_HILOGI("InputMethodAbility::HideKeyboardSelf"); + inputControlChannel->hideKeyboardSelf(1); + } +} +} \ No newline at end of file diff --git a/frameworks/inputmethod_ability/src/input_method_agent_proxy.cpp b/frameworks/inputmethod_ability/src/input_method_agent_proxy.cpp new file mode 100644 index 00000000..5155eff8 --- /dev/null +++ b/frameworks/inputmethod_ability/src/input_method_agent_proxy.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2021 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 "input_method_agent_proxy.h" + +namespace OHOS { +namespace MiscServices { + using namespace ErrorCode; + InputMethodAgentProxy::InputMethodAgentProxy(const sptr &object) : IRemoteProxy(object) { + } + + int32_t InputMethodAgentProxy::DispatchKey(int32_t key, int32_t status) { + IMSA_HILOGI("InputMethodAgentProxy::DispatchKey key = %{public}d, status = %{public}d", key, status); + MessageParcel data, reply; + MessageOption option; + if (!data.WriteInterfaceToken(GetDescriptor())) { + IMSA_HILOGI("InputMethodAgentProxy::DispatchKey descriptor is not match"); + return ERROR_EX_PARCELABLE; + } + + data.WriteInt32(key); + data.WriteInt32(status); + + auto ret = Remote()->SendRequest(DISPATCH_KEY, data, reply, option); + return ret; + } +} +} diff --git a/frameworks/inputmethod_ability/src/input_method_agent_stub.cpp b/frameworks/inputmethod_ability/src/input_method_agent_stub.cpp new file mode 100644 index 00000000..980e9475 --- /dev/null +++ b/frameworks/inputmethod_ability/src/input_method_agent_stub.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2021 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 "input_method_agent_stub.h" +#include "global.h" +#include "message_handler.h" +#include "message.h" + +namespace OHOS { +namespace MiscServices { + using namespace MessageID; + + InputMethodAgentStub::InputMethodAgentStub() { + } + + InputMethodAgentStub::~InputMethodAgentStub() { + } + + int32_t InputMethodAgentStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) { + IMSA_HILOGI("InputMethodAgentStub::OnRemoteRequest code = %{public}d", code); + auto descriptorToken = data.ReadInterfaceToken(); + if (descriptorToken != GetDescriptor()) { + return ErrorCode::ERROR_STATUS_UNKNOWN_TRANSACTION; + } + + switch (code) { + case DISPATCH_KEY: { + int32_t key = data.ReadInt32(); + int32_t status = data.ReadInt32(); + int32_t result = DispatchKey(key, status); + if (result == ErrorCode::NO_ERROR) { + reply.WriteNoException(); + } else { + reply.WriteInt32(result); + } + return result; + } + default: { + return IRemoteStub::OnRemoteRequest(code, data, reply, option); + } + } + return ErrorCode::NO_ERROR; + } + + int32_t InputMethodAgentStub::DispatchKey(int32_t key, int32_t status) { + IMSA_HILOGI("InputMethodAgentStub::DispatchKey key = %{public}d, status = %{public}d", key, status); + if (msgHandler_ == nullptr) { + return ErrorCode::ERROR_NULL_POINTER; + } + MessageParcel* data = new MessageParcel(); + data->WriteInt32(key); + data->WriteInt32(status); + Message* message = new Message(MessageID::MSG_ID_DISPATCH_KEY, data); + msgHandler_->SendMessage(message); + return ErrorCode::NO_ERROR; + } + + void InputMethodAgentStub::SetMessageHandler(MessageHandler* msgHandler) { + msgHandler_ = msgHandler; + } +} +} \ No newline at end of file diff --git a/frameworks/inputmethod_ability/src/input_method_core_proxy.cpp b/frameworks/inputmethod_ability/src/input_method_core_proxy.cpp new file mode 100644 index 00000000..b6cf309b --- /dev/null +++ b/frameworks/inputmethod_ability/src/input_method_core_proxy.cpp @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2021 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 "input_method_core_proxy.h" +#include "message_parcel.h" +#include "message_option.h" +#include "input_attribute.h" + +namespace OHOS { +namespace MiscServices { + InputMethodCoreProxy::InputMethodCoreProxy(const OHOS::sptr &impl) : IRemoteProxy(impl) { + } + + InputMethodCoreProxy::~InputMethodCoreProxy() = default; + + int32_t InputMethodCoreProxy::initializeInput(sptr &startInputToken, int32_t displayId, sptr &inputControlChannel) { + IMSA_HILOGI("InputMethodCoreProxy::initializeInput"); + if (startInputToken == nullptr) { + IMSA_HILOGI("InputMethodCoreProxy::initializeInput startInputToken is nullptr"); + } + + if (inputControlChannel == nullptr) { + IMSA_HILOGI("InputMethodCoreProxy::initializeInput inputControlChannel is nullptr"); + } + IMSA_HILOGI("InputMethodCoreProxy::initializeInput displayId = %{public}d", displayId); + MessageParcel data, reply; + data.WriteInterfaceToken(GetDescriptor()); + data.WriteInt32(displayId); + sptr channelObject = inputControlChannel->AsObject(); + if (channelObject == nullptr) { + IMSA_HILOGI("InputMethodCoreProxy::initializeInput channelObject is nullptr"); + } + bool wor = data.WriteRemoteObject(channelObject); + if (wor) { + IMSA_HILOGI("InputMethodCoreProxy::initializeInput Success to write inputControlChannel"); + } else { + IMSA_HILOGI("InputMethodCoreProxy::initializeInput Failed to write inputControlChannel"); + } + MessageOption option { MessageOption::TF_SYNC }; + int32_t status = Remote()->SendRequest(INITIALIZE_INPUT, data, reply, option); + if (status != ErrorCode::NO_ERROR) { + IMSA_HILOGI("InputMethodCoreProxy::initializeInput status = %{public}d", status); + return status; + } + int32_t code = reply.ReadException(); + return code; + } + + bool InputMethodCoreProxy::startInput(const sptr &inputDataChannel, const InputAttribute& editorAttribute, bool supportPhysicalKbd) { + IMSA_HILOGI("InputMethodCoreProxy::startInput"); + if (inputDataChannel == nullptr) { + IMSA_HILOGI("InputMethodCoreProxy::startInput inputDataChannel is nullptr"); + } + + MessageParcel data; + if (!(data.WriteInterfaceToken(GetDescriptor()) + && data.WriteRemoteObject(inputDataChannel->AsObject()) + && data.WriteParcelable(&editorAttribute) + && data.WriteBool(supportPhysicalKbd))) { + IMSA_HILOGI("InputMethodCoreProxy::startInput write error"); + return false; + } + MessageParcel reply; + MessageOption option { MessageOption::TF_SYNC }; + + int32_t status = Remote()->SendRequest(START_INPUT, data, reply, option); + if (status != ErrorCode::NO_ERROR) { + IMSA_HILOGI("InputMethodCoreProxy::startInput status = %{public}d", status); + return false; + } + + int32_t code = reply.ReadException(); + return code == ErrorCode::NO_ERROR; + } + + int32_t InputMethodCoreProxy::stopInput() { + IMSA_HILOGI("InputMethodCoreProxy::stopInput"); + MessageParcel data, reply; + data.WriteInterfaceToken(GetDescriptor()); + MessageOption option { MessageOption::TF_SYNC }; + int32_t status = Remote()->SendRequest(STOP_INPUT, data, reply, option); + if (status != ErrorCode::NO_ERROR) { + IMSA_HILOGI("InputMethodCoreProxy::stopInput status = %{public}d",status); + return status; + } + int code = reply.ReadException(); + if (code != ErrorCode::NO_ERROR) { + IMSA_HILOGI("InputMethodCoreProxy::stopInput code = %{public}d",code); + return code; + } + return reply.ReadInt32(); + } + + bool InputMethodCoreProxy::showKeyboard(int32_t flags) { + IMSA_HILOGI("InputMethodCoreProxy::showKeyboard"); + auto remote = Remote(); + if (remote == nullptr){ + IMSA_HILOGI("InputMethodCoreProxy::showKeyboard remote is nullptr"); + return false; + } + + MessageParcel data; + if (!(data.WriteInterfaceToken(GetDescriptor()) && data.WriteInt32(flags))) { + return false; + } + MessageParcel reply; + MessageOption option{ MessageOption::TF_SYNC }; + + int32_t res = remote->SendRequest(SHOW_KEYBOARD, data, reply, option); + if (res != ErrorCode::NO_ERROR) { + return false; + } + return true; + } + + bool InputMethodCoreProxy::hideKeyboard(int32_t flags) { + IMSA_HILOGI("InputMethodCoreProxy::hideKeyboard"); + auto remote = Remote(); + if (remote == nullptr) { + return false; + } + + MessageParcel data; + if (!(data.WriteInterfaceToken(GetDescriptor()) && data.WriteInt32(flags))) { + return false; + } + MessageParcel reply; + MessageOption option{ MessageOption::TF_SYNC }; + + int32_t res = remote->SendRequest(HIDE_KEYBOARD, data, reply, option); + if (res != ErrorCode::NO_ERROR) { + return false; + } + return true; + } + + int32_t InputMethodCoreProxy::setKeyboardType(const KeyboardType& type) { + IMSA_HILOGI("InputMethodCoreProxy::setKeyboardType"); + MessageParcel data, reply; + data.WriteInterfaceToken(GetDescriptor()); + data.WriteParcelable(&type); + MessageOption option{ MessageOption::TF_SYNC }; + int32_t status = Remote()->SendRequest(SET_KEYBOARD_TYPE, data, reply, option); + if (status != ErrorCode::NO_ERROR) { + return status; + } + int32_t code = reply.ReadException(); + return code; + } + + int32_t InputMethodCoreProxy::getKeyboardWindowHeight(int32_t * retHeight) { + IMSA_HILOGI("InputMethodCoreProxy::getKeyboardWindowHeight"); + MessageParcel data, reply; + data.WriteInterfaceToken(GetDescriptor()); + MessageOption option { MessageOption::TF_SYNC }; + int32_t status = Remote()->SendRequest(GET_KEYBOARD_WINDOW_HEIGHT, data, reply, option); + if (status != ErrorCode::NO_ERROR) { + return status; + } + int32_t code = reply.ReadException(); + if (code != 0) { + return code; + } + *retHeight = reply.ReadInt32(); + return ErrorCode::NO_ERROR; + } +} +} diff --git a/frameworks/inputmethod_ability/src/input_method_core_stub.cpp b/frameworks/inputmethod_ability/src/input_method_core_stub.cpp new file mode 100644 index 00000000..07c39fae --- /dev/null +++ b/frameworks/inputmethod_ability/src/input_method_core_stub.cpp @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2021 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 "message_handler.h" +#include "i_input_data_channel.h" +#include "input_method_core_stub.h" +#include "input_channel.h" +#include "i_input_method_proxy.h" +#include "platform.h" +#include "message_parcel.h" +#include "input_control_channel_proxy.h" + +namespace OHOS { +namespace MiscServices { + using namespace MessageID; + /** + * param userId the id of the user to whom the object is linking + * @param userId + */ + InputMethodCoreStub::InputMethodCoreStub(int userId) { + userId_ = userId; + } + + InputMethodCoreStub::~InputMethodCoreStub() { + } + + int32_t InputMethodCoreStub::OnRemoteRequest(uint32_t code, MessageParcel & data, MessageParcel & reply, MessageOption & option) { + IMSA_HILOGI("InputMethodCoreStub::OnRemoteRequest"); + auto descriptorToken = data.ReadInterfaceToken(); + if (descriptorToken != GetDescriptor()) { + IMSA_HILOGI("InputMethodCoreStub::OnRemoteRequest descriptorToken is invalid"); + return ErrorCode::ERROR_STATUS_UNKNOWN_TRANSACTION; + } + switch (code) { + case INITIALIZE_INPUT: { + sptr startInputToken = nullptr; + int32_t displayId = data.ReadInt32(); + IMSA_HILOGI("InputMethodCoreStub::OnRemoteRequest displayId = %{public}d", displayId); + sptr channelObject = data.ReadRemoteObject(); + if (channelObject == nullptr) { + IMSA_HILOGI("InputMethodCoreStub::OnRemoteRequest channelObject is nullptr"); + } + sptr inputControlChannel = new InputControlChannelProxy(channelObject); + if (inputControlChannel == nullptr) { + IMSA_HILOGI("InputMethodCoreStub::OnRemoteRequest inputControlChannel is nullptr"); + } + + initializeInput(startInputToken, displayId, inputControlChannel); + reply.WriteNoException(); + break; + } + case START_INPUT: { + sptr inputDataChannel = iface_cast(data.ReadRemoteObject()); + InputAttribute* editorAttribute = data.ReadParcelable(); + bool supportPhysicalKbd = data.ReadBool(); + + if (inputDataChannel == nullptr) { + IMSA_HILOGI("InputMethodCoreStub::OnRemoteRequest START_INPUT inputDataChannel is nulltpr"); + } + startInput(inputDataChannel, *editorAttribute, supportPhysicalKbd); + reply.WriteNoException(); + break; + } + case STOP_INPUT: { + stopInput(); + reply.WriteNoException(); + break; + } + case SHOW_KEYBOARD: { + int32_t flags = data.ReadInt32(); + showKeyboard(flags); + reply.WriteNoException(); + break; + } + case HIDE_KEYBOARD: { + int32_t flags = data.ReadInt32(); + hideKeyboard(flags); + reply.WriteNoException(); + break; + } + case SET_KEYBOARD_TYPE: { + KeyboardType* type = data.ReadParcelable(); + setKeyboardType(*type); + reply.WriteNoException(); + break; + } + case GET_KEYBOARD_WINDOW_HEIGHT: { + int32_t* retHeight = nullptr; + getKeyboardWindowHeight(retHeight); + reply.WriteNoException(); + break; + } + default: { + return IRemoteStub::OnRemoteRequest(code, data, reply, option); + } + } + return NO_ERROR; + } + + int32_t InputMethodCoreStub::initializeInput(sptr& startInputToken, int32_t displayId, sptr& inputControlChannel) { + IMSA_HILOGI("InputMethodCoreStub::initializeInput"); + if (msgHandler_==nullptr) { + return ErrorCode::ERROR_NULL_POINTER; + } + + if (startInputToken == nullptr) { + IMSA_HILOGI("InputMethodCoreStub::initializeInput startInputToken is nullptr"); + } + + MessageParcel* data = new MessageParcel(); + data->WriteInt32(displayId); + if (inputControlChannel != nullptr) { + IMSA_HILOGI("InputMethodCoreStub::initializeInput. inputControlChannel is not nullptr"); + data->WriteRemoteObject(inputControlChannel->AsObject()); + } + Message* msg = new Message(MessageID::MSG_ID_INITIALIZE_INPUT, data); + msgHandler_->SendMessage(msg); + return ErrorCode::NO_ERROR; + } + + bool InputMethodCoreStub::startInput(const sptr& inputDataChannel, const InputAttribute& editorAttribute, bool supportPhysicalKbd) { + IMSA_HILOGI("InputMethodCoreStub::startInput"); + if (msgHandler_ == nullptr) { + return ErrorCode::ERROR_NULL_POINTER; + } + MessageParcel* data = new MessageParcel(); + if (inputDataChannel !=nullptr) { + IMSA_HILOGI("InputMethodCoreStub::startInput inputDataChannel is not nullptr"); + data->WriteRemoteObject(inputDataChannel->AsObject()); + } + data->WriteParcelable(&editorAttribute); + data->WriteBool(supportPhysicalKbd); + Message* msg = new Message(MessageID::MSG_ID_START_INPUT, data); + msgHandler_->SendMessage(msg); + return true; + } + + int32_t InputMethodCoreStub::stopInput() { + IMSA_HILOGI("InputMethodCoreStub::stopInput"); + if (msgHandler_ == nullptr) { + return ErrorCode::ERROR_NULL_POINTER; + } + MessageParcel* data = new MessageParcel(); + Message* msg = new Message(MessageID::MSG_ID_STOP_INPUT, data); + msgHandler_->SendMessage(msg); + return ErrorCode::NO_ERROR; + } + + bool InputMethodCoreStub::showKeyboard(int32_t flags) { + IMSA_HILOGI("InputMethodCoreStub::showKeyboard"); + if (msgHandler_==nullptr) { + return false; + } + MessageParcel* data = new MessageParcel(); + data->WriteInt32(userId_); + data->WriteInt32(flags); + + Message* msg = new Message(MessageID::MSG_ID_SHOW_KEYBOARD, data); + msgHandler_->SendMessage(msg); + return true; + } + + bool InputMethodCoreStub::hideKeyboard(int32_t flags) { + IMSA_HILOGI("InputMethodCoreStub::hideKeyboard"); + if (msgHandler_==nullptr) { + return ErrorCode::ERROR_NULL_POINTER; + } + MessageParcel* data = new MessageParcel(); + data->WriteInt32(userId_); + data->WriteInt32(flags); + + Message* msg = new Message(MessageID::MSG_ID_HIDE_KEYBOARD, data); + msgHandler_->SendMessage(msg); + return true; + } + + int32_t InputMethodCoreStub::setKeyboardType(const KeyboardType& type) { + IMSA_HILOGI("InputMethodCoreStub::setKeyboardType"); + if (msgHandler_==nullptr) { + return ErrorCode::ERROR_NULL_POINTER; + } + MessageParcel* data = new MessageParcel(); + data->WriteParcelable(&type); + + Message* msg = new Message(MessageID::MSG_ID_SET_KEYBOARD_TYPE, data); + msgHandler_->SendMessage(msg); + return ErrorCode::NO_ERROR; + } + + int32_t InputMethodCoreStub::getKeyboardWindowHeight(int32_t * retHeight) { + IMSA_HILOGI("InputMethodCoreStub::getKeyboardWindowHeight"); + if (msgHandler_==nullptr) { + return ErrorCode::ERROR_NULL_POINTER; + } + MessageParcel* data = new MessageParcel(); + + Message* msg = new Message(MessageID::MSG_ID_GET_KEYBOARD_WINDOW_HEIGHT, data); + msgHandler_->SendMessage(msg); + return ErrorCode::NO_ERROR; + } + + void InputMethodCoreStub::SetMessageHandler(MessageHandler* msgHandler) { + msgHandler_=msgHandler; + } +} +} \ No newline at end of file diff --git a/frameworks/inputmethod_controller/BUILD.gn b/frameworks/inputmethod_controller/BUILD.gn new file mode 100644 index 00000000..597d87b3 --- /dev/null +++ b/frameworks/inputmethod_controller/BUILD.gn @@ -0,0 +1,69 @@ +# Copyright (c) 2021 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. +import("//base/miscservices/inputmethod/inputmethod.gni") +import("//build/ohos.gni") + +config("inputmethod_client_native_config") { + visibility = [ ":*" ] + include_dirs = [ + "include", + "//utils/native/base/include", + ] +} + +config("inputmethod_client_native_public_config") { + visibility = [] + include_dirs = [ + "//base/miscservices/inputmethod/frameworks/inputmethod_controller/include", + "//base/miscservices/inputmethod/frameworks/inputmethod_ability/include", + "//foundation/communication/ipc/interfaces/innerkits/ipc_core/include", + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", + "//base/miscservices/inputmethod/services/include", + "//utils/native/base/include", + ] +} + +ohos_shared_library("inputmethod_client") { + sources = [ + "src/input_data_channel_stub.cpp", + "src/input_data_channel_proxy.cpp", + "src/input_client_proxy.cpp", + "src/input_client_stub.cpp", + "src/input_method_system_ability_proxy.cpp", + "src/input_method_controller.cpp", + ] + + deps = [ + "//utils/native/base:utils", + "//foundation/communication/ipc/interfaces/innerkits/ipc_core:ipc_core", + "//foundation/communication/ipc/interfaces/innerkits/ipc_single:ipc_single", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//base/miscservices/inputmethod/services:inputmethod_service", + "//base/miscservices/inputmethod/frameworks/inputmethod_ability:inputmethod_ability", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + ] + + configs = [ + ":inputmethod_client_native_config", + "//utils/native/base:utils_config", + ] + + public_configs = [ ":inputmethod_client_native_public_config" ] + + subsystem_name = "miscservices" + part_name = "inputmethod_native" +} \ No newline at end of file diff --git a/frameworks/inputmethod_controller/include/i_input_client.h b/frameworks/inputmethod_controller/include/i_input_client.h new file mode 100644 index 00000000..09438928 --- /dev/null +++ b/frameworks/inputmethod_controller/include/i_input_client.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2021 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 FM_IMMS_PROJECT_IINPUTCLIENT_H +#define FM_IMMS_PROJECT_IINPUTCLIENT_H + +#include "iremote_broker.h" +#include "i_input_method_agent.h" +#include "input_channel.h" +#include "global.h" + +/** + * brief Definition of interface IInputClient + * It defines the remote calls from input method management service to input client. + */ +namespace OHOS { +namespace MiscServices { + class IInputClient : public IRemoteBroker { + public: + enum { + ON_INPUT_READY = 0, + ON_INPUT_RELEASED , + SET_DISPLAY_MODE , + }; + + DECLARE_INTERFACE_DESCRIPTOR(u"ohos.miscservices.inputmethod.InputClient"); + + virtual int32_t onInputReady(int32_t retValue, const sptr& agent, const InputChannel* channel) = 0; + virtual int32_t onInputReleased(int32_t retValue) = 0; + virtual int32_t setDisplayMode(int32_t mode) = 0; + }; +} +} + +#endif // FM_IMMS_PROJECT_IINPUTCLIENT_H diff --git a/frameworks/inputmethod_controller/include/i_input_data_channel.h b/frameworks/inputmethod_controller/include/i_input_data_channel.h new file mode 100644 index 00000000..fc4270e2 --- /dev/null +++ b/frameworks/inputmethod_controller/include/i_input_data_channel.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2021 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 FM_IMMS_PROJECT_IINPUTDATACHANNEL_H +#define FM_IMMS_PROJECT_IINPUTDATACHANNEL_H +#include +#include "iremote_broker.h" +#include "global.h" + +/** + * brief Definition of interface IInputDataChannel + * It defines the remote calls from input method service to input client + */ +namespace OHOS { +namespace MiscServices { + class IInputDataChannel: public IRemoteBroker { + public: + enum { + INSERT_TEXT = 0, + DELETE_BACKWARD, + CLOSE, + }; + + DECLARE_INTERFACE_DESCRIPTOR(u"ohos.miscservices.inputmethod.IInputDataChannel"); + + virtual bool InsertText(const std::u16string& text) = 0; + virtual bool DeleteBackward(int32_t length) = 0; + virtual void Close() = 0; + }; +} +} +#endif // FM_IMMS_PROJECT_IINPUTDATACHANNEL_H diff --git a/frameworks/inputmethod_controller/include/input_client_proxy.h b/frameworks/inputmethod_controller/include/input_client_proxy.h new file mode 100644 index 00000000..8d0fb6cc --- /dev/null +++ b/frameworks/inputmethod_controller/include/input_client_proxy.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2021 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 FM_IMC_PROJECT_INPUTCLIENTPROXY_H +#define FM_IMC_PROJECT_INPUTCLIENTPROXY_H + +#include "iremote_proxy.h" +#include "i_input_client.h" + +namespace OHOS { +namespace MiscServices { + +class InputClientProxy : public IRemoteProxy +{ +public: + explicit InputClientProxy(const sptr &object); + ~InputClientProxy() = default; + DISALLOW_COPY_AND_MOVE(InputClientProxy); + + int32_t onInputReady(int32_t retValue, const sptr& agent, const InputChannel* channel) override; + int32_t onInputReleased(int32_t retValue) override; + int32_t setDisplayMode(int32_t mode) override; + +private: + static inline BrokerDelegator delegator_; +}; +} +} +#endif \ No newline at end of file diff --git a/frameworks/inputmethod_controller/include/input_client_stub.h b/frameworks/inputmethod_controller/include/input_client_stub.h new file mode 100644 index 00000000..8eddca28 --- /dev/null +++ b/frameworks/inputmethod_controller/include/input_client_stub.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2021 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 FM_IMC_PROJECT_INPUTCLIENTSTUB_H +#define FM_IMC_PROJECT_INPUTCLIENTSTUB_H + +#include "iremote_stub.h" +#include "i_input_client.h" +#include "message_handler.h" + +namespace OHOS { +namespace MiscServices { +class InputClientStub : public IRemoteStub { +public: + DISALLOW_COPY_AND_MOVE(InputClientStub); + int32_t OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + InputClientStub(); + ~InputClientStub(); + void SetHandler(MessageHandler* handler); + + int32_t onInputReady(int32_t retValue, const sptr& agent, const InputChannel* channel) override; + int32_t onInputReleased(int32_t retValue) override; + int32_t setDisplayMode(int32_t mode) override; +private: + MessageHandler* msgHandler = nullptr; +}; +} +} +#endif \ No newline at end of file diff --git a/frameworks/inputmethod_controller/include/input_data_channel_proxy.h b/frameworks/inputmethod_controller/include/input_data_channel_proxy.h new file mode 100644 index 00000000..db55eb4a --- /dev/null +++ b/frameworks/inputmethod_controller/include/input_data_channel_proxy.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2021 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 FM_IMC_PROJECT_INPUTDATACHANNELPROXY_H +#define FM_IMC_PROJECT_INPUTDATACHANNELPROXY_H + +#include "iremote_proxy.h" +#include "i_input_data_channel.h" + +namespace OHOS { +namespace MiscServices { + +class InputDataChannelProxy : public IRemoteProxy +{ +public: + explicit InputDataChannelProxy(const sptr &object); + ~InputDataChannelProxy() = default; + DISALLOW_COPY_AND_MOVE(InputDataChannelProxy); + + bool InsertText(const std::u16string& text) override; + bool DeleteBackward(int32_t length) override; + void Close() override; + +private: + static inline BrokerDelegator delegator_; +}; +} +} +#endif \ No newline at end of file diff --git a/frameworks/inputmethod_controller/include/input_data_channel_stub.h b/frameworks/inputmethod_controller/include/input_data_channel_stub.h new file mode 100644 index 00000000..aaefdec2 --- /dev/null +++ b/frameworks/inputmethod_controller/include/input_data_channel_stub.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2021 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 FM_IMC_PROJECT_INPUTDATACHANNELSTUB_H +#define FM_IMC_PROJECT_INPUTDATACHANNELSTUB_H + +#include "i_input_data_channel.h" +#include "iremote_stub.h" +#include "message_handler.h" + +namespace OHOS { +namespace MiscServices { +class InputDataChannelStub : public IRemoteStub { +public: + DISALLOW_COPY_AND_MOVE(InputDataChannelStub); + int32_t OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + InputDataChannelStub(); + ~InputDataChannelStub(); + void SetHandler(MessageHandler* handler); + + bool InsertText(const std::u16string& text) override; + bool DeleteBackward(int32_t length) override; + void Close() override; +private: + MessageHandler* msgHandler; +}; +} +} +#endif \ No newline at end of file diff --git a/frameworks/inputmethod_controller/include/input_method_controller.h b/frameworks/inputmethod_controller/include/input_method_controller.h new file mode 100644 index 00000000..474c7de4 --- /dev/null +++ b/frameworks/inputmethod_controller/include/input_method_controller.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2021 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 FM_IMC_PROJECT_INPUTMETHODCONTROLLER_H +#define FM_IMC_PROJECT_INPUTMETHODCONTROLLER_H + +//#include "refbase.h" +#include +#include +#include "input_data_channel_stub.h" +#include "input_client_stub.h" +#include "input_method_system_ability_proxy.h" +#include "input_method_agent_proxy.h" +#include "i_input_method_agent.h" +#include "message_handler.h" +#include "iremote_object.h" + +namespace OHOS { +namespace MiscServices { + + class OnTextChangedListener : public virtual RefBase { + public: + virtual void InsertText(const std::u16string& text) = 0; + virtual void DeleteBackward(int32_t length) = 0; + virtual void SetKeyboardStatus(bool status) = 0; + }; + + class ImsaDeathRecipient : public IRemoteObject::DeathRecipient { + public: + explicit ImsaDeathRecipient(); + ~ImsaDeathRecipient() = default; + + void OnRemoteDied(const wptr &object) override; + }; + + class InputMethodController : public RefBase { + public: + static sptr GetInstance(); + void Attach(); + void ShowTextInput(sptr &listener); + void HideTextInput(); + void Close(); + void OnRemoteSaDied(const wptr &object); + private: + InputMethodController(); + ~InputMethodController(); + + bool Initialize(); + sptr GetImsaProxy(); + void PrepareInput(int32_t displayId,sptr &client,sptr &channel,InputAttribute &attribute); + void StartInput(sptr &client); + void StopInput(sptr &client); + void ReleaseInput(sptr &client); + void WorkThread(); + + sptr mInputDataChannel; + sptr mClient; + sptr mImms; + sptr deathRecipient_; + sptr mAgent; + sptr textListener; + InputAttribute mAttribute; + + static std::mutex instanceLock_; + static sptr instance_; + std::thread workThreadHandler; + MessageHandler* msgHandler; + }; +} +} +#endif \ No newline at end of file diff --git a/frameworks/inputmethod_controller/include/input_method_system_ability_proxy.h b/frameworks/inputmethod_controller/include/input_method_system_ability_proxy.h new file mode 100644 index 00000000..447b78a5 --- /dev/null +++ b/frameworks/inputmethod_controller/include/input_method_system_ability_proxy.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2021 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 FM_IMC_PROJECT_INPUTMETHODSYSTEMABILITYPROXY_H +#define FM_IMC_PROJECT_INPUTMETHODSYSTEMABILITYPROXY_H + +#include +#include "iremote_proxy.h" +#include "i_input_method_system_ability.h" +#include "message_parcel.h" +#include "keyboard_type.h" +#include "input_method_property.h" +#include "input_client_stub.h" +#include "input_data_channel_stub.h" +#include "input_attribute.h" +#include "global.h" + +namespace OHOS { +namespace MiscServices { + +class InputMethodSystemAbilityProxy : public IRemoteProxy +{ +public: + explicit InputMethodSystemAbilityProxy(const sptr &object); + ~InputMethodSystemAbilityProxy() = default; + DISALLOW_COPY_AND_MOVE(InputMethodSystemAbilityProxy); + + virtual void prepareInput(MessageParcel& data) override; + virtual void releaseInput(MessageParcel& data) override; + virtual void startInput(MessageParcel& data) override; + virtual void stopInput(MessageParcel& data) override; + virtual int32_t setInputMethodCore(sptr &core) override; + + int32_t Prepare(int32_t displayId, sptr &client, sptr &channel, InputAttribute &attribute); + int32_t Release(sptr &client); + int32_t Start(sptr &client); + int32_t Stop(sptr &client); + + virtual int32_t getDisplayMode(int32_t *retMode) override; + virtual int32_t getKeyboardWindowHeight(int32_t *retHeight) override; + virtual int32_t getCurrentKeyboardType(KeyboardType* retType) override; + virtual int32_t listInputMethodEnabled(std::vector *properties) override; + virtual int32_t listInputMethod(std::vector *properties) override; + virtual int32_t listKeyboardType(const std::u16string& imeId, std::vector *types) override; + +private: + static inline BrokerDelegator delegator_; +}; +} +} +#endif \ No newline at end of file diff --git a/frameworks/inputmethod_controller/src/input_client_proxy.cpp b/frameworks/inputmethod_controller/src/input_client_proxy.cpp new file mode 100644 index 00000000..25e66b23 --- /dev/null +++ b/frameworks/inputmethod_controller/src/input_client_proxy.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2021 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 "input_client_proxy.h" + +namespace OHOS { +namespace MiscServices { +using namespace ErrorCode; + InputClientProxy::InputClientProxy(const sptr &object) : IRemoteProxy(object) + { + } + + int32_t InputClientProxy::onInputReady(int32_t retValue, const sptr& agent, const InputChannel* channel) + { + IMSA_HILOGI("InputClientProxy::onInputReady"); + MessageParcel data, reply; + MessageOption option; + if (!data.WriteInterfaceToken(GetDescriptor())) { + return ERROR_EX_PARCELABLE; + } + + if (!data.WriteInt32(retValue)){ + return ERROR_EX_PARCELABLE; + } + if (agent ==nullptr) { + data.WriteInt32(0); + } else { + data.WriteInt32(1); + data.WriteRemoteObject(agent->AsObject().GetRefPtr()); + } + + if (channel == nullptr) { + data.WriteInt32(0); + } else { + data.WriteInt32(1); + data.WriteParcelable(channel); + } + + auto ret = Remote()->SendRequest(ON_INPUT_READY, data, reply, option); + if (ret != NO_ERROR) { + IMSA_HILOGI("InputClientProxy::onInputReady SendRequest failed"); + return ERROR_STATUS_FAILED_TRANSACTION; + } + + return NO_ERROR; + } + + int32_t InputClientProxy::onInputReleased(int32_t retValue) + { + MessageParcel data, reply; + MessageOption option; + + data.WriteInterfaceToken(GetDescriptor()); + data.WriteInt32(retValue); + auto status = Remote()->SendRequest(ON_INPUT_RELEASED, data, reply, option); + return status; + } + + int32_t InputClientProxy::setDisplayMode(int32_t mode) + { + MessageParcel data, reply; + MessageOption option; + + data.WriteInterfaceToken(GetDescriptor()); + data.WriteInt32(mode); + auto status = Remote()->SendRequest(SET_DISPLAY_MODE, data, reply, option); + return status; + } +} +} diff --git a/frameworks/inputmethod_controller/src/input_client_stub.cpp b/frameworks/inputmethod_controller/src/input_client_stub.cpp new file mode 100644 index 00000000..4d7de3df --- /dev/null +++ b/frameworks/inputmethod_controller/src/input_client_stub.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2021 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 "input_client_stub.h" +#include "global.h" + +namespace OHOS { +namespace MiscServices { + +InputClientStub::InputClientStub() +{ + +} + +InputClientStub::~InputClientStub() +{ + +} + +int32_t InputClientStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, + MessageOption &option) +{ + IMSA_HILOGI("InputClientStub::OnRemoteRequest. code = %{public}u", code); + auto descriptorToken = data.ReadInterfaceToken(); + if (descriptorToken != GetDescriptor()) { + return ErrorCode::ERROR_STATUS_UNKNOWN_TRANSACTION; + } + switch (code) { + case ON_INPUT_READY: { + if (msgHandler == nullptr) { + break; + } + MessageParcel* parcel = new MessageParcel(); + parcel->WriteInt32(data.ReadInt32()); + if (data.ReadInt32() > 0) { + parcel->WriteRemoteObject(data.ReadRemoteObject()); + } + if (data.ReadInt32() > 0) { + parcel->WriteParcelable(data.ReadParcelable()); + } + + Message* msg = new Message(MessageID::MSG_ID_ON_INPUT_READY, parcel); + msgHandler->SendMessage(msg); + break; + } + case ON_INPUT_RELEASED: { + if (msgHandler == nullptr) { + break; + } + MessageParcel* parcel = new MessageParcel(); + parcel->WriteInt32(data.ReadInt32()); + Message* msg = new Message(MessageID::MSG_ID_EXIT_SERVICE, parcel); + msgHandler->SendMessage(msg); + break; + } + case SET_DISPLAY_MODE: { + if (msgHandler == nullptr) { + break; + } + MessageParcel* parcel = new MessageParcel(); + parcel->WriteInt32(data.ReadInt32()); + Message* msg = new Message(MessageID::MSG_ID_SET_DISPLAY_MODE, parcel); + msgHandler->SendMessage(msg); + break; + } + default: + return IPCObjectStub::OnRemoteRequest(code, data, reply, option); + } + return NO_ERROR; +} + +int32_t InputClientStub::onInputReady(int32_t retValue, const sptr& agent, const InputChannel* channel) +{ + return ErrorCode::NO_ERROR; +} + +int32_t InputClientStub::onInputReleased(int32_t retValue) +{ + return ErrorCode::NO_ERROR; +} + +int32_t InputClientStub::setDisplayMode(int32_t mode) +{ + return ErrorCode::NO_ERROR; +} + +void InputClientStub::SetHandler(MessageHandler* handler) +{ + msgHandler = handler; +} + +} +} \ No newline at end of file diff --git a/frameworks/inputmethod_controller/src/input_data_channel_proxy.cpp b/frameworks/inputmethod_controller/src/input_data_channel_proxy.cpp new file mode 100644 index 00000000..71ceb3e2 --- /dev/null +++ b/frameworks/inputmethod_controller/src/input_data_channel_proxy.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2021 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 "input_data_channel_proxy.h" +#include "message_parcel.h" +#include "utils.h" + +namespace OHOS { +namespace MiscServices { + +InputDataChannelProxy::InputDataChannelProxy(const sptr &object) : IRemoteProxy(object) +{ + +} + +bool InputDataChannelProxy::InsertText(const std::u16string& text) +{ + IMSA_HILOGI("InputDataChannelProxy::InsertText"); + MessageParcel data, reply; + MessageOption option; + data.WriteInterfaceToken(GetDescriptor()); + data.WriteString16(text); + + auto ret = Remote()->SendRequest(INSERT_TEXT, data, reply, option); + if (ret != NO_ERROR) { + return false; + } + auto result = reply.ReadBool(); + return result; +} + +bool InputDataChannelProxy::DeleteBackward(int32_t length) +{ + IMSA_HILOGI("InputDataChannelProxy::DeleteBackward"); + MessageParcel data, reply; + MessageOption option; + data.WriteInterfaceToken(GetDescriptor()); + data.WriteInt32(length); + + auto ret = Remote()->SendRequest(DELETE_BACKWARD, data, reply, option); + if (ret != NO_ERROR) { + return false; + } + auto result = reply.ReadBool(); + return result; +} + +void InputDataChannelProxy::Close() +{ + IMSA_HILOGI("InputDataChannelProxy::Close"); + MessageParcel data, reply; + MessageOption option; + data.WriteInterfaceToken(GetDescriptor()); + + auto ret = Remote()->SendRequest(CLOSE, data, reply, option); + if (ret != NO_ERROR) { + + } +} +} +} \ No newline at end of file diff --git a/frameworks/inputmethod_controller/src/input_data_channel_stub.cpp b/frameworks/inputmethod_controller/src/input_data_channel_stub.cpp new file mode 100644 index 00000000..517c7fce --- /dev/null +++ b/frameworks/inputmethod_controller/src/input_data_channel_stub.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2021 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 "input_data_channel_stub.h" + +namespace OHOS { +namespace MiscServices { +InputDataChannelStub::InputDataChannelStub() : msgHandler(nullptr) +{ + +} + +InputDataChannelStub::~InputDataChannelStub() +{ + if (msgHandler != nullptr) { + delete msgHandler; + } +} + +int32_t InputDataChannelStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, + MessageOption &option) +{ + IMSA_HILOGI("InputDataChannelStub::OnRemoteRequest code = %{public}d", code); + auto descriptorToken = data.ReadInterfaceToken(); + if (descriptorToken != GetDescriptor()) { + return ErrorCode::ERROR_STATUS_UNKNOWN_TRANSACTION; + } + switch (code) { + case INSERT_TEXT: { + auto text = data.ReadString16(); + InsertText(text); + break; + } + case DELETE_BACKWARD: { + auto length = data.ReadInt32(); + DeleteBackward(length); + break; + } + case CLOSE: { + Close(); + break; + } + default: + return IPCObjectStub::OnRemoteRequest(code, data, reply, option); + } + return NO_ERROR; +} + +bool InputDataChannelStub::InsertText(const std::u16string& text) +{ + IMSA_HILOGI("InputDataChannelStub::InsertText"); + if (msgHandler != nullptr) { + MessageParcel* parcel = new MessageParcel; + parcel->WriteString16(text); + Message* msg = new Message(MessageID::MSG_ID_INSERT_CHAR, parcel); + msgHandler->SendMessage(msg); + IMSA_HILOGI("InputDataChannelStub::InsertText return true"); + return true; + } + return false; +} + +bool InputDataChannelStub::DeleteBackward(int32_t length) +{ + IMSA_HILOGI("InputDataChannelStub::DeleteBackward"); + if (msgHandler != nullptr) { + MessageParcel* parcel = new MessageParcel; + parcel->WriteInt32(length); + Message* msg = new Message(MessageID::MSG_ID_DELETE_BACKWARD, parcel); + msgHandler->SendMessage(msg); + return true; + } + return false; +} + +void InputDataChannelStub::Close() +{ + +} + +void InputDataChannelStub::SetHandler(MessageHandler* handler) +{ + msgHandler = handler; +} +} +} \ No newline at end of file diff --git a/frameworks/inputmethod_controller/src/input_method_controller.cpp b/frameworks/inputmethod_controller/src/input_method_controller.cpp new file mode 100644 index 00000000..153bcd6e --- /dev/null +++ b/frameworks/inputmethod_controller/src/input_method_controller.cpp @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2021 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 "input_method_controller.h" +#include "iservice_registry.h" +#include "system_ability_definition.h" +#include "global.h" + +namespace OHOS { +namespace MiscServices { +using namespace MessageID; + sptr InputMethodController::instance_; + std::mutex InputMethodController::instanceLock_; + + InputMethodController::InputMethodController() + { + IMSA_HILOGI("InputMethodController structure"); + Initialize(); + } + + InputMethodController::~InputMethodController() + { + if (msgHandler != nullptr) { + delete msgHandler; + } + } + + sptr InputMethodController::GetInstance() + { + IMSA_HILOGI("InputMethodController::GetInstance"); + if (instance_ == nullptr) { + std::lock_guard autoLock(instanceLock_); + if (instance_ == nullptr) { + IMSA_HILOGI("InputMethodController::GetInstance instance_ is nullptr"); + instance_ = new InputMethodController(); + } + } + return instance_; + } + + bool InputMethodController::Initialize() + { + mImms = GetImsaProxy(); + + msgHandler = new MessageHandler(); + + mClient = new InputClientStub(); + mClient->SetHandler(msgHandler); + + mInputDataChannel = new InputDataChannelStub(); + mInputDataChannel->SetHandler(msgHandler); + + workThreadHandler = std::thread([this]{WorkThread();}); + mAttribute.SetInputPattern(InputAttribute::PATTERN_TEXT); + return true; + } + + sptr InputMethodController::GetImsaProxy() + { + IMSA_HILOGI("InputMethodController::GetImsaProxy"); + sptr systemAbilityManager = + SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (systemAbilityManager == nullptr) { + IMSA_HILOGI("InputMethodController::GetImsaProxy systemAbilityManager is nullptr"); + return nullptr; + } + + auto systemAbility = systemAbilityManager->GetSystemAbility(INPUT_METHOD_SYSTEM_ABILITY_ID, ""); + if (systemAbility == nullptr) { + IMSA_HILOGI("InputMethodController::GetImsaProxy systemAbility is nullptr"); + return nullptr; + } + + if (deathRecipient_ == nullptr) { + deathRecipient_ = new ImsaDeathRecipient(); + } + systemAbility->AddDeathRecipient(deathRecipient_); + + sptr iface = new InputMethodSystemAbilityProxy(systemAbility); + return iface; + } + + void InputMethodController::WorkThread() + { + while(1) { + Message* msg = msgHandler->GetMessage(); + switch(msg->msgId_) { + case MSG_ID_INSERT_CHAR:{ + MessageParcel* data = msg->msgContent_; + std::u16string text = data->ReadString16(); + if(textListener != nullptr){ + textListener->InsertText(text); + } + break; + } + case MSG_ID_DELETE_BACKWARD:{ + MessageParcel* data = msg->msgContent_; + int32_t length = data->ReadInt32(); + if(textListener != nullptr){ + textListener->DeleteBackward(length); + } + break; + } + case MSG_ID_SET_DISPLAY_MODE:{ + MessageParcel* data = msg->msgContent_; + int32_t ret = data->ReadInt32(); + IMSA_HILOGI("MSG_ID_SET_DISPLAY_MODE : %{public}d", ret); + break; + } + case MSG_ID_ON_INPUT_READY:{ + MessageParcel* data = msg->msgContent_; + int32_t ret = data->ReadInt32(); + if(ret != ErrorCode::NO_ERROR) { + if (textListener != nullptr){ + textListener->SetKeyboardStatus(false); + } + mAgent=nullptr; + break; + } + sptr object = data->ReadRemoteObject(); + mAgent = new InputMethodAgentProxy(object); + if (textListener != nullptr){ + textListener->SetKeyboardStatus(true); + } + break; + } + case MSG_ID_EXIT_SERVICE:{ + MessageParcel* data = msg->msgContent_; + int32_t ret = data->ReadInt32(); + IMSA_HILOGI("MSG_ID_EXIT_SERVICE : %{public}d", ret); + break; + } + default:{ + break; + } + } + delete msg; + } + } + + void InputMethodController::Attach() + { + PrepareInput(0,mClient,mInputDataChannel,mAttribute); + } + + void InputMethodController::ShowTextInput(sptr &listener) + { + IMSA_HILOGI("InputMethodController::ShowTextInput"); + textListener=listener; + StartInput(mClient); + } + + void InputMethodController::HideTextInput() + { + IMSA_HILOGI("InputMethodController::HideTextInput"); + StopInput(mClient); + } + + void InputMethodController::Close() + { + ReleaseInput(mClient); + } + + void InputMethodController::PrepareInput(int32_t displayId,sptr &client,sptr &channel,InputAttribute &attribute) + { + IMSA_HILOGI("InputMethodController::PrepareInput"); + if(mImms == nullptr){ + return; + } + MessageParcel data; + if(!(data.WriteInterfaceToken(mImms->GetDescriptor()) + &&data.WriteInt32(displayId) + &&data.WriteRemoteObject(client->AsObject()) + &&data.WriteRemoteObject(channel->AsObject()) + &&data.WriteParcelable(&attribute))){ + return; + } + mImms->prepareInput(data); + } + + void InputMethodController::StartInput(sptr &client) + { + IMSA_HILOGI("InputMethodController::StartInput"); + if(mImms == nullptr){ + return; + } + MessageParcel data; + if(!(data.WriteInterfaceToken(mImms->GetDescriptor()) + &&data.WriteRemoteObject(client->AsObject()))){ + return; + } + mImms->startInput(data); + } + + void InputMethodController::ReleaseInput(sptr &client) + { + IMSA_HILOGI("InputMethodController::ReleaseInput"); + if(mImms == nullptr){ + return; + } + MessageParcel data; + if(!(data.WriteInterfaceToken(mImms->GetDescriptor()) + &&data.WriteRemoteObject(client->AsObject().GetRefPtr()))) { + return; + } + mImms->releaseInput(data); + } + + void InputMethodController::StopInput(sptr &client) + { + IMSA_HILOGI("InputMethodController::StopInput"); + if(mImms == nullptr){ + return; + } + MessageParcel data; + if(!(data.WriteInterfaceToken(mImms->GetDescriptor()) + &&data.WriteRemoteObject(client->AsObject().GetRefPtr()))) { + return; + } + mImms->stopInput(data); + } + + void InputMethodController::OnRemoteSaDied(const wptr &remote) { + mImms = GetImsaProxy(); + } + + ImsaDeathRecipient::ImsaDeathRecipient() + { + + } + + void ImsaDeathRecipient::OnRemoteDied(const wptr &object) + { + InputMethodController::GetInstance()->OnRemoteSaDied(object); + } +} +} \ No newline at end of file diff --git a/frameworks/inputmethod_controller/src/input_method_system_ability_proxy.cpp b/frameworks/inputmethod_controller/src/input_method_system_ability_proxy.cpp new file mode 100644 index 00000000..5c631daf --- /dev/null +++ b/frameworks/inputmethod_controller/src/input_method_system_ability_proxy.cpp @@ -0,0 +1,410 @@ +/* + * Copyright (C) 2021 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 "input_method_system_ability_proxy.h" + +namespace OHOS { +namespace MiscServices { +using namespace ErrorCode; + +InputMethodSystemAbilityProxy::InputMethodSystemAbilityProxy(const sptr &object) + : IRemoteProxy(object) +{ + +} + +void InputMethodSystemAbilityProxy::prepareInput(MessageParcel& data) +{ + MessageParcel reply; + MessageOption option; + + auto ret = Remote()->SendRequest(PREPARE_INPUT, data, reply, option); + if (ret != NO_ERROR) { + IMSA_HILOGI("InputMethodSystemAbilityProxy::prepareInput SendRequest failed"); + return; + } + + ret = reply.ReadInt32(); + if (ret != NO_ERROR) { + IMSA_HILOGI("InputMethodSystemAbilityProxy::prepareInput reply failed"); + return; + } +} + +void InputMethodSystemAbilityProxy::releaseInput(MessageParcel& data) +{ + MessageParcel reply; + MessageOption option; + + auto ret = Remote()->SendRequest(RELEASE_INPUT, data, reply, option); + if (ret != NO_ERROR) { + IMSA_HILOGI("InputMethodSystemAbilityProxy::releaseInput SendRequest failed"); + return; + } + + ret = reply.ReadInt32(); + if (ret != NO_ERROR) { + IMSA_HILOGI("InputMethodSystemAbilityProxy::releaseInput reply failed"); + return; + } +} + +void InputMethodSystemAbilityProxy::startInput(MessageParcel& data) +{ + IMSA_HILOGI("InputMethodSystemAbilityProxy::startInput"); + MessageParcel reply; + MessageOption option; + + auto ret = Remote()->SendRequest(START_INPUT,data,reply,option); + if (ret != NO_ERROR) { + IMSA_HILOGI("InputMethodSystemAbilityProxy::startInput SendRequest failed"); + return; + } + + ret = reply.ReadInt32(); + if (ret != NO_ERROR) { + IMSA_HILOGI("InputMethodSystemAbilityProxy::startInput reply failed"); + return; + } +} + +void InputMethodSystemAbilityProxy::stopInput(MessageParcel& data) +{ + IMSA_HILOGI("InputMethodSystemAbilityProxy::stopInput"); + MessageParcel reply; + MessageOption option; + + auto ret = Remote()->SendRequest(STOP_INPUT,data,reply,option); + if (ret != NO_ERROR) { + IMSA_HILOGI("InputMethodSystemAbilityProxy::stopInput SendRequest failed"); + return; + } + + ret = reply.ReadInt32(); + if (ret != NO_ERROR) { + IMSA_HILOGI("InputMethodSystemAbilityProxy::stopInput reply failed"); + return; + } +} + + int32_t InputMethodSystemAbilityProxy::setInputMethodCore(sptr &core) + { + IMSA_HILOGI("InputMethodSystemAbilityProxy::setInputMethodCore"); + + if (core == nullptr) { + IMSA_HILOGI("InputMethodSystemAbilityProxy::setInputMethodCore inputDataChannel is nullptr"); + } + auto remote = Remote(); + if (remote == nullptr) + return -1; + MessageParcel data; + if (!(data.WriteInterfaceToken(GetDescriptor()) + && data.WriteRemoteObject(core->AsObject()))) + return -1; + MessageParcel reply; + MessageOption option { MessageOption::TF_SYNC }; + + int32_t status = Remote()->SendRequest(SET_INPUT_METHOD_CORE, data, reply, option); + + return status; + } + +int32_t InputMethodSystemAbilityProxy::Prepare(int32_t displayId, sptr &client, sptr &channel, InputAttribute &attribute) +{ + MessageParcel data, reply; + MessageOption option; + if (!data.WriteInterfaceToken(GetDescriptor())) { + return ERROR_EX_PARCELABLE; + } + + if (!(data.WriteInt32(displayId) + && data.WriteRemoteObject(client->AsObject()) + && data.WriteRemoteObject(channel->AsObject()) + && data.WriteParcelable(&attribute))) { + return ERROR_EX_PARCELABLE; + } + + auto ret = Remote()->SendRequest(PREPARE_INPUT, data, reply, option); + if (ret != NO_ERROR) { + return ERROR_STATUS_FAILED_TRANSACTION; + } + + ret = reply.ReadInt32(); + if (ret != NO_ERROR) { + return ret; + } + + return NO_ERROR; +} + +int32_t InputMethodSystemAbilityProxy::Release(sptr &client) +{ + IMSA_HILOGI("InputMethodSystemAbilityProxy::Release"); + MessageParcel data, reply; + MessageOption option; + if (!data.WriteInterfaceToken(GetDescriptor())) { + return ERROR_EX_PARCELABLE; + } + + if (!data.WriteRemoteObject(client->AsObject().GetRefPtr())) { + return ERROR_EX_PARCELABLE; + } + + auto ret = Remote()->SendRequest(RELEASE_INPUT, data, reply, option); + if (ret != NO_ERROR) { + return ERROR_STATUS_FAILED_TRANSACTION; + } + + ret = reply.ReadInt32(); + if (ret != NO_ERROR) { + return ret; + } + + return NO_ERROR; +} + +int32_t InputMethodSystemAbilityProxy::Start(sptr &client) +{ + MessageParcel data, reply; + MessageOption option; + if (!data.WriteInterfaceToken(GetDescriptor())) { + return ERROR_EX_PARCELABLE; + } + + if (!data.WriteRemoteObject(client->AsObject().GetRefPtr())) { + return ERROR_EX_PARCELABLE; + } + + auto ret = Remote()->SendRequest(START_INPUT, data, reply, option); + if (ret != NO_ERROR) { + return ERROR_STATUS_FAILED_TRANSACTION; + } + + ret = reply.ReadInt32(); + if (ret != NO_ERROR) { + return ret; + } + + return NO_ERROR; +} + +int32_t InputMethodSystemAbilityProxy::Stop(sptr &client) +{ + MessageParcel data, reply; + MessageOption option; + if (!data.WriteInterfaceToken(GetDescriptor())) { + return ERROR_EX_PARCELABLE; + } + + if (!data.WriteRemoteObject(client->AsObject().GetRefPtr())) { + return ERROR_EX_PARCELABLE; + } + + auto ret = Remote()->SendRequest(STOP_INPUT, data, reply, option); + if (ret != NO_ERROR) { + return ERROR_STATUS_FAILED_TRANSACTION; + } + + ret = reply.ReadInt32(); + if (ret != NO_ERROR) { + return ret; + } + + return NO_ERROR; +} + +int32_t InputMethodSystemAbilityProxy::getDisplayMode(int32_t *retMode) +{ + MessageParcel data, reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + return ERROR_EX_PARCELABLE; + } + + auto ret = Remote()->SendRequest(GET_DISPLAY_MODE, data, reply, option); + if (ret != NO_ERROR) { + return ERROR_STATUS_FAILED_TRANSACTION; + } + + ret = reply.ReadInt32(); + if (ret != NO_ERROR) { + return ret; + } + + if (!reply.ReadInt32(*retMode)) { + return ERROR_STATUS_BAD_VALUE; + } + return NO_ERROR; +} + +int32_t InputMethodSystemAbilityProxy::getKeyboardWindowHeight(int32_t *retHeight) +{ + if (retHeight == nullptr) { + return ERROR_NULL_POINTER; + } + + MessageParcel data, reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + return ERROR_EX_PARCELABLE; + } + + auto ret = Remote()->SendRequest(GET_KEYBOARD_WINDOW_HEIGHT, data, reply, option); + if (ret != NO_ERROR) { + return ERROR_STATUS_FAILED_TRANSACTION; + } + + ret = reply.ReadInt32(); + if (ret != NO_ERROR) { + return ret; + } + + if (!reply.ReadInt32(*retHeight)) { + return ERROR_STATUS_BAD_VALUE; + } + return NO_ERROR; +} + +int32_t InputMethodSystemAbilityProxy::getCurrentKeyboardType(KeyboardType* retType) +{ + if (retType == nullptr) { + return ERROR_NULL_POINTER; + } + + MessageParcel data, reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + return ERROR_EX_PARCELABLE; + } + + auto ret = Remote()->SendRequest(GET_CURRENT_KEYBOARD_TYPE, data, reply, option); + if (ret != NO_ERROR) { + return ERROR_STATUS_FAILED_TRANSACTION; + } + + ret = reply.ReadInt32(); + if (ret != NO_ERROR) { + return ret; + } + + KeyboardType* keyType = reply.ReadParcelable(); + *retType = *keyType; + delete keyType; + return NO_ERROR; +} + +int32_t InputMethodSystemAbilityProxy::listInputMethodEnabled(std::vector *properties) +{ + if (properties == nullptr) { + return ERROR_NULL_POINTER; + } + + MessageParcel data, reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + return ERROR_EX_PARCELABLE; + } + + auto ret = Remote()->SendRequest(LIST_INPUT_METHOD_ENABLED, data, reply, option); + if (ret != NO_ERROR) { + return ERROR_STATUS_FAILED_TRANSACTION; + } + + ret = reply.ReadInt32(); + if (ret != NO_ERROR) { + return ret; + } + + auto size = reply.ReadInt32(); + while (size > 0) { + InputMethodProperty* imp = reply.ReadParcelable(); + properties->push_back(imp); + size--; + } + + return NO_ERROR; +} + +int32_t InputMethodSystemAbilityProxy::listInputMethod(std::vector *properties) +{ + if (properties == nullptr) { + return ERROR_NULL_POINTER; + } + + MessageParcel data, reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + return ERROR_EX_PARCELABLE; + } + + auto ret = Remote()->SendRequest(LIST_INPUT_METHOD, data, reply, option); + if (ret != NO_ERROR) { + return ERROR_STATUS_FAILED_TRANSACTION; + } + + ret = reply.ReadInt32(); + if (ret != NO_ERROR) { + return ret; + } + + auto size = reply.ReadInt32(); + + while (size > 0) { + InputMethodProperty* imp = reply.ReadParcelable(); + properties->push_back(imp); + size--; + } + + return NO_ERROR; +} + +int32_t InputMethodSystemAbilityProxy::listKeyboardType(const std::u16string& imeId, std::vector *types) +{ + if (types == nullptr) { + return ERROR_NULL_POINTER; + } + + MessageParcel data, reply; + MessageOption option; + + if (!(data.WriteInterfaceToken(GetDescriptor()) && data.WriteString16(imeId))) { + return ERROR_EX_PARCELABLE; + } + + auto ret = Remote()->SendRequest(LIST_KEYBOARD_TYPE, data, reply, option); + if (ret != NO_ERROR) { + return ERROR_STATUS_FAILED_TRANSACTION; + } + + ret = reply.ReadInt32(); + if (ret != NO_ERROR) { + return ret; + } + + auto size = reply.ReadInt32(); + while (size > 0) { + KeyboardType* kt = reply.ReadParcelable(); + types->push_back(kt); + size--; + } + return NO_ERROR; +} +} +} \ No newline at end of file diff --git a/inputmethod.gni b/inputmethod.gni new file mode 100644 index 00000000..a9bee410 --- /dev/null +++ b/inputmethod.gni @@ -0,0 +1,20 @@ +# Copyright (C) 2021 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. + +inputmethod_path = "//base/miscservices/inputmethod" + +kits_path = "${inputmethod_path}/interfaces/kits" + +innerkits_path = "${inputmethod_path}/interfaces/innerkits" + +adapter_path = "${inputmethod_path}/adapter" \ No newline at end of file diff --git a/interfaces/kits/js/declaration/BUILD.gn b/interfaces/kits/js/declaration/BUILD.gn new file mode 100644 index 00000000..0fd94c41 --- /dev/null +++ b/interfaces/kits/js/declaration/BUILD.gn @@ -0,0 +1,31 @@ +# Copyright (C) 2021 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. + +import("//build/ohos.gni") +import("//build/ohos/ace/ace.gni") + +js_declaration("inputmethod") { + part_name = "inputmethod_native" + sources = [ + "./api", + ] +} + +ohos_copy("inputmethod_declaration") { + sources = [ + "./api" + ] + outputs = [ target_out_dir + "/$target_name/" ] + module_source_dir = target_out_dir + "/$target_name" + module_install_name = "" +} diff --git a/interfaces/kits/js/declaration/api/@ohos.inputmethodability.d.ts b/interfaces/kits/js/declaration/api/@ohos.inputmethodability.d.ts new file mode 100644 index 00000000..6ef576dc --- /dev/null +++ b/interfaces/kits/js/declaration/api/@ohos.inputmethodability.d.ts @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2021 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. + */ + +import { AsyncCallback } from './basic'; + +/** + * inputmethod + * + * @since 6 + * @import inputmethod from '@ohos.inputmethod'; + * @devices phone, tablet, tv, wearable + */ +declare namespace inputMethodAbility { + function on(type: 'keyboardShow', callback: () => void): void; + function off(type: 'keyboardShow', callback: () => void): void; + + function on(type: 'keyboardHide', callback: () => void): void; + function off(type: 'keyboardHide', callback: () => void): void; + + function insertText(text: string, callback: AsyncCallback): void; + function insertText(text: string): Promise; + + function DeleteBackward(length: number, callback: () => void): void; + function DeleteBackward(length: number): Promise; + + function HideKeyboardSelf(callback: callback: () => void): void; + function HideKeyboardSelf(): Promise; +} + +export default inputMethodAbility; diff --git a/interfaces/kits/js/napi/BUILD.gn b/interfaces/kits/js/napi/BUILD.gn new file mode 100644 index 00000000..6697b5eb --- /dev/null +++ b/interfaces/kits/js/napi/BUILD.gn @@ -0,0 +1,76 @@ +# Copyright (C) 2021 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. + +import("//build/ohos.gni") + +config("inputmethodability_native_config") { + visibility = [ ":*" ] + include_dirs = [ + "include", + ] + +} + +config("inputmethodability_native_public_config") { + visibility = [] + include_dirs = [ "include" ] +} + +ohos_shared_library("inputmethodability") { + include_dirs = [ + "//third_party/node/src", + "//foundation/ace/napi/interfaces/kits", + ] + + cflags = [ + "-fPIC", + "-g3", + ] + + sources = [ "js_input_method_ability.cpp" ] + + configs = [ ":inputmethodability_native_config" ] + + deps = [ + "//base/miscservices/inputmethod/frameworks/inputmethod_ability:inputmethod_ability", + "//foundation/ace/napi/:ace_napi", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//utils/native/base:utils", + "//base/global/resmgr_standard/frameworks/resmgr:global_resmgr", + "//foundation/aafwk/standard/frameworks/kits/ability/native:abilitykit_native", + "//foundation/aafwk/standard/interfaces/innerkits/ability_manager:ability_manager", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/intent:intent", + "//foundation/multimodalinput/input/interfaces/native/innerkits/event:mmi_event", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler:libeventhandler", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//foundation/communication/ipc/interfaces/innerkits/ipc_core:ipc_core", + "//foundation/communication/ipc/interfaces/innerkits/ipc_single:ipc_single", + "//foundation/multimodalinput/input/interfaces/native/innerkits/event:mmi_event", + "//foundation/distributedschedule/dmsfwk/interfaces/innerkits/uri:zuri", + "//base/miscservices/inputmethod/services:inputmethod_service", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] + + relative_install_dir = "module" + + subsystem_name = "miscservices" + part_name = "inputmethod_native" +} diff --git a/interfaces/kits/js/napi/js_input_method_ability.cpp b/interfaces/kits/js/napi/js_input_method_ability.cpp new file mode 100644 index 00000000..05b325dc --- /dev/null +++ b/interfaces/kits/js/napi/js_input_method_ability.cpp @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2021 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 "event_target.h" +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "global.h" + +using namespace OHOS::MiscServices; + +napi_value JS_Constructor(napi_env env, napi_callback_info cbInfo) +{ + IMSA_HILOGI("JS_Constructor() is called!"); + napi_value thisVar = nullptr; + void* data = nullptr; + napi_get_cb_info(env, cbInfo, nullptr, nullptr, &thisVar, &data); + + OHOS::MiscServices::EventTarget* imeAbility = new OHOS::MiscServices::EventTarget(env,thisVar); + napi_wrap(env, thisVar, imeAbility, + [](napi_env env, void* data, void* hint){ + EventTarget* imeAbility = (EventTarget*)data; + delete imeAbility; + }, + nullptr, nullptr); + OHOS::sptr eventTarget_=imeAbility; + InputMethodAbility::GetInstance()->setEventTarget(eventTarget_); + return thisVar; +} + +napi_value JS_InsertText(napi_env env, napi_callback_info cbInfo) +{ + IMSA_HILOGI("JS_InsertText() is called!"); + size_t argc = 1; + napi_value argv[2] = { 0 }; + napi_value thisVar = nullptr; + void* data = nullptr; + napi_get_cb_info(env, cbInfo, &argc, argv, &thisVar, &data); + + EventTarget* imeAbility = nullptr; + napi_unwrap(env, thisVar, (void **)&imeAbility); + + char type[64] = { 0 }; + size_t typeLen = 0; + napi_get_value_string_utf8(env, argv[0], type, sizeof(type), &typeLen); + std::string text=type; + InputMethodAbility::GetInstance()->InsertText(text); + + napi_value result = nullptr; + napi_get_undefined(env, &result); + IMSA_HILOGI("JS_InsertText() is end!"); + return result; +} + +napi_value JS_DeleteBackward(napi_env env, napi_callback_info cbInfo) +{ + IMSA_HILOGI("JS_DeleteBackward() is called!"); + size_t argc = 1; + napi_value argv[2] = { 0 }; + napi_value thisVar = nullptr; + void* data = nullptr; + napi_get_cb_info(env, cbInfo, &argc, argv, &thisVar, &data); + + EventTarget* imeAbility = nullptr; + napi_unwrap(env, thisVar, (void **)&imeAbility); + + int32_t value32 = 0; + napi_get_value_int32(env, argv[0], &value32); + InputMethodAbility::GetInstance()->DeleteBackward(value32); + + napi_value result = nullptr; + napi_get_undefined(env, &result); + return result; +} + +napi_value JS_HideKeyboardSelf(napi_env env, napi_callback_info cbInfo) +{ + IMSA_HILOGI("JS_HideKeyboardSelf() is called!"); + size_t argc = 1; + napi_value argv[2] = { 0 }; + napi_value thisVar = nullptr; + void* data = nullptr; + napi_get_cb_info(env, cbInfo, &argc, argv, &thisVar, &data); + + EventTarget* imeAbility = nullptr; + napi_unwrap(env, thisVar, (void **)&imeAbility); + + InputMethodAbility::GetInstance()->HideKeyboardSelf(); + + napi_value result = nullptr; + napi_get_undefined(env, &result); + return result; +} + +napi_value JS_On(napi_env env, napi_callback_info cbInfo) +{ + IMSA_HILOGI("JS_On() is called!"); + size_t requireArgc = 2; + size_t argc = 2; + napi_value argv[2] = { 0 }; + napi_value thisVar = 0; + void* data = nullptr; + napi_get_cb_info(env, cbInfo, &argc, argv, &thisVar, &data); + + EventTarget* imeAbility = nullptr; + napi_unwrap(env, thisVar, (void **)&imeAbility); + + NAPI_ASSERT(env, argc >= requireArgc, "requires 2 parameter"); + + napi_valuetype eventValueType; + napi_typeof(env, argv[0], &eventValueType); + NAPI_ASSERT(env, eventValueType == napi_string, "type mismatch for parameter 1"); + + napi_valuetype eventHandleType; + napi_typeof(env, argv[1], &eventHandleType); + NAPI_ASSERT(env, eventHandleType == napi_function, "type mismatch for parameter 2"); + + char type[64] = { 0 }; + size_t typeLen = 0; + napi_get_value_string_utf8(env, argv[0], type, sizeof(type), &typeLen); + + IMSA_HILOGI("call ima on function"); + imeAbility->On((const char*)type, argv[1]); + + napi_value result = nullptr; + napi_get_undefined(env, &result); + IMSA_HILOGI("JS_On() is end!"); + return result; +} + +napi_value JS_Off(napi_env env, napi_callback_info cbInfo) +{ + size_t requireArgc = 1; + size_t argc = 2; + napi_value argv[2] = { 0 }; + napi_value thisVar = 0; + void* data = nullptr; + napi_get_cb_info(env, cbInfo, &argc, argv, &thisVar, &data); + + EventTarget* imeAbility = nullptr; + napi_unwrap(env, thisVar, (void **)&imeAbility); + + NAPI_ASSERT(env, argc >= requireArgc, "requires 2 parameter"); + + napi_valuetype eventValueType; + napi_typeof(env, argv[0], &eventValueType); + NAPI_ASSERT(env, eventValueType == napi_string, "type mismatch for parameter 1"); + + char* type = nullptr; + size_t typeLen = 0; + napi_get_value_string_utf8(env, argv[0], nullptr, 0, &typeLen); + type = new char[typeLen + 1]; + napi_get_value_string_utf8(env, argv[0], type, typeLen + 1, &typeLen); + + if (argc > requireArgc) { + NAPI_ASSERT(env, eventValueType == napi_function, "type mismatch for parameter 2"); + + imeAbility->Off(type, argv[1]); + } else { + imeAbility->Off(type); + } + + delete type; + delete type; + napi_value result = nullptr; + napi_get_undefined(env, &result); + return result; +} + +napi_value InputMethodAbilityInit(napi_env env, napi_value exports) +{ + IMSA_HILOGI("InputMethodAbilityInit() is called!"); + const char className[] = "EventTarget"; + napi_value constructor = nullptr; + napi_property_descriptor desc[] = { + DECLARE_NAPI_FUNCTION("insertText", JS_InsertText), + DECLARE_NAPI_FUNCTION("DeleteBackward", JS_DeleteBackward), + DECLARE_NAPI_FUNCTION("HideKeyboardSelf", JS_HideKeyboardSelf), + DECLARE_NAPI_FUNCTION("on", JS_On), + DECLARE_NAPI_FUNCTION("off", JS_Off), + }; + napi_define_class(env, className, sizeof(className),JS_Constructor, nullptr, + sizeof(desc) / sizeof(desc[0]), desc, &constructor); + napi_set_named_property(env, exports, "InputMethodAbility", constructor); + return exports; +} + +/* + * module define + */ +static napi_module inputMethodAbilityModule = { +.nm_version = 1, +.nm_flags = 0, +.nm_filename = nullptr, +.nm_register_func = InputMethodAbilityInit, +.nm_modname = "inputMethodAbility", +.nm_priv = ((void*)0), +.reserved = { 0 }, +}; +/* + * module register + */ +extern "C" __attribute__((constructor)) void RegisterModule() +{ +IMSA_HILOGI("RegisterModule() is called!"); +napi_module_register(&inputMethodAbilityModule); +} \ No newline at end of file diff --git a/ohos.build b/ohos.build new file mode 100644 index 00000000..5d953715 --- /dev/null +++ b/ohos.build @@ -0,0 +1,53 @@ +{ + "subsystem": "miscservices", + "parts": { + "inputmethod_native": { + "variants": [ + "phone", + "wearable", + "ivi" + ], + "module_list": [ + "//base/miscservices/inputmethod:inputmethod_native_packages" + ], + "inner_kits": [ + { + "name": "//base/miscservices/inputmethod/frameworks/inputmethod_controller:inputmethod_client", + "header": { + "header_files": [ + "i_input_client.h", + "i_input_data_channel.h", + "input_client_proxy.h", + "input_client_stub.h", + "input_data_channel_proxy.h", + "input_data_channel_stub.h", + "input_method_controller.h", + "input_method_system_ability_proxy.h" + ], + "header_base": "//base/miscservices/inputmethod/frameworks/inputmethod_controller/include" + } + }, + { + "name": "//base/miscservices/inputmethod/frameworks/inputmethod_ability:inputmethod_ability", + "header": { + "header_files": [ + "event_target.h", + "i_input_method_agent.h", + "i_input_method_core.h", + "input_method_ability.h", + "input_method_agent_proxy.h", + "input_method_agent_stub.h", + "input_method_core_proxy.h", + "input_method_core_stub.h" + ], + "header_base": "//base/miscservices/inputmethod/frameworks/inputmethod_ability/include" + } + } + ], + "test_list": [ + "//base/miscservices/inputmethod/unitest:InputMethodControllerTest", + "//base/miscservices/inputmethod/unitest:InputMethodAbilityTest" + ] + } + } +} diff --git a/profile/3703.xml b/profile/3703.xml new file mode 100644 index 00000000..d7736f4d --- /dev/null +++ b/profile/3703.xml @@ -0,0 +1,24 @@ + + + + inputmethod_service + + 3703 + libinputmethod_service.z.so + true + false + 1 + + \ No newline at end of file diff --git a/profile/BUILD.gn b/profile/BUILD.gn new file mode 100644 index 00000000..f23eb6eb --- /dev/null +++ b/profile/BUILD.gn @@ -0,0 +1,19 @@ +# Copyright (C) 2021 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. + +import("//build/ohos/sa_profile/sa_profile.gni") + +ohos_sa_profile("miscservices_inputmethod_sa_profiles") { + sources = [ "3703.xml" ] + part_name = "inputmethod_native" +} diff --git a/services/BUILD.gn b/services/BUILD.gn new file mode 100644 index 00000000..286b97f2 --- /dev/null +++ b/services/BUILD.gn @@ -0,0 +1,96 @@ +# Copyright (c) 2021 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. +import("//base/miscservices/inputmethod/inputmethod.gni") +import("//build/ohos.gni") + +config("inputmethod_services_native_config") { + visibility = [ ":*" ] + include_dirs = [ + "include", + "${inputmethod_path}/frameworks/inputmethod_ability/include", + "${inputmethod_path}/frameworks/inputmethod_controller/include", + ] + + cflags_cc = [ "-fexceptions" ] +} + +ohos_shared_library("inputmethod_service") { + sources = [ + "../services/src/input_attribute.cpp", + "../services/src/global.cpp", + "../services/src/input_channel.cpp", + "../services/src/keyboard_type.cpp", + "../services/src/input_method_property.cpp", + "../services/src/message.cpp", + "../services/src/message_handler.cpp", + "../services/src/input_method_system_ability_stub.cpp", + "../services/src/input_method_setting.cpp", + "../services/src/peruser_setting.cpp", + "../services/src/peruser_session.cpp", + "../services/src/input_method_system_ability.cpp", + "../services/src/input_control_channel_proxy.cpp", + "../services/src/input_control_channel_stub.cpp", + + "../services/src/platform.cpp", + "../services/src/platform_callback_stub.cpp", + "../services/src/platform_callback_proxy.cpp", + "../services/src/platform_api_proxy.cpp", + "../services/src/input_method_ability_connection_stub.cpp", + + + "${inputmethod_path}/frameworks/inputmethod_ability/src/input_method_agent_proxy.cpp", + "${inputmethod_path}/frameworks/inputmethod_ability/src/input_method_core_proxy.cpp", + "${inputmethod_path}/frameworks/inputmethod_ability/src/input_method_core_stub.cpp", + "${inputmethod_path}/frameworks/inputmethod_ability/src/input_method_ability.cpp", + "${inputmethod_path}/frameworks/inputmethod_ability/src/input_method_agent_stub.cpp", + "${inputmethod_path}/frameworks/inputmethod_controller/src/input_client_proxy.cpp", + "${inputmethod_path}/frameworks/inputmethod_controller/src/input_data_channel_proxy.cpp", + "${inputmethod_path}/frameworks/inputmethod_controller/src/input_method_system_ability_proxy.cpp", + ] + + configs = [ ":inputmethod_services_native_config" ] + + public_configs = [ + ":inputmethod_services_native_config", + ] + + deps = [ + "//utils/native/base:utils", + "//base/global/resmgr_standard/frameworks/resmgr:global_resmgr", + "//foundation/aafwk/standard/frameworks/kits/ability/native:abilitykit_native", + "//foundation/aafwk/standard/interfaces/innerkits/ability_manager:ability_manager", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//foundation/aafwk/standard/interfaces/innerkits/base:base", + "//foundation/aafwk/standard/interfaces/innerkits/intent:intent", + "//foundation/ace/napi/:ace_napi", + "//foundation/multimodalinput/input/interfaces/native/innerkits/event:mmi_event", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_base:appexecfwk_base", + "//foundation/appexecfwk/standard/interfaces/innerkits/appexecfwk_core:appexecfwk_core", + "//foundation/appexecfwk/standard/interfaces/innerkits/libeventhandler:libeventhandler", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//foundation/communication/ipc/interfaces/innerkits/ipc_core:ipc_core", + "//foundation/communication/ipc/interfaces/innerkits/ipc_single:ipc_single", + "//foundation/multimodalinput/input/interfaces/native/innerkits/event:mmi_event", + "//foundation/distributedschedule/dmsfwk/interfaces/innerkits/uri:zuri", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//foundation/aafwk/standard/services/abilitymgr:abilityms", + "//foundation/ace/napi/:ace_napi", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + ] + + subsystem_name = "miscservices" + part_name = "inputmethod_native" +} \ No newline at end of file diff --git a/services/include/global.h b/services/include/global.h new file mode 100644 index 00000000..90db0c0c --- /dev/null +++ b/services/include/global.h @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2021 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 FM_IMMS_PROJECT_GLOBAL_H +#define FM_IMMS_PROJECT_GLOBAL_H + +#include +#include +#include +#include "iremote_broker.h" +#include "peer_holder.h" +#include "ipc_object_stub.h" +#include "refbase.h" +#include "hilog/log.h" + +namespace OHOS { +namespace MiscServices { +#define PLATFORM OHOS + +using BRemoteObject = IPCObjectStub; + +#define INPUTMETHOD_DEBUG 0 + +#define LOG_INFO(fmt, args...) \ + LogTimeStamp();printf("I %s:%d %s - " fmt, basename(__FILE__), __LINE__, __FUNCTION__, ##args) + +#define LOG_ERROR(fmt, args...) \ + LogTimeStamp();printf("E %s:%d %s - " fmt, basename(__FILE__), __LINE__, __FUNCTION__, ##args) + +#define LOG_WARNING(fmt, args...) \ + LogTimeStamp();printf("W %s:%d %s - " fmt, basename(__FILE__), __LINE__, __FUNCTION__, ##args) + +#if DEBUG +#define LOG_DEBUG(fmt, args...) \ + LogTimeStamp();printf("D %s:%d %s - " fmt, basename(__FILE__), __LINE__, __FUNCTION__, ##args) +#else +#define LOG_DEBUG(fmt, args...) +#endif + +void LogTimeStamp(); + +namespace CommonEvent { + //! the events handled in input method management system + enum { + COMMON_EVENT_USER_STARTED = 10001, /*!< a user is started. */ + COMMON_EVENT_USER_STOPPED = 10002, /*!< a user is stopped. */ + COMMON_EVENT_USER_UNLOCKED = 10003, /*!< a user is unlocked. */ + COMMON_EVENT_USER_LOCKED = 10004, /*!< a user is locked. */ + COMMON_EVENT_SETTING_CHANGED = 10005, /*!< input method setting data is changed. */ + COMMON_EVENT_PACKAGE_ADDED = 10006, /*!< a package is installed. */ + COMMON_EVENT_PACKAGE_REMOVED = 10007, /*!< a package is removed */ + }; +}; + +//! User State +namespace UserState { + /*! The states of a user in the system. */ + enum { + USER_STATE_NOT_AVAILABLE = -1, + USER_STATE_STARTED = 0, /*!< a user is started. */ + USER_STATE_UNLOCKED, /*!< a user is unlocked. */ + }; +}; + +//! Error Code +namespace ErrorCode { + /*! Error Code definition in the input method management system */ + enum { + ERROR_STATUS_UNKNOWN_ERROR = (-2147483647 - 1), //!< unknown error + ERROR_STATUS_NO_MEMORY = -ENOMEM, //!< no memory + ERROR_STATUS_INVALID_OPERATION = -ENOSYS, //!< invalid operation + ERROR_STATUS_BAD_VALUE = -EINVAL, //!< bad value + ERROR_STATUS_BAD_TYPE = ERROR_STATUS_UNKNOWN_ERROR+1, //!< bad type + ERROR_STATUS_NAME_NOT_FOUND = -ENOENT, //!< name not found + ERROR_STATUS_PERMISSION_DENIED = -EPERM, //!< permission denied + ERROR_STATUS_NO_INIT = -ENODEV, //!< no init + ERROR_STATUS_ALREADY_EXISTS = -EEXIST, //!< already exist + ERROR_STATUS_DEAD_OBJECT = -EPIPE, //!< dead object + ERROR_STATUS_FAILED_TRANSACTION = ERROR_STATUS_UNKNOWN_ERROR+2, //!< failed transaction + ERROR_STATUS_BAD_INDEX = -EOVERFLOW, //!< bad index + ERROR_STATUS_NOT_ENOUGH_DATA = -ENODATA, //!< not enough data + ERROR_STATUS_WOULD_BLOCK = -EWOULDBLOCK, //!< would block + ERROR_STATUS_TIMED_OUT = -ETIMEDOUT, //!< time out + ERROR_STATUS_UNKNOWN_TRANSACTION = -EBADMSG, //!< unknown transaction + ERROR_STATUS_FDS_NOT_ALLOWED = ERROR_STATUS_UNKNOWN_ERROR+7, //!< fds not allowed + ERROR_STATUS_UNEXPECTED_NULL = ERROR_STATUS_UNKNOWN_ERROR+8, //!< unexpected null, + + // binder exception error code from Status.h + ERROR_EX_ILLEGAL_ARGUMENT = -3, //!< illegal argument exception + ERROR_EX_NULL_POINTER = -4, //!< null pointer exception + ERROR_EX_ILLEGAL_STATE = -5, //!< illegal state exception + ERROR_EX_NETWORK_MAIN_THREAD = -6, //!< network main thread exception + ERROR_EX_UNSUPPORTED_OPERATION = -7, //!< unsupported operation exception + ERROR_EX_SERVICE_SPECIFIC = -8, //!< service specific exception + ERROR_EX_PARCELABLE = -9, //!< parcelable exception + // no error + NO_ERROR = 0, //!< no error + + // system service error + ERROR_NULL_POINTER, //!< null pointer + ERROR_BAD_PARAMETERS, //!< bad parameters + ERROR_SERVICE_START_FAILED, //!< failed to start service + ERROR_USER_NOT_STARTED, //!< user is not started + ERROR_USER_ALREADY_STARTED, //!< user has already started + ERROR_USER_NOT_UNLOCKED, //!< user is not unlocked + ERROR_USER_ALREADY_UNLOCKED, //!< user has already unlocked + ERROR_USER_NOT_LOCKED, //!< user is not locked + + ERROR_IME_NOT_AVAILABLE, //!< input method engine is not available + ERROR_SECURITY_IME_NOT_AVAILABLE, //!< security input method engine is not available + ERROR_TOKEN_CREATE_FAILED, //!< failed to create window token + ERROR_TOKEN_DESTROY_FAILED, //!< failed to destroy window token + ERROR_IME_BIND_FAILED, //!< failed to bind IME service + ERROR_IME_UNBIND_FAILED, //!< failed to unbind IME service + ERROR_IME_START_FAILED, //!< failed to start IME service + ERROR_IME_STOP_FAILED, //!< failed to stop IME service + ERROR_KBD_SHOW_FAILED, //!< failed to show keyboard + ERROR_KBD_HIDE_FAILED, //!< failed to hide keyboard + ERROR_IME_NOT_STARTED, //!< input method service is not started + ERROR_KBD_IS_OCCUPIED, //!< keyboard is showing by other client + ERROR_KBD_IS_NOT_SHOWING, //!< keyboard is not showing + ERROR_IME_ALREADY_STARTED, //!< input method service has already started + ERROR_NOT_IME_PACKAGE, //!< not an IME package + ERROR_IME_PACKAGE_DUPLICATED, //!< duplicated IME package + ERROR_SETTING_SAME_VALUE, //!< same setting value + ERROR_NO_NEXT_IME, //!< no next ime is available + ERROR_CLIENTWINDOW_NOT_FOCUSED, //!< the input client window is not focused + ERROR_CLIENT_NOT_WINDOW, //!< the input client is not from a valid window + // error from ime + ERROR_REMOTE_IME_DIED, //!< remote input method service died abnormally + ERROR_RESTART_IME_FAILED, //!< failed to restart input method service + // error from client + ERROR_REMOTE_CLIENT_DIED, //!< remote client died abnormally + ERROR_CLIENT_DUPLICATED, //!< duplicated client + ERROR_CLIENT_NOT_FOUND, //!< client is not found + + }; + const char* ToString(int errorCode); +}; + +static constexpr HiviewDFX::HiLogLabel g_SMALL_SERVICES_LABEL = { + LOG_CORE, + 0xD001C00, + "ImsaKit" +}; + +#define IMSA_HILOGD(fmt, ...) (void)OHOS::HiviewDFX::HiLog::Debug(OHOS::MiscServices::g_SMALL_SERVICES_LABEL, \ + "line: %d, function: %s," fmt, __LINE__, __FUNCTION__, ##__VA_ARGS__) +#define IMSA_HILOGE(fmt, ...) (void)OHOS::HiviewDFX::HiLog::Error(OHOS::MiscServices::g_SMALL_SERVICES_LABEL, \ + "line: %d, function: %s," fmt, __LINE__, __FUNCTION__, ##__VA_ARGS__) +#define IMSA_HILOGF(fmt, ...) (void)OHOS::HiviewDFX::HiLog::Fatal(OHOS::MiscServices::g_SMALL_SERVICES_LABEL, \ + "line: %d, function: %s," fmt, __LINE__FILE__, __FUNCTION__, ##__VA_ARGS__) +#define IMSA_HILOGI(fmt, ...) (void)OHOS::HiviewDFX::HiLog::Info(OHOS::MiscServices::g_SMALL_SERVICES_LABEL, \ + "line: %d, function: %s," fmt, __LINE__, __FUNCTION__, ##__VA_ARGS__) +#define IMSA_HILOGW(fmt, ...) (void)OHOS::HiviewDFX::HiLog::Warn(OHOS::MiscServices::g_SMALL_SERVICES_LABEL, \ + "line: %d, function: %s," fmt, __LINE__, __FUNCTION__, ##__VA_ARGS__) + +} +} +#endif // FM_IMMS_PROJECT_GLOBAL_H diff --git a/services/include/i_input_control_channel.h b/services/include/i_input_control_channel.h new file mode 100644 index 00000000..39f89b9d --- /dev/null +++ b/services/include/i_input_control_channel.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2021 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 FM_IMMS_PROJECT_IINPUTCONTROLCHANNEL_H +#define FM_IMMS_PROJECT_IINPUTCONTROLCHANNEL_H + +#include "iremote_broker.h" +#include "input_channel.h" +#include "i_input_method_agent.h" +#include "global.h" + +namespace OHOS { + namespace MiscServices { + class IInputControlChannel : public IRemoteBroker { + public: + enum { + ON_AGENT_CREATED = FIRST_CALL_TRANSACTION, + HIDE_KEYBOARD_SELF, + ADVANCE_TO_NEXT, + SET_DISPLAY_MODE, + ON_KEYBOARD_SHOWED, + }; + + DECLARE_INTERFACE_DESCRIPTOR(u"ohos.miscservices.inputmethod.InputControlChannel"); + + virtual void onAgentCreated(sptr& agent, InputChannel* channel) = 0; + virtual void hideKeyboardSelf(int flags) = 0; + virtual bool advanceToNext(bool isCurrentIme) = 0; + virtual void setDisplayMode(int mode) = 0; + virtual void onKeyboardShowed() = 0; + }; + } +} + +#endif // FM_IMMS_PROJECT_IINPUTCONTROLCHANNEL_H diff --git a/services/include/i_input_method_proxy.h b/services/include/i_input_method_proxy.h new file mode 100644 index 00000000..f5122608 --- /dev/null +++ b/services/include/i_input_method_proxy.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2021 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 FM_IMMS_PROJECT_IINPUTMETHODAGENT_H +#define FM_IMMS_PROJECT_IINPUTMETHODAGENT_H + +#include "iremote_broker.h" +#include "iremote_object.h" +#include "global.h" + +namespace OHOS { + namespace MiscServices { + class IInputMethodProxy : public IRemoteBroker { + public: + enum { + DISPATCH_KEY = FIRST_CALL_TRANSACTION, + }; + + DECLARE_INTERFACE_DESCRIPTOR(u"ohos.miscservices.inputmethod.IInputMethodProxy"); + + virtual int32_t dispatchKey(int key, int status) = 0; + }; + } +} + +#endif // FM_IMMS_PROJECT_IINPUTMETHODAGENT_H diff --git a/services/include/i_input_method_system_ability.h b/services/include/i_input_method_system_ability.h new file mode 100644 index 00000000..a4c36655 --- /dev/null +++ b/services/include/i_input_method_system_ability.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2021 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 FM_IMMS_PROJECT_IINPUTMETHODSYSTEMABILITY_H +#define FM_IMMS_PROJECT_IINPUTMETHODSYSTEMABILITY_H + +#include +#include +#include "iremote_broker.h" +#include "i_input_client.h" +#include "i_input_data_channel.h" +#include "input_attribute.h" +#include "input_method_property.h" +#include "keyboard_type.h" +#include "global.h" +#include "message_parcel.h" +#include "i_input_method_core.h" + +namespace OHOS { +namespace MiscServices { +class IInputMethodSystemAbility : public IRemoteBroker { +public: + enum { + PREPARE_INPUT = 0, + RELEASE_INPUT, + START_INPUT, + STOP_INPUT, + SET_INPUT_METHOD_CORE, + GET_DISPLAY_MODE, + GET_KEYBOARD_WINDOW_HEIGHT, + GET_CURRENT_KEYBOARD_TYPE, + LIST_INPUT_METHOD_ENABLED, + LIST_INPUT_METHOD, + LIST_KEYBOARD_TYPE, + }; + + DECLARE_INTERFACE_DESCRIPTOR(u"ohos.miscservices.inputmethod.IInputMethodSystemAbility"); + + virtual void prepareInput(MessageParcel& data) = 0; + virtual void releaseInput(MessageParcel& data) = 0; + virtual void startInput(MessageParcel& data) = 0; + virtual void stopInput(MessageParcel& data) = 0; + virtual int32_t setInputMethodCore(sptr &core)=0; + + virtual int32_t getDisplayMode(int32_t *retMode) = 0; + virtual int32_t getKeyboardWindowHeight(int32_t *retHeight) = 0; + virtual int32_t getCurrentKeyboardType(KeyboardType* retType) = 0; + virtual int32_t listInputMethodEnabled(std::vector *properties) = 0; + virtual int32_t listInputMethod(std::vector *properties) = 0; + virtual int32_t listKeyboardType(const std::u16string& imeId, std::vector *types) = 0; +}; +} +} + +#endif // FM_IMMS_PROJECT_IINPUTMETHODSYSTEMABILITY_H diff --git a/services/include/i_platform_api.h b/services/include/i_platform_api.h new file mode 100644 index 00000000..4daf8514 --- /dev/null +++ b/services/include/i_platform_api.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2021 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 FM_IMMS_PROJECT_IPLATFORMAPI_H +#define FM_IMMS_PROJECT_IPLATFORMAPI_H + +#include +#include +#include "iremote_broker.h" +#include "ipc_types.h" + +#include "i_platform_callback.h" +#include "input_method_property.h" +#include "input_method_setting.h" +#include "i_input_method_core.h" +#include "global.h" + +namespace OHOS { + namespace MiscServices { + class IPlatformApi : public IRemoteBroker { + public: + enum { + REGISTER_CALLBACK = FIRST_CALL_TRANSACTION, + BIND_IMS, + UNBIND_IMS, + CREATE_WINDOW_TOKEN, + DESTROY_WINDOW_TOKEN, + LIST_INPUT_METHOD, + GET_INPUT_METHOD_PROPERTY, + GET_INPUT_METHOD_SETTING, + SET_INPUT_METHOD_SETTING, + }; + + DECLARE_INTERFACE_DESCRIPTOR(u"ohos.miscservices.inputmethod.IPlatformApi"); + + virtual int32_t registerCallback(const sptr& cb) = 0; + virtual sptr bindInputMethodService(const std::u16string& packageName, + const std::u16string& intention, int userId) = 0; + virtual int32_t unbindInputMethodService(int userId, const std::u16string& packageName) = 0; + virtual sptr createWindowToken(int userId, int displayId, const std::u16string& packageName) = 0; + virtual int32_t destroyWindowToken(int userId, const std::u16string& packageName) = 0; + virtual int32_t listInputMethod(int userId, std::vector *inputMethodProperties) = 0; + virtual int32_t getInputMethodProperty(int userId, const std::u16string& packageName, + InputMethodProperty *inputMethodProperty) = 0; + virtual int32_t getInputMethodSetting(int userId, InputMethodSetting *inputMethodSetting) = 0; + virtual int32_t setInputMethodSetting(int userId, const InputMethodSetting& inputMethodSetting) = 0; + + }; +} +} +#endif // FM_IMMS_PROJECT_IPLATFORMAPI_H diff --git a/services/include/i_platform_callback.h b/services/include/i_platform_callback.h new file mode 100644 index 00000000..e4554866 --- /dev/null +++ b/services/include/i_platform_callback.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2021 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 FM_IMMS_PROJECT_IPLATFORMCALLBACK_H +#define FM_IMMS_PROJECT_IPLATFORMCALLBACK_H + +#include +#include +#include "iremote_broker.h" +#include "ipc_types.h" +#include "global.h" + +namespace OHOS { + namespace MiscServices { + class IPlatformCallback : public IRemoteBroker { + public: + enum { + NOTIFY_EVENT = OHOS::FIRST_CALL_TRANSACTION, + }; + + DECLARE_INTERFACE_DESCRIPTOR(u"ohos.miscservices.inputmethod.IPlatformCallback"); + + virtual void notifyEvent(int eventId, int userId, const std::vector& eventContent) = 0; + }; + } +} +#endif // FM_IMMS_PROJECT_IPLATFORMCALLBACK_H diff --git a/services/include/input_attribute.h b/services/include/input_attribute.h new file mode 100644 index 00000000..a15513fa --- /dev/null +++ b/services/include/input_attribute.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2021 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 FM_IMMS_PROJECT_INPUTATTRIBUTE_H +#define FM_IMMS_PROJECT_INPUTATTRIBUTE_H +#include "parcel.h" + +namespace OHOS { +namespace MiscServices { +class InputAttribute : public Parcelable { +public: + InputAttribute(); + InputAttribute(const InputAttribute& attribute); + InputAttribute& operator=(const InputAttribute& attribute); + ~InputAttribute(); + virtual bool Marshalling(Parcel &parcel) const override; + static InputAttribute *Unmarshalling(Parcel &parcel); + void SetInputPattern(int32_t pattern); + bool GetSecurityFlag(); + static const int32_t PATTERN_TEXT = 0x00000001; + static const int32_t PATTERN_PASSWORD = 0x00000007; +private: + int32_t inputPattern; + int32_t enterKeyType; + int32_t inputOption; +}; +} +} + +#endif // FM_IMMS_PROJECT_INPUTATTRIBUTE_H diff --git a/services/include/input_channel.h b/services/include/input_channel.h new file mode 100644 index 00000000..670b1cef --- /dev/null +++ b/services/include/input_channel.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2021 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 FM_IMMS_PROJECT__INPUTCHANNEL_H +#define FM_IMMS_PROJECT__INPUTCHANNEL_H +#include "parcel.h" +#include "global.h" +#include "message_parcel.h" +#include + +namespace OHOS { +namespace MiscServices { + class InputChannel : public Parcelable{ + public: + InputChannel(); + ~InputChannel(); + virtual bool Marshalling(Parcel &parcel) const override; + static InputChannel *Unmarshalling(Parcel &parcel); + private: + std::u16string name; + MessageParcel inputChannelParcel; + InputChannel(const InputChannel& channel); + InputChannel& operator=(const InputChannel& channel); + }; +} +} +#endif // INPUTMETHODSYSTEMSERVICE_INPUTCHANNEL_H diff --git a/services/include/input_control_channel_proxy.h b/services/include/input_control_channel_proxy.h new file mode 100644 index 00000000..f08b4d0e --- /dev/null +++ b/services/include/input_control_channel_proxy.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2021 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 FM_IMMS_PROJECT_INPUTCONTROLCHANNELPROXY_H +#define FM_IMMS_PROJECT_INPUTCONTROLCHANNELPROXY_H + +#include "parcel.h" +#include "iremote_broker.h" +#include "message_parcel.h" +#include "message_handler.h" + +#include "global.h" +#include "iremote_proxy.h" +#include "i_input_control_channel.h" +#include "i_input_method_agent.h" + +namespace OHOS { +namespace MiscServices { + class InputControlChannelProxy : public IRemoteProxy { + public: + InputControlChannelProxy(const sptr &impl); + ~InputControlChannelProxy(); + + virtual void onAgentCreated(sptr& agent, InputChannel* channel) override; + virtual void hideKeyboardSelf(int flags) override; + virtual bool advanceToNext(bool isCurrentIme) override; + virtual void setDisplayMode(int mode) override; + virtual void onKeyboardShowed() override; + }; +} +} +#endif // FM_IMMS_PROJECT_INPUTCONTROLCHANNELPROXY_H + + diff --git a/services/include/input_control_channel_stub.h b/services/include/input_control_channel_stub.h new file mode 100644 index 00000000..af616457 --- /dev/null +++ b/services/include/input_control_channel_stub.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2021 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 FM_IMMS_PROJECT_INPUTCONTROLCHANNEL_SK_H +#define FM_IMMS_PROJECT_INPUTCONTROLCHANNEL_SK_H + +#include "iremote_broker.h" +#include "iremote_stub.h" +#include "i_input_method_agent.h" +#include "input_channel.h" +#include +#include +#include "message_parcel.h" +#include "i_input_control_channel.h" + +namespace OHOS { + namespace MiscServices { + class InputControlChannelStub : public IRemoteStub { + public: + explicit InputControlChannelStub(int userId); + virtual ~InputControlChannelStub(); + virtual int OnRemoteRequest(uint32_t code, + MessageParcel &data, + MessageParcel &reply, + MessageOption &option) override; + virtual void onAgentCreated(sptr& agent, InputChannel* channel) override; + virtual void hideKeyboardSelf(int flags) override; + virtual bool advanceToNext(bool isCurrentIme) override; + virtual void setDisplayMode(int mode) override; + virtual void onKeyboardShowed() override; + + void ResetFlag(); + bool GetAgentAndChannel(sptr* retAgent, InputChannel** retChannel); + bool WaitKeyboardReady(); + private: + int userId_; + sptr agent = nullptr; + InputChannel* channel = nullptr; + + std::mutex mtx; + std::condition_variable cv; + bool agentReadyFlag = false; + bool keyboardReadyFlag = false; + }; +} +} +#endif // FM_IMMS_PROJECT_INPUTCONTROLCHANNEL_SK_H diff --git a/services/include/input_method_ability_connection_stub.h b/services/include/input_method_ability_connection_stub.h new file mode 100644 index 00000000..f6739ce6 --- /dev/null +++ b/services/include/input_method_ability_connection_stub.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2021 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 SERVICES_INPUTMETHODABILITYCONNECTIONSTUB_H +#define SERVICES_INPUTMETHODABILITYCONNECTIONSTUB_H +#include "ability_connect_callback_stub.h" +#include "want.h" +#include "element_name.h" +#include "message_handler.h" +#include "iremote_object.h" +#include "global.h" + +namespace OHOS { + namespace MiscServices { + class InputMethodAbilityConnectionStub : public AAFwk::AbilityConnectionStub { + public: + enum MessageID { + MSG_ID_ABILITY_CONNECT_DONE = 1, + MSG_ID_ABILITY_DISCONNECT_DONE, + }; + + InputMethodAbilityConnectionStub(const int index); + ~InputMethodAbilityConnectionStub(); + void OnAbilityConnectDone(const AppExecFwk::ElementName &element, const sptr &remoteObject, int resultCode) override; + void OnAbilityDisconnectDone(const AppExecFwk::ElementName &element, int resultCode) override; + void SetHandler(MessageHandler* handler); + + + private: + MessageHandler* messageHandler; + int mIndex; + }; + } +} +#endif // SERVICES_INPUTMETHODABILITYCONNECTIONSTUB_H \ No newline at end of file diff --git a/services/include/input_method_property.h b/services/include/input_method_property.h new file mode 100644 index 00000000..da09a696 --- /dev/null +++ b/services/include/input_method_property.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2021 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 FM_IMMS_PROJECT_INPUTMETHODPROPERTY_H +#define FM_IMMS_PROJECT_INPUTMETHODPROPERTY_H +#include +#include "parcel.h" +#include +#include "keyboard_type.h" + +namespace OHOS { +namespace MiscServices { +class InputMethodProperty : public Parcelable { +public: + std::u16string mImeId; + std::u16string mPackageName; + std::u16string mAbilityName; + std::u16string mConfigurationPage; + bool isSystemIme; + int32_t mDefaultImeId; + std::vector mTypes; + + InputMethodProperty(); + ~InputMethodProperty(); + InputMethodProperty(const InputMethodProperty& property); + InputMethodProperty& operator=(const InputMethodProperty& property); + virtual bool Marshalling(Parcel &parcel) const override; + static InputMethodProperty *Unmarshalling(Parcel &parcel); +}; +} +} +#endif // FM_IMMS_PROJECT_INPUTMETHODPROPERTY_H diff --git a/services/include/input_method_setting.h b/services/include/input_method_setting.h new file mode 100644 index 00000000..143fe8b9 --- /dev/null +++ b/services/include/input_method_setting.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2021 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 FM_IMMS_PROJECT_INPUTMETHODSETTING_H +#define FM_IMMS_PROJECT_INPUTMETHODSETTING_H +#include +#include +#include "global.h" +#include "parcel.h" +#include "string.h" + +namespace OHOS { +namespace MiscServices { + class InputMethodSetting : public Parcelable { + public: + + const static std::u16string CURRENT_INPUT_METHOD_TAG; //!< the item name of 'default IME' in the system setting + const static std::u16string ENABLED_INPUT_METHODS_TAG; //!< the item name of 'enabled IME list' in the system setting + const static std::u16string CURRENT_KEYBOARD_TYPE_TAG; //!< the item name of 'default keyboard type' in the system setting + const static std::u16string CURRENT_SYS_KEYBOARD_TYPE_TAG; + //!< the item name of 'default keyboard type for security IME in the system setting + + const static std::u16string SYSTEM_LOCALE_TAG; //!< the item name of locale list supported in the system + + + InputMethodSetting(); + ~InputMethodSetting(); + InputMethodSetting(const InputMethodSetting& inputMethodSetting); + InputMethodSetting& operator=(const InputMethodSetting& inputMethodSetting); + + void SetValue(const std::u16string& key, const std::u16string& value); + std::u16string GetValue(const std::u16string& key) const; + + std::u16string GetCurrentInputMethod() const; + void SetCurrentInputMethod(const std::u16string& imeId); + + std::vector GetEnabledInputMethodList(); + bool AddEnabledInputMethod(const std::u16string& imeId, const std::vector& types); + bool RemoveEnabledInputMethod(const std::u16string& imdId); + + std::vector GetEnabledKeyboardTypes(const std::u16string& imeId); + int32_t GetCurrentKeyboardType(); + void SetCurrentKeyboardType(int32_t type); + int32_t GetCurrentSysKeyboardType(); + void SetCurrentSysKeyboardType(int32_t type); + void ClearData(); + bool FindKey(const std::u16string& key) const; + + virtual bool Marshalling(Parcel &parcel) const override; + static InputMethodSetting *Unmarshalling(Parcel &parcel); + + private: + std::map setting; + const char16_t DELIM_IME = ':'; + const char16_t DELIM_KBD_TYPE = ';'; + std::vector Split(const std::u16string& str, char16_t delim); + std::u16string BuildString(const std::vector& vector, char16_t delim); + }; +} +} +#endif // FM_IMMS_PROJECT_INPUTMETHODSETTING_H diff --git a/services/include/input_method_system_ability.h b/services/include/input_method_system_ability.h new file mode 100644 index 00000000..85080b89 --- /dev/null +++ b/services/include/input_method_system_ability.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2021 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 FM_IMMS_PROJECT_INPUTMETHODSYSTEMABILITY_H +#define FM_IMMS_PROJECT_INPUTMETHODSYSTEMABILITY_H + +#include +#include +#include "system_ability.h" +#include "input_method_system_ability_stub.h" +#include "peruser_setting.h" +#include "peruser_session.h" +#include "event_handler.h" +#include "input_method_ability.h" + +namespace OHOS { +namespace MiscServices { + enum class ServiceRunningState { + STATE_NOT_START, + STATE_RUNNING + }; + + class InputMethodSystemAbility : public SystemAbility, public InputMethodSystemAbilityStub { + DECLARE_SYSTEM_ABILITY(InputMethodSystemAbility); + public: + DISALLOW_COPY_AND_MOVE(InputMethodSystemAbility); + InputMethodSystemAbility(int32_t systemAbilityId, bool runOnCreate); + InputMethodSystemAbility(); + ~InputMethodSystemAbility(); + static sptr GetInstance(); + + int32_t GetUserState(int32_t userId); + + int32_t OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + virtual int32_t getDisplayMode(int32_t *retMode) override; + virtual int32_t getKeyboardWindowHeight(int32_t *retHeight) override; + virtual int32_t getCurrentKeyboardType(KeyboardType* retType) override; + virtual int32_t listInputMethodEnabled(std::vector *properties) override; + virtual int32_t listInputMethod(std::vector *properties) override; + virtual int32_t listKeyboardType(const std::u16string& imeId, std::vector *types) override; + int32_t dump(int32_t fd, const std::vector& args); + virtual int32_t setInputMethodCore(sptr &core) override; + protected: + void OnStart() override; + void OnStop() override; + private: + int32_t Init(); + void Initialize(); + + std::thread workThreadHandler; /*!< thread handler of the WorkThread */ + + std::map userSettings; + + std::map userSessions; + std::map msgHandlers; + + void WorkThread(); + PerUserSetting* GetUserSetting(int32_t userId); + PerUserSession* GetUserSession(int32_t userId); + int32_t OnUserStarted(const Message* msg); + int32_t OnUserStopped(const Message* msg); + int32_t OnUserUnlocked(const Message* msg); + int32_t OnUserLocked(const Message* msg); + int32_t OnPrepareInput(Message* msg); + int32_t OnHandleMessage(Message* msg); + int32_t OnRemotePeerDied(const Message* msg); + int32_t OnSettingChanged(const Message* msg); + int32_t OnPackageRemoved(const Message* msg); + int32_t OnPackageAdded(const Message* msg); + int32_t OnDisableIms(const Message* msg); + int32_t OnAdvanceToNext(const Message* msg); + + ServiceRunningState state_; + sptr inputMethodAbility_; + void InitServiceHandler(); + static std::mutex instanceLock_; + static sptr instance_; + static std::shared_ptr serviceHandler_; + }; +} +} +#endif // FM_IMMS_PROJECT_INPUTMETHODSYSTEMABILITY_H diff --git a/services/include/input_method_system_ability_stub.h b/services/include/input_method_system_ability_stub.h new file mode 100644 index 00000000..3b193e40 --- /dev/null +++ b/services/include/input_method_system_ability_stub.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2021 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 FM_IMMS_PROJECT_INPUTMETHODSYSTEMABILITY_SK_H +#define FM_IMMS_PROJECT_INPUTMETHODSYSTEMABILITY_SK_H +#include +#include "refbase.h" +#include "i_input_method_system_ability.h" +#include "iremote_stub.h" +#include "global.h" +#include "message_parcel.h" + +namespace OHOS { +namespace MiscServices { +class InputMethodSystemAbilityStub : public IRemoteStub { +public: + int32_t OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + + virtual void prepareInput(MessageParcel& data) override; + virtual void releaseInput(MessageParcel& data) override; + virtual void startInput(MessageParcel& data) override; + virtual void stopInput(MessageParcel& data) override; + void setInputMethodCoreFromHap(MessageParcel& data); +protected: + int32_t getUserId(int32_t uid); +}; +} +} + +#endif // FM_IMMS_PROJECT_INPUTMETHODSYSTEMABILITY_SK_H diff --git a/services/include/keyboard_type.h b/services/include/keyboard_type.h new file mode 100644 index 00000000..da68164e --- /dev/null +++ b/services/include/keyboard_type.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2021 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 FM_IMMS_PROJECT_KEYBOARDTYPE_H +#define FM_IMMS_PROJECT_KEYBOARDTYPE_H + +#include +#include "parcel.h" +#include + +namespace OHOS { +namespace MiscServices { +class KeyboardType : public Parcelable { +public: + KeyboardType(); + KeyboardType(const KeyboardType& type); + ~KeyboardType(); + KeyboardType& operator=(const KeyboardType& type); + virtual bool Marshalling(Parcel &parcel) const override; + static KeyboardType *Unmarshalling(Parcel &parcel); + void setId(int32_t typeId); + void setLabelId(int32_t labelId); + void setIconId(int32_t iconId); + void setAsciiCapability(bool isAsciiCapable); + void setLanguage(std::u16string language); + void setInputSource(std::u16string inputSource); + void setCustomizedValue(std::u16string keyBoardTypeCustomizedValue); + int32_t getId() const; + int32_t getLabelId() const; + int32_t getIconId() const; + int32_t getHashCode() const; + std::u16string getLanguage() const; + std::u16string getInputSource() const; + std::u16string getCustomizedValue() const; + bool supportsAscii(); + +private: + int32_t mId; + int32_t mHashCode; + int32_t mLabelId; + int32_t mIconId; + bool mIsAsciiCapable; + std::u16string mLanguage; + std::u16string mInputSource; + std::u16string mCustomizedValue; + + const int32_t ID_NONE = 0; +}; +} +} +#endif // FM_IMMS_PROJECT_KEYBOARDTYPE_H diff --git a/services/include/message.h b/services/include/message.h new file mode 100644 index 00000000..2f5581a2 --- /dev/null +++ b/services/include/message.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2021 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. + */ + +/*! \file MessageHandler.h */ +#ifndef FM_IMMS_PROJECT_MESSAGE_H +#define FM_IMMS_PROJECT_MESSAGE_H + +#include "global.h" +#include "message_parcel.h" +namespace OHOS { +namespace MiscServices { +class Message { +public: + int32_t msgId_; //!< message id + MessageParcel *msgContent_ = nullptr; //!< message content + Message(int32_t msgId, MessageParcel* msgContent); + explicit Message(const Message& msg); + Message& operator= (const Message& msg); + ~Message(); +private: + Message(const Message&&); + Message& operator= (const Message&&); +}; +} +} + +#endif // FM_IMMS_PROJECT_MESSAGE_H \ No newline at end of file diff --git a/services/include/message_handler.h b/services/include/message_handler.h new file mode 100644 index 00000000..88fa4c31 --- /dev/null +++ b/services/include/message_handler.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2021 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. + */ + +/*! \file MessageHandler.h */ +#ifndef FM_IMMS_PROJECT_MESSAGEHANDLER_H +#define FM_IMMS_PROJECT_MESSAGEHANDLER_H + +#include +#include +#include +#include "global.h" +#include "message_parcel.h" +#include "message.h" + +namespace OHOS { +namespace MiscServices { +namespace MessageID { + enum { + // for system broadcast + MSG_ID_SYSTEM_START = 0, //!< system started + MSG_ID_SYSTEM_STOP, //!< system stopped + MSG_ID_USER_START, //!< a user started + MSG_ID_USER_STOP, //!< a user stopped + MSG_ID_USER_UNLOCK, //!< a user unlocked + MSG_ID_USER_LOCK, //!< a user locked + MSG_ID_PACKAGE_ADDED, //!< a package is installed + MSG_ID_PACKAGE_REMOVED, //!< a package is removed + MSG_ID_SETTING_CHANGED, //!< input method setting is changed + + // the request from client + MSG_ID_PREPARE_INPUT, //!< prepare input + MSG_ID_START_INPUT, //!< start input + MSG_ID_STOP_INPUT, //!< stop input + MSG_ID_RELEASE_INPUT, //!< release input + MSG_ID_SET_INPUT_METHOD_CORE, + + // the request to handle the condition that the remote object died + MSG_ID_CLIENT_DIED, //!< input client died + MSG_ID_IMS_DIED, //!< input method service died + MSG_ID_DISABLE_IMS, //!< disable input method service + MSG_ID_RESTART_IMS, //!< restart input method service + MSG_ID_HIDE_KEYBOARD_SELF, //!< hide the current keyboard + MSG_ID_ADVANCE_TO_NEXT, //!< switch to next + MSG_ID_SET_DISPLAY_MODE, //!< set display mode + + MSG_ID_SHELL_COMMAND, //!< shell command + MSG_ID_EXIT_SERVICE, //!< exit service + + //the request from IMSA to IMC + MSG_ID_INSERT_CHAR, + MSG_ID_DELETE_BACKWARD, + MSG_ID_CLOSE, + MSG_ID_ON_INPUT_READY, + + // the request from IMSA to IMA + MSG_ID_SHOW_KEYBOARD, // + MSG_ID_INITIALIZE_INPUT, // + MSG_ID_HIDE_KEYBOARD, // + MSG_ID_SET_KEYBOARD_TYPE, + MSG_ID_GET_KEYBOARD_WINDOW_HEIGHT, + + // the request from IMC to IMA + MSG_ID_DISPATCH_KEY,//!< dispatch key from PhysicalKbd + }; +} + +class MessageHandler { +public: + MessageHandler(); + ~MessageHandler(); + void SendMessage(Message* msg); + Message* GetMessage(); + static MessageHandler* Instance(); + +private: + std::mutex mMutex; //!< a mutex to guard message queue + std::condition_variable mCV; //!< condition variable to work with mMutex + std::queue mQueue ;//!< Message queue, guarded by mMutex; + + MessageHandler(const MessageHandler&); + MessageHandler& operator= (const MessageHandler&); + MessageHandler(const MessageHandler&&); + MessageHandler& operator= (const MessageHandler&&); +}; +} +} + +#endif // FM_IMMS_PROJECT_MESSAGEHANDLER_H diff --git a/services/include/peruser_session.h b/services/include/peruser_session.h new file mode 100644 index 00000000..e8e3f0be --- /dev/null +++ b/services/include/peruser_session.h @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2021 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 FM_IMMS_PROJECT_PERUSERSESSION_H +#define FM_IMMS_PROJECT_PERUSERSESSION_H + +#include +#include +#include +#include + +#include "iremote_object.h" +#include "i_input_control_channel.h" +#include "i_input_client.h" +#include "i_input_method_core.h" +#include "i_input_data_channel.h" +#include "i_input_method_agent.h" +#include "input_attribute.h" +#include "input_method_property.h" +#include "input_method_setting.h" +#include "input_control_channel_stub.h" +#include "message.h" +#include "message_handler.h" +#include "global.h" +#include "platform.h" +#include "keyboard_type.h" +#include "ability_manager_interface.h" +#include "ability_connect_callback_proxy.h" +#include "input_method_ability.h" + +namespace OHOS { + namespace MiscServices { + + + class RemoteObjectDeathRecipient : public IRemoteObject::DeathRecipient { + public: + RemoteObjectDeathRecipient(int userId, int msgId); + ~RemoteObjectDeathRecipient(); + void OnRemoteDied(const wptr& who) override; + private : + int userId_; //!< the id of the user to whom the object is linking + int msgId_; //!< the message id can be MessageID::MSG_ID_CLIENT_DIED and MessageID::MSG_ID_IMS_DIED + }; + + /*! \class ClientInfo + \brief The class defines the details of an input client. + */ + class ClientInfo { + public: + int pid; //!< the process id of the process in which the input client is running + int uid; //!< the uid of the process in which the input client is running + int userId; //!< the user if of the user under which the input client is running + int displayId; //!< the display id on which the input client is showing + sptr client; //!< the remote object handler for the service to callback to the input client + sptr channel; //!< the remote object handler for input method service callback to input client + InputAttribute attribute; //!< the input attribute of the input client + + ClientInfo(int pid, int uid, int userId, int displayId, const sptr& client, + const sptr& channel, const InputAttribute& attribute) + { + this->pid = pid; + this->uid = uid; + this->userId = userId; + this->displayId = displayId; + this->client = client; + this->channel = channel; + this->attribute = attribute; + }; + + ~ClientInfo() + { + this->client = nullptr; + this->channel = nullptr; + }; + }; + + /*! \class PerUserSession + \brief The class provides session management in input method management service + + This class manages the sessions between input clients and input method engines for each unlocked user. + */ + class PerUserSession { + enum { + DEFAULT_IME = 0, //!< index for default input method service + SECURITY_IME = 1, //!< index for security input method service + MAX_IME = 2, //!< the maximum count of ims started for a user + }; + + public: + explicit PerUserSession(int userId); + ~PerUserSession(); + + void SetCurrentIme(InputMethodProperty* ime); + void SetSecurityIme(InputMethodProperty* ime); + void SetInputMethodSetting(InputMethodSetting* setting); + void ResetIme(InputMethodProperty* defaultIme, InputMethodProperty* securityIme); + void OnPackageRemoved(const std::u16string& packageName); + + int GetDisplayMode(); + int GetKeyboardWindowHeight(int *retHeight); + KeyboardType* GetCurrentKeyboardType(); + + int OnSettingChanged(const std::u16string& key, const std::u16string& value); + void Dump(int fd); + void CreateWorkThread(MessageHandler& handler); + void JoinWorkThread(); + void SetInputMethodAbility(sptr &inputMethodAbility); + static void BindInputAbility(); + private: + int userId_; //!< the id of the user to whom the object is linking + int userState; //!< the state of the user to whom the object is linking + int displayId; //!< the id of the display screen on which the user is + int currentIndex; + std::map, ClientInfo*> mapClients; //!< a map to manage the input clients connected to the service + /*!< \n key is the remote IInputClient handler + \n value is an object of an ClientInfo */ + + InputMethodProperty* currentIme[MAX_IME]; //!< 0 - the default ime. 1 - security ime + /*!< \n The pointers are referred to the objects in the PerUserSetting */ + + InputControlChannelStub* localControlChannel[MAX_IME]; //!< inputControlChannel object used by the local process + sptr inputControlChannel[MAX_IME]; //!< channels between the service and input method service + sptr imsCore[MAX_IME]; //!< the remote handlers of input method service + sptr inputMethodToken[MAX_IME]; //!< the window token of keyboard + int currentKbdIndex[MAX_IME]; //!< current keyboard index + int lastImeIndex; //!< The last ime which showed keyboard + InputMethodSetting* inputMethodSetting; //!< The pointer referred to the object in PerUserSetting + int currentDisplayMode; //!< the display mode of the current keyboard + + sptr imsAgent; + InputChannel* imsChannel; //!< the write channel created by input method service + sptr currentClient; //!< the current input client + sptr needReshowClient; //!< the input client for which keyboard need to re-show + + sptr clientDeathRecipient; //!< remote object death monitor for input client + sptr imsDeathRecipient; //!< remote object death monitor for input method service + MessageHandler* msgHandler = nullptr; //!< message handler working with Work Thread + std::thread workThreadHandler; //!< work thread handler + std::mutex mtx; //!< mutex to lock the operations among multi work threads + sptr connCallback; + sptr inputMethodAbility_; + + PerUserSession(const PerUserSession&); + PerUserSession& operator= (const PerUserSession&); + PerUserSession(const PerUserSession&&); + PerUserSession& operator= (const PerUserSession&&); + int IncreaseOrResetImeError(bool resetFlag, int imeIndex); + KeyboardType* GetKeyboardType(int imeIndex, int typeIndex); + void ResetCurrentKeyboardType(int imeIndex); + int OnCurrentKeyboardTypeChanged(int index, const std::u16string& value); + void DumpClientInfo(int fd, const ClientInfo& clientInfo); + void DumpCurrentSession(int fd); + void CopyInputMethodService(int imeIndex); + ClientInfo* GetClientInfo(const sptr& inputClient); + void WorkThread(); + void OnPrepareInput(Message* msg); + void OnReleaseInput(Message* msg); + void OnStartInput(Message* msg); + void OnStopInput(Message* msg); + void OnClientDied(const wptr& who); + void OnImsDied(const wptr& who); + void OnHideKeyboardSelf(int flags); + void OnAdvanceToNext(); + void OnSetDisplayMode(int mode); + void OnRestartIms(int index, const std::u16string& imeId); + void OnUserLocked(); + int AddClient(int pid, int uid, int displayId, const sptr& inputClient, + const sptr& channel, + const InputAttribute& attribute); + int RemoveClient(const sptr& inputClient, int *retClientNum); + int StartInputMethod(int index); + int StopInputMethod(int index); + int ShowKeyboard(const sptr& inputClient); + int HideKeyboard(const sptr& inputClient); + void SetDisplayId(int displayId); + int GetImeIndex(const sptr& inputClient); + static sptr GetAbilityManagerService(); + void onSetInputMethodCore(Message* msg); + + }; + } +} + +#endif // FM_IMMS_PROJECT_PERUSERSESSION_H diff --git a/services/include/peruser_setting.h b/services/include/peruser_setting.h new file mode 100644 index 00000000..37e4cb86 --- /dev/null +++ b/services/include/peruser_setting.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2021 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 FM_IMMS_PROJECT_PERUSERSETTING_H +#define FM_IMMS_PROJECT_PERUSERSETTING_H + +#include +#include +#include +#include "input_method_property.h" +#include "input_method_setting.h" +#include "global.h" + +namespace OHOS { +namespace MiscServices { +class PerUserSetting { +public: + explicit PerUserSetting(int32_t userId); + + ~PerUserSetting(); + + void Initialize(); + int32_t GetUserState(); + InputMethodProperty* GetCurrentInputMethod(); + InputMethodProperty* GetSecurityInputMethod(); + InputMethodProperty* GetNextInputMethod(); + InputMethodSetting* GetInputMethodSetting(); + InputMethodProperty* GetInputMethodProperty(const std::u16string& imeId); + + int32_t OnPackageAdded(std::u16string& packageName, bool* isSecurityIme = nullptr); + int32_t OnPackageRemoved(std::u16string& packageName, bool* isSecurityIme = nullptr); + int32_t OnSettingChanged(const std::u16string& key, const std::u16string& value); + void OnAdvanceToNext(); + void OnUserLocked(); + void Dump(int32_t fd); + + int32_t ListInputMethodEnabled(std::vector *properties); + int32_t ListInputMethod(std::vector *properties); + int32_t ListKeyboardType(const std::u16string& imeId, std::vector *types); + + static bool CheckIfSecurityIme(const InputMethodProperty& property); + +private: + int32_t userId_; //!< the id of the user to whom the object is linking + int32_t userState; //!< the state of the user to whom the object is linking + std::vector inputMethodProperties; //!< a vector to save all IME installed for this user + std::u16string currentImeId; //!< the id of the default input method engine. + InputMethodSetting inputMethodSetting; //!< the object to manage the setting data for this user + + PerUserSetting(const PerUserSetting&); + PerUserSetting& operator= (const PerUserSetting&); + PerUserSetting(const PerUserSetting&&); + PerUserSetting& operator= (const PerUserSetting&&); + void InitInputMethodSetting(); + void ResetCurrentInputMethod(); + std::u16string GetKeyboardTypeLanguage(const InputMethodProperty* property, int32_t hashCode); + std::u16string GetImeId(const std::u16string& packageName); +}; +} +} +#endif // FM_IMMS_PROJECT_PERUSERSETTING_H diff --git a/services/include/platform.h b/services/include/platform.h new file mode 100644 index 00000000..0ea58d18 --- /dev/null +++ b/services/include/platform.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2021 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 FM_IMMS_PROJECT_PLATFORMAPI_H +#define FM_IMMS_PROJECT_PLATFORMAPI_H + +#include +#include +#include +#include "iremote_broker.h" +#include "iremote_object.h" +#include "i_platform_api.h" +#include "i_input_method_core.h" +#include "input_method_property.h" +#include "input_method_setting.h" + +namespace OHOS { + namespace MiscServices { + + + class Platform { + public: + static Platform* Instance(); + void SetPlatform(const sptr& platformApi); + sptr BindInputMethodService(int userId, const std::u16string& packageName, const std::u16string& intention); + int UnbindInputMethodService(int userId, const std::u16string& packageName); + sptr CreateWindowToken(int userId, int displayId, const std::u16string& packageName); + int DestroyWindowToken(int userId, const std::u16string& packageName); + int ListInputMethod(int userId, std::vector* inputMethodProperties); + int GetInputMethodProperty(int userId, const std::u16string& packageName, InputMethodProperty* inputMethodProperty); + int GetInputMethodSetting(int userId, InputMethodSetting* inputMethodSetting); + int SetInputMethodSetting(int userId, const InputMethodSetting& inputMethodSetting); + bool CheckPhysicalKeyboard(); + bool IsValidWindow(int uid, int pid, int displayId); + bool IsWindowFocused(int uid, int pid, int displayId); + + static inline sptr RemoteBrokerToObject(const sptr& broker) + { + return broker->AsObject(); + } + + private: + sptr platformApi; + Platform(); + ~Platform(); + Platform(const Platform&); + Platform& operator = (const Platform&); + Platform(const Platform&&); + Platform& operator = (const Platform&&); + }; + + } +} +#endif // FM_IMMS_PROJECT_PLATFORMAPI_H diff --git a/services/include/platform_callback_stub.h b/services/include/platform_callback_stub.h new file mode 100644 index 00000000..5a9b33ff --- /dev/null +++ b/services/include/platform_callback_stub.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2021 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 FM_IMMS_PROJECT_PLATFORMCALLBACK_SK_H +#define FM_IMMS_PROJECT_PLATFORMCALLBACK_SK_H + +#include +#include "iremote_stub.h" +#include "message_option.h" +#include "message_parcel.h" +#include "i_platform_callback.h" + +namespace OHOS { + namespace MiscServices { + + class PlatformCallbackStub : public IRemoteStub { + public: + PlatformCallbackStub(); + ~PlatformCallbackStub(); + + virtual int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + virtual void notifyEvent(int eventId, int userId, const std::vector& eventContent) override; + }; + + } +} +#endif // FM_IMMS_PROJECT_PLATFORMCALLBACK_SK_H diff --git a/services/include/utils.h b/services/include/utils.h new file mode 100644 index 00000000..33365d65 --- /dev/null +++ b/services/include/utils.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2021 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. + */ + +/*! \file utils.h */ + +#ifndef FM_IMMS_PROJECT_UTILS_H +#define FM_IMMS_PROJECT_UTILS_H + +#include +#include +#include +#include + +namespace OHOS { +namespace MiscServices { +class Utils { + public: + static std::string to_utf8( std::u16string str16 ) { + return std::wstring_convert< std::codecvt_utf8_utf16, char16_t >{}.to_bytes(str16); + } + static std::u16string to_utf16( std::string str ) { + return std::wstring_convert< std::codecvt_utf8_utf16, char16_t >{}.from_bytes(str); + } +}; +} +} + +#endif \ No newline at end of file diff --git a/services/src/global.cpp b/services/src/global.cpp new file mode 100644 index 00000000..06440da0 --- /dev/null +++ b/services/src/global.cpp @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2021 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 "global.h" + +namespace OHOS { +namespace MiscServices { + +void LogTimeStamp() +{ + struct timeval tv; + gettimeofday(&tv, nullptr); + struct tm nowTime; + localtime_r(&tv.tv_sec, &nowTime); + printf("%02d-%02d %02d:%02d:%02d.%03d\t", nowTime.tm_mon, nowTime.tm_mday, + nowTime.tm_hour, nowTime.tm_min, nowTime.tm_sec, (int)tv.tv_usec/1000); +} + +namespace ErrorCode { + const char* ToString(int errorCode) + { + switch (errorCode) { + case NO_ERROR: { + return "no error"; + } + case ERROR_NULL_POINTER: { + return "null pointer"; + } + case ERROR_BAD_PARAMETERS: { + return "bad parameters"; + } + case ERROR_SERVICE_START_FAILED: { + return "failed to start service"; + } + case ERROR_USER_NOT_STARTED: { + return "user has not started"; + } + case ERROR_USER_ALREADY_STARTED: { + return "user has already started"; + } + case ERROR_USER_NOT_UNLOCKED: { + return "user has not unlocked"; + } + case ERROR_USER_ALREADY_UNLOCKED: { + return "user has already unlocked"; + } + case ERROR_USER_NOT_LOCKED: { + return "user has not locked"; + } + case ERROR_IME_NOT_AVAILABLE: { + return "input method engine is not available"; + } + case ERROR_SECURITY_IME_NOT_AVAILABLE: { + return "security input method engine is not available"; + } + case ERROR_TOKEN_CREATE_FAILED: { + return "failed to create token"; + } + case ERROR_TOKEN_DESTROY_FAILED: { + return "failed to destroy token"; + } + case ERROR_IME_BIND_FAILED: { + return "failed to bind service"; + } + case ERROR_IME_UNBIND_FAILED: { + return "failed to unbind service"; + } + case ERROR_IME_START_FAILED: { + return "failed to start input"; + } + case ERROR_IME_STOP_FAILED: { + return "failed to stop input"; + } + case ERROR_KBD_SHOW_FAILED: { + return "failed to show keyboard"; + } + case ERROR_KBD_HIDE_FAILED: { + return "failed to hide keyboard"; + } + case ERROR_IME_NOT_STARTED: { + return "input method service has not started"; + } + case ERROR_KBD_IS_OCCUPIED: { + return "keyboard is showing by another client"; + } + case ERROR_KBD_IS_NOT_SHOWING: { + return "keyboard is not showing"; + } + case ERROR_IME_ALREADY_STARTED: { + return "input method service has already started"; + } + case ERROR_NOT_IME_PACKAGE: { + return "not an input method engine package"; + } + case ERROR_IME_PACKAGE_DUPLICATED: { + return "duplicated input method engine package"; + } + case ERROR_SETTING_SAME_VALUE: { + return "same setting value"; + } + case ERROR_NO_NEXT_IME: { + return "next input method engine is not available"; + } + case ERROR_CLIENTWINDOW_NOT_FOCUSED: { + return "input client window is not focused"; + } + case ERROR_CLIENT_NOT_WINDOW: { + return "input client is not from a valid window"; + } + case ERROR_REMOTE_IME_DIED: { + return "input method service died"; + } + case ERROR_RESTART_IME_FAILED: { + return "failed to restart input method service"; + } + case ERROR_REMOTE_CLIENT_DIED: { + return "input client died"; + } + case ERROR_CLIENT_DUPLICATED: { + return "duplicated client"; + } + case ERROR_CLIENT_NOT_FOUND: { + return "client is not found"; + } + case ERROR_STATUS_UNKNOWN_ERROR: { + return "unknown error"; + } + case ERROR_STATUS_NO_MEMORY: { + return "no memory"; + } + case ERROR_STATUS_INVALID_OPERATION: { + return "invalid operation"; + } + case ERROR_STATUS_BAD_VALUE: { + return "bad value"; + } + case ERROR_STATUS_BAD_TYPE: { + return "bad type"; + } + case ERROR_STATUS_NAME_NOT_FOUND: { + return "name not found"; + } + case ERROR_STATUS_PERMISSION_DENIED: { + return "permission denied"; + } + case ERROR_STATUS_NO_INIT: { + return "no init"; + } + case ERROR_STATUS_ALREADY_EXISTS: { + return "already exists"; + } + case ERROR_STATUS_DEAD_OBJECT: { + return "dead object"; + } + case ERROR_STATUS_FAILED_TRANSACTION: { + return "failed transaction"; + } + case ERROR_STATUS_BAD_INDEX: { + return "bad index"; + } + case ERROR_STATUS_NOT_ENOUGH_DATA: { + return "not enough data"; + } + case ERROR_STATUS_WOULD_BLOCK: { + return "would block"; + } + case ERROR_STATUS_TIMED_OUT: { + return "time out"; + } + case ERROR_STATUS_UNKNOWN_TRANSACTION: { + return "unknown transaction"; + } + case ERROR_STATUS_FDS_NOT_ALLOWED: { + return "fds not allowed"; + } + case ERROR_STATUS_UNEXPECTED_NULL: { + return "unexpected null"; + } + case ERROR_EX_ILLEGAL_ARGUMENT: { + return "illegal argument exception"; + } + case ERROR_EX_NULL_POINTER: { + return "null pointer exception"; + } + case ERROR_EX_ILLEGAL_STATE: { + return "illegal state exception"; + } + case ERROR_EX_NETWORK_MAIN_THREAD: { + return "network main thread exception"; + } + case ERROR_EX_UNSUPPORTED_OPERATION: { + return "unsupported operation exception"; + } + case ERROR_EX_SERVICE_SPECIFIC: { + return "service specific exception"; + } + case ERROR_EX_PARCELABLE: { + return "parcelable exception"; + } + default: { + return "error is out of definition"; + } + } + return "error is out of definition"; + }; +} + +} +} + diff --git a/services/src/input_attribute.cpp b/services/src/input_attribute.cpp new file mode 100644 index 00000000..9bba4f6b --- /dev/null +++ b/services/src/input_attribute.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2021 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 "input_attribute.h" + +namespace OHOS { +namespace MiscServices { +/*! Constructor +*/ +InputAttribute::InputAttribute() : enterKeyType(0), inputOption(0) +{ +} + +/*! Constructor + \param attribute the source attribute copied to this instance +*/ +InputAttribute::InputAttribute(const InputAttribute& attribute) +{ + inputPattern = attribute.inputPattern; + enterKeyType = attribute.enterKeyType; + inputOption = attribute.inputOption; +} + +/*! Destructor +*/ +InputAttribute::~InputAttribute() +{ +} + +/*! operator= + \param attribute the source attribute copied to this instance + \return return this +*/ +InputAttribute& InputAttribute::operator=(const InputAttribute& attribute) +{ + if (this == &attribute) { + return *this; + } + inputPattern = attribute.inputPattern; + enterKeyType = attribute.enterKeyType; + inputOption = attribute.inputOption; + return *this; +} + +/*! Write InputAttribute to parcel + \param[out] parcel write the data of InputAttribute to this parcel returned to caller + \return ErrorCode::NO_ERROR + \return ErrorCode::ERROR_NULL_POINTER parcel is null +*/ +bool InputAttribute::Marshalling(OHOS::Parcel &parcel) const { + if (!(parcel.WriteInt32(inputPattern) + && parcel.WriteInt32(enterKeyType) + && parcel.WriteInt32(inputOption))) + return false; + return true; +} + +/*! Read InputAttribute from parcel + \param parcel read the data of InputAttribute from this parcel + \return ErrorCode::NO_ERROR + \return ErrorCode::ERROR_NULL_POINTER parcel is null +*/ +InputAttribute* InputAttribute::Unmarshalling(OHOS::Parcel &parcel) { + auto info = new InputAttribute(); + info->inputPattern = parcel.ReadInt32(); + info->enterKeyType = parcel.ReadInt32(); + info->inputOption = parcel.ReadInt32(); + return info; +} + +/*! Get the security flag + \return true - It's password EditView. The input method management service should start system + security input method engine for this view. + \return false - It's an normal view. +*/ +bool InputAttribute::GetSecurityFlag() +{ + if (inputPattern == PATTERN_PASSWORD) { + return true; + } + return false; +} + +/*! Set input pattern. + \n It's added for Unit test of PerUserSession + \param pattern PATTERN_PASSWORD or 0. +*/ +void InputAttribute::SetInputPattern(int32_t pattern) +{ + inputPattern = pattern; +} +} +} diff --git a/services/src/input_channel.cpp b/services/src/input_channel.cpp new file mode 100644 index 00000000..60eb4032 --- /dev/null +++ b/services/src/input_channel.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2021 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 "input_channel.h" +#include "input_attribute.h" +#include "global.h" + +namespace OHOS { +namespace MiscServices { +/*! Constructor +*/ +InputChannel::InputChannel() +{ +} + +/*! Destructor +*/ +InputChannel::~InputChannel() +{ +} + +/*! Write InputChannel to parcel + \param[out] parcel the data of InputChannel is written to this parcel returned to caller + \return ErrorCode::NO_ERROR + \return ErrorCode::ERROR_NULL_POINTER parcel is null +*/ +bool InputChannel::Marshalling(Parcel &parcel) const { + parcel.ParseFrom(inputChannelParcel.GetData(), inputChannelParcel.GetDataSize()); + return NO_ERROR; +} + +/*! Get InputChannel from parcel + \param parcel get the data of InputChannel from this parcel + \return ErrorCode::NO_ERROR + \return ErrorCode::ERROR_NULL_POINTER parcel is null +*/ +InputChannel* InputChannel::Unmarshalling(Parcel &parcel) { + auto inputChannel = new InputChannel(); + inputChannel->inputChannelParcel.RewindRead(0); + inputChannel->inputChannelParcel.ParseFrom(parcel.GetData(), parcel.GetDataSize()); + inputChannel->inputChannelParcel.RewindRead(0); + + inputChannel->name = inputChannel->inputChannelParcel.ReadString16(); + inputChannel->inputChannelParcel.RewindRead(0); + return inputChannel; +} +} +} diff --git a/services/src/input_control_channel_proxy.cpp b/services/src/input_control_channel_proxy.cpp new file mode 100644 index 00000000..a5f0181c --- /dev/null +++ b/services/src/input_control_channel_proxy.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2021 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 "parcel.h" +#include "iremote_broker.h" +#include "message_parcel.h" +#include "message_handler.h" + +#include "global.h" +#include "iremote_proxy.h" +#include "i_input_control_channel.h" +#include "i_input_method_agent.h" +#include "input_control_channel_proxy.h" + + +/*! \class InputControlChannelProxy + \brief The proxy implementation of IInputControlChannel + + This class should be implemented by input method service +*/ +namespace OHOS { +namespace MiscServices { + InputControlChannelProxy::InputControlChannelProxy(const sptr &impl) : IRemoteProxy(impl) { + } + + InputControlChannelProxy::~InputControlChannelProxy() + { + } + + void InputControlChannelProxy::onAgentCreated(sptr &agent, InputChannel* channel) + { + IMSA_HILOGI("InputControlChannelProxy::onAgentCreated start."); + MessageParcel data, reply; + MessageOption option; + + data.WriteInterfaceToken(GetDescriptor()); + data.WriteRemoteObject(agent->AsObject()); + if (channel == nullptr) { + data.WriteInt32(0); + } else { + data.WriteInt32(1); + data.WriteParcelable(channel); + } + Remote()->SendRequest(ON_AGENT_CREATED, data, reply, option); + IMSA_HILOGI("InputMethodCoreStub::onAgentCreated end."); + } + + void InputControlChannelProxy::hideKeyboardSelf(int flags) + { + IMSA_HILOGI("InputControlChannelProxy::hideKeyboardSelf"); + MessageParcel data, reply; + MessageOption option; + data.WriteInterfaceToken(GetDescriptor()); + data.WriteInt32(flags); + Remote()->SendRequest(HIDE_KEYBOARD_SELF, data, reply, option); + } + + bool InputControlChannelProxy::advanceToNext(bool isCurrentIme) + { + MessageParcel data, reply; + MessageOption option; + + data.WriteInterfaceToken(GetDescriptor()); + data.WriteBool(isCurrentIme); + Remote()->SendRequest(MessageID::MSG_ID_ADVANCE_TO_NEXT, data, reply, option); + IMSA_HILOGI("InputControlChannelProxy::advanceToNext."); + return true; + } + + void InputControlChannelProxy::setDisplayMode(int mode) + { + MessageParcel data, reply; + MessageOption option; + + data.WriteInterfaceToken(GetDescriptor()); + data.WriteInt32(mode); + Remote()->SendRequest(MessageID::MSG_ID_SET_DISPLAY_MODE, data, reply, option); + IMSA_HILOGI("InputControlChannelProxy::setDisplayMode."); + } + + void InputControlChannelProxy::onKeyboardShowed() + { + MessageParcel data, reply; + MessageOption option; + + data.WriteInterfaceToken(GetDescriptor()); + Remote()->SendRequest(ON_KEYBOARD_SHOWED, data, reply, option); + IMSA_HILOGI("InputControlChannelProxy::onKeyboardShowed."); + } +} +} + + diff --git a/services/src/input_control_channel_stub.cpp b/services/src/input_control_channel_stub.cpp new file mode 100644 index 00000000..e86661b1 --- /dev/null +++ b/services/src/input_control_channel_stub.cpp @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2021 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 "message_handler.h" +#include "input_control_channel_stub.h" +#include "i_input_control_channel.h" +#include "input_channel.h" +#include "input_method_agent_proxy.h" +#include "message_parcel.h" + +namespace OHOS { + namespace MiscServices { + /*! Constructor + \param userId the id of the user to whom the object is linking + */ + InputControlChannelStub::InputControlChannelStub(int userId) + { + userId_ = userId; + } + + /*! Destructor + */ + InputControlChannelStub::~InputControlChannelStub() { + } + + /*! Handle the transaction from the remote binder + \n Run in binder thread + \param code transaction code number + \param data the params from remote binder + \param[out] reply the result of the transaction replied to the remote binder + \param flags the flags of handling transaction + \return int32_t + */ + int32_t InputControlChannelStub::OnRemoteRequest(uint32_t code, MessageParcel& data, MessageParcel& reply, MessageOption& option) + { + IMSA_HILOGI("InputControlChannelStub::OnRemoteRequest code = %{public}u", code); + auto descriptorToken = data.ReadInterfaceToken(); + if (descriptorToken != GetDescriptor()) { + return ErrorCode::ERROR_STATUS_UNKNOWN_TRANSACTION; + } + switch (code) { + case ON_AGENT_CREATED: { + sptr proxy = new InputMethodAgentProxy(data.ReadRemoteObject()); + sptr agent = proxy; + + InputChannel* channel = nullptr; + if (data.ReadInt32() > 0) { + channel = data.ReadParcelable(); + } + onAgentCreated(agent, channel); + reply.WriteNoException(); + break; + } + case HIDE_KEYBOARD_SELF: { + int flag = data.ReadInt32(); + hideKeyboardSelf(flag); + reply.WriteNoException(); + break; + } + case ADVANCE_TO_NEXT: { + bool isCurrentIme = data.ReadInt32(); + bool ret = advanceToNext(isCurrentIme); + reply.WriteNoException(); + reply.WriteBool(ret); + break; + } + case SET_DISPLAY_MODE: { + int mode = data.ReadInt32(); + setDisplayMode(mode); + reply.WriteNoException(); + break; + } + case ON_KEYBOARD_SHOWED: { + onKeyboardShowed(); + reply.WriteNoException(); + break; + } + default: { + return IRemoteStub::OnRemoteRequest(code, data, reply, option); + } + } + return NO_ERROR; + } + + + /*! Called when input method service creates InputMethodAgentProxy + \n This call is running in binder thread + \param agent the remote handler from input method service, with which input client can remotely callback to + input method service + \param channel channel for sending physical keyboard event from input client to input method service + */ + void InputControlChannelStub::onAgentCreated(sptr < IInputMethodAgent >& agent, InputChannel* channel) + { + IMSA_HILOGI("InputControlChannelStub::onAgentCreated"); + { + std::unique_lock < std::mutex > lck(mtx); + agentReadyFlag = true; + } + this->agent = agent; + this->channel = channel; + cv.notify_one(); + } + + /*! Called when input method service showed keyboard + \n This call is running in binder thread + */ + void InputControlChannelStub::onKeyboardShowed() + { + IMSA_HILOGI("InputControlChannelStub::onKeyboardShowed"); + { + std::unique_lock < std::mutex > lck(mtx); + keyboardReadyFlag = true; + } + cv.notify_one(); + } + + /*! Send hideKeyboardSelf command to work thread. + \n This call is running in binder thread, + but the handling of hideKeyboardSelf is in the work thread of PerUserSession. + \see PerUserSession::OnHideKeyboardSelf + \param flags the flag value of hiding keyboard + */ + void InputControlChannelStub::hideKeyboardSelf(int flags) + { + IMSA_HILOGI("InputControlChannelStub::hideKeyboardSelf flags = %{public}d", flags); + MessageParcel* parcel = new MessageParcel(); + parcel->WriteInt32(userId_); + parcel->WriteInt32(flags); + + Message* msg = new Message(MessageID::MSG_ID_HIDE_KEYBOARD_SELF, parcel); + MessageHandler::Instance()->SendMessage(msg); + } + + /*! Send advanceToNext command to work thread. + \n This call is running in binder thread, + but the handling of advanceToNext is in the work thread of InputMethodSystemAbility service + \n or in the work thread of PerUserSession + \see InputMethodSystemAbility::OnAdvanceToNext PerUserSession::OnAdvanceToNext + \see PerUserSetting::OnAdvanceToNext + \param isCurrentIme true - switch to next keyboard type within current input method engine + \n false - switch to next input method engine + \return true + */ + bool InputControlChannelStub::advanceToNext(bool isCurrentIme) + { + IMSA_HILOGI("InputControlChannelStub::advanceToNext"); + MessageParcel* parcel = new MessageParcel(); + parcel->WriteInt32(userId_); + parcel->WriteBool(isCurrentIme); + + Message* msg = new Message(MessageID::MSG_ID_ADVANCE_TO_NEXT, parcel); + MessageHandler::Instance()->SendMessage(msg); + return true; + } + + /*! Send setDisplayMode command to work thread. + \n This call is running in binder thread, + but the handling of setDisplayMode is in the work thread of PerUserSession. + \see PerUserSession::OnSetDisplayMode + \param mode 0 - part screen mode, 1 - full screen mode + */ + void InputControlChannelStub::setDisplayMode(int mode) + { + IMSA_HILOGI("InputControlChannelStub::setDisplayMode start"); + MessageParcel* parcel = new MessageParcel(); + parcel->WriteInt32(userId_); + parcel->WriteInt32(mode); + + Message* msg = new Message(MessageID::MSG_ID_SET_DISPLAY_MODE, parcel); + MessageHandler::Instance()->SendMessage(msg); + } + + /*! Reset ready flag to be false + \n This should be called before imsCore->startInput() in work thread of PerUserSession + */ + void InputControlChannelStub::ResetFlag() + { + IMSA_HILOGI("InputControlChannelStub::ResetFlag"); + std::unique_lock < std::mutex > lck(mtx); + keyboardReadyFlag = false; + agentReadyFlag = false; + if (agent) { + agent = nullptr; + } + if (channel) { + delete channel; + channel = nullptr; + } + } + /*! Get input method agent and input write channel + \n This should be called in work thread of PerUserSession + \param[out] retAgent remote handler of InputMethodAgentProxy returned to the caller + \param[out] retChannel input write channel returned to caller + \return true - onAgentCreated is called by input method service in time + \n false - onAgentCreated is not called by input method service in time + */ + bool InputControlChannelStub::GetAgentAndChannel(sptr* retAgent, InputChannel** retChannel) + { + IMSA_HILOGI("InputControlChannelStub::GetAgentAndChannel"); + std::chrono::milliseconds millsec(300); + bool ret = false; + { + std::unique_lock < std::mutex > lck(mtx); + ret = cv.wait_for(lck, millsec, [this] { + return agentReadyFlag; + }); + } + if (ret) { + if (retAgent) { + *retAgent = agent; + agent = nullptr; + } + if (retChannel) { + *retChannel = channel; + channel = nullptr; + } + return true; + } + return false; + } + + /*! Wait for keyboard to be ready + \n This should be called in work thread of PerUserSession + \return true - onKeyboardShowed is called by input method service in time + \n false - onKeyboardShowed is not called by input method service in time + */ + bool InputControlChannelStub::WaitKeyboardReady() + { + IMSA_HILOGI("InputControlChannelStub::WaitKeyboardReady"); + std::chrono::milliseconds millsec(300); + bool ret = false; + { + std::unique_lock < std::mutex > lck(mtx); + ret = cv.wait_for(lck, millsec, [this] { + return keyboardReadyFlag; + }); + } + return ret; + } + } +} \ No newline at end of file diff --git a/services/src/input_method_ability_connection_stub.cpp b/services/src/input_method_ability_connection_stub.cpp new file mode 100644 index 00000000..97f65fa6 --- /dev/null +++ b/services/src/input_method_ability_connection_stub.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2021 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 "input_method_ability_connection_stub.h" +#include "message_parcel.h" +#include "message.h" + + +namespace OHOS { + namespace MiscServices { + InputMethodAbilityConnectionStub::InputMethodAbilityConnectionStub(const int index){ + mIndex = index; + } + + InputMethodAbilityConnectionStub::~InputMethodAbilityConnectionStub(){ + + } + + void InputMethodAbilityConnectionStub::OnAbilityConnectDone(const AppExecFwk::ElementName &element, const sptr &remoteObject, int resultCode){ + IMSA_HILOGE("ConnectAbility: OnAbilityConnectDone."); + if(messageHandler != nullptr){ + MessageParcel* data = new MessageParcel(); + data->WriteParcelable(&element); + data->WriteRemoteObject(remoteObject); + data->WriteInt32(mIndex); + Message* msg = new Message(MessageID::MSG_ID_ABILITY_CONNECT_DONE, data); + messageHandler->SendMessage(msg); + } + } + + void InputMethodAbilityConnectionStub::OnAbilityDisconnectDone(const AppExecFwk::ElementName &element, int resultCode) { + IMSA_HILOGE("ConnectAbility: OnAbilityDisconnectDone."); + if(messageHandler != nullptr){ + MessageParcel* data = new MessageParcel(); + data->WriteParcelable(&element); + data->WriteInt32(mIndex); + Message* msg = new Message(MessageID::MSG_ID_ABILITY_DISCONNECT_DONE, data); + messageHandler->SendMessage(msg); + } + } + + void InputMethodAbilityConnectionStub::SetHandler(MessageHandler* handler){ + messageHandler = handler; + } + + } +} \ No newline at end of file diff --git a/services/src/input_method_agent_proxy.cpp b/services/src/input_method_agent_proxy.cpp new file mode 100644 index 00000000..7a2de408 --- /dev/null +++ b/services/src/input_method_agent_proxy.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2021 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 "i_input_method_agent.h" +#include "iremote_proxy.h" +#include "iremote_broker.h" +#include "global.h" + +/*! \class BpInputMethodAgentProxy + \brief The proxy implementation of IInputMethodAgent + + This class should be implemented by input client +*/ +namespace OHOS { + namespace MiscServices { + class InputMethodAgentProxy : public IRemoteProxy { + public: + InputMethodAgentProxy(const sptr& impl) + : IRemoteProxy(impl) + { + } + + ~InputMethodAgentProxy() + { + } + + int32_t dispatchKey(int key, int status) + { + (void)key; + (void)status; + return NO_ERROR; + } + + }; + + } +} + diff --git a/services/src/input_method_property.cpp b/services/src/input_method_property.cpp new file mode 100644 index 00000000..78ff9e79 --- /dev/null +++ b/services/src/input_method_property.cpp @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2021 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 "input_method_property.h" + +namespace OHOS { +namespace MiscServices { +using namespace std; +/*! Constructor +*/ +InputMethodProperty::InputMethodProperty() +{ +} + +/*! Destructor +*/ +InputMethodProperty::~InputMethodProperty() +{ + for(int32_t i=0; i<(int32_t)mTypes.size(); i++) { + delete mTypes[i]; + } + mTypes.clear(); +} + +/*! Constructor +\param property the source property will be copied to this instance. +*/ +InputMethodProperty::InputMethodProperty(const InputMethodProperty& property) +{ + mImeId = property.mImeId; + mPackageName = property.mPackageName; + mAbilityName = property.mAbilityName; + mConfigurationPage = property.mConfigurationPage; + isSystemIme = property.isSystemIme; + mDefaultImeId = property.mDefaultImeId; + + for(int i = 0; i < (int)mTypes.size(); i++) { + KeyboardType* type = new KeyboardType(*property.mTypes[i]); + mTypes.push_back(type); + } +} + +/*! operator= +\param property the source property will be copied to this instance. +\return return this +*/ +InputMethodProperty& InputMethodProperty::operator=(const InputMethodProperty& property) +{ + if (this == &property) { + return *this; + } + mImeId = property.mImeId; + mPackageName = property.mPackageName; + mAbilityName = property.mAbilityName; + mConfigurationPage = property.mConfigurationPage; + isSystemIme = property.isSystemIme; + mDefaultImeId = property.mDefaultImeId; + + for(int i = 0; i < (int)mTypes.size(); i++) { + KeyboardType* type = new KeyboardType(*property.mTypes[i]); + mTypes.push_back(type); + } + return *this; +} + +/*! Write InputMethodProperty to parcel +\param[out] parcel the information is written to this parcel returned to caller +\return ErrorCode::NO_ERROR +\return ErrorCode::ERROR_NULL_POINTER parcel is null +*/ +bool InputMethodProperty::Marshalling(Parcel &parcel) const +{ + if (!(parcel.WriteString16(mImeId) + &&parcel.WriteString16(mPackageName) + &&parcel.WriteString16(mAbilityName) + &&parcel.WriteString16(mConfigurationPage) + &&parcel.WriteBool(isSystemIme) + &&parcel.WriteInt32(mDefaultImeId))) + return false; + int32_t size = (int32_t)mTypes.size(); + parcel.WriteInt32(size); + if (size == 0) + return true; + for(int i=0; imImeId = parcel.ReadString16(); + info->mPackageName = parcel.ReadString16(); + info->mAbilityName = parcel.ReadString16(); + info->mConfigurationPage = parcel.ReadString16(); + info->isSystemIme = parcel.ReadBool(); + info->mDefaultImeId = parcel.ReadInt32(); + + int32_t size = parcel.ReadInt32(); + if (size == 0) + return info; + for (int i =0; i < size; i++) { + info->mTypes.push_back(parcel.ReadParcelable()); + } + return info; +} +} +} + + + + diff --git a/services/src/input_method_setting.cpp b/services/src/input_method_setting.cpp new file mode 100644 index 00000000..c80e6382 --- /dev/null +++ b/services/src/input_method_setting.cpp @@ -0,0 +1,342 @@ +/* + * Copyright (C) 2021 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 "input_method_setting.h" +#include "utils.h" + +namespace OHOS { +namespace MiscServices { + const std::u16string InputMethodSetting::CURRENT_INPUT_METHOD_TAG = u"imms_current_input_method"; + const std::u16string InputMethodSetting::ENABLED_INPUT_METHODS_TAG = u"imms_enabled_input_methods"; + const std::u16string InputMethodSetting::CURRENT_KEYBOARD_TYPE_TAG = u"imms_current_keyboard_type"; + const std::u16string InputMethodSetting::CURRENT_SYS_KEYBOARD_TYPE_TAG = u"imms_current_sys_keyboard_type"; + const std::u16string InputMethodSetting::SYSTEM_LOCALE_TAG = u"system_locales"; + + /*! Constructor + */ + InputMethodSetting::InputMethodSetting() + { + } + + /*! Destructor + */ + InputMethodSetting::~InputMethodSetting() + { + setting.clear(); + } + + /*! Constructor + \param inputMethodSetting the source InputMethodSetting copied to this instance + */ + InputMethodSetting::InputMethodSetting(const InputMethodSetting& inputMethodSetting) + { + setting = inputMethodSetting.setting; + } + + /*! operator= + \param inputMethodSetting the source InputMethodSetting copied to this instance + \return return this instance + */ + InputMethodSetting& InputMethodSetting::operator=(const InputMethodSetting& inputMethodSetting) + { + if (this == &inputMethodSetting) { + return *this; + } + setting = inputMethodSetting.setting; + return *this; + } + + /*! Write setting data to parcel + \param[out] parcel the setting data is written to parcel returned to caller. + \return ErrorCode::NO_ERROR + */ + bool InputMethodSetting::Marshalling(OHOS::Parcel &parcel) const { + int32_t size = setting.size(); + parcel.WriteInt32(size); + std::map::const_iterator it; + for(it = setting.cbegin(); it != setting.cend(); ++it) { + parcel.WriteString16(it->first); + parcel.WriteString16(it->second); + } + return ErrorCode::NO_ERROR; + } + + /*! Read setting data from parcel + \param parcel read the setting data from the given parcel + \return ErrorCode::NO_ERROR + */ + InputMethodSetting* InputMethodSetting::Unmarshalling(OHOS::Parcel &parcel) { + auto ims = new InputMethodSetting(); + int32_t size = parcel.ReadInt32(); + for(int i = 0; i < size; i++) { + std::u16string key = parcel.ReadString16(); + std::u16string value = parcel.ReadString16(); + ims->setting.insert(std::pair(key, value)); + } + return ims; + } + + /*! Set setting data for an item + \param key the name of setting item + \param value the value of setting item + */ + void InputMethodSetting::SetValue(const std::u16string& key, const std::u16string& value) + { + setting.insert_or_assign(key, value); + } + + /*! Get setting data for an item + \param key the name of setting item + \return the value of setting item if key is found + \return an empty string if key is not found + */ + std::u16string InputMethodSetting::GetValue(const std::u16string& key) const + { + std::map::const_iterator it = setting.find(key); + if (it == setting.end()) { + return u""; + } + return it->second; + } + + /*! Get the default input method engine + \return the imeId of the default input method engine + */ + std::u16string InputMethodSetting::GetCurrentInputMethod() const + { + return GetValue(CURRENT_INPUT_METHOD_TAG); + } + + /*! Set the default input method engine + \param imeId the ime Id of the given input method engine + */ + void InputMethodSetting::SetCurrentInputMethod(const std::u16string& imeId) + { + SetValue(CURRENT_INPUT_METHOD_TAG, imeId); + } + + /*! Get enabled input method engine list + \return a vector of ImeId + */ + std::vector InputMethodSetting::GetEnabledInputMethodList() + { + std::u16string value = GetValue(ENABLED_INPUT_METHODS_TAG); + std::vector tmp1 = Split(value, DELIM_IME); + std::vector imeList; + for(int i = 0; i < (int)tmp1.size(); i++) { + std::vector tmp2 = Split(tmp1[i], DELIM_KBD_TYPE); + imeList.push_back(tmp2[0]); + tmp2.clear(); + } + return imeList; + } + + /*! Add an input method engine to enabled ime list + \param imeId the ime id of the added input method engine + \param types a vector of hashCode of keyboard types which are supported by the added input method engine + \return true - added successfully. + \return false - the given input method engine is already enabled. + */ + bool InputMethodSetting::AddEnabledInputMethod(const std::u16string& imeId, const std::vector& types) + { + std::u16string str = GetValue(ENABLED_INPUT_METHODS_TAG); + std::vector imeList = Split(str, DELIM_IME); + + std::u16string typeStr; + for(int i = 0; i < (int)types.size(); i++) { + typeStr = typeStr + u";" + Utils::to_utf16(std::to_string(types[i])); + } + std::u16string imeStr = imeId + typeStr; + bool flag = false; + for(int i = 0; i < (int)imeList.size(); i++) { + if (imeList[i] == imeStr) { + return false; + } + if (imeList[i].find_first_of(imeId)) { + imeList[i] = imeStr; + flag = true; + break; + } + } + if (flag == false) { + imeList.push_back(imeStr); + } + + std::u16string value = BuildString(imeList, DELIM_IME); + SetValue(ENABLED_INPUT_METHODS_TAG, value); + imeList.clear(); + return true; + } + + /*! Remove an input method engine from enabled ime list. + \param imeId the ime id of the given input method engine + \return true - removed successfully. + \return false - ime id is not found in enabled ime list. + */ + bool InputMethodSetting::RemoveEnabledInputMethod(const std::u16string& imeId) + { + std::u16string str = GetValue(ENABLED_INPUT_METHODS_TAG); + std::vector imeList = Split(str, DELIM_IME); + bool flag = false; + std::vector::iterator it; + for(it = imeList.begin(); it < imeList.end(); ++it) { + if (it->find_first_of(imeId)) { + imeList.erase(it); + flag = true; + break; + } + } + if (flag == true) { + std::u16string value = BuildString(imeList, DELIM_IME); + SetValue(ENABLED_INPUT_METHODS_TAG, value); + } + imeList.clear(); + return flag; + } + + /*! Get the keyboard type list of the given input method engine + \param imeId the ime id of the given input method engine + \return a vector of hashCodes + */ + std::vector InputMethodSetting::GetEnabledKeyboardTypes(const std::u16string& imeId) + { + std::vector retValue; + std::u16string value = GetValue(ENABLED_INPUT_METHODS_TAG); + std::vector tmpVector = Split(value, DELIM_IME); + bool flag = false; + std::u16string imeStr; + for(int i = 0; i < (int)tmpVector.size(); i++) { + if (tmpVector[i].find_first_of(imeId) != std::u16string::npos) { + flag = true; + imeStr = tmpVector[i]; + break; + } + } + tmpVector.clear(); + if (flag == false) { + return retValue; + } + + std::vector tmp2 = Split(imeStr, DELIM_KBD_TYPE); + for(int i = 1; i < (int)tmp2.size(); i++) { + std::u16string str = tmp2[i]; + retValue.push_back(std::atoi(Utils::to_utf8(str).c_str())); + } + tmp2.clear(); + + return retValue; + } + + /*! Get the default keyboard type + \return return the hashCode value of the default keyboard type. + */ + int32_t InputMethodSetting::GetCurrentKeyboardType() + { + std::u16string value = GetValue(CURRENT_KEYBOARD_TYPE_TAG); + return std::atoi(Utils::to_utf8(value).c_str()); + } + + /*! Set the default keyboard type + \param type hashCode of the given keyboard type + */ + void InputMethodSetting::SetCurrentKeyboardType(int32_t type) + { + std::u16string str = Utils::to_utf16(std::to_string(type)); + SetValue(CURRENT_KEYBOARD_TYPE_TAG, str); + } + + /*! Get the default keyboard type for security input method engine + \return return hashCode of the default keyboard type of security IME + */ + int32_t InputMethodSetting::GetCurrentSysKeyboardType() + { + std::u16string value = GetValue(CURRENT_SYS_KEYBOARD_TYPE_TAG); + return std::atoi(Utils::to_utf8(value).c_str()); + } + + /*! Set the default keyboard type for security IME + \param type the hashCode of the given keyboard type of security IME + */ + void InputMethodSetting::SetCurrentSysKeyboardType(int32_t type) + { + std::u16string str = Utils::to_utf16(std::to_string(type)); + SetValue(CURRENT_SYS_KEYBOARD_TYPE_TAG, std::u16string(str)); + } + + /*! Clear setting data + */ + void InputMethodSetting::ClearData() + { + setting.clear(); + } + + /*! Find if the key is in the setting + \param key the name of setting item + \return true - key is found + \return false - key is not found + */ + bool InputMethodSetting::FindKey(const std::u16string& key) const + { + std::map::const_iterator it = setting.find(key); + if (it == setting.end()) { + return false; + } + return true; + } + + /*! Split a string into a vector + \param str the string to be split + \param delim the alphabet to split the string. + \return a vector of string + */ + std::vector InputMethodSetting::Split(const std::u16string& str, char16_t delim) + { + std::vector retValue; + std::u16string::size_type left,right; + left = 0; + right = str.find(delim, 0); + while(right != std::u16string::npos){ + if(right-left){ + retValue.emplace_back(str.substr(left,right-left)); + } + left = right + 1; + right = str.find(delim,left); + } + + if(left != str.size()){ + retValue.emplace_back(str.substr(left)); + } + return retValue; + } + + /*! Build a string from a vector + \param vector a vector of string + \delim a separator + \return return a string + */ + std::u16string InputMethodSetting::BuildString(const std::vector& vector, char16_t delim) + { + std::u16string retValue = u""; + char16_t delimStr[] = {delim, 0}; + for(int i = 0; i < (int)vector.size(); i++) { + retValue += vector[i]; + if (i<(int)vector.size()-1) { + retValue += std::u16string(delimStr); + } + } + return retValue; + } +} +} diff --git a/services/src/input_method_system_ability.cpp b/services/src/input_method_system_ability.cpp new file mode 100644 index 00000000..e9b97499 --- /dev/null +++ b/services/src/input_method_system_ability.cpp @@ -0,0 +1,863 @@ +/* + * Copyright (C) 2021 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 "input_method_system_ability.h" +#include "message_handler.h" +#include "system_ability.h" +#include "system_ability_definition.h" +#include "iservice_registry.h" +#include "ipc_skeleton.h" +#include "global.h" + +namespace OHOS { +namespace MiscServices { +using namespace MessageID; + +REGISTER_SYSTEM_ABILITY_BY_ID(InputMethodSystemAbility, INPUT_METHOD_SYSTEM_ABILITY_ID, true); +const std::int32_t INIT_INTERVAL = 10000L; +std::mutex InputMethodSystemAbility::instanceLock_; +sptr InputMethodSystemAbility::instance_; + +std::shared_ptr InputMethodSystemAbility::serviceHandler_; + +/*! Constructor +*/ +InputMethodSystemAbility::InputMethodSystemAbility(int32_t systemAbilityId, bool runOnCreate) +: SystemAbility(systemAbilityId, runOnCreate), state_(ServiceRunningState::STATE_NOT_START) +{ + +} + + +/*! Constructor +*/ +InputMethodSystemAbility::InputMethodSystemAbility() : state_(ServiceRunningState::STATE_NOT_START) +{ +} + +/*! Destructor +*/ +InputMethodSystemAbility::~InputMethodSystemAbility() +{ + if (workThreadHandler.joinable()) { + workThreadHandler.join(); + } + + std::map::const_iterator it; + for(it=userSessions.cbegin(); it!=userSessions.cend();) { + PerUserSession *session = it->second; + it = userSessions.erase(it); + delete session; + } + userSessions.clear(); + std::map::const_iterator it1; + for(it1=userSettings.cbegin(); it1!=userSettings.cend();) { + PerUserSetting *setting = it1->second; + it1 = userSettings.erase(it1); + delete setting; + } + userSettings.clear(); + std::map::const_iterator it2; + for(it2=msgHandlers.cbegin(); it2!=msgHandlers.cend();) { + MessageHandler *handler = it2->second; + it2 = msgHandlers.erase(it2); + delete handler; + } + msgHandlers.clear(); +} + +sptr InputMethodSystemAbility::GetInstance() +{ + if (instance_ == nullptr) { + std::lock_guard autoLock(instanceLock_); + if (instance_ == nullptr) { + instance_ = new InputMethodSystemAbility; + } + } + return instance_; +} + +void InputMethodSystemAbility::OnStart() +{ + IMSA_HILOGI("Enter OnStart."); + if (state_ == ServiceRunningState::STATE_RUNNING) { + IMSA_HILOGI("ImsaService is already running."); + return; + } + Initialize(); + InitServiceHandler(); + if (Init() != ErrorCode::NO_ERROR) { + auto callback = [=]() { Init(); }; + serviceHandler_->PostTask(callback, INIT_INTERVAL); + IMSA_HILOGE("Init failed. Try again 10s later"); + return; + } + + IMSA_HILOGI("Start ImsaService ErrorCode::NO_ERROR."); + return; +} + +int32_t InputMethodSystemAbility::Init() +{ + bool ret = Publish(InputMethodSystemAbility::GetInstance()); + if (!ret) { + IMSA_HILOGE("Publish failed."); + return -1; + } + IMSA_HILOGI("Publish ErrorCode::NO_ERROR."); + state_ = ServiceRunningState::STATE_RUNNING; + return ErrorCode::NO_ERROR; +} + +void InputMethodSystemAbility::OnStop() +{ + IMSA_HILOGI("OnStop started."); + if (state_ != ServiceRunningState::STATE_RUNNING) { + return; + } + serviceHandler_ = nullptr; + + state_ = ServiceRunningState::STATE_NOT_START; + IMSA_HILOGI("OnStop end."); +} + +void InputMethodSystemAbility::InitServiceHandler() +{ + IMSA_HILOGI("InitServiceHandler started."); + if (serviceHandler_ != nullptr) { + IMSA_HILOGI("InitServiceHandler already init."); + return; + } + std::shared_ptr runner = AppExecFwk::EventRunner::Create("InputMethodSystemAbility"); + serviceHandler_ = std::make_shared(runner); + + IMSA_HILOGI("InitServiceHandler succeeded."); +} + +/*! Initialization of Input method management service +\n It's called after the service starts, before any transaction. +*/ +void InputMethodSystemAbility::Initialize() +{ + IMSA_HILOGI("InputMethodSystemAbility::Initialize"); + // init work thread to handle the messages + workThreadHandler = std::thread([this] { + WorkThread(); + }); + PerUserSetting* setting=new PerUserSetting(0); + PerUserSession* session=new PerUserSession(0); + userSettings.insert(std::pair(0,setting)); + userSessions.insert(std::pair(0,session)); + + setting->Initialize(); +} + +/*! Get the state of user +\n This API is added for unit test. +\param userID the id of given user +\return user state can be one of the values of UserState +*/ +int32_t InputMethodSystemAbility::GetUserState(int32_t userId) +{ + PerUserSetting *setting = GetUserSetting(userId); + if (setting == nullptr) { + return UserState::USER_STATE_NOT_AVAILABLE; + } + return setting->GetUserState(); +} + +/*! Handle the transaction from the remote binder +\n Run in binder thread +\param code transaction code number +\param data the params from remote binder +\param[out] reply the result of the transaction replied to the remote binder +\param flags the flags of handling transaction +\return int32_t +*/ +int32_t InputMethodSystemAbility::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, + MessageOption &option) +{ + return InputMethodSystemAbilityStub::OnRemoteRequest(code, data, reply, option); +} + +/*! Get the display mode of keyboard +\n Run in binder thread +\param[out] retMode the display mode returned to the caller +\return ErrorCode::NO_ERROR no error +\return ErrorCode::ERROR_USER_NOT_UNLOCKED user not unlocked +*/ +int32_t InputMethodSystemAbility::getDisplayMode(int32_t *retMode) +{ + int32_t uid = IPCSkeleton::GetCallingUid(); + int32_t userId = getUserId(uid); + PerUserSetting* setting = GetUserSetting(userId); + if (setting == nullptr || setting->GetUserState() != UserState::USER_STATE_UNLOCKED) { + IMSA_HILOGE("%s %d\n", ErrorCode::ToString(ErrorCode::ERROR_USER_NOT_UNLOCKED), userId); + return ErrorCode::ERROR_USER_NOT_UNLOCKED; + } + *retMode = GetUserSession(userId)->GetDisplayMode(); + return ErrorCode::NO_ERROR; +} + +/*! Get the window height of the current keyboard +\n Run in binder thread +\param[out] retHeight the window height returned to the caller +\return ErrorCode::NO_ERROR no error +\return ErrorCode::ERROR_USER_NOT_UNLOCKED user not unlocked +*/ +int32_t InputMethodSystemAbility::getKeyboardWindowHeight(int32_t *retHeight) +{ + int32_t uid = IPCSkeleton::GetCallingUid(); + int32_t userId = getUserId(uid); + PerUserSetting* setting = GetUserSetting(userId); + if (setting == nullptr || setting->GetUserState() != UserState::USER_STATE_UNLOCKED) { + IMSA_HILOGE("%s %d\n", ErrorCode::ToString(ErrorCode::ERROR_USER_NOT_UNLOCKED), userId); + return ErrorCode::ERROR_USER_NOT_UNLOCKED; + } + + int32_t ret = GetUserSession(userId)->GetKeyboardWindowHeight(retHeight); + if (ret != ErrorCode::NO_ERROR) { + IMSA_HILOGE("Failed to get keyboard window height. ErrorCode=%d\n", ret); + } + return ret; +} + +/*! Get the current keyboard type +\n Run in binder thread +\param[out] retType the current keyboard type returned to the caller +\return ErrorCode::NO_ERROR no error +\return ErrorCode::ERROR_USER_NOT_UNLOCKED user not unlocked +\return ErrorCode::ERROR_NULL_POINTER current keyboard type is null +*/ +int32_t InputMethodSystemAbility::getCurrentKeyboardType(KeyboardType* retType) +{ + int32_t uid = IPCSkeleton::GetCallingUid(); + int32_t userId = getUserId(uid); + PerUserSetting* setting = GetUserSetting(userId); + if (setting == nullptr || setting->GetUserState() != UserState::USER_STATE_UNLOCKED) { + IMSA_HILOGE("%s %d\n", ErrorCode::ToString(ErrorCode::ERROR_USER_NOT_UNLOCKED), userId); + return ErrorCode::ERROR_USER_NOT_UNLOCKED; + } + + KeyboardType* type = GetUserSession(userId)->GetCurrentKeyboardType(); + if (type == nullptr) { + return ErrorCode::ERROR_NULL_POINTER; + } + *retType = *type; + return ErrorCode::NO_ERROR; +} + +/*! Get the enabled input method engine list +\n Run in binder thread +\param[out] properties input method engine list returned to the caller +\return ErrorCode::NO_ERROR no error +\return ErrorCode::ERROR_USER_NOT_UNLOCKED user not unlocked +*/ +int32_t InputMethodSystemAbility::listInputMethodEnabled(std::vector *properties) +{ + int32_t uid = IPCSkeleton::GetCallingUid(); + int32_t userId = getUserId(uid); + PerUserSetting* setting = GetUserSetting(userId); + if (setting == nullptr || setting->GetUserState() != UserState::USER_STATE_UNLOCKED) { + IMSA_HILOGE("%s %d\n", ErrorCode::ToString(ErrorCode::ERROR_USER_NOT_UNLOCKED), userId); + return ErrorCode::ERROR_USER_NOT_UNLOCKED; + } + setting->ListInputMethodEnabled(properties); + + std::vector::iterator it; + for(it=properties->begin(); it!=properties->end();) { + if (*it && (*it)->isSystemIme) { + it = properties->erase(it); + } else { + ++it; + } + } + return ErrorCode::NO_ERROR; +} + +/*! Get all of the input method engine list installed in the system +\n Run in binder thread +\param[out] properties input method engine list returned to the caller +\return ErrorCode::NO_ERROR no error +\return ErrorCode::ERROR_USER_NOT_UNLOCKED user not unlocked +*/ +int32_t InputMethodSystemAbility::listInputMethod(std::vector *properties) +{ + int32_t uid = IPCSkeleton::GetCallingUid(); + int32_t userId = getUserId(uid); + PerUserSetting* setting = GetUserSetting(userId); + if (setting == nullptr || setting->GetUserState() != UserState::USER_STATE_UNLOCKED) { + IMSA_HILOGE("%s %d\n", ErrorCode::ToString(ErrorCode::ERROR_USER_NOT_UNLOCKED), userId); + return ErrorCode::ERROR_USER_NOT_UNLOCKED; + } + setting->ListInputMethod(properties); + std::vector::iterator it; + for(it=properties->begin(); it!=properties->end();) { + if (*it && (*it)->isSystemIme) { + it = properties->erase(it); + } else { + ++it; + } + } + return ErrorCode::NO_ERROR; +} + +/*! Get the keyboard type list for the given input method engine +\n Run in binder thread +\param imeId the id of the given input method engine +\param[out] types keyboard type list returned to the caller +\return ErrorCode::NO_ERROR no error +\return ErrorCode::ERROR_USER_NOT_UNLOCKED user not unlocked +*/ +int32_t InputMethodSystemAbility::listKeyboardType(const std::u16string& imeId, std::vector *types) +{ + int32_t uid = IPCSkeleton::GetCallingUid(); + int32_t userId = getUserId(uid); + PerUserSetting* setting = GetUserSetting(userId); + if (setting == nullptr || setting->GetUserState() != UserState::USER_STATE_UNLOCKED) { + IMSA_HILOGE("%s %d\n", ErrorCode::ToString(ErrorCode::ERROR_USER_NOT_UNLOCKED), userId); + return ErrorCode::ERROR_USER_NOT_UNLOCKED; + } + return setting->ListKeyboardType(imeId, types); +} + +/*! Print service information for the input method management service. +\n Run in binder thread +\n The information includes : +\li The user information in the service +\li The input method engine information +\li The input method setting data +\li The session information in the service. +\param fd the raw file descriptor that the dump is being sent to +\param args the parameters for dump command. This parameter is ignored here. +\return ErrorCode::NO_ERROR +*/ +int32_t InputMethodSystemAbility::dump(int32_t fd, const std::vector& args) +{ + (void) args; + dprintf(fd, "\nInputMethodSystemAbility State:\n"); + std::map::const_iterator it; + int32_t index = 0; + dprintf(fd, "* User count = %d\n", userSettings.size()); + for(it=userSettings.cbegin(); it!=userSettings.cend(); ++it) { + PerUserSetting* setting = it->second; + int32_t userId = it->first; + int32_t userState = setting->GetUserState(); + if (userState == UserState::USER_STATE_STARTED) { + dprintf(fd, "[%d] User information: UserId = %d, UserState = USER_STATE_STARTED\n", index++, userId); + } else if (userState == UserState::USER_STATE_UNLOCKED) { + dprintf(fd, "[%d] User information: UserId = %d, UserState = USER_STATE_UNLOCKED\n", index++, userId); + setting->Dump(fd); + PerUserSession* session = GetUserSession(userId); + session->Dump(fd); + } + dprintf(fd, "\n"); + } + dprintf(fd, "\n"); + + return ErrorCode::NO_ERROR; +} + +/*! Get the instance of PerUserSetting for the given user +\param userId the user id of the given user +\return a pointer of the instance if the user is found +\return null if the user is not found +*/ +PerUserSetting* InputMethodSystemAbility::GetUserSetting(int32_t userId) +{ + std::map::iterator it = userSettings.find(userId); + if (it == userSettings.end()) { + return nullptr; + } + return it->second; +} + +/*! Get the instance of PerUserSession for the given user +\param userId the user id of the given user +\return a pointer of the instance if the user is found +\return null if the user is not found +*/ +PerUserSession* InputMethodSystemAbility::GetUserSession(int32_t userId) +{ + std::map::iterator it = userSessions.find(userId); + if (it == userSessions.end()) { + return nullptr; + } + return it->second; +} + +/*! Work Thread of input method management service +\n Remote commands which may change the state or data in the service will be handled sequentially in this thread. +*/ +void InputMethodSystemAbility::WorkThread() +{ + while(1){ + Message* msg = MessageHandler::Instance()->GetMessage(); + switch(msg->msgId_) { + case MSG_ID_USER_START : { + OnUserStarted(msg); + break; + } + case MSG_ID_USER_STOP: { + OnUserStopped(msg); + break; + } + case MSG_ID_USER_UNLOCK: { + OnUserUnlocked(msg); + break; + } + case MSG_ID_USER_LOCK : { + OnUserLocked(msg); + break; + } + case MSG_ID_PACKAGE_ADDED: { + OnPackageAdded(msg); + break; + } + case MSG_ID_PACKAGE_REMOVED: { + OnPackageRemoved(msg); + break; + } + case MSG_ID_SETTING_CHANGED: { + OnSettingChanged(msg); + break; + } + case MSG_ID_PREPARE_INPUT: { + OnPrepareInput(msg); + break; + } + case MSG_ID_RELEASE_INPUT: + case MSG_ID_START_INPUT: + case MSG_ID_STOP_INPUT: + case MSG_ID_SET_INPUT_METHOD_CORE: + case MSG_ID_HIDE_KEYBOARD_SELF: + case MSG_ID_SET_DISPLAY_MODE: + case MSG_ID_CLIENT_DIED: + case MSG_ID_IMS_DIED: + case MSG_ID_RESTART_IMS: { + OnHandleMessage(msg); + break; + } + case MSG_ID_DISABLE_IMS: { + OnDisableIms(msg); + break; + } + case MSG_ID_ADVANCE_TO_NEXT: { + OnAdvanceToNext(msg); + break; + } + case MSG_ID_EXIT_SERVICE: { + std::map::const_iterator it; + for(it=msgHandlers.cbegin(); it!=msgHandlers.cend();) { + MessageHandler *handler = it->second; + Message* destMsg = new Message(MSG_ID_EXIT_SERVICE, nullptr); + handler->SendMessage(destMsg); + GetUserSession(it->first)->JoinWorkThread(); + it = msgHandlers.erase(it); + delete handler; + } + delete msg; + return; + } + default: { + break; + } + } +// delete msg; + } +} + +/*! Called when a user is started. (EVENT_USER_STARTED is received) +\n Run in work thread of input method management service +\param msg the parameters are saved in msg->msgContent_ +\return ErrorCode +*/ +int32_t InputMethodSystemAbility::OnUserStarted(const Message* msg) +{ + IMSA_HILOGI("Start...\n"); + if (msg->msgContent_ == nullptr) { + IMSA_HILOGE("Aborted! %s\n", ErrorCode::ToString(ErrorCode::ERROR_BAD_PARAMETERS)); + return ErrorCode::ERROR_BAD_PARAMETERS; + } + int32_t userId = msg->msgContent_->ReadInt32(); + PerUserSetting* setting = GetUserSetting(userId); + if (setting != nullptr) { + IMSA_HILOGE("Aborted! %s %d\n", ErrorCode::ToString(ErrorCode::ERROR_USER_ALREADY_STARTED), userId); + return ErrorCode::ERROR_USER_ALREADY_STARTED; + } + + setting = new PerUserSetting(userId); + PerUserSession* session = new PerUserSession(userId); + + userSettings.insert(std::pair(userId, setting)); + userSessions.insert(std::pair(userId, session)); + IMSA_HILOGI("End...[%d]\n", userId); + return ErrorCode::NO_ERROR; +} + +/*! Called when a user is stopped. (EVENT_USER_STOPPED is received) +\n Run in work thread of input method management service +\param msg the parameters are saved in msg->msgContent_ +\return ErrorCode +*/ +int32_t InputMethodSystemAbility::OnUserStopped(const Message* msg) +{ + IMSA_HILOGI("Start...\n"); + if (msg->msgContent_ == nullptr) { + IMSA_HILOGE("Aborted! %s\n", ErrorCode::ToString(ErrorCode::ERROR_BAD_PARAMETERS)); + return ErrorCode::ERROR_BAD_PARAMETERS; + } + int32_t userId = msg->msgContent_->ReadInt32(); + PerUserSetting* setting = GetUserSetting(userId); + PerUserSession* session = GetUserSession(userId); + if (setting == nullptr || session == nullptr) { + IMSA_HILOGE("Aborted! %s %d\n", ErrorCode::ToString(ErrorCode::ERROR_USER_NOT_STARTED), userId); + return ErrorCode::ERROR_USER_NOT_STARTED; + } + if (setting->GetUserState() == UserState::USER_STATE_UNLOCKED) { + IMSA_HILOGE("Aborted! %s %d\n", ErrorCode::ToString(ErrorCode::ERROR_USER_NOT_LOCKED), userId); + return ErrorCode::ERROR_USER_NOT_LOCKED; + } + std::map::iterator itSession = userSessions.find(userId); + userSessions.erase(itSession); + delete session; + + std::map::iterator itSetting = userSettings.find(userId); + userSettings.erase(itSetting); + delete setting; + IMSA_HILOGI("End...[%d]\n", userId); + return ErrorCode::NO_ERROR; +} + +int32_t InputMethodSystemAbility::setInputMethodCore(sptr &core){ + return ErrorCode::NO_ERROR; +} + +/*! Called when a user is unlocked. (EVENT_USER_UNLOCKED is received) +\n Run in work thread of input method management service +\param msg the parameters are saved in msg->msgContent_ +\return ErrorCode +*/ +int32_t InputMethodSystemAbility::OnUserUnlocked(const Message* msg) +{ + IMSA_HILOGI("Start...\n"); + if (msg->msgContent_ == nullptr) { + IMSA_HILOGE("Aborted! %s\n", ErrorCode::ToString(ErrorCode::ERROR_BAD_PARAMETERS)); + return ErrorCode::ERROR_BAD_PARAMETERS; + } + int32_t userId = msg->msgContent_->ReadInt32(); + PerUserSetting* setting = GetUserSetting(userId); + PerUserSession* session = GetUserSession(userId); + if (setting == nullptr || session == nullptr) { + IMSA_HILOGE("Aborted! %s %d\n", ErrorCode::ToString(ErrorCode::ERROR_USER_NOT_STARTED), userId); + return ErrorCode::ERROR_USER_NOT_STARTED; + } + if (setting->GetUserState() == UserState::USER_STATE_UNLOCKED) { + IMSA_HILOGE("Aborted! %s %d\n", ErrorCode::ToString(ErrorCode::ERROR_USER_ALREADY_UNLOCKED), userId); + return ErrorCode::ERROR_USER_ALREADY_UNLOCKED; + } + + setting->Initialize(); + + InputMethodProperty* ime = setting->GetSecurityInputMethod(); + session->SetSecurityIme(ime); + ime = setting->GetCurrentInputMethod(); + session->SetCurrentIme(ime); + session->SetInputMethodSetting(setting->GetInputMethodSetting()); + IMSA_HILOGI("End...[%d]\n", userId); + return ErrorCode::NO_ERROR; +} + +/*! Called when a user is locked. (EVENT_USER_LOCKED is received) +\n Run in work thread of input method management service +\param msg the parameters are saved in msg->msgContent_ +\return ErrorCode +*/ +int32_t InputMethodSystemAbility::OnUserLocked(const Message* msg) +{ + IMSA_HILOGI("Start...\n"); + if (msg->msgContent_ == nullptr) { + IMSA_HILOGE("Aborted! %s\n", ErrorCode::ToString(ErrorCode::ERROR_BAD_PARAMETERS)); + return ErrorCode::ERROR_BAD_PARAMETERS; + } + int32_t userId = msg->msgContent_->ReadInt32(); + PerUserSetting* setting = GetUserSetting(userId); + if (setting == nullptr || setting->GetUserState() != UserState::USER_STATE_UNLOCKED) { + IMSA_HILOGE("Aborted! %s %d\n", ErrorCode::ToString(ErrorCode::ERROR_USER_NOT_UNLOCKED), userId); + return ErrorCode::ERROR_USER_NOT_UNLOCKED; + } + std::map::iterator it = msgHandlers.find(userId); + if (it!=msgHandlers.end()) { + MessageHandler* handler = it->second; + Message* destMsg = new Message(MSG_ID_USER_LOCK , nullptr); + handler->SendMessage(destMsg); + GetUserSession(userId)->JoinWorkThread(); + msgHandlers.erase(it); + delete handler; + } + setting->OnUserLocked(); + IMSA_HILOGI("End...[%d]\n", userId); + return ErrorCode::NO_ERROR; +} + +/*! Prepare input. Called by an input client. +\n Run in work thread of input method management service +\param msg the parameters from remote client are saved in msg->msgContent_ +\return ErrorCode::NO_ERROR +\return ErrorCode::ERROR_USER_NOT_UNLOCKED user not unlocked +*/ +int32_t InputMethodSystemAbility::OnPrepareInput(Message* msg) +{ + IMSA_HILOGI("InputMethodSystemAbility::OnPrepareInput"); + MessageParcel* data = msg->msgContent_; + int32_t userId = data->ReadInt32(); + + PerUserSetting* setting = GetUserSetting(userId); + if (setting == nullptr || setting->GetUserState() != UserState::USER_STATE_UNLOCKED) { + IMSA_HILOGE("InputMethodSystemAbility::OnPrepareInput GetUserSetting Aborted! %{public}s %{public}d\n", ErrorCode::ToString(ErrorCode::ERROR_USER_NOT_UNLOCKED), userId); + return ErrorCode::ERROR_USER_NOT_UNLOCKED; + } + + std::map::const_iterator it = msgHandlers.find(userId); + if(it==msgHandlers.end()) { + PerUserSession* session = GetUserSession(userId); + MessageHandler* handler = new MessageHandler(); + session->CreateWorkThread(*handler); + msgHandlers.insert(std::pair(userId, handler)); + it = msgHandlers.find(userId); + } + + if (it!=msgHandlers.end()) { + MessageHandler* handler = it->second; + handler->SendMessage(msg); + } + return 0; +} + +/*! Handle message +\param msgId the id of message to run +\msg the parameters are saved in msg->msgContent_ +\return ErrorCode::NO_ERROR +\return ErrorCode::ERROR_USER_NOT_UNLOCKED user not unlocked +*/ +int32_t InputMethodSystemAbility::OnHandleMessage(Message* msg) +{ + MessageParcel* data = msg->msgContent_; + int32_t userId = data->ReadInt32(); + PerUserSetting* setting = GetUserSetting(userId); + if (setting == nullptr || setting->GetUserState() != UserState::USER_STATE_UNLOCKED) { + IMSA_HILOGE("Aborted! %s %d\n", ErrorCode::ToString(ErrorCode::ERROR_USER_NOT_UNLOCKED), userId); + return ErrorCode::ERROR_USER_NOT_UNLOCKED; + } + + std::map::const_iterator it = msgHandlers.find(userId); + if (it!=msgHandlers.end()) { + MessageHandler* handler = it->second; +// Message* destMsg = new Message(*msg); + handler->SendMessage(msg); + } + return ErrorCode::NO_ERROR; +} + +/*! Called when a package is installed. +\n Run in work thread of input method management service +\param msg the parameters are saved in msg->msgContent_ +\return ErrorCode::NO_ERROR +\return ErrorCode::ERROR_USER_NOT_UNLOCKED user not unlocked +\return ErrorCode::ERROR_BAD_PARAMETERS bad parameter +*/ +int32_t InputMethodSystemAbility::OnPackageAdded(const Message* msg) +{ + IMSA_HILOGI("Start...\n"); + MessageParcel* data = msg->msgContent_; + int32_t userId = data->ReadInt32(); + int32_t size = data->ReadInt32(); + + if (size <= 0) { + IMSA_HILOGE("Aborted! %s\n", ErrorCode::ToString(ErrorCode::ERROR_BAD_PARAMETERS)); + return ErrorCode::ERROR_BAD_PARAMETERS; + } + std::u16string packageName = data->ReadString16(); + PerUserSetting* setting = GetUserSetting(userId); + if (setting == nullptr || setting->GetUserState() != UserState::USER_STATE_UNLOCKED) { + IMSA_HILOGE("Aborted! %s %d\n", ErrorCode::ToString(ErrorCode::ERROR_USER_NOT_UNLOCKED), userId); + return ErrorCode::ERROR_USER_NOT_UNLOCKED; + } + bool securityImeFlag = false; + int32_t ret = setting->OnPackageAdded(packageName, &securityImeFlag); + if (ret != ErrorCode::NO_ERROR) { + IMSA_HILOGI("End...\n"); + return ret; + } + if (securityImeFlag == true) { + InputMethodProperty* securityIme = setting->GetSecurityInputMethod(); + InputMethodProperty* defaultIme = setting->GetCurrentInputMethod(); + GetUserSession(userId)->ResetIme(defaultIme, securityIme); + } + IMSA_HILOGI("End...\n"); + return 0; +} + +/*! Called when a package is removed. +\n Run in work thread of input method management service +\param msg the parameters are saved in msg->msgContent_ +\return ErrorCode::NO_ERROR +\return ErrorCode::ERROR_USER_NOT_UNLOCKED user not unlocked +\return ErrorCode::ERROR_BAD_PARAMETERS bad parameter +*/ +int32_t InputMethodSystemAbility::OnPackageRemoved(const Message* msg) +{ + IMSA_HILOGI("Start...\n"); + MessageParcel* data = msg->msgContent_; + int32_t userId = data->ReadInt32(); + int32_t size = data->ReadInt32(); + + if (size <= 0) { + IMSA_HILOGE("Aborted! %s\n", ErrorCode::ToString(ErrorCode::ERROR_BAD_PARAMETERS)); + return ErrorCode::ERROR_BAD_PARAMETERS; + } + std::u16string packageName = data->ReadString16(); + PerUserSetting* setting = GetUserSetting(userId); + if (setting == nullptr || setting->GetUserState() != UserState::USER_STATE_UNLOCKED) { + IMSA_HILOGE("Aborted! %s %d\n", ErrorCode::ToString(ErrorCode::ERROR_USER_NOT_UNLOCKED), userId); + return ErrorCode::ERROR_USER_NOT_UNLOCKED; + } + PerUserSession* session = GetUserSession(userId); + session->OnPackageRemoved(packageName); + bool securityImeFlag = false; + int32_t ret = setting->OnPackageRemoved(packageName, &securityImeFlag); + if (ret != ErrorCode::NO_ERROR) { + IMSA_HILOGI("End...\n"); + return ret; + } + if (securityImeFlag == true) { + InputMethodProperty* securityIme = setting->GetSecurityInputMethod(); + InputMethodProperty* defaultIme = setting->GetCurrentInputMethod(); + GetUserSession(userId)->ResetIme(defaultIme, securityIme); + } + return 0; +} + +/*! Called when input method setting data is changed. +\n Run in work thread of input method management service +\param msg the parameters from remote binder are saved in msg->msgContent_ +\return ErrorCode::NO_ERROR +\return ErrorCode::ERROR_USER_NOT_UNLOCKED user not unlocked +\return ErrorCode::ERROR_BAD_PARAMETERS bad parameter +*/ +int32_t InputMethodSystemAbility::OnSettingChanged(const Message* msg) +{ + IMSA_HILOGI("Start...\n"); + MessageParcel* data = msg->msgContent_; + int32_t userId = data->ReadInt32(); + int32_t size = data->ReadInt32(); + if (size < 2) { + IMSA_HILOGE("Aborted! %s\n", ErrorCode::ToString(ErrorCode::ERROR_BAD_PARAMETERS)); + return ErrorCode::ERROR_BAD_PARAMETERS; + } + std::u16string updatedKey = data->ReadString16(); + std::u16string updatedValue = data->ReadString16(); + PerUserSetting* setting = GetUserSetting(userId); + if (setting == nullptr || setting->GetUserState() != UserState::USER_STATE_UNLOCKED) { + IMSA_HILOGE("Aborted! %s %d\n", ErrorCode::ToString(ErrorCode::ERROR_USER_NOT_UNLOCKED), userId); + return ErrorCode::ERROR_USER_NOT_UNLOCKED; + } + PerUserSession* session = GetUserSession(userId); + int32_t ret = session->OnSettingChanged(updatedKey, updatedValue); + if (ret == ErrorCode::ERROR_SETTING_SAME_VALUE) { + IMSA_HILOGI("End...No need to update\n"); + return ret; + } + + // PerUserSetting does not need handle keyboard type change notification + if (updatedKey == InputMethodSetting::CURRENT_KEYBOARD_TYPE_TAG || + updatedKey == InputMethodSetting::CURRENT_SYS_KEYBOARD_TYPE_TAG) { + IMSA_HILOGI("End...\n"); + return ErrorCode::NO_ERROR; + } + + ret = setting->OnSettingChanged(updatedKey, updatedValue); + if (ret != 0) { + IMSA_HILOGI("End...No need to update\n"); + return ret; + } + + InputMethodProperty* securityIme = setting->GetSecurityInputMethod(); + InputMethodProperty* defaultIme = setting->GetCurrentInputMethod(); + session->ResetIme(defaultIme, securityIme); + IMSA_HILOGI("End...\n"); + return ErrorCode::NO_ERROR; +} + +/*! Disable input method service. Called from PerUserSession module +\n Run in work thread of input method management service +\param msg the parameters are saved in msg->msgContent_ +\return ErrorCode::NO_ERROR +\return ErrorCode::ERROR_USER_NOT_UNLOCKED user not unlocked +*/ +int32_t InputMethodSystemAbility::OnDisableIms(const Message* msg) +{ + IMSA_HILOGI("Start...\n"); + MessageParcel* data = msg->msgContent_; + int32_t userId = data->ReadInt32(); + std::u16string imeId = data->ReadString16(); + PerUserSetting* setting = GetUserSetting(userId); + if (setting == nullptr || setting->GetUserState() != UserState::USER_STATE_UNLOCKED) { + IMSA_HILOGE("Aborted! %s %d\n", ErrorCode::ToString(ErrorCode::ERROR_USER_NOT_UNLOCKED), userId); + return ErrorCode::ERROR_USER_NOT_UNLOCKED; + } + + InputMethodSetting tmpSetting; + std::u16string key = InputMethodSetting::ENABLED_INPUT_METHODS_TAG; + tmpSetting.SetValue(key, setting->GetInputMethodSetting()->GetValue(key)); + tmpSetting.RemoveEnabledInputMethod(imeId); + //Platform::Instance()->SetInputMethodSetting(userId, tmpSetting); + IMSA_HILOGI("End...\n"); + return ErrorCode::NO_ERROR; +} + +/*! Switch to next ime or next keyboard type. It's called by input method service +\n Run in work thread of input method management service or the work thread of PerUserSession +\param msg the parameters from remote binder are saved in msg->msgContent_ +\return ErrorCode::NO_ERROR +\return ErrorCode::ERROR_USER_NOT_UNLOCKED user not unlocked +*/ +int32_t InputMethodSystemAbility::OnAdvanceToNext(const Message* msg) +{ + IMSA_HILOGI("Start...\n"); + MessageParcel* data = msg->msgContent_; + int32_t userId = data->ReadInt32(); + bool isCurrentIme = data->ReadBool(); + PerUserSetting* setting = GetUserSetting(userId); + if (setting == nullptr || setting->GetUserState() != UserState::USER_STATE_UNLOCKED) { + IMSA_HILOGE("Aborted! %s %d\n", ErrorCode::ToString(ErrorCode::ERROR_USER_NOT_UNLOCKED), userId); + return ErrorCode::ERROR_USER_NOT_UNLOCKED; + } + if (isCurrentIme) { + std::map::const_iterator it = msgHandlers.find(userId); + if (it!=msgHandlers.end()) { + Message* destMsg = new Message(msg->msgId_, nullptr); + it->second->SendMessage(destMsg); + } + } else { + setting->OnAdvanceToNext(); + } + IMSA_HILOGI("End...\n"); + return ErrorCode::NO_ERROR; +} +} +} + diff --git a/services/src/input_method_system_ability_stub.cpp b/services/src/input_method_system_ability_stub.cpp new file mode 100644 index 00000000..df8687d3 --- /dev/null +++ b/services/src/input_method_system_ability_stub.cpp @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2021 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 "input_method_system_ability_stub.h" +#include "message_handler.h" +#include "ipc_skeleton.h" + +namespace OHOS { +namespace MiscServices { + +using namespace MessageID; +/*! Handle the transaction from the remote binder +\n Run in binder thread +\param code transaction code number +\param data the parameters from remote binder +\param[out] reply the result of the transaction replied to the remote binder +\param flags the flags of handling transaction +\return int32_t +*/ +int32_t InputMethodSystemAbilityStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, + MessageOption &option) +{ + IMSA_HILOGI("InputMethodSystemAbilityStub::OnRemoteRequest code = %{public}u", code); + auto descriptorToken = data.ReadInterfaceToken(); + if (descriptorToken != GetDescriptor()) { + return ErrorCode::ERROR_STATUS_UNKNOWN_TRANSACTION; + } + + switch(code) { + case PREPARE_INPUT: { + prepareInput(data); + reply.WriteInt32(NO_ERROR); + break; + } + case RELEASE_INPUT: { + MessageParcel* msgParcel = (MessageParcel*) &data; + releaseInput(*msgParcel); + reply.WriteInt32(NO_ERROR); + break; + } + case START_INPUT: { + MessageParcel* msgParcel = (MessageParcel*) &data; + startInput(*msgParcel); + reply.WriteInt32(NO_ERROR); + break; + } + case STOP_INPUT: { + MessageParcel* msgParcel = (MessageParcel*) &data; + stopInput(*msgParcel); + reply.WriteInt32(NO_ERROR); + break; + } + case SET_INPUT_METHOD_CORE:{ + MessageParcel* msgParcel = (MessageParcel*) &data; + setInputMethodCoreFromHap(*msgParcel); + reply.WriteInt32(NO_ERROR); + break; + } + case GET_DISPLAY_MODE: { + int32_t mode = 0; + int32_t status = getDisplayMode(&mode); + if (status == ErrorCode::NO_ERROR) { + reply.WriteInt32(NO_ERROR); + reply.WriteInt32(mode); + } else { + reply.WriteInt32(ErrorCode::ERROR_EX_ILLEGAL_STATE); + reply.WriteInt32(-1); + } + break; + } + case GET_KEYBOARD_WINDOW_HEIGHT: { + int32_t height = 0; + int32_t status = getKeyboardWindowHeight(&height); + if (status == ErrorCode::NO_ERROR) { + reply.WriteInt32(NO_ERROR); + reply.WriteInt32(height); + } else { + reply.WriteInt32(ErrorCode::ERROR_EX_ILLEGAL_STATE); + reply.WriteInt32(-1); + } + break; + } + case GET_CURRENT_KEYBOARD_TYPE: { + KeyboardType type; + int32_t status = getCurrentKeyboardType(&type); + if (status == ErrorCode::NO_ERROR) { + reply.WriteInt32(NO_ERROR); + reply.WriteParcelable(&type); + } else if (status == ErrorCode::ERROR_NULL_POINTER) { + reply.WriteInt32(NO_ERROR); + reply.WriteInt32(0); + } else { + reply.WriteInt32(ErrorCode::ERROR_EX_ILLEGAL_STATE); + reply.WriteInt32(-1); + } + break; + } + case LIST_INPUT_METHOD_ENABLED: { + std::vector properties; + int32_t ret = listInputMethodEnabled(&properties); + if (ret != ErrorCode::NO_ERROR) { + reply.WriteInt32(ErrorCode::ERROR_EX_ILLEGAL_STATE); // write exception code + reply.WriteInt32(-1); + } else { + reply.WriteInt32(NO_ERROR); + int32_t size = properties.size(); + reply.WriteInt32(size); + for(int32_t i=0; i properties; + int32_t ret = listInputMethod(&properties); + if (ret != ErrorCode::NO_ERROR) { + reply.WriteInt32(ErrorCode::ERROR_EX_ILLEGAL_STATE); // write exception code + reply.WriteInt32(-1); + return ret; + } + reply.WriteInt32(NO_ERROR); + int32_t size = properties.size(); + reply.WriteInt32(size); + for(int32_t i=0; i kbdTypes; + int32_t ret = listKeyboardType(imeId, &kbdTypes); + if (ret != ErrorCode::NO_ERROR) { + reply.WriteInt32(ErrorCode::ERROR_EX_ILLEGAL_STATE); + reply.WriteInt32(-1); + return ret; + } + reply.WriteInt32(NO_ERROR); + int32_t size = kbdTypes.size(); + reply.WriteInt32(size); + for(int32_t i=0; iWriteInt32(userId); + parcel->WriteInt32(pid); + parcel->WriteInt32(uid); + parcel->WriteInt32(data.ReadInt32()); + parcel->WriteRemoteObject(data.ReadRemoteObject()); + parcel->WriteRemoteObject(data.ReadRemoteObject()); + parcel->WriteParcelable(data.ReadParcelable()); + + Message* msg = new Message(MSG_ID_PREPARE_INPUT, parcel); + MessageHandler::Instance()->SendMessage(msg); +} + +/*! Release input +\n Send releaseInput command to work thread. + The handling of releaseInput is in the work thread of PerUserSession. +\see PerUserSession::OnReleaseInput +\param data the parcel in which the parameters are saved +*/ +void InputMethodSystemAbilityStub::releaseInput(MessageParcel& data) +{ + IMSA_HILOGE("InputMethodSystemAbilityStub::releaseInput"); + int32_t uid = IPCSkeleton::GetCallingUid(); + int32_t userId = getUserId(uid); + MessageParcel* parcel = new MessageParcel(); + parcel->WriteInt32(userId); + parcel->WriteRemoteObject(data.ReadRemoteObject()); + + Message* msg = new Message(MSG_ID_RELEASE_INPUT, parcel); + MessageHandler::Instance()->SendMessage(msg); + +} + +/*! Start input +\n Send startInput command to work thread. + The handling of startInput is in the work thread of PerUserSession. +\see PerUserSession::OnStartInput +\param data the parcel in which the parameters are saved +*/ +void InputMethodSystemAbilityStub::startInput(MessageParcel& data) +{ + int32_t uid = IPCSkeleton::GetCallingUid(); + int32_t userId = getUserId(uid); + MessageParcel* parcel = new MessageParcel(); + parcel->WriteInt32(userId); + parcel->WriteRemoteObject(data.ReadRemoteObject()); + + Message* msg = new Message(MSG_ID_START_INPUT, parcel); + MessageHandler::Instance()->SendMessage(msg); +} + +/*! Stop input +\n Send stopInput command to work thread. + The handling of stopInput is in the work thread of PerUserSession. +\see PerUserSession::OnStopInput +\param data the parcel in which the parameters are saved +*/ +void InputMethodSystemAbilityStub::stopInput(MessageParcel& data) +{ + int32_t uid = IPCSkeleton::GetCallingUid(); + int32_t userId = getUserId(uid); + MessageParcel* parcel = new MessageParcel(); + parcel->WriteInt32(userId); + parcel->WriteRemoteObject(data.ReadRemoteObject()); + + Message* msg = new Message(MSG_ID_STOP_INPUT, parcel); + MessageHandler::Instance()->SendMessage(msg); +} + + /*! Prepare input +\n Send prepareInput command to work thread. + The handling of prepareInput is in the work thread of PerUserSession. +\see PerUserSession::OnPrepareInput +\param data the parcel in which the parameters are saved +*/ + void InputMethodSystemAbilityStub::setInputMethodCoreFromHap(MessageParcel& data) + { + IMSA_HILOGI("InputMethodSystemAbilityStub::setInputMethodCoreFromHap"); + int32_t uid = IPCSkeleton::GetCallingUid(); + int32_t userId = getUserId(uid); + MessageParcel* parcel = new MessageParcel(); + parcel->WriteInt32(userId); + parcel->WriteRemoteObject(data.ReadRemoteObject()); + + Message* msg = new Message(MSG_ID_SET_INPUT_METHOD_CORE, parcel); + MessageHandler::Instance()->SendMessage(msg); + } + +/*! Get user id from uid +\param uid the uid from which the remote call is +\return return user id of the remote caller +*/ +int32_t InputMethodSystemAbilityStub::getUserId(int32_t uid) +{ + return uid/1000000; +} +} +} diff --git a/services/src/keyboard_type.cpp b/services/src/keyboard_type.cpp new file mode 100644 index 00000000..269cd75b --- /dev/null +++ b/services/src/keyboard_type.cpp @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2021 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 "keyboard_type.h" + +namespace OHOS { +namespace MiscServices { +using namespace std; +/*! Constructor +*/ +KeyboardType::KeyboardType() +{ +} + +/*! Constructor from another instance + \param type the source instance +*/ +KeyboardType::KeyboardType(const KeyboardType& type) +{ + mId = type.mId; + mHashCode = type.mHashCode; + mLabelId = type.mLabelId; + mIconId = type.mIconId; + mIsAsciiCapable = type.mIsAsciiCapable; + mLanguage = type.mLanguage; + mInputSource = type.mInputSource; + mCustomizedValue = type.mCustomizedValue; +} + +/*! Destructor +*/ +KeyboardType::~KeyboardType() +{ +} + +/*! Get value from another instance + \param type source instance + \return return this +*/ +KeyboardType& KeyboardType::operator=(const KeyboardType& type) +{ + if (this == &type) { + return *this; + } + + mId = type.mId; + mHashCode = type.mHashCode; + mLabelId = type.mLabelId; + mIconId = type.mIconId; + mIsAsciiCapable = type.mIsAsciiCapable; + mLanguage = type.mLanguage; + mInputSource = type.mInputSource; + mCustomizedValue = type.mCustomizedValue; + + return *this; +} + +/*! Write the details of object to parcel +*/ +bool KeyboardType::Marshalling(Parcel &parcel) const +{ + if (!(parcel.WriteInt32(mId) + && parcel.WriteInt32(mHashCode) + && parcel.WriteInt32(mLabelId) + && parcel.WriteInt32(mIconId) + && parcel.WriteBool(mIsAsciiCapable) + && parcel.WriteString16(mLanguage) + && parcel.WriteString16(mInputSource) + && parcel.WriteString16(mCustomizedValue))) + return false; + return true; +} + +/*! Read the details of object from parcel + \param parcel read the details of object from this parcel + \return ErrorCode::NO_ERROR + \return ErrorCode::ERROR_NULL_POINTER parcel is null +*/ +KeyboardType* KeyboardType::Unmarshalling(Parcel &parcel) +{ + auto info = new KeyboardType(); + info->mId = parcel.ReadInt32(); + info->mHashCode = parcel.ReadInt32(); + info->mLabelId = parcel.ReadInt32(); + info->mIconId = parcel.ReadInt32(); + info->mIsAsciiCapable = parcel.ReadBool(); + info->mLanguage = parcel.ReadString16(); + info->mInputSource = parcel.ReadString16(); + info->mCustomizedValue = parcel.ReadString16(); + return info; +} + +void KeyboardType::setId(int32_t typeId) +{ + mId = typeId; + if (typeId != ID_NONE) { + mHashCode = typeId; + } else { + mHashCode = ID_NONE; + } + +} + +void KeyboardType::setLabelId(int32_t labelId) +{ + mLabelId = labelId; +} + +void KeyboardType::setIconId(int32_t iconId) +{ + mIconId = iconId; +} + +void KeyboardType::setAsciiCapability(bool isAsciiCapable) +{ + mIsAsciiCapable = isAsciiCapable; +} + +void KeyboardType::setLanguage(u16string language) +{ + mLanguage = language; +} + +void KeyboardType::setInputSource(u16string inputSource) +{ + mInputSource = inputSource; +} + +void KeyboardType::setCustomizedValue(u16string keyBoardTypeCustomizedValue) +{ + mCustomizedValue = keyBoardTypeCustomizedValue; +} + +int32_t KeyboardType::getId() const +{ + return mId; +} + +int32_t KeyboardType::getLabelId() const +{ + return mLabelId; +} + +int32_t KeyboardType::getIconId() const +{ + return mIconId; +} + +/*! Get hash code of the object + \return return hashCode value +*/ +int KeyboardType::getHashCode() const +{ + return mHashCode; +} + +/*! Get language of the object + \return return the language of this object +*/ +u16string KeyboardType::getLanguage() const +{ + return mLanguage; +} + +u16string KeyboardType::getInputSource() const +{ + return mInputSource; +} + +u16string KeyboardType::getCustomizedValue() const +{ + return mCustomizedValue; +} +} +} \ No newline at end of file diff --git a/services/src/message.cpp b/services/src/message.cpp new file mode 100644 index 00000000..fa5d1c82 --- /dev/null +++ b/services/src/message.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2021 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 "message.h" + +namespace OHOS { +namespace MiscServices { +/*! Constructor +\param msgId a message Id +\param msgContent the content of a message +*/ +Message::Message(int32_t msgId, MessageParcel* msgContent) +{ + msgId_ = msgId; + msgContent_ = msgContent; + if (msgContent_) { + msgContent_->RewindRead(0); + } +} + +/*! Constructor +\param msg a source message +*/ +Message::Message(const Message& msg) +{ + msgId_ = msg.msgId_; + if (msgContent_ != nullptr) { + delete msgContent_; + } + MessageParcel* src = msg.msgContent_; + if (src) { + msgContent_ = new MessageParcel(); + msgContent_->ParseFrom(src->GetData(), src->GetDataSize()); +// msgContent_->RewindRead(0); + } +} + +Message& Message::operator=(const Message& msg) +{ + if (this == &msg) { + return *this; + } + msgId_ = msg.msgId_; + if (msgContent_ != nullptr) { + delete msgContent_; + } + if (msg.msgContent_) { + msgContent_ = new MessageParcel(); + msgContent_->ParseFrom(msg.msgContent_->GetData(), msg.msgContent_->GetDataSize()); + msgContent_->RewindRead(0); + } + return *this; +} + +Message::~Message( ) { + if (msgContent_) { + delete msgContent_; + } +} +} +} \ No newline at end of file diff --git a/services/src/message_handler.cpp b/services/src/message_handler.cpp new file mode 100644 index 00000000..60c52d10 --- /dev/null +++ b/services/src/message_handler.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2021 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 "message_handler.h" + +namespace OHOS { +namespace MiscServices { + /*! Constructor + */ + MessageHandler::MessageHandler() + { + } + + /*! Destructor + */ + MessageHandler::~MessageHandler() + { + std::unique_lock lock(mMutex); + while (! mQueue.empty()) { + Message* msg = mQueue.front(); + mQueue.pop(); + delete msg; + } + } + + /*! Send a message + \param msg a message to be sent + \note the msg pointer should not be freed by the caller + */ + void MessageHandler::SendMessage(Message* msg) + { + { + std::unique_lock lock(mMutex); + mQueue.push(msg); + } + mCV.notify_one(); + } + + /*! Get a message + \return a pointer referred to an object of message + \note the returned pointer should be freed by the caller. + */ + Message* MessageHandler::GetMessage() + { + std::unique_lock lock(mMutex); + mCV.wait(lock, [this]{ + return !this->mQueue.empty(); + }); + + Message* msg = (Message*) mQueue.front(); + mQueue.pop(); + return msg; + } + + /*! The single instance of MessageHandler in the service + \return the pointer referred to an object. + */ + MessageHandler* MessageHandler::Instance() + { + static MessageHandler *handler = nullptr; + if (handler == nullptr) { + handler = new MessageHandler(); + } + return handler; + } +} +} + diff --git a/services/src/peruser_session.cpp b/services/src/peruser_session.cpp new file mode 100644 index 00000000..db7f4524 --- /dev/null +++ b/services/src/peruser_session.cpp @@ -0,0 +1,1423 @@ +/* + * Copyright (C) 2021 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 "unistd.h" //usleep +#include "peruser_session.h" +#include "platform.h" +#include "parcel.h" +#include "message_parcel.h" +#include "utils.h" +#include "want.h" +#include "input_method_ability_connection_stub.h" +#include "ability_connect_callback_proxy.h" +#include "ability_manager_interface.h" +#include "sa_mgr_client.h" +#include "element_name.h" +#include "system_ability_definition.h" +#include "input_client_proxy.h" +#include "input_data_channel_proxy.h" +#include "input_control_channel_proxy.h" +#include "ipc_skeleton.h" +#include "input_method_core_proxy.h" + +namespace OHOS { +namespace MiscServices { + using namespace MessageID; + /*! Constructor + \param userId the id of the given user + \param msgId the msg id can be MessageID::MSG_ID_CLIENT_DIED (to monitor input client) + \n or MessageID::MSG_ID_IMS_DIED (to monitor input method service) + */ + RemoteObjectDeathRecipient::RemoteObjectDeathRecipient(int userId, int msgId) + { + userId_ = userId; + msgId_ = msgId; + } + + RemoteObjectDeathRecipient::~RemoteObjectDeathRecipient(){} + + /*! Notify that a remote object died. + \n It's called when the linked remote object died. + \param who the IRemoteObject handler of the remote object died. + */ + void RemoteObjectDeathRecipient::OnRemoteDied(const wptr& who) + { + MessageParcel* parcel = new MessageParcel(); + parcel->WriteInt32(userId_); + parcel->WriteRemoteObject(who.promote()); + Message* msg = new Message(msgId_, parcel); + MessageHandler::Instance()->SendMessage(msg); + } + + /*! Constructor + \param userId the user id of this user whose session are managed by this instance of PerUserSession. + */ + PerUserSession::PerUserSession(int userId) + { + userState = UserState::USER_STATE_STARTED; + userId_ = userId; + currentIme[0] = nullptr; + currentIme[1] = nullptr; + + needReshowClient = nullptr; + + clientDeathRecipient = new RemoteObjectDeathRecipient(userId, MSG_ID_CLIENT_DIED); + imsDeathRecipient = new RemoteObjectDeathRecipient(userId, MSG_ID_IMS_DIED); + } + + /*! Destructor + */ + PerUserSession::~PerUserSession() + { + if (userState == UserState::USER_STATE_UNLOCKED) { + OnUserLocked(); + } + clientDeathRecipient = nullptr; + imsDeathRecipient = nullptr; + if (workThreadHandler.joinable()) { + workThreadHandler.join(); + } + } + + + /*! Create work thread for this user + \param handle message handle to receive the message + */ + void PerUserSession::CreateWorkThread(MessageHandler& handler) + { + msgHandler = &handler; + workThreadHandler = std::thread([this]{WorkThread();}); + } + + /*! Wait till work thread exits + */ + void PerUserSession::JoinWorkThread() + { + if (workThreadHandler.joinable()) { + workThreadHandler.join(); + } + } + + void PerUserSession::SetInputMethodAbility(sptr &inputMethodAbility) { + inputMethodAbility_ = inputMethodAbility; + } + + /*! Work thread for this user + */ + void PerUserSession::WorkThread() + { + if (msgHandler == nullptr) { + return ; + } + while(1){ + Message* msg = msgHandler->GetMessage(); + std::unique_lock lock(mtx); + switch(msg->msgId_) { + case MSG_ID_USER_LOCK: + case MSG_ID_EXIT_SERVICE: { + OnUserLocked(); + delete msg; + return; + } + case MSG_ID_PREPARE_INPUT: { + OnPrepareInput(msg); + break; + } + case MSG_ID_RELEASE_INPUT: { + OnReleaseInput(msg); + break; + } + case MSG_ID_START_INPUT: { + OnStartInput(msg); + break; + } + case MSG_ID_STOP_INPUT: { + OnStopInput(msg); + break; + } + case MSG_ID_SET_INPUT_METHOD_CORE:{ + onSetInputMethodCore(msg); + break; + } + case MSG_ID_CLIENT_DIED: { + wptr who = msg->msgContent_->ReadRemoteObject(); + OnClientDied(who); + break; + } + case MSG_ID_IMS_DIED: { + wptr who = msg->msgContent_->ReadRemoteObject(); + OnImsDied(who); + break; + } + case MSG_ID_HIDE_KEYBOARD_SELF: { + int flag = msg->msgContent_->ReadInt32(); + OnHideKeyboardSelf(flag); + break; + } + case MSG_ID_ADVANCE_TO_NEXT: { + OnAdvanceToNext(); + break; + } + case MSG_ID_SET_DISPLAY_MODE: { + int mode = msg->msgContent_->ReadInt32(); + OnSetDisplayMode(mode); + break; + } + case MSG_ID_RESTART_IMS: { + int index = msg->msgContent_->ReadInt32(); + std::u16string imeId = msg->msgContent_->ReadString16(); + OnRestartIms(index, imeId); + break; + } + default: { + break; + } + } + delete msg; + } + } + + /*! Set display Id + \param displayId the Id of display screen on which the input method keyboard show. + */ + void PerUserSession::SetDisplayId(int displayId) + { + this->displayId = displayId; + } + + /*! Set the current input method engine + \param ime the current (default) IME pointer referred to the instance in PerUserSetting. + */ + void PerUserSession::SetCurrentIme(InputMethodProperty* ime) + { + currentIme[DEFAULT_IME] = ime; + userState = UserState::USER_STATE_UNLOCKED; + } + + /*! Set the system security input method engine + \param ime system security IME pointer referred to the instance in PerUserSetting. + */ + void PerUserSession::SetSecurityIme(InputMethodProperty* ime) + { + currentIme[SECURITY_IME] = ime; + } + + /*! Set the input method setting data + \param setting InputMethodSetting pointer referred to the instance in PerUserSetting. + */ + void PerUserSession::SetInputMethodSetting(InputMethodSetting* setting) + { + inputMethodSetting = setting; + } + + /*! Reset input method engine + \param defaultIme default ime pointer referred to the instance in PerUserSetting + \param security security ime pointer referred to the instance in PerUserSetting + \n Two input method engines can be running at the same time for one user. + \n One is the default ime, another is security ime + */ + void PerUserSession::ResetIme(InputMethodProperty* defaultIme, InputMethodProperty* securityIme) + { + IMSA_HILOGI("PerUserSession::ResetIme"); + std::unique_lock lock(mtx); + InputMethodProperty* ime[] = {defaultIme, securityIme}; + for(int i=0; i<2; i++) { + if (currentIme[i] == ime[i] && ime[i] != nullptr) { + continue; + } + if (imsCore[i]) { + StopInputMethod(i); + } + IncreaseOrResetImeError(true, i); + currentIme[i] = ime[i]; + if (currentIme[i]==nullptr) { + if (needReshowClient && GetImeIndex(needReshowClient)==i) { + needReshowClient = nullptr; + } + continue; + } + + std::map, ClientInfo*>::const_iterator it; + bool flag = false; + for(it=mapClients.cbegin(); it!=mapClients.cend(); ++it) { + if ((i == DEFAULT_IME && it->second->attribute.GetSecurityFlag() == false) || + (i == SECURITY_IME && it->second->attribute.GetSecurityFlag() == true)) { + flag = true; + break; + } + } + if (flag) { + int ret = StartInputMethod(i); + if (needReshowClient && GetImeIndex(needReshowClient)==i) { + if (ret==ErrorCode::NO_ERROR) { + ShowKeyboard(needReshowClient); + } + needReshowClient = nullptr; + } + } + } + } + + /*! Called when a package is removed + \param packageName the name of package removed + */ + void PerUserSession::OnPackageRemoved(const std::u16string& packageName) + { + IMSA_HILOGI("PerUserSession::OnPackageRemoved"); + InputMethodSetting tmpSetting; + bool flag = false; + std::unique_lock lock(mtx); + for(int i=0; imPackageName == packageName) { + if (currentClient && GetImeIndex(currentClient)==i) { + needReshowClient = currentClient; + HideKeyboard(currentClient); + } + StopInputMethod(i); + currentIme[i] = nullptr; + if (i==DEFAULT_IME) { + tmpSetting.SetCurrentKeyboardType(-1); + inputMethodSetting->SetCurrentKeyboardType(-1); + } else if (i==SECURITY_IME) { + tmpSetting.SetCurrentSysKeyboardType(-1); + inputMethodSetting->SetCurrentSysKeyboardType(-1); + } + currentKbdIndex[i] = 0; + flag = true; + } + } + if (flag) { + Platform::Instance()->SetInputMethodSetting(userId_, tmpSetting); + } + + } + + /*! Add an input client + \param pid the process pid of the input client + \param uid the uid of the the input client + \param displayId the display id of the input client + \param inputClient the remote object handler of the input client + \param channel the remote InputDataChannel object handler for the input client. + \n It will be transferred to input method service + \param attribute the input attribute of the input client. + \return \li ErrorCode::NO_ERROR no error + \return \li ErrorCode::ERROR_CLIENT_DUPLICATED client is duplicated + */ + int PerUserSession::AddClient(int pid, int uid, int displayId, const sptr& inputClient, + const sptr& channel, + const InputAttribute& attribute) + { + IMSA_HILOGI("PerUserSession::AddClient"); + ClientInfo* clientInfo = GetClientInfo(inputClient); + if (clientInfo != nullptr) { + IMSA_HILOGE("PerUserSession::AddClient clientInfo is not nullptr"); + return ErrorCode::ERROR_CLIENT_DUPLICATED; + } + + sptr obj = inputClient->AsObject(); + if (obj == nullptr) { + IMSA_HILOGE("PerUserSession::AddClient inputClient AsObject is nullptr"); + return ErrorCode::ERROR_REMOTE_CLIENT_DIED; + } + clientInfo = new ClientInfo(pid, uid, userId_, displayId, inputClient, channel, attribute); + mapClients.insert(std::pair, ClientInfo*>(obj, clientInfo)); + int ret = obj->AddDeathRecipient(clientDeathRecipient); + if (ret != ErrorCode::NO_ERROR) { + IMSA_HILOGE("PerUserSession::AddClient AddDeathRecipient return : %{public}s [%{public}d]", ErrorCode::ToString(ret), userId_); + } + return ErrorCode::NO_ERROR; + } + + /*! Remove an input client + \param inputClient remote object handler of the input client + \param[out] remainClientNum remained count of the same kinds of clients for this user + \n (i.e. if inputClient is an normal client, remainClientNum is the count of remained normal clients. + \n if inputClient is a security client, remainClientNum is the count of remained security clients.) + \return ErrorCode::NO_ERROR no error + \return ErrorCode::ERROR_CLIENT_NOT_FOUND client is not found + */ + int PerUserSession::RemoveClient(const sptr& inputClient, int *remainClientNum) + { + IMSA_HILOGE("PerUserSession::RemoveClient"); + sptr b = inputClient->AsObject(); + std::map, ClientInfo*>::iterator it = mapClients.find(b); + if (it == mapClients.end()) { + IMSA_HILOGE("PerUserSession::RemoveClient %{public}s [%{public}d]", ErrorCode::ToString(ErrorCode::ERROR_CLIENT_NOT_FOUND), userId_); + return ErrorCode::ERROR_CLIENT_NOT_FOUND; + } + ClientInfo* clientInfo = it->second; + bool flag = clientInfo->attribute.GetSecurityFlag(); + int ret = b->RemoveDeathRecipient(clientDeathRecipient); + if (ret != ErrorCode::NO_ERROR) { + IMSA_HILOGE("PerUserSession::RemoveClient RemoveDeathRecipient return : %{public}s [%{public}d]\n", ErrorCode::ToString(ret), userId_); + } + ret = clientInfo->client->onInputReleased(0); + if (ret != ErrorCode::NO_ERROR) { + IMSA_HILOGE("PerUserSession::RemoveClient onInputReleased return : %{public}s [%{public}d]\n", ErrorCode::ToString(ret), userId_); + } + delete clientInfo; + mapClients.erase(it); + + if(remainClientNum!=nullptr) { + *remainClientNum = 0; + for(it=mapClients.begin(); it!=mapClients.end(); ++it) { + if (it->second->attribute.GetSecurityFlag() == flag) { + (*remainClientNum)++; + } + } + } + return ErrorCode::NO_ERROR; + } + + /*! Start input method service + \param index it can be 0 or 1. 0 - default ime, 1 - security ime + \return ErrorCode::NO_ERROR no error + \return ErrorCode::ERROR_IME_BIND_FAILED failed to bind ime + \return ErrorCode::ERROR_IME_NOT_AVAILABLE no ime is available + \return ErrorCode::ERROR_SECURITY_IME_NOT_AVAILABLE no security ime is available + \return ErrorCode::ERROR_TOKEN_CREATE_FAILED failed to create window token + \return other errors returned by binder driver + */ + int PerUserSession::StartInputMethod(int index) + { + IMSA_HILOGI("PerUserSession::StartInputMethod index=%{public}d [%{public}d]\n", index, userId_); + + if (imsCore[index] == nullptr) { + IMSA_HILOGI("PerUserSession::StartInputMethod imscore is null"); + return ErrorCode::ERROR_IME_BIND_FAILED; + } + + sptr b = imsCore[index]->AsObject(); + inputMethodToken[index] = IPCSkeleton::GetInstance().GetContextObject(); + localControlChannel[index] = new InputControlChannelStub(userId_); + inputControlChannel[index] = localControlChannel[index]; + int ret_init = imsCore[index]->initializeInput(inputMethodToken[index], displayId, inputControlChannel[index]); + if (ret_init != ErrorCode::NO_ERROR) { + IMSA_HILOGE("PerUserSession::StartInputMethod initializeInput return : %{public}s [%{public}d]\n", ErrorCode::ToString(ret_init), userId_); + localControlChannel[index] = nullptr; + inputControlChannel[index] = nullptr; + return ret_init; + } + return ErrorCode::NO_ERROR; + } + + /*! Stop input method service + \param index it can be 0 or 1. 0 - default ime, 1 - security ime + \return ErrorCode::NO_ERROR no error + \return ErrorCode::ERROR_IME_NOT_STARTED ime not started + \return ErrorCode::ERROR_IME_UNBIND_FAILED failed to unbind ime + \return ErrorCode::ERROR_TOKEN_DESTROY_FAILED failed to destroy window token + \return other errors returned by binder driver + */ + int PerUserSession::StopInputMethod(int index) + { + IMSA_HILOGI("Start... index = %{public}d [%{public}d]\n", index, userId_); + if (index >= MAX_IME || index < 0) { + IMSA_HILOGE("Aborted! %{public}s [%{public}d]\n", ErrorCode::ToString(ErrorCode::ERROR_BAD_PARAMETERS), userId_); + return ErrorCode::ERROR_BAD_PARAMETERS; + } + if (imsCore[index] == nullptr || currentIme[index] == nullptr) { + IMSA_HILOGE("Aborted! %{public}s [%{public}d]\n", ErrorCode::ToString(ErrorCode::ERROR_IME_NOT_STARTED), userId_); + return ErrorCode::ERROR_IME_NOT_STARTED; + } + if (currentIme[index] == currentIme[1-index] && imsCore[1-index] != nullptr) { + imsCore[index] = nullptr; + inputControlChannel[index] = nullptr; + localControlChannel[index] = nullptr; + IMSA_HILOGI("End...[%{public}d]\n", userId_); + return ErrorCode::NO_ERROR; + } + + IMSA_HILOGD("unbindInputMethodService...\n"); + + IMSA_HILOGD("destroyWindowToken...\n"); + int errorCode = ErrorCode::NO_ERROR; + int ret = Platform::Instance()->DestroyWindowToken(userId_, currentIme[index]->mPackageName); + inputMethodToken[index] = nullptr; + if (ret != ErrorCode::NO_ERROR) { + IMSA_HILOGE("destroyWindowToken return : %{public}s [%{public}d]\n", ErrorCode::ToString(ret), userId_); + errorCode = ErrorCode::ERROR_TOKEN_DESTROY_FAILED; + } + sptr b = imsCore[index]->AsObject(); + ret = b->RemoveDeathRecipient(imsDeathRecipient); + if (ret != ErrorCode::NO_ERROR) { + IMSA_HILOGE("RemoveDeathRecipient return : %{public}s [%{public}d]\n", ErrorCode::ToString(ret), userId_); + } + imsCore[index] = nullptr; + inputControlChannel[index] = nullptr; + localControlChannel[index] = nullptr; + IMSA_HILOGI("End...[%{public}d]\n", userId_); + return errorCode; + } + + /*! Show keyboard + \param inputClient the remote object handler of the input client. + \return ErrorCode::NO_ERROR no error + \return ErrorCode::ERROR_IME_NOT_STARTED ime not started + \return ErrorCode::ERROR_KBD_IS_OCCUPIED keyboard is showing by other client + \return ErrorCode::ERROR_CLIENT_NOT_FOUND the input client is not found + \return ErrorCode::ERROR_IME_START_FAILED failed to start input method service + \return ErrorCode::ERROR_KBD_SHOW_FAILED failed to show keyboard + \return other errors returned by binder driver + */ + int PerUserSession::ShowKeyboard( const sptr& inputClient ) + { + IMSA_HILOGI("PerUserSession::ShowKeyboard"); + ClientInfo* clientInfo = GetClientInfo(inputClient); + int index = GetImeIndex(inputClient); + if (index == -1 || clientInfo == nullptr) { + IMSA_HILOGE("PerUserSession::ShowKeyboard Aborted! index = -1 or clientInfo is nullptr"); + return ErrorCode::ERROR_CLIENT_NOT_FOUND; + } + + lastImeIndex = index; + bool supportPhysicalKbd = Platform::Instance()->CheckPhysicalKeyboard(); + localControlChannel[index]->ResetFlag(); + bool ret = imsCore[index]->startInput(clientInfo->channel, clientInfo->attribute, supportPhysicalKbd); + if (!ret || + localControlChannel[index]->GetAgentAndChannel(&imsAgent, &imsChannel)==false) { + IMSA_HILOGE("PerUserSession::ShowKeyboard Aborted! client is not ready"); + int result = clientInfo->client->onInputReady(1, nullptr, nullptr); + if (result != ErrorCode::NO_ERROR) { + IMSA_HILOGE("PerUserSession::ShowKeyboard onInputReady return : %{public}s [%{public}d]\n", ErrorCode::ToString(ret), userId_); + } + return ErrorCode::ERROR_IME_START_FAILED; + } + + ret = imsCore[index]->showKeyboard(1); + if (!ret) { + IMSA_HILOGE("PerUserSession::ShowKeyboard Aborted! showKeyboard has error : %{public}s", ErrorCode::ToString(ret)); + + int ret_client = clientInfo->client->onInputReady(1, nullptr, nullptr); + if (ret_client != ErrorCode::NO_ERROR) { + IMSA_HILOGE("PerUserSession::ShowKeyboard onInputReady has error : %{public}s", ErrorCode::ToString(ret_client)); + } + return ErrorCode::ERROR_KBD_SHOW_FAILED; + } + + if(clientInfo->client == nullptr){ + IMSA_HILOGI("PerUserSession::ShowKeyboard clientInfo->client is nullptr"); + } + + int result = clientInfo->client->onInputReady(0, imsAgent, imsChannel); + if (result != ErrorCode::NO_ERROR) { + IMSA_HILOGE("PerUserSession::ShowKeyboard Aborted! onInputReady return : %{public}s", ErrorCode::ToString(ret)); + return result; + } + currentClient = inputClient; + return ErrorCode::NO_ERROR; + } + + /*! hide keyboard + \param inputClient the remote object handler of the input client. + \return ErrorCode::NO_ERROR no error + \return ErrorCode::ERROR_IME_NOT_STARTED ime not started + \return ErrorCode::ERROR_KBD_IS_NOT_SHOWING keyboard has not been showing + \return ErrorCode::ERROR_CLIENT_NOT_FOUND the input client is not found + \return ErrorCode::ERROR_KBD_HIDE_FAILED failed to hide keyboard + \return other errors returned by binder driver + */ + int PerUserSession::HideKeyboard(const sptr& inputClient) + { + IMSA_HILOGI("PerUserSession::HideKeyboard"); + int index = GetImeIndex(inputClient); + if (index == -1) { + IMSA_HILOGE("PerUserSession::HideKeyboard Aborted! %{public}s [%{public}d]\n", ErrorCode::ToString(ErrorCode::ERROR_CLIENT_NOT_FOUND), userId_); + return ErrorCode::ERROR_CLIENT_NOT_FOUND; + } + ClientInfo* clientInfo = GetClientInfo(inputClient); + if(clientInfo == nullptr){ + IMSA_HILOGE("PerUserSession::HideKeyboard GetClientInfo pointer nullptr"); + } + if (imsCore[index] == nullptr) { + IMSA_HILOGE("PerUserSession::HideKeyboard imsCore[index] is nullptr"); + clientInfo->client->onInputReady(1, nullptr, nullptr); + return ErrorCode::ERROR_IME_NOT_STARTED; + } + + if (currentClient == nullptr) { + clientInfo->client->onInputReady(1, nullptr, nullptr); + IMSA_HILOGE("PerUserSession::HideKeyboard Aborted! %{public}s [%{public}d]\n", ErrorCode::ToString(ErrorCode::ERROR_KBD_IS_NOT_SHOWING), userId_); + return ErrorCode::ERROR_KBD_IS_NOT_SHOWING; + } + bool ret = imsCore[index]->hideKeyboard(1); + if(!ret) { + IMSA_HILOGE("PerUserSession::HideKeyboard [imsCore->hideKeyboard] failed"); + ret=ErrorCode::ERROR_KBD_HIDE_FAILED; + } + int ret_stop = imsCore[index]->stopInput(); + if (ret_stop != ErrorCode::NO_ERROR) { + IMSA_HILOGE("PerUserSession::HideKeyboard Aborted! stopInput return : %{public}s [%{public}d]\n", ErrorCode::ToString(ret_stop), userId_); + ret = ErrorCode::ERROR_KBD_HIDE_FAILED; + } + + int ret_client_stop = clientInfo->client->onInputReady(1, nullptr, nullptr); + if (ret_client_stop != ErrorCode::NO_ERROR) { + IMSA_HILOGE("PerUserSession::HideKeyboard onInputReady return : %{public}s [%{public}d]\n", ErrorCode::ToString(ret_client_stop), userId_); + } + currentClient = nullptr; + imsAgent = nullptr; + if (imsChannel != nullptr) { + delete imsChannel; + imsChannel = nullptr; + } + return ErrorCode::NO_ERROR; + } + + /*! Get the display mode of the current keyboard showing + \return return display mode. + \n 0 - part sceen mode, 1 - full sceen mode + */ + int PerUserSession::GetDisplayMode() + { + return currentDisplayMode; + } + + /*! Get the keyboard window height + \param[out] retHeight the height of keyboard window showing or showed returned to caller + \return ErrorCode + */ + int PerUserSession::GetKeyboardWindowHeight(int *retHeight) + { + if (retHeight == nullptr) { + return ErrorCode::ERROR_BAD_PARAMETERS; + } + if (imsCore[lastImeIndex] != nullptr) { + int ret = imsCore[lastImeIndex]->getKeyboardWindowHeight(retHeight); + if (ret != ErrorCode::NO_ERROR) { + IMSA_HILOGE("getKeyboardWindowHeight return : %{public}s [%{public}d]\n", ErrorCode::ToString(ret), userId_); + } + return ret; + } + IMSA_HILOGW("No IME is started [%{public}d]\n", userId_); + return ErrorCode::ERROR_IME_NOT_STARTED; + } + + /*! Get the current keyboard type + \return return the pointer of the object of current keyboard type. + \n null if no keyboard type supported by the current ime. + \note The returned pointer should NOT be freed by the caller. + */ + KeyboardType* PerUserSession::GetCurrentKeyboardType() + { + if (inputMethodSetting == nullptr || currentIme[DEFAULT_IME] == nullptr) { + IMSA_HILOGI("Ime has not started ! [%{public}d]\n", userId_); + return nullptr; + } + if (currentIme[DEFAULT_IME] == currentIme[SECURITY_IME]) { + return nullptr; + } + int hashCode = inputMethodSetting->GetCurrentKeyboardType(); // To be checked. + if (hashCode == -1) { + std::vector hashCodeList = inputMethodSetting->GetEnabledKeyboardTypes(currentIme[DEFAULT_IME]->mImeId); + if (hashCodeList.size() == 0) { + IMSA_HILOGE("Cannot find any keyboard types for the current ime [%{public}d]\n", userId_); + return nullptr; + } + hashCode = hashCodeList[0]; + } + + for(int i=0; i<(int)currentIme[DEFAULT_IME]->mTypes.size(); i++) { + if (currentIme[DEFAULT_IME]->mTypes[i]->getHashCode() == hashCode) { + return currentIme[DEFAULT_IME]->mTypes[i]; + } + } + return nullptr; + } + + /*! Handle the situation a remote input client died\n + It's called when a remote input client died + \param who the remote object handler of the input client died. + */ + void PerUserSession::OnClientDied(const wptr& who) + { + IMSA_HILOGI("PerUserSession::OnClientDied Start...[%{public}d]\n", userId_); + bool flag = false; + std::map, ClientInfo*>::iterator it; + + for (it=mapClients.begin(); it!=mapClients.end(); ++it) { + if (it->first == who) { + flag = true; + break; + } + } + if (flag == false) { + IMSA_HILOGW("Aborted! The client died is not found! [%{public}d]\n", userId_); + return; + } + + sptr client = iface_cast(it->first); + int remainClientNum = 0; + if (currentClient == client) { + HideKeyboard(client); + } + RemoveClient(client, &remainClientNum); + } + + /*! Handle the situation a input method service died\n + It's called when an input method service died + \param who the remote object handler of input method service who died. + */ + void PerUserSession::OnImsDied(const wptr& who) + { + (void) who; // temporary void it, as we will add support for security IME. + IMSA_HILOGI("Start...[%{public}d]\n", userId_); + int index = 0; + for(int i=0; i b = imsCore[i]->AsObject(); + if (b == who) { + index = i; + break; + } + } + if (currentClient && (GetImeIndex(currentClient)==index || + currentIme[index] == currentIme[1-index])) { + needReshowClient = currentClient; + HideKeyboard(currentClient); + } + StopInputMethod(index); + if (currentIme[index] == currentIme[1-index]) { + StopInputMethod(1-index); + } + + if (IncreaseOrResetImeError(false, index) == 3) { + // call to disable the current input method. + MessageParcel *parcel = new MessageParcel(); + parcel->WriteInt32(userId_); + parcel->WriteString16(currentIme[index]->mImeId); + Message* msg = new Message(MSG_ID_DISABLE_IMS, parcel); + MessageHandler::Instance()->SendMessage(msg); + } else { + // restart current input method. + IMSA_HILOGI("IME died. Restart input method ! [%{public}d]\n", userId_); + MessageParcel *parcel = new MessageParcel(); + parcel->WriteInt32(userId_); + parcel->WriteInt32(index); + parcel->WriteString16(currentIme[index]->mImeId); + Message* msg = new Message(MSG_ID_RESTART_IMS, parcel); + usleep(1600*1000); // wait that PACKAGE_REMOVED message is received if this ime has been removed + MessageHandler::Instance()->SendMessage(msg); + } + IMSA_HILOGI("End...[%{public}d]\n", userId_); + } + + /*! It's called when input method setting data in the system is changed + \param key the name of setting item changed. + \param value the value of setting item changed. + \return ErrorCode::NO_ERROR no error + \return ErrorCode::ERROR_SETTING_SAME_VALUE the current value is same as the one in the system. + */ + int PerUserSession::OnSettingChanged(const std::u16string& key, const std::u16string& value) + { + IMSA_HILOGI("Start...[%{public}d]\n", userId_); + std::unique_lock lock(mtx); + if (inputMethodSetting == nullptr) { + return ErrorCode::ERROR_NULL_POINTER; + } + std::u16string currentValue = inputMethodSetting->GetValue(key); + + IMSA_HILOGD("%{public}s=%{public}s, currentValue = %{public}s\n", Utils::to_utf8(key).c_str(), Utils::to_utf8(value).c_str(), Utils::to_utf8(currentValue).c_str()); + + if (currentValue == value) { + IMSA_HILOGI("End...[%{public}d]\n", userId_); + return ErrorCode::ERROR_SETTING_SAME_VALUE; + } + + if (key == InputMethodSetting::CURRENT_KEYBOARD_TYPE_TAG) { + return OnCurrentKeyboardTypeChanged(DEFAULT_IME, value); + } else if (key == InputMethodSetting::CURRENT_SYS_KEYBOARD_TYPE_TAG) { + return OnCurrentKeyboardTypeChanged(SECURITY_IME, value); + } else if (key == InputMethodSetting::CURRENT_INPUT_METHOD_TAG) { + if (currentIme[DEFAULT_IME] == nullptr || + value == currentIme[DEFAULT_IME]->mImeId) { + return ErrorCode::NO_ERROR; + } + if (currentClient != nullptr && GetImeIndex(currentClient)==DEFAULT_IME) { + needReshowClient = currentClient; + HideKeyboard(currentClient); + } + StopInputMethod(DEFAULT_IME); + currentIme[DEFAULT_IME] = nullptr; + currentKbdIndex[DEFAULT_IME] = 0; + inputMethodSetting->SetCurrentKeyboardType(-1); + } else if (key == InputMethodSetting::ENABLED_INPUT_METHODS_TAG) { + if (currentIme[DEFAULT_IME] && currentIme[DEFAULT_IME]!=currentIme[SECURITY_IME] && + value.find(currentIme[DEFAULT_IME]->mImeId) == std::string::npos) { + if (currentClient != nullptr && GetImeIndex(currentClient)==DEFAULT_IME) { + needReshowClient = currentClient; + HideKeyboard(currentClient); + } + StopInputMethod(DEFAULT_IME); + currentIme[DEFAULT_IME] = nullptr; + currentKbdIndex[DEFAULT_IME] = 0; + inputMethodSetting->SetCurrentKeyboardType(-1); + } + } + IMSA_HILOGI("End...[%{public}d]\n", userId_); + return ErrorCode::NO_ERROR; + } + + /*! Change current keyboard type. + \param index it can be 0 or 1. 0 - default ime, 1 - security ime. + \param value the hash code of keyboard type + \return ErrorCode::NO_ERROR no error + \return ErrorCode::ERROR_SETTING_SAME_VALUE the current value is same as the one in the system. + */ + int PerUserSession::OnCurrentKeyboardTypeChanged(int index, const std::u16string& value) + { + std::string str = Utils::to_utf8(value); + int hashCode = std::atoi(str.c_str()); + if (hashCode == -1) { + return ErrorCode::ERROR_SETTING_SAME_VALUE;; + } + // switch within the current ime. + if (index == SECURITY_IME || currentIme[DEFAULT_IME] == currentIme[SECURITY_IME]) { + int num = currentKbdIndex[index]; + if (currentIme[index]->mTypes[num]->getHashCode() == hashCode) { + return ErrorCode::ERROR_SETTING_SAME_VALUE; + } + for(int i=0; i<(int)currentIme[index]->mTypes.size(); i++) { + if (currentIme[index]->mTypes[i]->getHashCode() == hashCode) { + currentKbdIndex[index] = i; + break; + } + } + } else { + std::u16string imeId = currentIme[index]->mImeId; + std::vector currentKbdTypes = inputMethodSetting->GetEnabledKeyboardTypes(imeId); + int num = currentKbdIndex[index]; + if (currentKbdTypes[num] == hashCode) { + return ErrorCode::ERROR_SETTING_SAME_VALUE; + } + for(int i=0; i<(int)currentKbdTypes.size(); i++) { + if (currentKbdTypes[i] == hashCode) { + currentKbdIndex[index] = i; + break; + } + } + } + KeyboardType* type = GetKeyboardType(index, currentKbdIndex[index]); + if (type != nullptr) { + if (currentClient != nullptr) { + int ret = imsCore[index]->setKeyboardType(*type); + if (ret != ErrorCode::NO_ERROR) { + IMSA_HILOGE("setKeyboardType return : %{public}s [%{public}d]\n", ErrorCode::ToString(ret), userId_); + } + } + if (imsCore[index] == imsCore[1-index]) { + inputMethodSetting->SetCurrentKeyboardType(type->getHashCode()); + inputMethodSetting->SetCurrentSysKeyboardType(type->getHashCode()); + currentKbdIndex[1-index] = currentKbdIndex[index]; + } else if (index == DEFAULT_IME) { + inputMethodSetting->SetCurrentKeyboardType(type->getHashCode()); + } else { + inputMethodSetting->SetCurrentSysKeyboardType(type->getHashCode()); + } + } + return ErrorCode::NO_ERROR; + } + + /*! Hide current keyboard + \param flag the flag to hide keyboard. + */ + void PerUserSession::OnHideKeyboardSelf(int flags) + { + IMSA_HILOGW("PerUserSession::OnHideKeyboardSelf"); + (void) flags; + HideKeyboard(currentClient); + } + + /*! Switch to next keyboard type + */ + void PerUserSession::OnAdvanceToNext( ) + { + int index = GetImeIndex(currentClient); + if (index == -1) { + IMSA_HILOGW("%{public}s [%{public}d]\n", ErrorCode::ToString(ErrorCode::ERROR_CLIENT_NOT_FOUND), userId_); + return ; + } + int size = 0; + if (index==SECURITY_IME || currentIme[DEFAULT_IME] == currentIme[SECURITY_IME] ) { + size = currentIme[index]->mTypes.size(); + } else { + std::u16string imeId = currentIme[index]->mImeId; + std::vector currentKbdTypes = inputMethodSetting->GetEnabledKeyboardTypes(imeId); + size = currentKbdTypes.size(); + } + if (size < 2) { + IMSA_HILOGW("No next keyboard is available. [%{public}d]\n", userId_); + return ; + } + + int num = currentKbdIndex[index]+1; + num %= size; + KeyboardType* type = GetKeyboardType(index, num); + if (type == nullptr) { + IMSA_HILOGW("No next keyboard is available. [%{public}d]\n", userId_); + return; + } + InputMethodSetting tmpSetting; + if (imsCore[index] == imsCore[1-index]) { + tmpSetting.SetCurrentKeyboardType(type->getHashCode()); + tmpSetting.SetCurrentSysKeyboardType(type->getHashCode()); + } + else if (index == DEFAULT_IME) { + tmpSetting.SetCurrentKeyboardType(type->getHashCode()); + } else { + tmpSetting.SetCurrentSysKeyboardType(type->getHashCode()); + } + Platform::Instance()->SetInputMethodSetting(userId_, tmpSetting); + } + + /*! Set display mode + \param mode the display mode of soft keyboard UI. + \n 0 - part sceen mode, 1 - full sceen mode + */ + void PerUserSession::OnSetDisplayMode(int mode) + { + currentDisplayMode = mode; + ClientInfo* clientInfo = GetClientInfo(currentClient); + if (clientInfo == nullptr) { + IMSA_HILOGE("%{public}s [%{public}d]\n", ErrorCode::ToString(ErrorCode::ERROR_CLIENT_NOT_FOUND), userId_); + return ; + } + int ret = clientInfo->client->setDisplayMode(mode); + if (ret != ErrorCode::NO_ERROR) { + IMSA_HILOGE("setDisplayMode return : %{public}s [%{public}d]\n", ErrorCode::ToString(ret), userId_); + } + } + + /*! Restart input method service + \param index it can be DEFAULT_IME or SECURITY_IME + \param imeId the id of the input method service going to restart + */ + void PerUserSession::OnRestartIms(int index, const std::u16string& imeId) + { + if (index<0 || index>=MAX_IME) { + return ; + } + IMSA_HILOGI("Start...[%{public}d]\n", userId_); + if (currentIme[index] && currentIme[index]->mImeId == imeId) { + int ret = StartInputMethod(index); + if (needReshowClient && GetImeIndex(needReshowClient)==index) { + if (ret == ErrorCode::NO_ERROR) { + ShowKeyboard(needReshowClient); + } + needReshowClient = nullptr; + } + } + IMSA_HILOGI("End...[%{public}d]\n", userId_); + } + + /*! It's called when this user is locked + */ + void PerUserSession::OnUserLocked() + { + IMSA_HILOGI("PerUserSession::OnUserLocked"); + if (userState == UserState::USER_STATE_STARTED) { + IMSA_HILOGI("End...[%{public}d]\n", userId_); + return; + } + userState = UserState::USER_STATE_STARTED; + // hide current keyboard + if (currentClient != nullptr) { + HideKeyboard(currentClient); + } + for(int i=0; i<2; i++) { + StopInputMethod(i); + currentIme[i] = nullptr; + } + // disconnect all clients. + std::map, ClientInfo*>::iterator it; + for(it=mapClients.begin(); it!=mapClients.end();) { + sptr b = it->first; + b->RemoveDeathRecipient(clientDeathRecipient); + ClientInfo* clientInfo = it->second; + if (clientInfo != nullptr) { + int ret = clientInfo->client->onInputReleased(0); + if (ret != ErrorCode::NO_ERROR) { + IMSA_HILOGE("2-onInputReleased return : %{public}s [%{public}d]\n", ErrorCode::ToString(ret), userId_); + } + delete clientInfo; + } + IMSA_HILOGD("erase client..\n"); + it = mapClients.erase(it); + } + mapClients.clear(); + + // reset values + inputMethodSetting = nullptr; + currentClient = nullptr; + needReshowClient = nullptr; + } + + /*! Print the session information of this user into the given stream + \n The information includes: + \li the information of all the input clients connected to the input method management system. + \li current input method engine information + \li security input method engine information + \li current session information + \param fd the raw file descriptor that the dump is being sent to + */ + void PerUserSession::Dump(int fd) + { + std::map, ClientInfo*>::const_iterator it; + dprintf(fd, "\n - User Session State :\n"); + dprintf(fd, " * Client count = %d\n", mapClients.size()); + int index = 0; + for(it=mapClients.cbegin(); it!=mapClients.cend(); ++it) { + if (currentClient != nullptr && + Platform::RemoteBrokerToObject(currentClient) == it->first) { + dprintf(fd, " *[%d] Client Information: (current client)\n", index++); + } else { + dprintf(fd, " [%d] Client Information:\n", index++); + } + DumpClientInfo(fd, *(it->second)); + } + std::string header[2] = {"Current", "Security"}; + for(int i=0; i<2; i++) { + if (currentIme[i] != nullptr) { + dprintf(fd, "\n * %s IME mImeId = %s\n", header[i].c_str(), Utils::to_utf8(currentIme[i]->mImeId).c_str()); + KeyboardType* type = currentIme[i]->mTypes.at(currentKbdIndex[i]); + dprintf(fd, " %s KeyboardType mHashCode = %d, mLanguage = %s\n", header[i].c_str(), + type->getHashCode(), Utils::to_utf8(type->getLanguage()).c_str()); + + if (imsCore[i] != nullptr) { + sptr b = imsCore[i]->AsObject(); + dprintf(fd, " %s IME Service = %s#%p\n", header[i].c_str(), + Utils::to_utf8(b->GetObjectDescriptor()).c_str(), b.GetRefPtr()); + b=inputControlChannel[i]->AsObject(); + dprintf(fd, " %s InputControlChannel = %s#%p\n", + header[i].c_str(), Utils::to_utf8(b->GetObjectDescriptor()).c_str(), b.GetRefPtr()); + dprintf(fd, " %s inputMethodWindowToken = %p\n", header[i].c_str(), inputMethodToken[i].GetRefPtr()); + } else { + dprintf(fd, " %s IME Service = null (not started)\n", header[i].c_str()); + } + } else { + dprintf(fd, "\n * %s IME = null\n", header[i].c_str()); + } + } + DumpCurrentSession(fd); + } + + /*! dump current session + \param fd the file descriptor to output the information + */ + void PerUserSession::DumpCurrentSession(int fd) + { + if (currentClient == nullptr) { + dprintf(fd, "\n * Current Session = null (keyboard is not showing by any client)\n"); + return; + } + sptr b = Platform::RemoteBrokerToObject(currentClient); + std::map, ClientInfo*>::iterator it = mapClients.find(b); + int index = GetImeIndex(currentClient); + dprintf(fd, "\n * Current Session State :\n"); + dprintf(fd, " current client [= %s#%p] information :\n", + Utils::to_utf8(b->GetObjectDescriptor()).c_str(), b.GetRefPtr()); + DumpClientInfo(fd, *(it->second)); + + dprintf(fd, " current IME mImeID = %s\n", Utils::to_utf8(currentIme[index]->mImeId).c_str()); + b = Platform::RemoteBrokerToObject(imsCore[index]); + dprintf(fd, " IME service = %s#%p\n", Utils::to_utf8(b->GetObjectDescriptor()).c_str(), b.GetRefPtr()); + b = Platform::RemoteBrokerToObject(imsAgent); + dprintf(fd, " inputAgent = %s#%p\n", Utils::to_utf8(b->GetObjectDescriptor()).c_str(), b.GetRefPtr()); + b = Platform::RemoteBrokerToObject(inputControlChannel[index]); + dprintf(fd, " inputControlChannel = %s#%p\n", Utils::to_utf8(b->GetObjectDescriptor()).c_str(), b.GetRefPtr()); + dprintf(fd, " inputMethodWindowToken = #%p\n", inputMethodToken[index].GetRefPtr()); + dprintf(fd, " displayId = %d\n", displayId); + if (currentDisplayMode == 0) { + dprintf(fd, " displayMode = %d [ part sceen ]\n", currentDisplayMode); + } else { + dprintf(fd, " displayMode = %d [ full sceen ]\n", currentDisplayMode); + } + int height = 0; + GetKeyboardWindowHeight(&height); + dprintf(fd, " keyboard window height = %d\n", height); + } + + /*! dump a client information + \param fd the file descriptor to output the information + \param clientInfo client information of a remote input client + */ + void PerUserSession::DumpClientInfo(int fd, const ClientInfo& clientInfo) + { + dprintf(fd, " pid = %d\n", clientInfo.pid); + dprintf(fd, " uid = %d\n", clientInfo.uid); + dprintf(fd, " userId = %d\n", clientInfo.userId); + dprintf(fd, " displayId = %d\n", clientInfo.displayId); + + sptr b = Platform::RemoteBrokerToObject(clientInfo.client); + dprintf(fd, " inputClient = %s#%p\n", Utils::to_utf8(b->GetObjectDescriptor()).c_str(), b.GetRefPtr()); + b = Platform::RemoteBrokerToObject(clientInfo.channel); + dprintf(fd, " inputDataChannel = %s#%p\n", Utils::to_utf8(b->GetObjectDescriptor()).c_str(), b.GetRefPtr()); + } + + /*! Increase or reset ime error number + \param resetFlag the flag to increase or reset number. + \n resetFlag=true, reset error number to 0; + \n resetFlag=false, increase error number. + \param imeIndex index=0 default ime; index=1 security ime + \return return the error count value. It is less or equal 3. + */ + int PerUserSession::IncreaseOrResetImeError(bool resetFlag, int imeIndex) + { + static int errorNum[2] = {0, 0}; + static time_t past[2] = {time(0), time(0)}; + if (resetFlag == true) { + errorNum[imeIndex] = 0; + past[imeIndex] = 0; + return 0; + } + + errorNum[imeIndex]++; + time_t now = time(0); + double diffSeconds = difftime(now, past[imeIndex]); + + //time difference is more than 5 minutes, reset time and error num; + if (diffSeconds > 300) { + past[imeIndex] = now; + errorNum[imeIndex] = 1; + } + return errorNum[imeIndex]; + } + + /*! Get keyboard type + \param imeIndex it can be 0 or 1. 0 - default ime, 1 - security ime + \param typeIndex the index of keyboard type. + \return a KeyboardType pointer when it's found. + \return null when it's not found. + \note The returned pointer should not be freed by caller. + */ + KeyboardType* PerUserSession::GetKeyboardType(int imeIndex, int typeIndex) + { + if(typeIndex < 0) { + return nullptr; + } + if (imeIndex == SECURITY_IME || currentIme[DEFAULT_IME] == currentIme[SECURITY_IME]) { + if (typeIndex >= (int)currentIme[imeIndex]->mTypes.size()) { + return nullptr; + } + return currentIme[imeIndex]->mTypes[typeIndex]; + } else { + std::u16string imeId = currentIme[imeIndex]->mImeId; + std::vector currentKbdTypes = inputMethodSetting->GetEnabledKeyboardTypes(imeId); + int size = currentKbdTypes.size(); + if (typeIndex >= size) { + return nullptr; + } + int hashCode = currentKbdTypes[typeIndex]; + for(int i=0; i<(int)currentIme[imeIndex]->mTypes.size(); i++) { + if (currentIme[imeIndex]->mTypes[i]->getHashCode() == hashCode) { + return currentIme[imeIndex]->mTypes[i]; + } + } + } + return nullptr; + } + + /*! Reset current keyboard type + \param imeIndex it can be 0 or 1. 0 - default ime, 1 - security ime + */ + void PerUserSession::ResetCurrentKeyboardType(int imeIndex) + { + currentKbdIndex[imeIndex] = 0; + int hashCode = 0; + if (imeIndex == DEFAULT_IME) { + hashCode = inputMethodSetting->GetCurrentKeyboardType(); + } else { + hashCode = inputMethodSetting->GetCurrentSysKeyboardType(); + } + KeyboardType* type = nullptr; + if (hashCode == -1) { + type = GetKeyboardType(imeIndex, currentKbdIndex[imeIndex]); + } else { + bool flag = false; + if (imeIndex == SECURITY_IME || currentIme[DEFAULT_IME] == currentIme[SECURITY_IME]) { + for(int i=0; i<(int)currentIme[imeIndex]->mTypes.size(); i++) { + if (currentIme[imeIndex]->mTypes[i]->getHashCode()==hashCode) { + currentKbdIndex[imeIndex] = i; + flag = true; + break; + } + } + } else { + std::vector hashCodeList = inputMethodSetting->GetEnabledKeyboardTypes(currentIme[imeIndex]->mImeId); + for(int i=0; i<(int)hashCodeList.size(); i++) { + if (hashCode == hashCodeList[i]) { + currentKbdIndex[imeIndex] = i; + flag = true; + break; + } + } + } + if (flag == false) { + IMSA_HILOGW("The current keyboard type [hashCode=%{public}d] is not found in the current IME. Reset it! [%{public}d]\n", + hashCode, userId_); + type = GetKeyboardType(imeIndex, currentKbdIndex[imeIndex]); + } else if (imsCore[imeIndex] == imsCore[1-imeIndex]) { + currentKbdIndex[1-imeIndex] = currentKbdIndex[imeIndex]; + } + } + if (type != nullptr) { + InputMethodSetting tmpSetting; + if (imsCore[imeIndex] == imsCore[1-imeIndex]) { + inputMethodSetting->SetCurrentKeyboardType(type->getHashCode()); + inputMethodSetting->SetCurrentSysKeyboardType(type->getHashCode()); + currentKbdIndex[1-imeIndex] = currentKbdIndex[imeIndex]; + tmpSetting.SetCurrentKeyboardType(type->getHashCode()); + tmpSetting.SetCurrentSysKeyboardType(type->getHashCode()); + } else if (imeIndex == DEFAULT_IME) { + tmpSetting.SetCurrentKeyboardType(type->getHashCode()); + inputMethodSetting->SetCurrentKeyboardType(type->getHashCode()); + } else { + tmpSetting.SetCurrentSysKeyboardType(type->getHashCode()); + inputMethodSetting->SetCurrentSysKeyboardType(type->getHashCode()); + } + Platform::Instance()->SetInputMethodSetting(userId_, tmpSetting); + } + } + + /*! Get ime index for the input client + \param inputClient the remote object handler of an input client. + \return 0 - default ime + \return 1 - security ime + \return -1 - input client is not found + */ + int PerUserSession::GetImeIndex(const sptr& inputClient) + { + if (inputClient == nullptr) { + IMSA_HILOGW("PerUserSession::GetImeIndex inputClient is nullptr"); + return -1; + } + + ClientInfo *clientInfo = GetClientInfo(inputClient); + if (clientInfo == nullptr) { + IMSA_HILOGW("PerUserSession::GetImeIndex clientInfo is nullptr"); + return -1; + } + + if (clientInfo->attribute.GetSecurityFlag() == true) { + return SECURITY_IME; + } + return DEFAULT_IME; + } + + /*! Copy session data from one IME to another IME + \param imeIndex it can be 0 or 1. + \n 0 - default ime, 1 - security ime + */ + void PerUserSession::CopyInputMethodService(int imeIndex) + { + imsCore[imeIndex] = imsCore[1-imeIndex]; + localControlChannel[imeIndex] = localControlChannel[1-imeIndex]; + inputControlChannel[imeIndex] = inputControlChannel[1-imeIndex]; + inputMethodToken[imeIndex] = inputMethodToken[1-imeIndex]; + currentKbdIndex[imeIndex] = currentKbdIndex[1-imeIndex]; + int hashCode[2]; + hashCode[0] = inputMethodSetting->GetCurrentKeyboardType(); + hashCode[1] = inputMethodSetting->GetCurrentSysKeyboardType(); + if (hashCode[imeIndex] != hashCode[1-imeIndex]) { + hashCode[imeIndex] = hashCode[1-imeIndex]; + inputMethodSetting->SetCurrentKeyboardType(hashCode[0]); + inputMethodSetting->SetCurrentSysKeyboardType(hashCode[1]); + + InputMethodSetting tmpSetting; + tmpSetting.ClearData(); + tmpSetting.SetCurrentKeyboardType(hashCode[0]); + tmpSetting.SetCurrentSysKeyboardType(hashCode[1]); + Platform::Instance()->SetInputMethodSetting(userId_, tmpSetting); + } + } + + /*! Get ClientInfo + \param inputClient the IInputClient remote handler of given input client + \return a pointer of ClientInfo if client is found + \n null if client is not found + \note the clientInfo pointer should not be freed by caller + */ + ClientInfo* PerUserSession::GetClientInfo(const sptr& inputClient) + { + if (inputClient == nullptr) { + IMSA_HILOGE("PerUserSession::GetClientInfo inputClient is nullptr"); + return nullptr; + } + sptr b = Platform::RemoteBrokerToObject(inputClient); + std::map, ClientInfo*>::iterator it = mapClients.find(b); + if (it == mapClients.end()) { + return nullptr; + } + + return (ClientInfo*) it->second; + } + + void PerUserSession::BindInputAbility(){ + IMSA_HILOGE("PerUserSession::BindInputAbility"); + AAFwk::Want want; + want.SetAction("action.system.inputmethod"); + want.SetElementName("com.example.kikakeyboard","com.example.kikakeyboard.MainAbility"); + sptr stub(new (std::nothrow) InputMethodAbilityConnectionStub(0)); + sptr connCallback = new (std::nothrow) AAFwk::AbilityConnectionProxy(stub); + GetAbilityManagerService()->StartAbility(want); + } + + sptr PerUserSession::GetAbilityManagerService() + { + IMSA_HILOGE("GetAbilityManagerService start"); + sptr abilityMsObj = + OHOS::DelayedSingleton::GetInstance()->GetSystemAbility(ABILITY_MGR_SERVICE_ID); + if (abilityMsObj == nullptr) { + IMSA_HILOGE("failed to get ability manager service"); + return nullptr; + } + return iface_cast(abilityMsObj); + } + + /*! Prepare input. Called by an input client. + \n Run in work thread of this user + \param msg the parameters from remote client are saved in msg->msgContent_ + \return ErrorCode + */ + void PerUserSession::OnPrepareInput(Message* msg) + { + IMSA_HILOGI("PerUserSession::OnPrepareInput Start...[%{public}d]\n", userId_); + MessageParcel* data = msg->msgContent_; + int pid = data->ReadInt32(); + int uid = data->ReadInt32(); + int displayId = data->ReadInt32(); + + sptr clientObject = data->ReadRemoteObject(); + if (clientObject == nullptr) { + IMSA_HILOGI("PerUserSession::OnPrepareInput clientObject is null"); + } + sptr client = new InputClientProxy(clientObject); + sptr channelObject = data->ReadRemoteObject(); + if (channelObject == nullptr) { + IMSA_HILOGI("PerUserSession::OnPrepareInput channelObject is null"); + } + sptr channel = new InputDataChannelProxy(channelObject); + InputAttribute* attribute = data->ReadParcelable(); + if (attribute ==nullptr) { + IMSA_HILOGI("PerUserSession::OnPrepareInput attribute is nullptr"); + } + + int ret = AddClient(pid, uid, displayId, client, channel, *attribute); + if (ret != ErrorCode::NO_ERROR) { + IMSA_HILOGE("PerUserSession::OnPrepareInput Aborted! %{public}s [%{public}d]\n", ErrorCode::ToString(ret), userId_); + return; + } + SetDisplayId(displayId); + int index = GetImeIndex(client); + IMSA_HILOGI("PerUserSession::OnPrepareInput index = %{public}d",index); + currentIndex = index; + IMSA_HILOGI("PerUserSession::OnPrepareInput BindInputAbility start"); + BindInputAbility(); + IMSA_HILOGI("PerUserSession::OnPrepareInput BindInputAbility end"); + } + + /*! Release input. Called by an input client. + \n Run in work thread of this user + \param msg the parameters from remote client are saved in msg->msgContent_ + \return ErrorCode + */ + void PerUserSession::OnReleaseInput(Message* msg) + { + IMSA_HILOGI("PerUserSession::OnReleaseInput Start...[%{public}d]\n", userId_); + MessageParcel* data = msg->msgContent_; + + sptr clientObject = data->ReadRemoteObject(); + sptr client = new InputClientProxy(clientObject); + sptr interface = client; + int remainClientNum = 0; + if (currentClient == interface) { + HideKeyboard(client); + } + int ret = RemoveClient(client, &remainClientNum); + if (ret != ErrorCode::NO_ERROR) { + IMSA_HILOGE("PerUserSession::OnReleaseInput Aborted! Failed to RemoveClient [%{public}d]\n", userId_); + } + IMSA_HILOGI("PerUserSession::OnReleaseInput End...[%{public}d]\n", userId_); + } + + /*! Start input. Called by an input client. + \n Run in work thread of this user + \param msg the parameters from remote client are saved in msg->msgContent_ + \return ErrorCode + */ + void PerUserSession::OnStartInput(Message* msg) + { + IMSA_HILOGI("PerUserSession::OnStartInput"); + MessageParcel* data = msg->msgContent_; + sptr clientObject = data->ReadRemoteObject(); + sptr client = new InputClientProxy(clientObject); + int ret = ShowKeyboard(client); + if (ret != ErrorCode::NO_ERROR) { + IMSA_HILOGE("PerUserSession::OnStartInput Aborted! %{public}s [%{public}d]\n", ErrorCode::ToString(ret), userId_); + } else { + IMSA_HILOGI("PerUserSession::OnStartInput End...[%{public}d]\n", userId_); + } + } + + void PerUserSession::onSetInputMethodCore(Message* msg) + { + IMSA_HILOGI("PerUserSession::onSetInputMethodCore Start...[%{public}d]\n", userId_); + MessageParcel* data = msg->msgContent_; + + sptr coreObject = data->ReadRemoteObject(); + sptr core = new InputMethodCoreProxy(coreObject); + int index = currentIndex; + IMSA_HILOGI("PerUserSession::onSetInputMethodCore index = [%{public}d]\n", index); + if (index >= MAX_IME || index < 0) { + IMSA_HILOGE("PerUserSession::onSetInputMethodCore Aborted! %{public}s [%{public}d]\n", ErrorCode::ToString(ErrorCode::ERROR_BAD_PARAMETERS), userId_); + return; + } + if (imsCore[index] != nullptr) { + IMSA_HILOGI("PerUserSession::onSetInputMethodCore End... Input Method Service has already been started ! [%{public}d]\n", userId_); + return; + } + imsCore[index]=core; + int ret = StartInputMethod(index); + if (ret != ErrorCode::NO_ERROR) { + IMSA_HILOGE("PerUserSession::onSetInputMethodCore Aborted! %{public}s [%{public}d]\n", ErrorCode::ToString(ret), userId_); + } else { + IMSA_HILOGI("PerUserSession::onSetInputMethodCore End...[%{public}d]\n", userId_); + } + } + + /*! Stop input. Called by an input client. + \n Run in work thread of this user + \param msg the parameters from remote client are saved in msg->msgContent_ + \return ErrorCode + */ + void PerUserSession::OnStopInput(Message* msg) + { + IMSA_HILOGI("PerUserSession::OnStopInput"); + MessageParcel* data = msg->msgContent_; + + sptr clientObject = data->ReadRemoteObject(); + sptr client = new InputClientProxy(clientObject); + int ret = HideKeyboard(client); + if (ret != ErrorCode::NO_ERROR) { + IMSA_HILOGE("PerUserSession::OnStopInput Aborted! %{public}s [%{public}d]\n", ErrorCode::ToString(ret), userId_); + } else { + IMSA_HILOGI("PerUserSession::OnStopInput End...[%{public}d]\n", userId_); + } + } + } +} diff --git a/services/src/peruser_setting.cpp b/services/src/peruser_setting.cpp new file mode 100644 index 00000000..64608a70 --- /dev/null +++ b/services/src/peruser_setting.cpp @@ -0,0 +1,577 @@ +/* + * Copyright (C) 2021 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 "unistd.h" //usleep +#include "peruser_setting.h" +#include "platform.h" +#include "utils.h" +namespace OHOS { +namespace MiscServices { + /*! Constructor + \param userId the id number of this user + */ + PerUserSetting::PerUserSetting(int userId) + { + userId_ = userId; + currentImeId = Utils::to_utf16(""); + userState = UserState::USER_STATE_STARTED; + } + + /*! Destructor + */ + PerUserSetting::~PerUserSetting() + { + if (userState == UserState::USER_STATE_UNLOCKED) { + OnUserLocked(); + } + } + + /*! Initialize data for this user. + \n It's called when this user is unlocked. The work includes: + \li read all installed input method engine information from the system + \li read input method setting data from the system + */ + void PerUserSetting::Initialize() + { + userState = UserState::USER_STATE_UNLOCKED; + + inputMethodProperties.clear(); + int ret = Platform::Instance()->ListInputMethod(userId_, &inputMethodProperties); + if (ret != ErrorCode::NO_ERROR) { + IMSA_HILOGE("Failed to listInputMethod [%d]\n", userId_); + } + int size = inputMethodProperties.size(); + if (size == 0) { + currentImeId = Utils::to_utf16(""); + } + + ret = Platform::Instance()->GetInputMethodSetting(userId_, &inputMethodSetting); + if (ret != ErrorCode::NO_ERROR) { + IMSA_HILOGE("Failed to getInputMethodSetting [%d]\n", userId_); + } else { + if (size > 0) { + InitInputMethodSetting(); + } + } + } + + /*! Add an input method engine. + \n It's called when a package is installed in the system. + \param packageName the package name of installed package. + \param[out] isSecurityIme check if the added ime is a security ime. + \return ErrorCode::NO_ERROR The installed package is an IME package, and is added in the input method management system + \return ErrorCode::ERROR_NOT_IME_PACKAGE The installed package is not an IME package. + \return ErrorCode::ERROR_IME_PACKAGE_DUPLICATED The installed package is duplicated. + */ + int PerUserSetting::OnPackageAdded(std::u16string& packageName, bool* isSecurityIme) + { + if (isSecurityIme) { + *isSecurityIme = false; + } + std::u16string imeId = GetImeId(packageName); + if (imeId.size() != 0) { + IMSA_HILOGI("%s [%d]\n", ErrorCode::ToString(ErrorCode::ERROR_IME_PACKAGE_DUPLICATED), userId_); + return ErrorCode::ERROR_IME_PACKAGE_DUPLICATED; + } + // retake the input method list installed in the system. + InputMethodProperty *property = new InputMethodProperty(); + int ret = Platform::Instance()->GetInputMethodProperty(userId_, packageName, property); + if (ret != ErrorCode::NO_ERROR) { + delete property; + IMSA_HILOGI("%s [%d]\n", ErrorCode::ToString(ErrorCode::ERROR_NOT_IME_PACKAGE), userId_); + return ErrorCode::ERROR_NOT_IME_PACKAGE; + } + inputMethodProperties.push_back(property); + if (CheckIfSecurityIme(*property)) { + if (isSecurityIme) { + *isSecurityIme = true; + } + return ErrorCode::NO_ERROR; + } + + std::vector types; + for(int i=0; i<(int)property->mTypes.size(); i++) { + types.push_back(property->mTypes[i]->getHashCode()); + } + + InputMethodSetting imSetting; + std::u16string key = InputMethodSetting::ENABLED_INPUT_METHODS_TAG; + imSetting.SetValue(key, inputMethodSetting.GetValue(key)); + imSetting.AddEnabledInputMethod(property->mImeId, types); + types.clear(); + Platform::Instance()->SetInputMethodSetting(userId_, imSetting); + return ErrorCode::NO_ERROR; + } + + /*! Remove an input method engine. + \n It's called when a package is removed from the system. + \param packageName the package name of installed package. + \param[out] isSecurityIme check if the removed ime is a security ime. + \return ErrorCode::NO_ERROR The removed package is an IME package, and is removed from the input method management system + \return ErrorCode::ERROR_NOT_IME_PACKAGE The removed package is not an IME package. + */ + int PerUserSetting::OnPackageRemoved(std::u16string& packageName, bool* isSecurityIme) + { + if (isSecurityIme) { + *isSecurityIme = false; + } + std::u16string imeId = GetImeId(packageName); + if (imeId.size() == 0) { + IMSA_HILOGI("%s [%d]\n", ErrorCode::ToString(ErrorCode::ERROR_NOT_IME_PACKAGE), userId_); + return ErrorCode::ERROR_NOT_IME_PACKAGE; + } + bool securityFlag = false; + std::vector::iterator it; + for(it=inputMethodProperties.begin(); itmImeId == imeId) { + if (CheckIfSecurityIme(*node)==true) { + securityFlag = true; + } + inputMethodProperties.erase(it); + delete node; + break; + } + } + if (securityFlag) { + if (isSecurityIme) { + *isSecurityIme = true; + } + return ErrorCode::NO_ERROR; + } + + InputMethodSetting imSetting; + std::u16string key = InputMethodSetting::ENABLED_INPUT_METHODS_TAG; + imSetting.SetValue(key, inputMethodSetting.GetValue(key)); + + int flag = imSetting.RemoveEnabledInputMethod(imeId); + if (flag == false) { + IMSA_HILOGI("The package removed is not an enabled IME. [%d]\n", userId_); + return ErrorCode::NO_ERROR; + } + Platform::Instance()->SetInputMethodSetting(userId_, imSetting); + // wait for some time so that the setting change will not be overrided by the followed transact + usleep(100*1000); + return ErrorCode::NO_ERROR; + } + + /*! Update input method setting data. + \n It's called when the input method setting data in the system is changed. + \param key the name of setting item + \param value the value of the setting item + \return ErrorCode::NO_ERROR update the setting data to input method management system. + \return ErrorCode::ERROR_SETTING_SAME_VALUE the current value is same as the one in the system. + */ + int PerUserSetting::OnSettingChanged(const std::u16string& key, const std::u16string& value) + { + std::u16string currentValue = inputMethodSetting.GetValue(key); + + if (currentValue == value) { + return ErrorCode::ERROR_SETTING_SAME_VALUE; + } + + inputMethodSetting.SetValue(key, value); + + if (key == InputMethodSetting::CURRENT_INPUT_METHOD_TAG) { + currentImeId = inputMethodSetting.GetCurrentInputMethod(); + } else if (key == InputMethodSetting::ENABLED_INPUT_METHODS_TAG) { + if ((currentImeId.size()>0 && value.find(currentImeId) == std::string::npos) || + currentImeId.size()==0 ){ + ResetCurrentInputMethod(); + InputMethodSetting tmpSetting; + tmpSetting.ClearData(); + tmpSetting.SetCurrentInputMethod(currentImeId); + tmpSetting.SetCurrentKeyboardType(-1); + Platform::Instance()->SetInputMethodSetting(userId_, tmpSetting); + } + } + return ErrorCode::NO_ERROR; + } + + /*! Switch to the next input method service. + */ + void PerUserSetting::OnAdvanceToNext() + { + bool flag = false; + std::u16string enabledInputMethods = inputMethodSetting.GetValue(InputMethodSetting::ENABLED_INPUT_METHODS_TAG); + std::u16string imeId; + std::u16string nextImeId = Utils::to_utf16(""); + InputMethodProperty* firstEnabledProperty = nullptr; + for(int i=0; i<(int)inputMethodProperties.size(); i++) { + imeId = inputMethodProperties[i]->mImeId; + if (imeId == currentImeId) { + flag = true; + } else if (enabledInputMethods.find(imeId) != std::string::npos) { + if (flag == true) { + nextImeId = imeId; + break; + } else if (firstEnabledProperty == nullptr) { + firstEnabledProperty = inputMethodProperties[i]; + } + } + } + + if (nextImeId.size() == 0 && firstEnabledProperty) { + nextImeId = firstEnabledProperty->mImeId; + } + + // next enabled ime is not available. + if (nextImeId.size() == 0) { + IMSA_HILOGW("No next IME is available. [%d]\n", userId_); + return ; + } + + InputMethodSetting tmpSetting; + tmpSetting.SetCurrentInputMethod(nextImeId); + tmpSetting.SetCurrentKeyboardType(-1); + Platform::Instance()->SetInputMethodSetting(userId_, tmpSetting); + } + + /*! It's Called when this user is locked. + \n Release data for this user including: + \li release input method engine information + \li release input method setting data + */ + void PerUserSetting::OnUserLocked() + { + if (userState == UserState::USER_STATE_STARTED) { + return; + } + userState = UserState::USER_STATE_STARTED; + currentImeId = Utils::to_utf16(""); + + // release input method properties + std::vector::iterator it; + for(it=inputMethodProperties.begin(); it imeList = inputMethodSetting.GetEnabledInputMethodList(); + size = imeList.size(); + dprintf(fd, "\n * Enabled IME count : %d\n",size); + for(int i=0; i hashCodeList = inputMethodSetting.GetEnabledKeyboardTypes(imeList[i]); + dprintf(fd, " Enabled keyboard count = %d, hashcode list : ", hashCodeList.size()); + for(int j=0; j<(int)hashCodeList.size(); j++) { + dprintf(fd, "%d", hashCodeList[j]); + if (j<(int)hashCodeList.size()-1) { + dprintf(fd, ", "); + } + } + dprintf(fd, "\n"); + hashCodeList.clear(); + } + imeList.clear(); + } + + /*! Get the state of this user + \return UserState::USER_STATE_STARTED user is started + \return UserState::USER_STATE_UNLOCKED user is unlocked + */ + int PerUserSetting::GetUserState() + { + return userState; + } + + /*! Get the current IME + \return a pointer of InputMethodProperty when an IME is available. + \return null when there is no enabled IME in the system. + \note The returned pointer should NOT be freed by caller + */ + InputMethodProperty* PerUserSetting::GetCurrentInputMethod() + { + for(int i=0; i<(int)inputMethodProperties.size(); i++) { + if (currentImeId == inputMethodProperties[i]->mImeId) { + return inputMethodProperties[i]; + } + } + // if default ime is null, we use security ime as default ime. + return GetSecurityInputMethod(); + } + + /*! Get the system security IME + \return a pointer of InputMethodProperty when an system security IME is available. + \return null when there is no security IME in the system. + \note The returned pointer should NOT be freed by caller + */ + InputMethodProperty* PerUserSetting::GetSecurityInputMethod() + { + InputMethodProperty* ime = nullptr; + std::u16string systemLocales = inputMethodSetting.GetValue(InputMethodSetting::SYSTEM_LOCALE_TAG); + for(int i=0; i<(int)inputMethodProperties.size(); i++) { + if (CheckIfSecurityIme(*inputMethodProperties[i])==false) { + continue; + } + // if systemLocales is not setting, return the first security ime + if (systemLocales.size()==0) { + return inputMethodProperties[i]; + } + if (ime==nullptr) { + ime = inputMethodProperties[i]; + } + for(int j=0; j<(int)inputMethodProperties[i]->mTypes.size(); j++) { + std::u16string language = inputMethodProperties[i]->mTypes[j]->getLanguage(); + // if the keyboard language is in the list of system locales, return the ime + if (systemLocales.find(language) != std::string::npos) { + return inputMethodProperties[i]; + } + } + } + return ime; + } + + /*! Get the next enabled IME + \return a pointer of InputMethodProperty when the next enabled IME is available. + \return null when the next enabled IME is not available. + \note The returned pointer should NOT be freed by caller + */ + InputMethodProperty* PerUserSetting::GetNextInputMethod() + { + bool flag = false; + std::u16string enabledInputMethods = inputMethodSetting.GetValue(InputMethodSetting::ENABLED_INPUT_METHODS_TAG); + std::u16string imeId; + InputMethodProperty* firstEnabledProperty = nullptr; + for(int i=0; i<(int)inputMethodProperties.size(); i++) { + imeId = inputMethodProperties[i]->mImeId; + if (imeId == currentImeId) { + flag = true; + } else if (enabledInputMethods.find(imeId) != std::string::npos) { + if (flag == true) { + return inputMethodProperties[i]; + } else if (firstEnabledProperty == nullptr) { + firstEnabledProperty = inputMethodProperties[i]; + } + } + } + return firstEnabledProperty; + } + + /*! Get the input method setting data + \return a pointer of InputMethodSetting. + \note The returned pointer should NOT be freed by caller + */ + InputMethodSetting* PerUserSetting::GetInputMethodSetting() + { + return &inputMethodSetting; + } + + /*! list the details of all the enabled input method engine + \param[out] properties the details will be written to the param properties + \return ErrorCode::NO_ERROR + */ + int32_t PerUserSetting::ListInputMethodEnabled(std::vector *properties) + { + std::u16string enabledInputMethods = inputMethodSetting.GetValue(InputMethodSetting::ENABLED_INPUT_METHODS_TAG); + for(int i=0; i<(int)inputMethodProperties.size(); i++) { + + if (enabledInputMethods.find(inputMethodProperties[i]->mImeId) != std::string::npos) { + properties->push_back(inputMethodProperties[i]); + } + } + return ErrorCode::NO_ERROR; + } + + /*! List the details of all input method engine installed in the system + \param[out] properties the details will be written to the param properties + \return ErrorCode::NO_ERROR + */ + int32_t PerUserSetting::ListInputMethod(std::vector *properties) + { + for(int i=0; i<(int)inputMethodProperties.size(); i++) { + properties->push_back(inputMethodProperties[i]); + } + return ErrorCode::NO_ERROR; + } + + /*! List the keyboard types of given input method engine + \param imeId the id of the given IME + \param[out] types the data of type list of the given IME will be written to types + \return ErrorCode::NO_ERROR + */ + int32_t PerUserSetting::ListKeyboardType(const std::u16string& imeId, std::vector *types) + { + for(int i=0; i<(int)inputMethodProperties.size(); i++) { + if (imeId == inputMethodProperties[i]->mImeId) { + for(int j=0; j<(int)inputMethodProperties[i]->mTypes.size(); j++) { + types->push_back(inputMethodProperties[i]->mTypes[j]); + } + break; + } + } + return ErrorCode::NO_ERROR; + } + + /*! Get the input method engine details of the given imeId + \param imeId the id of the given IME + \return a pointer of InputMethodProperty when the given IME exists. + \return null when the given IME is not available + \note the returned pointer should not be freed by the caller. + */ + InputMethodProperty* PerUserSetting::GetInputMethodProperty(const std::u16string& imeId) + { + for(int i=0; i<(int)inputMethodProperties.size(); i++) { + if (inputMethodProperties[i]->mImeId == imeId) { + return inputMethodProperties[i]; + } + } + return nullptr; + } + + /*! Get the language of keyboard type according to the given hashCode + \param property a pointer to an IME + \param hashCode the given hashCode + \return language value when the given hashCode is found + \return an empty string when the given hashCode is not found + */ + std::u16string PerUserSetting::GetKeyboardTypeLanguage(const InputMethodProperty* property, int hashCode) + { + for(int i=0; i<(int)property->mTypes.size(); i++) { + if (property->mTypes[i]->getHashCode() == hashCode) { + return property->mTypes[i]->getLanguage(); + } + } + return Utils::to_utf16(""); + } + + /*! Init input method setting data + */ + void PerUserSetting::InitInputMethodSetting() + { + bool flag = inputMethodSetting.FindKey(InputMethodSetting::ENABLED_INPUT_METHODS_TAG); + if (flag == false) { + for(int i=0; i<(int)inputMethodProperties.size(); i++) { + if (CheckIfSecurityIme(*inputMethodProperties[i])==true) { + continue; + } + std::vector types; + for(int j=0; j<(int)inputMethodProperties[i]->mTypes.size(); j++) { + types.push_back(inputMethodProperties[i]->mTypes[j]->getHashCode()); + } + inputMethodSetting.AddEnabledInputMethod(inputMethodProperties[i]->mImeId, types); + types.clear(); + } + } + + flag = inputMethodSetting.FindKey(InputMethodSetting::CURRENT_INPUT_METHOD_TAG); + std::u16string imeId = inputMethodSetting.GetCurrentInputMethod(); + if (flag == false) { + ResetCurrentInputMethod(); + } else { + currentImeId = imeId; + } + flag = inputMethodSetting.FindKey(InputMethodSetting::CURRENT_SYS_KEYBOARD_TYPE_TAG); + if (flag==false) { + inputMethodSetting.SetCurrentSysKeyboardType(-1); + } + Platform::Instance()->SetInputMethodSetting(userId_, inputMethodSetting); + } + + /*! Reset the current (default) input method engine + \li Look for the first keyboard language which is in the system locale list. + \li If no keyboard language is in system locale list, we use the first system ime as current ime. + \li If no system ime is there, we use the first enabled ime as current ime. + \li If no enabled ime, set current ime as null. + */ + void PerUserSetting::ResetCurrentInputMethod() + { + std::u16string systemLocales = inputMethodSetting.GetValue(InputMethodSetting::SYSTEM_LOCALE_TAG); + std::u16string enabledInputMethods = inputMethodSetting.GetValue(InputMethodSetting::ENABLED_INPUT_METHODS_TAG); + std::u16string imeId; + InputMethodProperty* firstEnabledIme = nullptr; + bool flag = false; + + for(int i=0; i<(int)inputMethodProperties.size(); i++) { + imeId = inputMethodProperties[i]->mImeId; + if (enabledInputMethods.find(imeId) == std::string::npos) { + continue; + } + if (firstEnabledIme == nullptr) { + firstEnabledIme = inputMethodProperties[i]; + } + + std::vector hashCodeList = inputMethodSetting.GetEnabledKeyboardTypes(imeId); + for(int j=0; j<(int)hashCodeList.size(); j++) { + std::u16string language = GetKeyboardTypeLanguage(inputMethodProperties[i], hashCodeList[j]); + if (systemLocales.find(language) != std::string::npos) { + currentImeId = imeId; + flag = true; + break; + } + } + if (flag) { + break; + } + } + + // if we cannot find any keyboard type which belongs to system locales, + // we will use the first enabled ime as current ime. + if (flag == false) { + if (firstEnabledIme) { + currentImeId = firstEnabledIme->mImeId; + } else { + currentImeId = Utils::to_utf16(""); + } + } + inputMethodSetting.SetCurrentInputMethod(currentImeId); + inputMethodSetting.SetCurrentKeyboardType(-1); + } + + /*! Get the id of the given input method engine + \param packageName the packageName of the given IME + \return the id of the given IME + */ + std::u16string PerUserSetting::GetImeId(const std::u16string& packageName) + { + for(int i=0; i<(int)inputMethodProperties.size(); i++) { + if (inputMethodProperties[i]->mPackageName == packageName) { + return inputMethodProperties[i]->mImeId; + } + } + return Utils::to_utf16(""); + } + + /*! Check if the InputMethodProperty object is a security ime + \param property the InputMethodProperty object needed to be checked + \return true - It's a security Ime + \n false - It's not a security Ime + */ + bool PerUserSetting::CheckIfSecurityIme(const InputMethodProperty& property) + { + return property.isSystemIme; + } +} +} \ No newline at end of file diff --git a/services/src/platform.cpp b/services/src/platform.cpp new file mode 100644 index 00000000..9dc3ffa7 --- /dev/null +++ b/services/src/platform.cpp @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2021 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 "global.h" +#include "platform.h" +#include "platform_callback_stub.h" + +namespace OHOS { +namespace MiscServices { + void Platform::SetPlatform(const sptr < IPlatformApi >& platformApi) + { + this->platformApi = platformApi; + sptr < IPlatformCallback > cb = new PlatformCallbackStub(); + this->platformApi->registerCallback(cb); + } + + /*! Constructor + */ + Platform::Platform() + { + } + + /*! Destructor + */ + Platform::~Platform() + { + } + + /*! Single instance exists in the service + */ + Platform* Platform::Instance() + { + static Platform* platform = nullptr; + if (platform == nullptr) { + platform = new Platform(); + } + return platform; + } + + /*! Start an input method service + \param userId the id of the given user. + \param packageName the packageName of the given input method engine which is going to start + \param intention the intention to start the service + \return the remote object handler of started input method service. + */ + sptr < IInputMethodCore > Platform::BindInputMethodService(int userId, const std::u16string& packageName, + const std::u16string& intention) + { + if (platformApi == nullptr) { + return nullptr; + } + return platformApi->bindInputMethodService(packageName, intention, userId); + } + + /*! Stop an input method service + \param userId the id of the given user. + \param packageName the packageName of the given input method engine which is going to stop + \return ErrorCode + */ + int Platform::UnbindInputMethodService(int userId, const std::u16string& packageName) + { + if (platformApi == nullptr) { + return ErrorCode::ERROR_NULL_POINTER; + } + return platformApi->unbindInputMethodService(userId, packageName); + } + + /*! Create window token + \param userId the id of the given user. + \param displayId the id of display screen + \param packageName the packageName of the given input method engine + \return ErrorCode + */ + sptr < IRemoteObject > Platform::CreateWindowToken(int userId, int displayId, const std::u16string& packageName) + { + if (platformApi == nullptr) { + return nullptr; + } + return platformApi->createWindowToken(userId, displayId, packageName); + } + + /*! Destroy window token + \param userId the id of the given user. + \param packageName the packageName of the given input method engine + \return ErrorCode + */ + int Platform::DestroyWindowToken(int userId, const std::u16string& packageName) + { + if (platformApi == nullptr) { + return ErrorCode::ERROR_NULL_POINTER; + } + return platformApi->destroyWindowToken(userId, packageName); + } + + /*! Get all the installed input method engines for the given user + \param userId the id of the given user. + \param[out] inputMethodProperties the input method engine list installed in the system for the given user + \return ErrorCode + */ + int Platform::ListInputMethod(int userId, std::vector < InputMethodProperty* > * inputMethodProperties) + { + return 0; + } + + /*! Get input method engine information of the given package for the given user + \param userId the id of the given user. + \param packageName the given package name for which to get input method engine information + \param[out] inputMethodProperty the input method engine information for the given package + \return ErrorCode + */ + int Platform::GetInputMethodProperty(int userId, const std::u16string& packageName, InputMethodProperty * inputMethodProperty) + { + if (platformApi == nullptr) { + return ErrorCode::ERROR_NULL_POINTER; + } + return platformApi->getInputMethodProperty(userId, packageName, inputMethodProperty); + } + + /*! Get the input method setting data for the given user + \param userId the id of the given user + \param[out] inputMethodSetting the input method setting data for the given user + \return ErrorCode + */ + int Platform::GetInputMethodSetting(int userId, InputMethodSetting * inputMethodSetting) + { + return 0; + } + + /*! Set the input method setting data for the given user + \param userId the id of the given user + \param inputMethodSetting the input method setting data for the given user + \return ErrorCode + */ + int Platform::SetInputMethodSetting(int userId, const InputMethodSetting& inputMethodSetting) + { + if (platformApi == nullptr) { + return ErrorCode::ERROR_NULL_POINTER; + } + return platformApi->setInputMethodSetting(userId, inputMethodSetting); + } + + /*! Check if a physical keyboard is connected to the system + \return true - a physical keyboard is connected + \n false - no physical keyboard + */ + bool Platform::CheckPhysicalKeyboard() + { + return true; + } + + /*! Check if the remote caller is from a valid window + \return true - the remote caller is from a valid window + \n false - the remote caller is not from a valid window + */ + bool Platform::IsValidWindow(int uid, int pid, int displayId) + { + (void)uid; + (void)pid; + (void)displayId; + return true; + } + + /*! Check if the remote caller is from a focused window + \return true - the remote caller is from a focused window + \n false - the remote caller is not from a focused window + */ + bool Platform::IsWindowFocused(int uid, int pid, int displayId) + { + (void)uid; + (void)pid; + (void)displayId; + return true; + } +} +} \ No newline at end of file diff --git a/services/src/platform_api_proxy.cpp b/services/src/platform_api_proxy.cpp new file mode 100644 index 00000000..3218f9a9 --- /dev/null +++ b/services/src/platform_api_proxy.cpp @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2021 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 "i_platform_api.h" +#include "i_input_method_core.h" +#include "iremote_proxy.h" +#include "message_parcel.h" +#include "peer_holder.h" +#include "input_method_setting.h" +#include "peer_holder.h" +#include "utils.h" +#include +#include + + +/*! \class PlatformApiProxy + \brief The proxy implementation of IPlatformApi + + \todo This class will be deleted on target platform +*/ +namespace OHOS { +namespace MiscServices { + class PlatformApi : public IRemoteProxy < IPlatformApi > { + public: + PlatformApi(const sptr < IRemoteObject >& impl) + : IRemoteProxy < IPlatformApi >(impl) + { + } + + ~PlatformApi() + { + } + + int32_t registerCallback(const sptr < IPlatformCallback >& cb) + { + MessageParcel data, reply; + MessageOption option; + data.WriteInterfaceToken(GetDescriptor()); + data.WriteRemoteObject(cb->AsObject()); + int32_t status = Remote()->SendRequest(REGISTER_CALLBACK, data, reply,option); + if (status != ErrorCode::NO_ERROR) { + return status; + } + int code = reply.ReadException(); + if (code != 0) { + return code; + } + return ErrorCode::NO_ERROR; + } + + std::u16string getInterfaceDescriptor() { + return Utils::to_utf16("20210814"); + } + + sptr < IInputMethodCore > bindInputMethodService(const std::u16string& packageName, const std::u16string& intention, int userId) + { + MessageParcel data, reply; + MessageOption option; + data.WriteInterfaceToken(GetDescriptor()); + data.WriteString16(packageName); + data.WriteString16(intention); + data.WriteInt32(userId); + int32_t status = Remote()->SendRequest(BIND_IMS, data, reply,option); + if (status != ErrorCode::NO_ERROR) { + LOG_DEBUG("status = %s\n", ErrorCode::ToString(status)); + return nullptr; + } + int code = reply.ReadException(); + if (code != 0) {// code=0, means no exception. + LOG_DEBUG("exception code : %d\n", code); + return nullptr; + } + sptr < IInputMethodCore > ims = nullptr; + reply.ReadRemoteObject(); + return ims; + } + + int32_t unbindInputMethodService(int userId, const std::u16string& packageName) + { + MessageParcel data, reply; + MessageOption option; + data.WriteInterfaceToken(GetDescriptor()); + data.WriteInt32(userId); + data.WriteString16(packageName); + int32_t status = Remote()->SendRequest(UNBIND_IMS, data, reply,option); + if (status != ErrorCode::NO_ERROR) { + return status; + } + int code = reply.ReadException(); + if (code != 0) { + return code; + } + return ErrorCode::NO_ERROR; + } + + sptr < IRemoteObject > createWindowToken(int userId, int displayId, const std::u16string& packageName) + { + MessageParcel data, reply; + MessageOption option; + data.WriteInterfaceToken(GetDescriptor()); + data.WriteInt32(userId); + data.WriteInt32(displayId); + data.WriteString16(packageName); + int32_t status = Remote()->SendRequest(CREATE_WINDOW_TOKEN, data, reply,option); + if (status != ErrorCode::NO_ERROR) { + return nullptr; + } + int code = reply.ReadException(); + if (code != 0) { // code=0, means no exception. + IMSA_HILOGE("Exception code = %d\n", code); + return nullptr; + } + sptr < IRemoteObject > token = reply.ReadRemoteObject(); + return token; + } + + int32_t destroyWindowToken(int userId, const std::u16string& packageName) + { + MessageParcel data, reply; + MessageOption option; + data.WriteInterfaceToken(GetDescriptor()); + data.WriteInt32(userId); + data.WriteString16(packageName); + int32_t status = Remote()->SendRequest(DESTROY_WINDOW_TOKEN, data, reply,option); + if (status != ErrorCode::NO_ERROR) { + return status; + } + int code = reply.ReadException(); + if (code != 0) // code=0, means no exception. + return code; + return ErrorCode::NO_ERROR; + } + + int32_t listInputMethod(int userId, std::vector < InputMethodProperty* > * inputMethodProperties) + { + MessageParcel data, reply; + MessageOption option; + data.WriteInterfaceToken(GetDescriptor()); + data.WriteInt32(userId); + int32_t status = Remote()->SendRequest(LIST_INPUT_METHOD, data, reply,option); + if (status != ErrorCode::NO_ERROR) { + return status; + } + int code = reply.ReadException(); + if (code != 0) // code=0, means no exception. + return code; + int size = reply.ReadInt32(); + for (int i = 0; i < size; i++) { + InputMethodProperty * property = new InputMethodProperty(); + property = reply.ReadParcelable(); + inputMethodProperties->push_back(property); + } + return ErrorCode::NO_ERROR; + } + + + virtual int32_t getInputMethodProperty(int userId, const std::u16string& packageName, InputMethodProperty * inputMethodProperty) + { + MessageParcel data, reply; + MessageOption option; + data.WriteInterfaceToken(GetDescriptor()); + data.WriteInt32(userId); + data.WriteString16(packageName); + int32_t status = Remote()->SendRequest(GET_INPUT_METHOD_PROPERTY, data, reply,option); + if (status != ErrorCode::NO_ERROR) { + return status; + } + int code = reply.ReadException(); + if (code != 0) // code=0, means no exception. + return code; + inputMethodProperty = reply.ReadParcelable(); + return status; + } + + int32_t getInputMethodSetting(int userId, InputMethodSetting * inputMethodSetting) + { + MessageParcel data, reply; + MessageOption option; + data.WriteInterfaceToken(GetDescriptor()); + data.WriteInt32(userId); + int32_t status = Remote()->SendRequest(GET_INPUT_METHOD_SETTING, data, reply,option); + if (status != ErrorCode::NO_ERROR) { + return status; + } + int code = reply.ReadException(); + if (code != 0) // code=0, means no exception. + return code; + inputMethodSetting = reply.ReadParcelable(); + return status; + } + + int32_t setInputMethodSetting(int userId, const InputMethodSetting& inputMethodSetting) + { + MessageParcel data, reply; + MessageOption option; + data.WriteInterfaceToken(GetDescriptor()); + data.WriteInt32(userId); + data.WriteParcelable(&inputMethodSetting); + int32_t status = Remote()->SendRequest(SET_INPUT_METHOD_SETTING, data, reply,option); + if (status != ErrorCode::NO_ERROR) { + return status; + } + int code = reply.ReadException(); + if (code != 0) // code=0, means no exception. + return code; + return ErrorCode::NO_ERROR; + } + }; +} +} + diff --git a/services/src/platform_callback_proxy.cpp b/services/src/platform_callback_proxy.cpp new file mode 100644 index 00000000..9f056358 --- /dev/null +++ b/services/src/platform_callback_proxy.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2021 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 "iremote_proxy.h" +#include "iremote_object.h" +#include "global.h" +#include "i_platform_callback.h" + + + +/*! \class PlatformCallbackProxy + \brief The proxy of IPlatformCallback + \todo This class will be deleted on target platform +*/ +namespace OHOS { +namespace MiscServices { + class PlatformCallbackProxy : public IRemoteProxy < IPlatformCallback > { + public: + PlatformCallbackProxy(const sptr < IRemoteObject >& impl) + : IRemoteProxy < IPlatformCallback >(impl) + { + } + + ~PlatformCallbackProxy() + { + } + + void notifyEvent(int eventId, int userId, const std::vector < std::u16string >& eventContent) + { + (void)eventId; + (void)userId; + (void)eventContent; + } + }; +} +} diff --git a/services/src/platform_callback_stub.cpp b/services/src/platform_callback_stub.cpp new file mode 100644 index 00000000..a9266cd6 --- /dev/null +++ b/services/src/platform_callback_stub.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2021 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 "message_handler.h" +#include "message.h" +#include "message_parcel.h" +#include "message_option.h" +#include "global.h" +#include "platform_callback_stub.h" + +namespace OHOS { +namespace MiscServices { + using namespace MessageID; + PlatformCallbackStub::PlatformCallbackStub() { + } + + PlatformCallbackStub::~PlatformCallbackStub() { + } + + int PlatformCallbackStub::OnRemoteRequest(uint32_t code, MessageParcel & data, MessageParcel & reply, MessageOption & option) { + switch (code) { + case NOTIFY_EVENT: { + int eventId = data.ReadInt32(); + int userId = data.ReadInt32(); + std::vector < std::u16string > eventContent; + int size = data.ReadInt32(); + for (int i = 0; i < size; i++) { + eventContent.push_back(data.ReadString16()); + } + notifyEvent(eventId, userId, eventContent); + break; + } + default: { + return IRemoteStub::OnRemoteRequest(code, data, reply, option); + } + } + return NO_ERROR; + } + + void PlatformCallbackStub::notifyEvent(int eventId, int userId, const std::vector& eventContent) { + int msgId = 0; + switch (eventId) { + case CommonEvent::COMMON_EVENT_USER_STARTED: { + msgId = MSG_ID_USER_START; + break; + } + case CommonEvent::COMMON_EVENT_USER_STOPPED: { + msgId = MSG_ID_USER_STOP; + break; + } + case CommonEvent::COMMON_EVENT_USER_UNLOCKED: { + msgId = MSG_ID_USER_UNLOCK; + break; + } + case CommonEvent::COMMON_EVENT_USER_LOCKED: { + msgId = MSG_ID_USER_LOCK; + break; + } + case CommonEvent::COMMON_EVENT_SETTING_CHANGED: { + msgId = MSG_ID_SETTING_CHANGED; + break; + } + case CommonEvent::COMMON_EVENT_PACKAGE_ADDED: { + msgId = MSG_ID_PACKAGE_ADDED; + break; + } + case CommonEvent::COMMON_EVENT_PACKAGE_REMOVED: { + msgId = MSG_ID_PACKAGE_REMOVED; + break; + } + default: { + return ; + } + } + + MessageParcel* parcel = new MessageParcel(); + parcel->WriteInt32(userId); + int size = eventContent.size(); + parcel->WriteInt32(size); + for (int i = 0; i < size; i++) { + parcel->WriteString16(eventContent[i]); + } + Message* msg = new Message(msgId, parcel); + MessageHandler::Instance()->SendMessage(msg); + } +} +} diff --git a/unitest/BUILD.gn b/unitest/BUILD.gn new file mode 100644 index 00000000..6abde55d --- /dev/null +++ b/unitest/BUILD.gn @@ -0,0 +1,98 @@ +# Copyright (C) 2021 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. + +import("//build/test.gni") + +config("module_private_config") { + visibility = [ ":*" ] + + include_dirs = [ + "include", + ] +} + +module_output_path = "inputmethod_native/inputmethod_service" + +ohos_unittest("InputMethodControllerTest") { + module_out_path = module_output_path + + sources = [ + "src/test_imc.cpp"] + + configs = [ + ":module_private_config", + ] + + deps = [ + "//base/miscservices/inputmethod/frameworks/inputmethod_controller:inputmethod_client", + "//base/miscservices/inputmethod/frameworks/inputmethod_ability:inputmethod_ability", + "//base/miscservices/inputmethod/services:inputmethod_service", + "//utils/native/base:utils", + "//foundation/communication/ipc/interfaces/innerkits/ipc_core:ipc_core", + "//foundation/communication/ipc/interfaces/innerkits/ipc_single:ipc_single", + "//third_party/googletest:gtest_main", + "//utils/native/base:utils", + "//foundation/aafwk/standard/services/abilitymgr:abilityms", + "//foundation/aafwk/standard/interfaces/innerkits/ability_manager:ability_manager", + "//foundation/distributedschedule/dmsfwk/interfaces/innerkits/uri:zuri", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//foundation/ace/napi/:ace_napi", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + ] +} + +ohos_unittest("InputMethodAbilityTest") { + module_out_path = module_output_path + + sources = [ + "src/test_ima.cpp"] + + configs = [ + ":module_private_config", + ] + + deps = [ + "//base/miscservices/inputmethod/frameworks/inputmethod_controller:inputmethod_client", + "//base/miscservices/inputmethod/frameworks/inputmethod_ability:inputmethod_ability", + "//base/miscservices/inputmethod/services:inputmethod_service", + "//utils/native/base:utils", + "//foundation/communication/ipc/interfaces/innerkits/ipc_core:ipc_core", + "//foundation/communication/ipc/interfaces/innerkits/ipc_single:ipc_single", + "//third_party/googletest:gtest_main", + "//utils/native/base:utils", + "//foundation/aafwk/standard/services/abilitymgr:abilityms", + "//foundation/aafwk/standard/interfaces/innerkits/ability_manager:ability_manager", + "//foundation/distributedschedule/dmsfwk/interfaces/innerkits/uri:zuri", + "//foundation/aafwk/standard/interfaces/innerkits/want:want", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk:system_ability_fwk", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy:samgr_proxy", + "//foundation/ace/napi/:ace_napi", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + ] +} + +group("unittest") { + testonly = true + + deps = [] + + deps += [ ":InputMethodControllerTest", ":InputMethodAbilityTest" ] +} diff --git a/unitest/src/test_ima.cpp b/unitest/src/test_ima.cpp new file mode 100644 index 00000000..09c03307 --- /dev/null +++ b/unitest/src/test_ima.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2021 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 +#include +#include +#include +#include "global.h" +#include "ability_manager_interface.h" +#include "ability_connect_callback_proxy.h" +#include "system_ability_definition.h" +#include "want.h" +#include "input_method_ability_connection_stub.h" +#include "ability_connect_callback_proxy.h" +#include "sa_mgr_client.h" +#include "element_name.h" +#include "input_method_ability.h" +#include "message_handler.h" + + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::MiscServices; +using namespace OHOS::AAFwk; + +class InputMethodAbilityTest : public testing::Test +{ +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + + +void InputMethodAbilityTest::SetUpTestCase(void) +{ + IMSA_HILOGI("InputMethodAbilityTest::SetUpTestCase"); +} + +void InputMethodAbilityTest::TearDownTestCase(void) +{ + IMSA_HILOGI("InputMethodAbilityTest::TearDownTestCase"); +} + +void InputMethodAbilityTest::SetUp(void) +{ + IMSA_HILOGI("InputMethodAbilityTest::SetUp"); +} + +void InputMethodAbilityTest::TearDown(void) +{ + IMSA_HILOGI("InputMethodAbilityTest::TearDown"); +} \ No newline at end of file diff --git a/unitest/src/test_imc.cpp b/unitest/src/test_imc.cpp new file mode 100644 index 00000000..aa4a6331 --- /dev/null +++ b/unitest/src/test_imc.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2021 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 +#include +#include +#include +#include "global.h" +#include "utils.h" + +#include "input_method_controller.h" +#include "i_input_method_system_ability.h" +#include "i_input_method_agent.h" +#include "input_data_channel_stub.h" +#include "input_client_stub.h" +#include "iservice_registry.h" +#include "system_ability_definition.h" + + +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::MiscServices; + +class TextListener : public OnTextChangedListener { +public: + TextListener() {} + ~TextListener() {} + void InsertText(const std::u16string& text) { + IMSA_HILOGI("IMC TEST TextListener InsertText: %{public}s", Utils::to_utf8(text).c_str()); + } + + void DeleteBackward(int32_t length){ + IMSA_HILOGI("IMC TEST TextListener DeleteBackward length: %{public}d", length); + } + + void SetKeyboardStatus(bool status) { + IMSA_HILOGI("IMC TEST TextListener SetKeyboardStatus %{public}d", status); + } +}; +class InputMethodControllerTest : public testing::Test +{ +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void InputMethodControllerTest::SetUpTestCase(void) +{ + IMSA_HILOGI("InputMethodControllerTest::SetUpTestCase"); +} + +void InputMethodControllerTest::TearDownTestCase(void) +{ + IMSA_HILOGI("InputMethodControllerTest::TearDownTestCase"); +} + +void InputMethodControllerTest::SetUp(void) +{ + IMSA_HILOGI("InputMethodControllerTest::SetUp"); +} + +void InputMethodControllerTest::TearDown(void) +{ + IMSA_HILOGI("InputMethodControllerTest::TearDown"); +} + +/** +* @tc.name: Imc001 +* @tc.desc: Bind IMSA. +* @tc.type: FUNC +*/ +HWTEST_F(InputMethodControllerTest, Imc001, TestSize.Level0) +{ + IMSA_HILOGI("IMC TEST START"); + sptr imc = InputMethodController::GetInstance(); + ASSERT_TRUE(imc!=nullptr); + sptr textListener = new TextListener(); + + IMSA_HILOGI("IMC Attach START"); + imc->Attach(); + int waitForStatusOk =2; + sleep(waitForStatusOk); + + IMSA_HILOGI("IMC ShowTextInput START"); + imc->ShowTextInput(textListener); + sleep(10); + + IMSA_HILOGI("IMC HideTextInput START"); + imc->HideTextInput(); + sleep(waitForStatusOk); + + IMSA_HILOGI("IMC Close START"); + imc->Close(); + sleep(waitForStatusOk); + IMSA_HILOGI("IMC TEST OVER"); +} \ No newline at end of file