* Copyright (c) 2022 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 "js_inputmethod_extension_context.h"
#include <cstdint>
#include "global.h"
#include "js_data_struct_converter.h"
#include "js_error_utils.h"
#include "js_extension_context.h"
#include "js_runtime.h"
#include "js_runtime_utils.h"
#include "js_util.h"
#include "js_utils.h"
#include "napi/native_api.h"
#include "napi_common_start_options.h"
#include "napi_common_util.h"
#include "napi_common_want.h"
#include "napi_remote_object.h"
#include "start_options.h"
namespace OHOS {
namespace AbilityRuntime {
using namespace OHOS::MiscServices;
namespace {
constexpr int32_t INDEX_ZERO = 0;
constexpr int32_t INDEX_ONE = 1;
constexpr int32_t INDEX_TWO = 2;
constexpr int32_t ERROR_CODE_ONE = 1;
constexpr int32_t ERROR_CODE_TWO = 2;
constexpr size_t ARGC_ZERO = 0;
constexpr size_t ARGC_ONE = 1;
constexpr size_t ARGC_TWO = 2;
constexpr size_t ARGC_THREE = 3;
constexpr size_t ARGC_FOUR = 4;
class JsInputMethodExtensionContext final {
public:
explicit JsInputMethodExtensionContext(const std::shared_ptr<InputMethodExtensionContext> &context)
: context_(context)
{
}
~JsInputMethodExtensionContext() = default;
JsInputMethodExtensionContext() = default;
static void Finalizer(napi_env env, void *data, void *hint)
{
IMSA_HILOGI("JsInputMethodExtensionContext::Finalizer is called.");
std::unique_ptr<JsInputMethodExtensionContext>(static_cast<JsInputMethodExtensionContext *>(data));
}
static napi_value StartAbility(napi_env env, napi_callback_info info)
{
GET_CB_INFO_AND_CALL(env, info, JsInputMethodExtensionContext, OnStartAbility);
}
static napi_value StartAbilityWithAccount(napi_env env, napi_callback_info info)
{
GET_CB_INFO_AND_CALL(env, info, JsInputMethodExtensionContext, OnStartAbilityWithAccount);
}
static napi_value ConnectAbilityWithAccount(napi_env env, napi_callback_info info)
{
GET_CB_INFO_AND_CALL(env, info, JsInputMethodExtensionContext, OnConnectAbilityWithAccount);
}
static napi_value TerminateAbility(napi_env env, napi_callback_info info)
{
GET_CB_INFO_AND_CALL(env, info, JsInputMethodExtensionContext, OnTerminateAbility);
}
static napi_value ConnectAbility(napi_env env, napi_callback_info info)
{
GET_CB_INFO_AND_CALL(env, info, JsInputMethodExtensionContext, OnConnectAbility);
}
static napi_value DisconnectAbility(napi_env env, napi_callback_info info)
{
GET_CB_INFO_AND_CALL(env, info, JsInputMethodExtensionContext, OnDisconnectAbility);
}
private:
std::weak_ptr<InputMethodExtensionContext> context_;
napi_value OnStartAbility(napi_env env, size_t argc, napi_value *argv)
{
IMSA_HILOGI("InputMethodExtensionContext OnStartAbility.");
PARAM_CHECK_RETURN(env, argc == ARGC_ONE || argc == ARGC_TWO || argc == ARGC_THREE,
"number of param should in [1,3]", TYPE_NONE, CreateJsUndefined(env));
PARAM_CHECK_RETURN(env, JsUtil::GetType(env, argv[0]) == napi_object, "param want type must be Want", TYPE_NONE,
JsUtil::Const::Null(env));
decltype(argc) unwrapArgc = 0;
AAFwk::Want want;
OHOS::AppExecFwk::UnwrapWant(env, argv[INDEX_ZERO], want);
IMSA_HILOGI("bundleName:%{public}s abilityName:%{public}s", want.GetBundle().c_str(),
want.GetElement().GetAbilityName().c_str());
unwrapArgc++;
AAFwk::StartOptions startOptions;
if (argc > ARGC_ONE) {
napi_valuetype valueType = napi_undefined;
napi_typeof(env, argv[INDEX_ONE], &valueType);
if (valueType == napi_object) {
IMSA_HILOGI("OnStartAbility start options is used.");
AppExecFwk::UnwrapStartOptions(env, argv[INDEX_ONE], startOptions);
unwrapArgc++;
}
}
napi_value lastParam = argc > unwrapArgc ? argv[unwrapArgc] : nullptr;
napi_value result = nullptr;
std::unique_ptr<NapiAsyncTask> napiAsyncTask = CreateEmptyAsyncTask(env, lastParam, &result);
auto asyncTask = [weak = context_, want, startOptions, unwrapArgc, env, task = napiAsyncTask.get()]() {
IMSA_HILOGI("startAbility start.");
auto context = weak.lock();
if (context == nullptr) {
IMSA_HILOGW("context is released.");
task->Reject(env, CreateJsError(env, ERROR_CODE_ONE, "Context is released"));
delete task;
return;
}
ErrCode errcode = ERR_OK;
(unwrapArgc == 1) ? errcode = context->StartAbility(want)
: errcode = context->StartAbility(want, startOptions);
if (errcode == 0) {
task->Resolve(env, CreateJsUndefined(env));
} else {
task->Reject(env, CreateJsErrorByNativeErr(env, errcode));
}
delete task;
};
if (napi_send_event(env, asyncTask, napi_eprio_high, "ime_OnStartAbility") != napi_status::napi_ok) {
napiAsyncTask->Reject(env, CreateJsError(env, ERROR_CODE_ONE, "send event failed"));
} else {
napiAsyncTask.release();
}
return result;
}
napi_value OnStartAbilityWithAccount(napi_env env, size_t argc, napi_value *argv)
{
CHECK_RETURN(argc == ARGC_TWO || argc == ARGC_THREE || argc == ARGC_FOUR,
"not enough params!", CreateJsUndefined(env));
decltype(argc) unwrapArgc = 0;
AAFwk::Want want;
OHOS::AppExecFwk::UnwrapWant(env, argv[INDEX_ZERO], want);
unwrapArgc++;
int32_t accountId = 0;
if (!OHOS::AppExecFwk::UnwrapInt32FromJS2(env, argv[INDEX_ONE], accountId)) {
IMSA_HILOGI("%{public}s called, the second parameter is invalid.", __func__);
return CreateJsUndefined(env);
}
IMSA_HILOGI("bundleName: %{public}s abilityName: %{public}s, accountId: %{public}d", want.GetBundle().c_str(),
want.GetElement().GetAbilityName().c_str(), accountId);
unwrapArgc++;
AAFwk::StartOptions startOptions;
napi_valuetype valueType = napi_undefined;
napi_typeof(env, argv[INDEX_ONE], &valueType);
if (argc > ARGC_TWO && valueType == napi_object) {
AppExecFwk::UnwrapStartOptions(env, argv[INDEX_TWO], startOptions);
unwrapArgc++;
}
napi_value lastParam = argc == unwrapArgc ? nullptr : argv[unwrapArgc];
napi_value result = nullptr;
std::unique_ptr<NapiAsyncTask> napiAsyncTask = CreateEmptyAsyncTask(env, lastParam, &result);
auto asyncTask = [weak = context_, want, accountId, startOptions, unwrapArgc, env,
task = napiAsyncTask.get()]() {
IMSA_HILOGI("startAbility start");
auto context = weak.lock();
if (context == nullptr) {
task->Reject(env, CreateJsError(env, ERROR_CODE_ONE, "Context is released"));
delete task;
return;
}
ErrCode errcode = (unwrapArgc == ARGC_TWO)
? context->StartAbilityWithAccount(want, accountId)
: context->StartAbilityWithAccount(want, accountId, startOptions);
if (errcode == 0) {
task->Resolve(env, CreateJsUndefined(env));
}
task->Reject(env, CreateJsError(env, errcode, "Start Ability failed."));
delete task;
};
if (napi_send_event(env, asyncTask, napi_eprio_high, "ime_OnStartAbilityWithAccount") != napi_status::napi_ok) {
napiAsyncTask->Reject(env, CreateJsError(env, ERROR_CODE_ONE, "send event failed"));
} else {
napiAsyncTask.release();
}
return result;
}
napi_value OnTerminateAbility(napi_env env, size_t argc, napi_value *argv)
{
IMSA_HILOGI("OnTerminateAbility is called.");
if (argc != ARGC_ZERO && argc != ARGC_ONE) {
IMSA_HILOGE("not enough params!");
return CreateJsUndefined(env);
}
napi_value lastParam = argc == ARGC_ZERO ? nullptr : argv[INDEX_ZERO];
napi_value result = nullptr;
std::unique_ptr<NapiAsyncTask> napiAsyncTask = CreateEmptyAsyncTask(env, lastParam, &result);
auto asyncTask = [weak = context_, env, task = napiAsyncTask.get()]() {
IMSA_HILOGI("TerminateAbility start.");
auto context = weak.lock();
if (context == nullptr) {
IMSA_HILOGW("context is released.");
task->Reject(env, CreateJsError(env, ERROR_CODE_ONE, "Context is released"));
delete task;
return;
}
auto errcode = context->TerminateAbility();
if (errcode == 0) {
task->Resolve(env, CreateJsUndefined(env));
} else {
task->Reject(env, CreateJsError(env, errcode, "Terminate Ability failed."));
}
delete task;
};
if (napi_send_event(env, asyncTask, napi_eprio_high, "ime_OnTerminateAbility") != napi_status::napi_ok) {
napiAsyncTask->Reject(env, CreateJsError(env, ERROR_CODE_ONE, "send event failed"));
} else {
napiAsyncTask.release();
}
return result;
}
napi_value OnConnectAbility(napi_env env, size_t argc, napi_value *argv)
{
IMSA_HILOGI("OnConnectAbility start.");
CHECK_RETURN(argc == ARGC_TWO, "not enough params!", CreateJsUndefined(env));
AAFwk::Want want;
OHOS::AppExecFwk::UnwrapWant(env, argv[INDEX_ZERO], want);
IMSA_HILOGI("%{public}s bundleName: %{public}s abilityName: %{public}s", __func__, want.GetBundle().c_str(),
want.GetElement().GetAbilityName().c_str());
sptr<JSInputMethodExtensionConnection> connection = new (std::nothrow) JSInputMethodExtensionConnection(env);
CHECK_RETURN(connection != nullptr, "connection is nullptr", CreateJsUndefined(env));
connection->SetJsConnectionObject(argv[1]);
int64_t connectId = serialNumber_;
ConnectionKey key = { want, serialNumber_ };
{
std::lock_guard<std::mutex> lock(g_connectMapMtx);
connects_.emplace(key, connection);
}
if (serialNumber_ < INT64_MAX) {
serialNumber_++;
} else {
serialNumber_ = 0;
}
napi_value result = nullptr;
napi_value lastParam = nullptr;
napi_value connectResult = nullptr;
std::unique_ptr<NapiAsyncTask> napiAsyncTask = CreateEmptyAsyncTask(env, lastParam, &result);
auto asyncTask = [weak = context_, want, connection, connectId, env, task = napiAsyncTask.get()]() {
IMSA_HILOGI("OnConnectAbility start.");
auto context = weak.lock();
if (context == nullptr) {
IMSA_HILOGW("context is released.");
task->Reject(env, CreateJsError(env, ERROR_CODE_ONE, "Context is released"));
delete task;
return;
}
IMSA_HILOGI("context->ConnectAbility connection: %{public}d.", static_cast<int32_t>(connectId));
if (!context->ConnectAbility(want, connection)) {
connection->CallJsFailed(ERROR_CODE_ONE);
}
task->Resolve(env, CreateJsUndefined(env));
delete task;
};
if (napi_send_event(env, asyncTask, napi_eprio_high, "ime_OnConnectAbility") != napi_status::napi_ok) {
napiAsyncTask->Reject(env, CreateJsError(env, ERROR_CODE_ONE, "send event failed"));
} else {
napiAsyncTask.release();
}
napi_create_int64(env, connectId, &connectResult);
return connectResult;
}
void CheckSerialNumber(int64_t &serialNumber)
{
if (serialNumber < INT64_MAX) {
serialNumber++;
} else {
serialNumber = 0;
}
}
napi_value OnConnectAbilityWithAccount(napi_env env, size_t argc, napi_value *argv)
{
CHECK_RETURN(argc == ARGC_THREE, "not enough params!", CreateJsUndefined(env));
AAFwk::Want want;
OHOS::AppExecFwk::UnwrapWant(env, argv[INDEX_ZERO], want);
IMSA_HILOGI("%{public}s bundleName: %{public}s, abilityName: %{public}s", __func__, want.GetBundle().c_str(),
want.GetElement().GetAbilityName().c_str());
int32_t accountId = 0;
if (!OHOS::AppExecFwk::UnwrapInt32FromJS2(env, argv[INDEX_ONE], accountId)) {
IMSA_HILOGI("%{public}s called, the second parameter is invalid.", __func__);
return CreateJsUndefined(env);
}
sptr<JSInputMethodExtensionConnection> connection = new (std::nothrow) JSInputMethodExtensionConnection(env);
CHECK_RETURN(connection != nullptr, "connection is nullptr", CreateJsUndefined(env));
connection->SetJsConnectionObject(argv[1]);
int64_t connectId = serialNumber_;
ConnectionKey key = { want, serialNumber_ };
{
std::lock_guard<std::mutex> lock(g_connectMapMtx);
connects_.emplace(key, connection);
}
CheckSerialNumber(serialNumber_);
napi_value result = nullptr;
napi_value lastParam = nullptr;
napi_value connectResult = nullptr;
std::unique_ptr<NapiAsyncTask> napiAsyncTask = CreateEmptyAsyncTask(env, lastParam, &result);
auto asyncTask = [weak = context_, want, accountId, connection, connectId, env, task = napiAsyncTask.get()]() {
auto context = weak.lock();
if (context == nullptr) {
IMSA_HILOGW("context is released.");
task->Reject(env, CreateJsError(env, ERROR_CODE_ONE, "Context is released"));
delete task;
return;
}
IMSA_HILOGI("context->ConnectAbilityWithAccount connection:%{public}d.", static_cast<int32_t>(connectId));
if (!context->ConnectAbilityWithAccount(want, accountId, connection)) {
connection->CallJsFailed(ERROR_CODE_ONE);
}
task->Resolve(env, CreateJsUndefined(env));
delete task;
};
if (napi_send_event(env, asyncTask, napi_eprio_high, "ime_ConnectAbilityWithAccount") != napi_status::napi_ok) {
napiAsyncTask->Reject(env, CreateJsError(env, ERROR_CODE_ONE, "send event failed"));
} else {
napiAsyncTask.release();
}
napi_create_int64(env, connectId, &connectResult);
return connectResult;
}
napi_value OnDisconnectAbility(napi_env env, size_t argc, napi_value *argv)
{
IMSA_HILOGI("OnDisconnectAbility is called.");
CHECK_RETURN(argc == ARGC_ONE || argc == ARGC_TWO, "not enough params!", CreateJsUndefined(env));
AAFwk::Want want;
int64_t connectId = -1;
sptr<JSInputMethodExtensionConnection> connection = nullptr;
napi_get_value_int64(env, argv[INDEX_ZERO], &connectId);
IMSA_HILOGI("OnDisconnectAbility connection: %{public}d.", static_cast<int32_t>(connectId));
{
std::lock_guard<std::mutex> lock(g_connectMapMtx);
auto item = std::find_if(connects_.begin(), connects_.end(),
[&connectId](const std::map<ConnectionKey, sptr<JSInputMethodExtensionConnection>>::value_type &obj) {
return connectId == obj.first.id;
});
if (item != connects_.end()) {
want = item->first.want;
connection = item->second;
}
}
napi_value lastParam = argc == ARGC_ONE ? nullptr : argv[INDEX_ONE];
napi_value result = nullptr;
std::unique_ptr<NapiAsyncTask> napiAsyncTask = CreateEmptyAsyncTask(env, lastParam, &result);
auto asyncTask = [weak = context_, want, connection, env, task = napiAsyncTask.get()]() {
IMSA_HILOGI("OnDisconnectAbility start.");
auto context = weak.lock();
if (context == nullptr) {
IMSA_HILOGW("context is released.");
task->Reject(env, CreateJsError(env, ERROR_CODE_ONE, "Context is released"));
delete task;
return;
}
if (connection == nullptr) {
IMSA_HILOGW("connection is nullptr.");
task->Reject(env, CreateJsError(env, ERROR_CODE_TWO, "not found connection"));
delete task;
return;
}
IMSA_HILOGI("context->DisconnectAbility.");
auto errcode = context->DisconnectAbility(want, connection);
errcode == 0 ? task->Resolve(env, CreateJsUndefined(env))
: task->Reject(env, CreateJsError(env, errcode, "Disconnect Ability failed."));
delete task;
};
if (napi_send_event(env, asyncTask, napi_eprio_high, "ime_OnDisconnectAbility") != napi_status::napi_ok) {
napiAsyncTask->Reject(env, CreateJsError(env, ERROR_CODE_ONE, "send event failed"));
} else {
napiAsyncTask.release();
}
return result;
}
};
}
napi_value CreateJsMetadata(napi_env env, const AppExecFwk::Metadata &info)
{
IMSA_HILOGI("CreateJsMetadata start.");
napi_value objValue = nullptr;
napi_create_object(env, &objValue);
napi_set_named_property(env, objValue, "name", CreateJsValue(env, info.name));
napi_set_named_property(env, objValue, "value", CreateJsValue(env, info.value));
napi_set_named_property(env, objValue, "resource", CreateJsValue(env, info.resource));
return objValue;
}
napi_value CreateJsMetadataArray(napi_env env, const std::vector<AppExecFwk::Metadata> &info)
{
IMSA_HILOGI("CreateJsMetadataArray start.");
napi_value arrayValue = nullptr;
napi_create_array_with_length(env, info.size(), &arrayValue);
uint32_t index = 0;
for (const auto &item : info) {
napi_set_element(env, arrayValue, index++, CreateJsMetadata(env, item));
}
return arrayValue;
}
napi_value CreateJsExtensionAbilityInfo(napi_env env, const AppExecFwk::ExtensionAbilityInfo &info)
{
IMSA_HILOGI("CreateJsExtensionAbilityInfo start.");
napi_value objValue = nullptr;
napi_create_object(env, &objValue);
napi_set_named_property(env, objValue, "bundleName", CreateJsValue(env, info.bundleName));
napi_set_named_property(env, objValue, "moduleName", CreateJsValue(env, info.moduleName));
napi_set_named_property(env, objValue, "name", CreateJsValue(env, info.name));
napi_set_named_property(env, objValue, "labelId", CreateJsValue(env, info.labelId));
napi_set_named_property(env, objValue, "descriptionId", CreateJsValue(env, info.descriptionId));
napi_set_named_property(env, objValue, "iconId", CreateJsValue(env, info.iconId));
napi_set_named_property(env, objValue, "isVisible", CreateJsValue(env, info.visible));
napi_set_named_property(env, objValue, "extensionAbilityType", CreateJsValue(env, info.type));
napi_value permissionArray = nullptr;
napi_create_array_with_length(env, info.permissions.size(), &permissionArray);
if (permissionArray != nullptr) {
int index = 0;
for (auto permission : info.permissions) {
napi_set_element(env, permissionArray, index++, CreateJsValue(env, permission));
}
}
napi_set_named_property(env, objValue, "permissions", permissionArray);
napi_set_named_property(env, objValue, "applicationInfo", CreateJsApplicationInfo(env, info.applicationInfo));
napi_set_named_property(env, objValue, "metadata", CreateJsMetadataArray(env, info.metadata));
napi_set_named_property(env, objValue, "enabled", CreateJsValue(env, info.enabled));
napi_set_named_property(env, objValue, "readPermission", CreateJsValue(env, info.readPermission));
napi_set_named_property(env, objValue, "writePermission", CreateJsValue(env, info.writePermission));
return objValue;
}
napi_value CreateJsInputMethodExtensionContext(napi_env env, std::shared_ptr<InputMethodExtensionContext> context)
{
IMSA_HILOGI("CreateJsInputMethodExtensionContext start.");
if (context != nullptr) {
auto abilityInfo = context->GetAbilityInfo();
}
napi_value objValue = CreateJsExtensionContext(env, context);
std::unique_ptr<JsInputMethodExtensionContext> jsContext = std::make_unique<JsInputMethodExtensionContext>(context);
napi_wrap(env, objValue, jsContext.release(), JsInputMethodExtensionContext::Finalizer, nullptr, nullptr);
const char *moduleName = "JsInputMethodExtensionContext";
BindNativeFunction(env, objValue, "startAbility", moduleName, JsInputMethodExtensionContext::StartAbility);
BindNativeFunction(env, objValue, "terminateSelf", moduleName, JsInputMethodExtensionContext::TerminateAbility);
BindNativeFunction(env, objValue, "destroy", moduleName, JsInputMethodExtensionContext::TerminateAbility);
BindNativeFunction(env, objValue, "connectAbility", moduleName, JsInputMethodExtensionContext::ConnectAbility);
BindNativeFunction(env, objValue, "disconnectAbility", moduleName,
JsInputMethodExtensionContext::DisconnectAbility);
BindNativeFunction(env, objValue, "startAbilityWithAccount", moduleName,
JsInputMethodExtensionContext::StartAbilityWithAccount);
BindNativeFunction(env, objValue, "connectAbilityWithAccount", moduleName,
JsInputMethodExtensionContext::ConnectAbilityWithAccount);
return objValue;
}
JSInputMethodExtensionConnection::JSInputMethodExtensionConnection(napi_env env) : env_(env),
handler_(std::make_shared<AppExecFwk::EventHandler>(AppExecFwk::EventRunner::GetMainEventRunner()))
{
}
JSInputMethodExtensionConnection::~JSInputMethodExtensionConnection() = default;
void JSInputMethodExtensionConnection::OnAbilityConnectDone(const AppExecFwk::ElementName &element,
const sptr<IRemoteObject> &remoteObject, int resultCode)
{
IMSA_HILOGI("OnAbilityConnectDone start, resultCode: %{public}d.", resultCode);
if (handler_ == nullptr) {
IMSA_HILOGI("handler_ is nullptr.");
return;
}
wptr<JSInputMethodExtensionConnection> connection = this;
auto task = [connection, element, remoteObject, resultCode]() {
sptr<JSInputMethodExtensionConnection> connectionSptr = connection.promote();
if (connectionSptr == nullptr) {
IMSA_HILOGE("connectionSptr is nullptr.");
return;
}
connectionSptr->HandleOnAbilityConnectDone(element, remoteObject, resultCode);
};
handler_->PostTask(task, "OnAbilityConnectDone", 0, AppExecFwk::EventQueue::Priority::VIP);
}
void JSInputMethodExtensionConnection::HandleOnAbilityConnectDone(const AppExecFwk::ElementName &element,
const sptr<IRemoteObject> &remoteObject, int resultCode)
{
IMSA_HILOGI("HandleOnAbilityConnectDone start, resultCode:%{public}d.", resultCode);
JsUtil::ScopeGuard scopeGuard(env_);
napi_value napiElementName = OHOS::AppExecFwk::WrapElementName(env_, element);
IMSA_HILOGI("OnAbilityConnectDone start NAPI_ohos_rpc_CreateJsRemoteObject.");
napi_value napiRemoteObject = NAPI_ohos_rpc_CreateJsRemoteObject(env_, remoteObject);
napi_value argv[] = { napiElementName, napiRemoteObject };
if (jsConnectionObject_ == nullptr) {
IMSA_HILOGE("jsConnectionObject_ is nullptr!");
return;
}
napi_value obj = nullptr;
if (napi_get_reference_value(env_, jsConnectionObject_, &obj) != napi_ok) {
IMSA_HILOGE("failed to get jsConnectionObject_!");
return;
}
if (obj == nullptr) {
IMSA_HILOGE("failed to get object!");
return;
}
napi_value methodOnConnect = nullptr;
napi_get_named_property(env_, obj, "onConnect", &methodOnConnect);
if (methodOnConnect == nullptr) {
IMSA_HILOGE("failed to get onConnect from object!");
return;
}
IMSA_HILOGI("JSInputMethodExtensionConnection::CallFunction onConnect, success.");
napi_value callResult = nullptr;
napi_call_function(env_, obj, methodOnConnect, ARGC_TWO, argv, &callResult);
IMSA_HILOGI("OnAbilityConnectDone end.");
}
void JSInputMethodExtensionConnection::OnAbilityDisconnectDone(const AppExecFwk::ElementName &element, int resultCode)
{
IMSA_HILOGI("OnAbilityDisconnectDone start, resultCode: %{public}d.", resultCode);
if (handler_ == nullptr) {
IMSA_HILOGI("handler_ is nullptr.");
return;
}
wptr<JSInputMethodExtensionConnection> connection = this;
auto task = [connection, element, resultCode]() {
sptr<JSInputMethodExtensionConnection> connectionSptr = connection.promote();
if (!connectionSptr) {
IMSA_HILOGE("connectionSptr is nullptr.");
return;
}
connectionSptr->HandleOnAbilityDisconnectDone(element, resultCode);
};
handler_->PostTask(task, "OnAbilityDisconnectDone", 0, AppExecFwk::EventQueue::Priority::VIP);
}
void JSInputMethodExtensionConnection::HandleOnAbilityDisconnectDone(const AppExecFwk::ElementName &element,
int resultCode)
{
IMSA_HILOGI("HandleOnAbilityDisconnectDone start, resultCode:%{public}d.", resultCode);
JsUtil::ScopeGuard scopeGuard(env_);
napi_value napiElementName = OHOS::AppExecFwk::WrapElementName(env_, element);
napi_value argv[] = { napiElementName };
if (jsConnectionObject_ == nullptr) {
IMSA_HILOGE("jsConnectionObject_ is nullptr!");
return;
}
napi_value obj = nullptr;
if (napi_get_reference_value(env_, jsConnectionObject_, &obj) != napi_ok) {
IMSA_HILOGE("failed to get jsConnectionObject_!");
return;
}
if (obj == nullptr) {
IMSA_HILOGE("failed to get object!");
return;
}
napi_value method = nullptr;
napi_get_named_property(env_, obj, "onDisconnect", &method);
if (method == nullptr) {
IMSA_HILOGE("failed to get onDisconnect from object!");
return;
}
HandleOnAbilityDisconnect(element);
IMSA_HILOGI("OnAbilityDisconnectDone CallFunction success.");
napi_value callResult = nullptr;
napi_call_function(env_, obj, method, ARGC_ONE, argv, &callResult);
}
void JSInputMethodExtensionConnection::HandleOnAbilityDisconnect(const AppExecFwk::ElementName &element)
{
std::string bundleName = element.GetBundleName();
std::string abilityName = element.GetAbilityName();
{
std::lock_guard<std::mutex> lock(g_connectMapMtx);
IMSA_HILOGI("OnAbilityDisconnectDone connects_.size: %{public}zu.", connects_.size());
auto item = std::find_if(connects_.begin(), connects_.end(),
[bundleName, abilityName](
const std::map<ConnectionKey, sptr<JSInputMethodExtensionConnection>>::value_type &obj) {
return (bundleName == obj.first.want.GetBundle()) &&
(abilityName == obj.first.want.GetElement().GetAbilityName());
});
if (item != connects_.end()) {
if (item->second != nullptr) {
item->second->ReleaseConnection();
}
connects_.erase(item);
IMSA_HILOGI("OnAbilityDisconnectDone erase connects_.size: %{public}zu.", connects_.size());
}
}
}
void JSInputMethodExtensionConnection::SetJsConnectionObject(napi_value jsConnectionObject)
{
napi_create_reference(env_, jsConnectionObject, 1, &jsConnectionObject_);
}
void JSInputMethodExtensionConnection::CallJsFailed(int32_t errorCode)
{
IMSA_HILOGI("CallJsFailed start");
if (jsConnectionObject_ == nullptr) {
IMSA_HILOGE("jsConnectionObject_ is nullptr!");
return;
}
napi_value obj = nullptr;
if (napi_get_reference_value(env_, jsConnectionObject_, &obj) != napi_ok) {
IMSA_HILOGE("failed to get jsConnectionObject_!");
return;
}
if (obj == nullptr) {
IMSA_HILOGE("failed to get object.");
return;
}
napi_value method = nullptr;
napi_get_named_property(env_, obj, "onFailed", &method);
if (method == nullptr) {
IMSA_HILOGE("failed to get onFailed from object!");
return;
}
napi_value result = nullptr;
napi_create_int32(env_, errorCode, &result);
napi_value argv[] = { result };
IMSA_HILOGI("CallJsFailed CallFunction success.");
napi_value callResult = nullptr;
napi_call_function(env_, obj, method, ARGC_ONE, argv, &callResult);
IMSA_HILOGI("CallJsFailed end.");
}
void JSInputMethodExtensionConnection::ReleaseConnection()
{
IMSA_HILOGD("ReleaseConnection");
if (jsConnectionObject_ != nullptr) {
napi_delete_reference(env_, jsConnectionObject_);
env_ = nullptr;
jsConnectionObject_ = nullptr;
}
}
}
}