1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "js_inputmethod_extension_context.h"
17
18 #include <cstdint>
19
20 #include "global.h"
21 #include "js_data_struct_converter.h"
22 #include "js_extension_context.h"
23 #include "js_runtime.h"
24 #include "js_runtime_utils.h"
25 #include "napi/native_api.h"
26 #include "napi_common_start_options.h"
27 #include "napi_common_util.h"
28 #include "napi_common_want.h"
29 #include "napi_remote_object.h"
30 #include "start_options.h"
31
32 namespace OHOS {
33 namespace AbilityRuntime {
34 namespace {
35 constexpr int32_t INDEX_ZERO = 0;
36 constexpr int32_t INDEX_ONE = 1;
37 constexpr int32_t INDEX_TWO = 2;
38 constexpr int32_t ERROR_CODE_ONE = 1;
39 constexpr int32_t ERROR_CODE_TWO = 2;
40 constexpr size_t ARGC_ZERO = 0;
41 constexpr size_t ARGC_ONE = 1;
42 constexpr size_t ARGC_TWO = 2;
43 constexpr size_t ARGC_THREE = 3;
44 constexpr size_t ARGC_FOUR = 4;
45
46 class JsInputMethodExtensionContext final {
47 public:
JsInputMethodExtensionContext(const std::shared_ptr<InputMethodExtensionContext> & context)48 explicit JsInputMethodExtensionContext(const std::shared_ptr<InputMethodExtensionContext> &context)
49 : context_(context)
50 {
51 }
52 ~JsInputMethodExtensionContext() = default;
53
Finalizer(NativeEngine * engine,void * data,void * hint)54 static void Finalizer(NativeEngine *engine, void *data, void *hint)
55 {
56 IMSA_HILOGI("JsInputMethodExtensionContext::Finalizer is called");
57 std::unique_ptr<JsInputMethodExtensionContext>(static_cast<JsInputMethodExtensionContext *>(data));
58 }
59
StartAbility(NativeEngine * engine,NativeCallbackInfo * info)60 static NativeValue *StartAbility(NativeEngine *engine, NativeCallbackInfo *info)
61 {
62 JsInputMethodExtensionContext *me = CheckParamsAndGetThis<JsInputMethodExtensionContext>(engine, info);
63 return (me != nullptr) ? me->OnStartAbility(*engine, *info) : nullptr;
64 }
65
StartAbilityWithAccount(NativeEngine * engine,NativeCallbackInfo * info)66 static NativeValue *StartAbilityWithAccount(NativeEngine *engine, NativeCallbackInfo *info)
67 {
68 JsInputMethodExtensionContext *me = CheckParamsAndGetThis<JsInputMethodExtensionContext>(engine, info);
69 return (me != nullptr) ? me->OnStartAbilityWithAccount(*engine, *info) : nullptr;
70 }
71
ConnectAbilityWithAccount(NativeEngine * engine,NativeCallbackInfo * info)72 static NativeValue *ConnectAbilityWithAccount(NativeEngine *engine, NativeCallbackInfo *info)
73 {
74 JsInputMethodExtensionContext *me = CheckParamsAndGetThis<JsInputMethodExtensionContext>(engine, info);
75 return (me != nullptr) ? me->OnConnectAbilityWithAccount(*engine, *info) : nullptr;
76 }
77
TerminateAbility(NativeEngine * engine,NativeCallbackInfo * info)78 static NativeValue *TerminateAbility(NativeEngine *engine, NativeCallbackInfo *info)
79 {
80 JsInputMethodExtensionContext *me = CheckParamsAndGetThis<JsInputMethodExtensionContext>(engine, info);
81 return (me != nullptr) ? me->OnTerminateAbility(*engine, *info) : nullptr;
82 }
83
ConnectAbility(NativeEngine * engine,NativeCallbackInfo * info)84 static NativeValue *ConnectAbility(NativeEngine *engine, NativeCallbackInfo *info)
85 {
86 JsInputMethodExtensionContext *me = CheckParamsAndGetThis<JsInputMethodExtensionContext>(engine, info);
87 return (me != nullptr) ? me->OnConnectAbility(*engine, *info) : nullptr;
88 }
89
DisconnectAbility(NativeEngine * engine,NativeCallbackInfo * info)90 static NativeValue *DisconnectAbility(NativeEngine *engine, NativeCallbackInfo *info)
91 {
92 JsInputMethodExtensionContext *me = CheckParamsAndGetThis<JsInputMethodExtensionContext>(engine, info);
93 return (me != nullptr) ? me->OnDisconnectAbility(*engine, *info) : nullptr;
94 }
95
96 private:
97 std::weak_ptr<InputMethodExtensionContext> context_;
98
OnStartAbility(NativeEngine & engine,NativeCallbackInfo & info)99 NativeValue *OnStartAbility(NativeEngine &engine, NativeCallbackInfo &info)
100 {
101 IMSA_HILOGI("InputMethodExtensionContext OnStartAbility");
102 // only support one or two or three params
103 if (info.argc != ARGC_ONE && info.argc != ARGC_TWO && info.argc != ARGC_THREE) {
104 IMSA_HILOGE("Not enough params");
105 return engine.CreateUndefined();
106 }
107
108 decltype(info.argc) unwrapArgc = 0;
109 AAFwk::Want want;
110 OHOS::AppExecFwk::UnwrapWant(
111 reinterpret_cast<napi_env>(&engine), reinterpret_cast<napi_value>(info.argv[INDEX_ZERO]), want);
112 IMSA_HILOGI("%{public}s bundlename:%{public}s abilityname:%{public}s", __func__, want.GetBundle().c_str(),
113 want.GetElement().GetAbilityName().c_str());
114 unwrapArgc++;
115
116 AAFwk::StartOptions startOptions;
117 if (info.argc > ARGC_ONE && info.argv[INDEX_ONE]->TypeOf() == NATIVE_OBJECT) {
118 IMSA_HILOGI("OnStartAbility start options is used.");
119 AppExecFwk::UnwrapStartOptions(
120 reinterpret_cast<napi_env>(&engine), reinterpret_cast<napi_value>(info.argv[INDEX_ONE]), startOptions);
121 unwrapArgc++;
122 }
123
124 AsyncTask::CompleteCallback complete = [weak = context_, want, startOptions, unwrapArgc](
125 NativeEngine &engine, AsyncTask &task, int32_t status) {
126 IMSA_HILOGI("startAbility begin");
127 auto context = weak.lock();
128 if (!context) {
129 IMSA_HILOGW("context is released");
130 task.Reject(engine, CreateJsError(engine, ERROR_CODE_ONE, "Context is released"));
131 return;
132 }
133
134 ErrCode errcode = ERR_OK;
135 (unwrapArgc == 1) ? errcode = context->StartAbility(want)
136 : errcode = context->StartAbility(want, startOptions);
137 if (errcode == 0) {
138 task.Resolve(engine, engine.CreateUndefined());
139 } else {
140 task.Reject(engine, CreateJsError(engine, errcode, "Start Ability failed."));
141 }
142 };
143
144 NativeValue *lastParam = (info.argc == unwrapArgc) ? nullptr : info.argv[unwrapArgc];
145 NativeValue *result = nullptr;
146 AsyncTask::Schedule("InputMethodExtensionContext::OnStartAbility", engine,
147 CreateAsyncTaskWithLastParam(engine, lastParam, nullptr, std::move(complete), &result));
148 return result;
149 }
150
OnStartAbilityWithAccount(NativeEngine & engine,NativeCallbackInfo & info)151 NativeValue *OnStartAbilityWithAccount(NativeEngine &engine, NativeCallbackInfo &info)
152 {
153 IMSA_HILOGI("OnStartAbilityWithAccount is called");
154 // only support two or three or four params
155 if (info.argc != ARGC_TWO && info.argc != ARGC_THREE && info.argc != ARGC_FOUR) {
156 IMSA_HILOGE("Not enough params");
157 return engine.CreateUndefined();
158 }
159
160 decltype(info.argc) unwrapArgc = 0;
161 AAFwk::Want want;
162 OHOS::AppExecFwk::UnwrapWant(
163 reinterpret_cast<napi_env>(&engine), reinterpret_cast<napi_value>(info.argv[INDEX_ZERO]), want);
164 IMSA_HILOGI("%{public}s bundlename:%{public}s abilityname:%{public}s", __func__, want.GetBundle().c_str(),
165 want.GetElement().GetAbilityName().c_str());
166 unwrapArgc++;
167
168 int32_t accountId = 0;
169 if (!OHOS::AppExecFwk::UnwrapInt32FromJS2(reinterpret_cast<napi_env>(&engine),
170 reinterpret_cast<napi_value>(info.argv[INDEX_ONE]), accountId)) {
171 IMSA_HILOGI("%{public}s called, the second parameter is invalid.", __func__);
172 return engine.CreateUndefined();
173 }
174 IMSA_HILOGI("%{public}d accountId:", accountId);
175 unwrapArgc++;
176
177 AAFwk::StartOptions startOptions;
178 if (info.argc > ARGC_TWO && info.argv[INDEX_TWO]->TypeOf() == NATIVE_OBJECT) {
179 IMSA_HILOGI("OnStartAbilityWithAccount start options is used.");
180 AppExecFwk::UnwrapStartOptions(
181 reinterpret_cast<napi_env>(&engine), reinterpret_cast<napi_value>(info.argv[INDEX_TWO]), startOptions);
182 unwrapArgc++;
183 }
184
185 AsyncTask::CompleteCallback complete = [weak = context_, want, accountId, startOptions, unwrapArgc](
186 NativeEngine &engine, AsyncTask &task, int32_t status) {
187 IMSA_HILOGI("startAbility begin");
188 auto context = weak.lock();
189 if (!context) {
190 IMSA_HILOGW("context is released");
191 task.Reject(engine, CreateJsError(engine, ERROR_CODE_ONE, "Context is released"));
192 return;
193 }
194
195 ErrCode errcode = ERR_OK;
196 (unwrapArgc == ARGC_TWO) ? errcode = context->StartAbilityWithAccount(want, accountId)
197 : errcode = context->StartAbilityWithAccount(want, accountId, startOptions);
198 if (errcode == 0) {
199 task.Resolve(engine, engine.CreateUndefined());
200 } else {
201 task.Reject(engine, CreateJsError(engine, errcode, "Start Ability failed."));
202 }
203 };
204
205 NativeValue *lastParam = (info.argc == unwrapArgc) ? nullptr : info.argv[unwrapArgc];
206 NativeValue *result = nullptr;
207 AsyncTask::Schedule("InputMethodExtensionContext::OnStartAbilityWithAccount", engine,
208 CreateAsyncTaskWithLastParam(engine, lastParam, nullptr, std::move(complete), &result));
209 return result;
210 }
211
OnTerminateAbility(NativeEngine & engine,NativeCallbackInfo & info)212 NativeValue *OnTerminateAbility(NativeEngine &engine, NativeCallbackInfo &info)
213 {
214 IMSA_HILOGI("OnTerminateAbility is called");
215 // only support one or zero params
216 if (info.argc != ARGC_ZERO && info.argc != ARGC_ONE) {
217 IMSA_HILOGE("Not enough params");
218 return engine.CreateUndefined();
219 }
220
221 AsyncTask::CompleteCallback complete = [weak = context_](
222 NativeEngine &engine, AsyncTask &task, int32_t status) {
223 IMSA_HILOGI("TerminateAbility begin");
224 auto context = weak.lock();
225 if (!context) {
226 IMSA_HILOGW("context is released");
227 task.Reject(engine, CreateJsError(engine, ERROR_CODE_ONE, "Context is released"));
228 return;
229 }
230
231 auto errcode = context->TerminateAbility();
232 if (errcode == 0) {
233 task.Resolve(engine, engine.CreateUndefined());
234 } else {
235 task.Reject(engine, CreateJsError(engine, errcode, "Terminate Ability failed."));
236 }
237 };
238
239 NativeValue *lastParam = (info.argc == ARGC_ZERO) ? nullptr : info.argv[INDEX_ZERO];
240 NativeValue *result = nullptr;
241 AsyncTask::Schedule("InputMethodExtensionContext::OnTerminateAbility", engine,
242 CreateAsyncTaskWithLastParam(engine, lastParam, nullptr, std::move(complete), &result));
243 return result;
244 }
245
OnConnectAbility(NativeEngine & engine,NativeCallbackInfo & info)246 NativeValue *OnConnectAbility(NativeEngine &engine, NativeCallbackInfo &info)
247 {
248 IMSA_HILOGI("OnConnectAbility");
249 // only support two params
250 if (info.argc != ARGC_TWO) {
251 IMSA_HILOGE("Not enough params");
252 return engine.CreateUndefined();
253 }
254
255 AAFwk::Want want;
256 OHOS::AppExecFwk::UnwrapWant(
257 reinterpret_cast<napi_env>(&engine), reinterpret_cast<napi_value>(info.argv[INDEX_ZERO]), want);
258 IMSA_HILOGI("%{public}s bundlename:%{public}s abilityname:%{public}s", __func__, want.GetBundle().c_str(),
259 want.GetElement().GetAbilityName().c_str());
260 sptr<JSInputMethodExtensionConnection> connection = new JSInputMethodExtensionConnection(engine);
261 connection->SetJsConnectionObject(info.argv[1]);
262 int64_t connectId = serialNumber_;
263 ConnecttionKey key;
264 key.id = serialNumber_;
265 key.want = want;
266 connects_.emplace(key, connection);
267 if (serialNumber_ < INT64_MAX) {
268 serialNumber_++;
269 } else {
270 serialNumber_ = 0;
271 }
272 AsyncTask::CompleteCallback complete = [weak = context_, want, connection, connectId](
273 NativeEngine &engine, AsyncTask &task, int32_t status) {
274 IMSA_HILOGI("OnConnectAbility begin");
275 auto context = weak.lock();
276 if (!context) {
277 IMSA_HILOGW("context is released");
278 task.Reject(engine, CreateJsError(engine, ERROR_CODE_ONE, "Context is released"));
279 return;
280 }
281 IMSA_HILOGI("context->ConnectAbility connection:%{public}d", (int32_t)connectId);
282 if (!context->ConnectAbility(want, connection)) {
283 connection->CallJsFailed(ERROR_CODE_ONE);
284 }
285 task.Resolve(engine, engine.CreateUndefined());
286 };
287 NativeValue *result = nullptr;
288 AsyncTask::Schedule("InputMethodExtensionContext::OnConnectAbility", engine,
289 CreateAsyncTaskWithLastParam(engine, nullptr, nullptr, std::move(complete), &result));
290 return engine.CreateNumber(connectId);
291 }
292
OnConnectAbilityWithAccount(NativeEngine & engine,NativeCallbackInfo & info)293 NativeValue *OnConnectAbilityWithAccount(NativeEngine &engine, NativeCallbackInfo &info)
294 {
295 IMSA_HILOGI("OnConnectAbilityWithAccount is called");
296 // only support three params
297 if (info.argc != ARGC_THREE) {
298 IMSA_HILOGE("Not enough params");
299 return engine.CreateUndefined();
300 }
301
302 AAFwk::Want want;
303 OHOS::AppExecFwk::UnwrapWant(
304 reinterpret_cast<napi_env>(&engine), reinterpret_cast<napi_value>(info.argv[INDEX_ZERO]), want);
305 IMSA_HILOGI("%{public}s bundlename:%{public}s abilityname:%{public}s", __func__, want.GetBundle().c_str(),
306 want.GetElement().GetAbilityName().c_str());
307
308 int32_t accountId = 0;
309 if (!OHOS::AppExecFwk::UnwrapInt32FromJS2(
310 reinterpret_cast<napi_env>(&engine), reinterpret_cast<napi_value>(info.argv[INDEX_ONE]), accountId)) {
311 IMSA_HILOGI("%{public}s called, the second parameter is invalid.", __func__);
312 return engine.CreateUndefined();
313 }
314
315 sptr<JSInputMethodExtensionConnection> connection = new JSInputMethodExtensionConnection(engine);
316 connection->SetJsConnectionObject(info.argv[1]);
317 int64_t connectId = serialNumber_;
318 ConnecttionKey key;
319 key.id = serialNumber_;
320 key.want = want;
321 connects_.emplace(key, connection);
322 if (serialNumber_ < INT64_MAX) {
323 serialNumber_++;
324 } else {
325 serialNumber_ = 0;
326 }
327 AsyncTask::CompleteCallback complete = [weak = context_, want, accountId, connection, connectId](
328 NativeEngine &engine, AsyncTask &task, int32_t status) {
329 IMSA_HILOGI("OnConnectAbilityWithAccount begin");
330 auto context = weak.lock();
331 if (!context) {
332 IMSA_HILOGW("context is released");
333 task.Reject(engine, CreateJsError(engine, ERROR_CODE_ONE, "Context is released"));
334 return;
335 }
336 IMSA_HILOGI("context->ConnectAbilityWithAccount connection:%{public}d", (int32_t)connectId);
337 if (!context->ConnectAbilityWithAccount(want, accountId, connection)) {
338 connection->CallJsFailed(ERROR_CODE_ONE);
339 }
340 task.Resolve(engine, engine.CreateUndefined());
341 };
342 NativeValue *result = nullptr;
343 AsyncTask::Schedule("InputMethodExtensionContext::OnConnectAbilityWithAccount", engine,
344 CreateAsyncTaskWithLastParam(engine, nullptr, nullptr, std::move(complete), &result));
345 return engine.CreateNumber(connectId);
346 }
347
OnDisconnectAbility(NativeEngine & engine,NativeCallbackInfo & info)348 NativeValue *OnDisconnectAbility(NativeEngine &engine, NativeCallbackInfo &info)
349 {
350 IMSA_HILOGI("OnDisconnectAbility is called");
351 // only support one or two params
352 if (info.argc != ARGC_ONE && info.argc != ARGC_TWO) {
353 IMSA_HILOGE("Not enough params");
354 return engine.CreateUndefined();
355 }
356
357 AAFwk::Want want;
358 int64_t connectId = -1;
359 sptr<JSInputMethodExtensionConnection> connection = nullptr;
360 napi_get_value_int64(
361 reinterpret_cast<napi_env>(&engine), reinterpret_cast<napi_value>(info.argv[INDEX_ZERO]), &connectId);
362 IMSA_HILOGI("OnDisconnectAbility connection:%{public}d", static_cast<int32_t>(connectId));
363 auto item = std::find_if(connects_.begin(), connects_.end(),
364 [&connectId](const std::map<ConnecttionKey,
365 sptr<JSInputMethodExtensionConnection>>::value_type &obj) {
366 return connectId == obj.first.id;
367 });
368 if (item != connects_.end()) {
369 // match id
370 want = item->first.want;
371 connection = item->second;
372 }
373 // begin disconnect
374 AsyncTask::CompleteCallback complete = [weak = context_, want, connection](
375 NativeEngine &engine, AsyncTask &task, int32_t status) {
376 IMSA_HILOGI("OnDisconnectAbility begin");
377 auto context = weak.lock();
378 if (!context) {
379 IMSA_HILOGW("context is released");
380 task.Reject(engine, CreateJsError(engine, ERROR_CODE_ONE, "Context is released"));
381 return;
382 }
383 if (connection == nullptr) {
384 IMSA_HILOGW("connection nullptr");
385 task.Reject(engine, CreateJsError(engine, ERROR_CODE_TWO, "not found connection"));
386 return;
387 }
388 IMSA_HILOGI("context->DisconnectAbility");
389 auto errcode = context->DisconnectAbility(want, connection);
390 errcode == 0 ? task.Resolve(engine, engine.CreateUndefined())
391 : task.Reject(engine, CreateJsError(engine, errcode, "Disconnect Ability failed."));
392 };
393
394 NativeValue *lastParam = (info.argc == ARGC_ONE) ? nullptr : info.argv[INDEX_ONE];
395 NativeValue *result = nullptr;
396 AsyncTask::Schedule("InputMethodExtensionContext::OnDisconnectAbility", engine,
397 CreateAsyncTaskWithLastParam(engine, lastParam, nullptr, std::move(complete), &result));
398 return result;
399 }
400 };
401 } // namespace
402
CreateJsMetadata(NativeEngine & engine,const AppExecFwk::Metadata & Info)403 NativeValue *CreateJsMetadata(NativeEngine &engine, const AppExecFwk::Metadata &Info)
404 {
405 IMSA_HILOGI("CreateJsMetadata");
406 NativeValue *objValue = engine.CreateObject();
407 NativeObject *object = ConvertNativeValueTo<NativeObject>(objValue);
408
409 object->SetProperty("name", CreateJsValue(engine, Info.name));
410 object->SetProperty("value", CreateJsValue(engine, Info.value));
411 object->SetProperty("resource", CreateJsValue(engine, Info.resource));
412 return objValue;
413 }
414
CreateJsMetadataArray(NativeEngine & engine,const std::vector<AppExecFwk::Metadata> & info)415 NativeValue *CreateJsMetadataArray(NativeEngine &engine, const std::vector<AppExecFwk::Metadata> &info)
416 {
417 IMSA_HILOGI("CreateJsMetadataArray");
418 NativeValue *arrayValue = engine.CreateArray(info.size());
419 NativeArray *array = ConvertNativeValueTo<NativeArray>(arrayValue);
420 uint32_t index = 0;
421 for (const auto &item : info) {
422 array->SetElement(index++, CreateJsMetadata(engine, item));
423 }
424 return arrayValue;
425 }
426
CreateJsExtensionAbilityInfo(NativeEngine & engine,const AppExecFwk::ExtensionAbilityInfo & info)427 NativeValue *CreateJsExtensionAbilityInfo(NativeEngine &engine, const AppExecFwk::ExtensionAbilityInfo &info)
428 {
429 IMSA_HILOGI("CreateJsExtensionAbilityInfo");
430 NativeValue *objValue = engine.CreateObject();
431 NativeObject *object = ConvertNativeValueTo<NativeObject>(objValue);
432 object->SetProperty("bundleName", CreateJsValue(engine, info.bundleName));
433 object->SetProperty("moduleName", CreateJsValue(engine, info.moduleName));
434 object->SetProperty("name", CreateJsValue(engine, info.name));
435 object->SetProperty("labelId", CreateJsValue(engine, info.labelId));
436 object->SetProperty("descriptionId", CreateJsValue(engine, info.descriptionId));
437 object->SetProperty("iconId", CreateJsValue(engine, info.iconId));
438 object->SetProperty("isVisible", CreateJsValue(engine, info.visible));
439 object->SetProperty("extensionAbilityType", CreateJsValue(engine, info.type));
440 NativeValue *permissionArrayValue = engine.CreateArray(info.permissions.size());
441 NativeArray *permissionArray = ConvertNativeValueTo<NativeArray>(permissionArrayValue);
442 if (permissionArray != nullptr) {
443 int index = 0;
444 for (auto permission : info.permissions) {
445 permissionArray->SetElement(index++, CreateJsValue(engine, permission));
446 }
447 }
448 object->SetProperty("permissions", permissionArrayValue);
449 object->SetProperty("applicationInfo", CreateJsApplicationInfo(engine, info.applicationInfo));
450 object->SetProperty("metadata", CreateJsMetadataArray(engine, info.metadata));
451 object->SetProperty("enabled", CreateJsValue(engine, info.enabled));
452 object->SetProperty("readPermission", CreateJsValue(engine, info.readPermission));
453 object->SetProperty("writePermission", CreateJsValue(engine, info.writePermission));
454 return objValue;
455 }
456
CreateJsInputMethodExtensionContext(NativeEngine & engine,std::shared_ptr<InputMethodExtensionContext> context)457 NativeValue *CreateJsInputMethodExtensionContext(
458 NativeEngine &engine, std::shared_ptr<InputMethodExtensionContext> context)
459 {
460 IMSA_HILOGI("CreateJsInputMethodExtensionContext begin");
461 if (context) {
462 auto abilityInfo = context->GetAbilityInfo();
463 }
464 NativeValue *objValue = CreateJsExtensionContext(engine, context);
465 NativeObject *object = ConvertNativeValueTo<NativeObject>(objValue);
466
467 std::unique_ptr<JsInputMethodExtensionContext> jsContext = std::make_unique<JsInputMethodExtensionContext>(context);
468 object->SetNativePointer(jsContext.release(), JsInputMethodExtensionContext::Finalizer, nullptr);
469
470 // make handler
471 handler_ = std::make_shared<AppExecFwk::EventHandler>(AppExecFwk::EventRunner::GetMainEventRunner());
472
473 const char *moduleName = "JsInputMethodExtensionContext";
474 BindNativeFunction(engine, *object, "startAbility", moduleName, JsInputMethodExtensionContext::StartAbility);
475 BindNativeFunction(engine, *object, "terminateSelf", moduleName, JsInputMethodExtensionContext::TerminateAbility);
476 BindNativeFunction(engine, *object, "destroy", moduleName, JsInputMethodExtensionContext::TerminateAbility);
477 BindNativeFunction(engine, *object, "connectAbility", moduleName, JsInputMethodExtensionContext::ConnectAbility);
478 BindNativeFunction(engine, *object,
479 "disconnectAbility", moduleName, JsInputMethodExtensionContext::DisconnectAbility);
480 BindNativeFunction(engine, *object,
481 "startAbilityWithAccount", moduleName, JsInputMethodExtensionContext::StartAbilityWithAccount);
482 BindNativeFunction(engine, *object,
483 "connectAbilityWithAccount", moduleName, JsInputMethodExtensionContext::ConnectAbilityWithAccount);
484 return objValue;
485 }
486
JSInputMethodExtensionConnection(NativeEngine & engine)487 JSInputMethodExtensionConnection::JSInputMethodExtensionConnection(NativeEngine &engine) : engine_(engine) {}
488
489 JSInputMethodExtensionConnection::~JSInputMethodExtensionConnection() = default;
490
OnAbilityConnectDone(const AppExecFwk::ElementName & element,const sptr<IRemoteObject> & remoteObject,int resultCode)491 void JSInputMethodExtensionConnection::OnAbilityConnectDone(
492 const AppExecFwk::ElementName &element, const sptr<IRemoteObject> &remoteObject, int resultCode)
493 {
494 IMSA_HILOGI("OnAbilityConnectDone begin, resultCode:%{public}d", resultCode);
495 if (handler_ == nullptr) {
496 IMSA_HILOGI("handler_ nullptr");
497 return;
498 }
499 wptr<JSInputMethodExtensionConnection> connection = this;
500 auto task = [connection, element, remoteObject, resultCode]() {
501 sptr<JSInputMethodExtensionConnection> connectionSptr = connection.promote();
502 if (!connectionSptr) {
503 IMSA_HILOGE("connectionSptr nullptr");
504 return;
505 }
506 connectionSptr->HandleOnAbilityConnectDone(element, remoteObject, resultCode);
507 };
508 handler_->PostTask(task, "OnAbilityConnectDone");
509 }
510
HandleOnAbilityConnectDone(const AppExecFwk::ElementName & element,const sptr<IRemoteObject> & remoteObject,int resultCode)511 void JSInputMethodExtensionConnection::HandleOnAbilityConnectDone(
512 const AppExecFwk::ElementName &element, const sptr<IRemoteObject> &remoteObject, int resultCode)
513 {
514 IMSA_HILOGI("HandleOnAbilityConnectDone begin, resultCode:%{public}d", resultCode);
515 // wrap ElementName
516 napi_value napiElementName = OHOS::AppExecFwk::WrapElementName(reinterpret_cast<napi_env>(&engine_), element);
517 NativeValue *nativeElementName = reinterpret_cast<NativeValue *>(napiElementName);
518
519 // wrap RemoteObject
520 IMSA_HILOGI("OnAbilityConnectDone begin NAPI_ohos_rpc_CreateJsRemoteObject");
521 napi_value napiRemoteObject =
522 NAPI_ohos_rpc_CreateJsRemoteObject(reinterpret_cast<napi_env>(&engine_), remoteObject);
523 NativeValue *nativeRemoteObject = reinterpret_cast<NativeValue *>(napiRemoteObject);
524 NativeValue *argv[] = { nativeElementName, nativeRemoteObject };
525 if (jsConnectionObject_ == nullptr) {
526 IMSA_HILOGE("jsConnectionObject_ nullptr");
527 return;
528 }
529 NativeValue *value = jsConnectionObject_->Get();
530 NativeObject *obj = ConvertNativeValueTo<NativeObject>(value);
531 if (obj == nullptr) {
532 IMSA_HILOGE("Failed to get object");
533 return;
534 }
535 NativeValue *methodOnConnect = obj->GetProperty("onConnect");
536 if (methodOnConnect == nullptr) {
537 IMSA_HILOGE("Failed to get onConnect from object");
538 return;
539 }
540 IMSA_HILOGI("JSInputMethodExtensionConnection::CallFunction onConnect, success");
541 engine_.CallFunction(value, methodOnConnect, argv, ARGC_TWO);
542 IMSA_HILOGI("OnAbilityConnectDone end");
543 }
544
OnAbilityDisconnectDone(const AppExecFwk::ElementName & element,int resultCode)545 void JSInputMethodExtensionConnection::OnAbilityDisconnectDone(const AppExecFwk::ElementName &element, int resultCode)
546 {
547 IMSA_HILOGI("OnAbilityDisconnectDone begin, resultCode:%{public}d", resultCode);
548 if (handler_ == nullptr) {
549 IMSA_HILOGI("handler_ nullptr");
550 return;
551 }
552 wptr<JSInputMethodExtensionConnection> connection = this;
553 auto task = [connection, element, resultCode]() {
554 sptr<JSInputMethodExtensionConnection> connectionSptr = connection.promote();
555 if (!connectionSptr) {
556 IMSA_HILOGE("connectionSptr nullptr");
557 return;
558 }
559 connectionSptr->HandleOnAbilityDisconnectDone(element, resultCode);
560 };
561 handler_->PostTask(task, "OnAbilityDisconnectDone");
562 }
563
HandleOnAbilityDisconnectDone(const AppExecFwk::ElementName & element,int resultCode)564 void JSInputMethodExtensionConnection::HandleOnAbilityDisconnectDone(
565 const AppExecFwk::ElementName &element, int resultCode)
566 {
567 IMSA_HILOGI("HandleOnAbilityDisconnectDone begin, resultCode:%{public}d", resultCode);
568 napi_value napiElementName = OHOS::AppExecFwk::WrapElementName(reinterpret_cast<napi_env>(&engine_), element);
569 NativeValue *nativeElementName = reinterpret_cast<NativeValue *>(napiElementName);
570 NativeValue *argv[] = { nativeElementName };
571 if (jsConnectionObject_ == nullptr) {
572 IMSA_HILOGE("jsConnectionObject_ nullptr");
573 return;
574 }
575 NativeValue *value = jsConnectionObject_->Get();
576 NativeObject *obj = ConvertNativeValueTo<NativeObject>(value);
577 if (obj == nullptr) {
578 IMSA_HILOGE("Failed to get object");
579 return;
580 }
581
582 NativeValue *method = obj->GetProperty("onDisconnect");
583 if (method == nullptr) {
584 IMSA_HILOGE("Failed to get onDisconnect from object");
585 return;
586 }
587
588 // release connect
589 IMSA_HILOGI("OnAbilityDisconnectDone connects_.size:%{public}zu", connects_.size());
590 std::string bundleName = element.GetBundleName();
591 std::string abilityName = element.GetAbilityName();
592 auto item = std::find_if(connects_.begin(), connects_.end(),
593 [bundleName, abilityName](
594 const std::map<ConnecttionKey, sptr<JSInputMethodExtensionConnection>>::value_type &obj) {
595 return (bundleName == obj.first.want.GetBundle())
596 && (abilityName == obj.first.want.GetElement().GetAbilityName());
597 });
598 if (item != connects_.end()) {
599 // match bundlename && abilityname
600 connects_.erase(item);
601 IMSA_HILOGI("OnAbilityDisconnectDone erase connects_.size:%{public}zu", connects_.size());
602 }
603 IMSA_HILOGI("OnAbilityDisconnectDone CallFunction success");
604 engine_.CallFunction(value, method, argv, ARGC_ONE);
605 }
606
SetJsConnectionObject(NativeValue * jsConnectionObject)607 void JSInputMethodExtensionConnection::SetJsConnectionObject(NativeValue *jsConnectionObject)
608 {
609 jsConnectionObject_ = std::unique_ptr<NativeReference>(engine_.CreateReference(jsConnectionObject, 1));
610 }
611
CallJsFailed(int32_t errorCode)612 void JSInputMethodExtensionConnection::CallJsFailed(int32_t errorCode)
613 {
614 IMSA_HILOGI("CallJsFailed begin");
615 if (jsConnectionObject_ == nullptr) {
616 IMSA_HILOGE("jsConnectionObject_ nullptr");
617 return;
618 }
619 NativeValue *value = jsConnectionObject_->Get();
620 NativeObject *obj = ConvertNativeValueTo<NativeObject>(value);
621 if (obj == nullptr) {
622 IMSA_HILOGE("Failed to get object");
623 return;
624 }
625
626 NativeValue *method = obj->GetProperty("onFailed");
627 if (method == nullptr) {
628 IMSA_HILOGE("Failed to get onFailed from object");
629 return;
630 }
631 NativeValue *argv[] = { engine_.CreateNumber(errorCode) };
632 IMSA_HILOGI("CallJsFailed CallFunction success");
633 engine_.CallFunction(value, method, argv, ARGC_ONE);
634 IMSA_HILOGI("CallJsFailed end");
635 }
636 } // namespace AbilityRuntime
637 } // namespace OHOS