mirror of
https://github.com/openharmony/miscservices_inputmethod.git
synced 2026-07-16 07:44:28 -04:00
d5cd7817f0
Signed-off-by: zhouyongfei <zhouyongfei@huawei.com>
1475 lines
60 KiB
C++
1475 lines
60 KiB
C++
/*
|
|
* 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 <vector>
|
|
#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<IRemoteObject>& 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_ = inputMethodAbility;
|
|
}
|
|
|
|
/*! Work thread for this user
|
|
*/
|
|
void PerUserSession::WorkThread()
|
|
{
|
|
if (msgHandler == nullptr) {
|
|
return ;
|
|
}
|
|
while(1) {
|
|
Message *msg = msgHandler->GetMessage();
|
|
std::unique_lock<std::mutex> lock(mtx);
|
|
switch (msg->msgId_) {
|
|
case MSG_ID_USER_LOCK:
|
|
case MSG_ID_EXIT_SERVICE: {
|
|
OnUserLocked();
|
|
delete msg;
|
|
msg = nullptr;
|
|
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<IRemoteObject> who = msg->msgContent_->ReadRemoteObject();
|
|
OnClientDied(who);
|
|
break;
|
|
}
|
|
case MSG_ID_IMS_DIED: {
|
|
wptr<IRemoteObject> 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;
|
|
msg = nullptr;
|
|
}
|
|
}
|
|
|
|
/*! 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<std::mutex> 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<sptr<IRemoteObject>, 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<std::mutex> lock(mtx);
|
|
for (int i = 0; i < MAX_IME; i++)
|
|
{
|
|
if (currentIme[i] && currentIme[i]->mPackageName == 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<IInputClient>& inputClient,
|
|
const sptr<IInputDataChannel>& 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<IRemoteObject> 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<sptr<IRemoteObject>, ClientInfo*>(obj, clientInfo));
|
|
int ret = obj->AddDeathRecipient(clientDeathRecipient);
|
|
if (ret != ErrorCode::NO_ERROR) {
|
|
IMSA_HILOGE("PerUserSession::AddClient AddDeathRecipient return : %{public}s", ErrorCode::ToString(ret));
|
|
}
|
|
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<IInputClient>& inputClient, int remainClientNum)
|
|
{
|
|
IMSA_HILOGE("PerUserSession::RemoveClient");
|
|
sptr<IRemoteObject> b = inputClient->AsObject();
|
|
std::map<sptr<IRemoteObject>, ClientInfo*>::iterator it = mapClients.find(b);
|
|
if (it == mapClients.end()) {
|
|
IMSA_HILOGE("PerUserSession::RemoveClient ErrorCode::ERROR_CLIENT_NOT_FOUND");
|
|
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 fail %{public}s", ErrorCode::ToString(ret));
|
|
}
|
|
ret = clientInfo->client->onInputReleased(0);
|
|
if (ret != ErrorCode::NO_ERROR) {
|
|
IMSA_HILOGE("PerUserSession::RemoveClient onInputReleased fail %{public}s", ErrorCode::ToString(ret));
|
|
}
|
|
delete clientInfo;
|
|
clientInfo = nullptr;
|
|
mapClients.erase(it);
|
|
|
|
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<IRemoteObject> 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 fail %{public}s", ErrorCode::ToString(ret_init));
|
|
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", ErrorCode::ToString(ErrorCode::ERROR_BAD_PARAMETERS));
|
|
return ErrorCode::ERROR_BAD_PARAMETERS;
|
|
}
|
|
if (imsCore[index] == nullptr || currentIme[index] == nullptr) {
|
|
IMSA_HILOGE("Aborted! %{public}s", ErrorCode::ToString(ErrorCode::ERROR_IME_NOT_STARTED));
|
|
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<IRemoteObject> 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<IInputClient>& 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", ErrorCode::ToString(ret));
|
|
}
|
|
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<IInputClient>& inputClient)
|
|
{
|
|
IMSA_HILOGI("PerUserSession::HideKeyboard");
|
|
int index = GetImeIndex(inputClient);
|
|
if (index == -1) {
|
|
IMSA_HILOGE("PerUserSession::HideKeyboard Aborted! ErrorCode::ERROR_CLIENT_NOT_FOUND");
|
|
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! ErrorCode::ERROR_KBD_IS_NOT_SHOWING");
|
|
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_client_stop = clientInfo->client->onInputReady(1, nullptr, nullptr);
|
|
if (ret_client_stop != ErrorCode::NO_ERROR) {
|
|
IMSA_HILOGE("PerUserSession::HideKeyboard onInputReady return : %{public}s", ErrorCode::ToString(ret_client_stop));
|
|
}
|
|
currentClient = nullptr;
|
|
imsAgent = nullptr;
|
|
imsCore[index] = 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 (imsCore[lastImeIndex] != nullptr) {
|
|
int ret = imsCore[lastImeIndex]->getKeyboardWindowHeight(retHeight);
|
|
if (ret != ErrorCode::NO_ERROR) {
|
|
IMSA_HILOGE("getKeyboardWindowHeight return : %{public}s", ErrorCode::ToString(ret));
|
|
}
|
|
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<int> 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<IRemoteObject>& who)
|
|
{
|
|
IMSA_HILOGI("PerUserSession::OnClientDied Start...[%{public}d]\n", userId_);
|
|
bool flag = false;
|
|
std::map<sptr<IRemoteObject>, 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<IInputClient> client = it->second->client;
|
|
int remainClientNum = 0;
|
|
if (currentClient != nullptr) {
|
|
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<IRemoteObject>& 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 < MAX_IME; i++)
|
|
{
|
|
if (imsCore[i] == nullptr)
|
|
{
|
|
continue;
|
|
}
|
|
sptr<IRemoteObject> 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<std::mutex> lock(mtx);
|
|
if (inputMethodSetting == nullptr) {
|
|
return ErrorCode::ERROR_NULL_POINTER;
|
|
}
|
|
std::u16string currentValue = inputMethodSetting->GetValue(key);
|
|
|
|
IMSA_HILOGD("PerUserSession::OnSettingChanged key = %{public}s", Utils::to_utf8(key).c_str());
|
|
IMSA_HILOGD("PerUserSession::OnSettingChanged value = %{public}s", Utils::to_utf8(value).c_str());
|
|
IMSA_HILOGD("PerUserSession::OnSettingChanged currentValue = %{public}s", 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<int> 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<int> 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<sptr<IRemoteObject>, ClientInfo*>::iterator it;
|
|
for (it = mapClients.begin(); it != mapClients.end();)
|
|
{
|
|
sptr<IRemoteObject> 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", ErrorCode::ToString(ret));
|
|
}
|
|
delete clientInfo;
|
|
clientInfo = nullptr;
|
|
}
|
|
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
|
|
* The information includes:
|
|
* the information of all the input clients connected to the input method management system.
|
|
* current input method engine information
|
|
* security input method engine information
|
|
* current session information
|
|
* param fd the raw file descriptor that the dump is being sent to
|
|
*/
|
|
void PerUserSession::Dump(int fd)
|
|
{
|
|
std::map<sptr<IRemoteObject>, 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<IRemoteObject> 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<IRemoteObject> b = Platform::RemoteBrokerToObject(currentClient);
|
|
std::map<sptr<IRemoteObject>, ClientInfo*>::iterator it = mapClients.find(b);
|
|
int index = GetImeIndex(currentClient);
|
|
if (index < 0 || index > MAX_IME)
|
|
{
|
|
dprintf(fd, "\n * PerUserSession::DumpCurrentSession: invalid index\n");
|
|
}
|
|
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<IRemoteObject> 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<int> 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<int> 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 is not found in the current IME. Reset it!");
|
|
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<IInputClient>& 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<IInputClient>& inputClient)
|
|
{
|
|
if (inputClient == nullptr) {
|
|
IMSA_HILOGE("PerUserSession::GetClientInfo inputClient is nullptr");
|
|
return nullptr;
|
|
}
|
|
sptr<IRemoteObject> b = Platform::RemoteBrokerToObject(inputClient);
|
|
std::map<sptr<IRemoteObject>, 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<InputMethodAbilityConnectionStub> stub(new (std::nothrow) InputMethodAbilityConnectionStub(0));
|
|
sptr<AAFwk::AbilityConnectionProxy> connCallback = new (std::nothrow) AAFwk::AbilityConnectionProxy(stub);
|
|
GetAbilityManagerService()->StartAbility(want);
|
|
}
|
|
|
|
sptr<AAFwk::IAbilityManager> PerUserSession::GetAbilityManagerService()
|
|
{
|
|
IMSA_HILOGE("GetAbilityManagerService start");
|
|
sptr<IRemoteObject> abilityMsObj =
|
|
OHOS::DelayedSingleton<AAFwk::SaMgrClient>::GetInstance()->GetSystemAbility(ABILITY_MGR_SERVICE_ID);
|
|
if (abilityMsObj == nullptr) {
|
|
IMSA_HILOGE("failed to get ability manager service");
|
|
return nullptr;
|
|
}
|
|
return iface_cast<AAFwk::IAbilityManager>(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<IRemoteObject> clientObject = data->ReadRemoteObject();
|
|
if (clientObject == nullptr) {
|
|
IMSA_HILOGI("PerUserSession::OnPrepareInput clientObject is null");
|
|
}
|
|
sptr<InputClientProxy> client = new InputClientProxy(clientObject);
|
|
sptr<IRemoteObject> channelObject = data->ReadRemoteObject();
|
|
if (channelObject == nullptr) {
|
|
IMSA_HILOGI("PerUserSession::OnPrepareInput channelObject is null");
|
|
}
|
|
sptr<InputDataChannelProxy> channel = new InputDataChannelProxy(channelObject);
|
|
InputAttribute *attribute = data->ReadParcelable<InputAttribute>();
|
|
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", ErrorCode::ToString(ret));
|
|
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<IRemoteObject> clientObject = data->ReadRemoteObject();
|
|
sptr<InputClientProxy> client = new InputClientProxy(clientObject);
|
|
sptr<IInputClient> 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<IRemoteObject> clientObject = data->ReadRemoteObject();
|
|
sptr<InputClientProxy> client = new InputClientProxy(clientObject);
|
|
int ret = ShowKeyboard(client);
|
|
if (ret != ErrorCode::NO_ERROR) {
|
|
IMSA_HILOGE("PerUserSession::OnStartInput Aborted! %{public}s", ErrorCode::ToString(ret));
|
|
} 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<IRemoteObject> coreObject = data->ReadRemoteObject();
|
|
sptr<InputMethodCoreProxy> 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! ErrorCode::ERROR_BAD_PARAMETERS");
|
|
return;
|
|
}
|
|
if (imsCore[index] != nullptr) {
|
|
IMSA_HILOGI("PerUserSession::onSetInputMethodCore End... Input Method Service has already been started ! ");
|
|
return;
|
|
}
|
|
imsCore[index] = core;
|
|
int ret = StartInputMethod(index);
|
|
if (ret != ErrorCode::NO_ERROR) {
|
|
IMSA_HILOGE("PerUserSession::onSetInputMethodCore Aborted! %{public}s", ErrorCode::ToString(ret));
|
|
} 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<IRemoteObject> clientObject = data->ReadRemoteObject();
|
|
sptr<InputClientProxy> client = new InputClientProxy(clientObject);
|
|
int ret = HideKeyboard(client);
|
|
if (ret != ErrorCode::NO_ERROR) {
|
|
IMSA_HILOGE("PerUserSession::OnStopInput Aborted! %{public}s", ErrorCode::ToString(ret));
|
|
} else {
|
|
IMSA_HILOGI("PerUserSession::OnStopInput End...[%{public}d]\n", userId_);
|
|
}
|
|
}
|
|
}
|
|
}
|