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 == nullptr) {
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(
170 reinterpret_cast<napi_env>(&engine), 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 == nullptr) {
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 == nullptr) {
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 ConnectionKey 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 == nullptr) {
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(reinterpret_cast<napi_env>(&engine),
310 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 ConnectionKey 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 == nullptr) {
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<ConnectionKey, sptr<JSInputMethodExtensionConnection>>::value_type &obj) {
365 return connectId == obj.first.id;
366 });
367 if (item != connects_.end()) {
368 // match id
369 want = item->first.want;
370 connection = item->second;
371 }
372 // begin disconnect
373 AsyncTask::CompleteCallback complete = [weak = context_, want, connection](
374 NativeEngine &engine, AsyncTask &task, int32_t status) {
375 IMSA_HILOGI("OnDisconnectAbility begin");
376 auto context = weak.lock();
377 if (context == nullptr) {
378 IMSA_HILOGW("context is released");
379 task.Reject(engine, CreateJsError(engine, ERROR_CODE_ONE, "Context is released"));
380 return;
381 }
382 if (connection == nullptr) {
383 IMSA_HILOGW("connection nullptr");
384 task.Reject(engine, CreateJsError(engine, ERROR_CODE_TWO, "not found connection"));
385 return;
386 }
387 IMSA_HILOGI("context->DisconnectAbility");
388 auto errcode = context->DisconnectAbility(want, connection);
389 errcode == 0 ? task.Resolve(engine, engine.CreateUndefined())
390 : task.Reject(engine, CreateJsError(engine, errcode, "Disconnect Ability failed."));
391 };
392
393 NativeValue *lastParam = (info.argc == ARGC_ONE) ? nullptr : info.argv[INDEX_ONE];
394 NativeValue *result = nullptr;
395 AsyncTask::Schedule("InputMethodExtensionContext::OnDisconnectAbility", engine,
396 CreateAsyncTaskWithLastParam(engine, lastParam, nullptr, std::move(complete), &result));
397 return result;
398 }
399 };
400 } // namespace
401
CreateJsMetadata(NativeEngine & engine,const AppExecFwk::Metadata & Info)402 NativeValue *CreateJsMetadata(NativeEngine &engine, const AppExecFwk::Metadata &Info)
403 {
404 IMSA_HILOGI("CreateJsMetadata");
405 NativeValue *objValue = engine.CreateObject();
406 NativeObject *object = ConvertNativeValueTo<NativeObject>(objValue);
407
408 object->SetProperty("name", CreateJsValue(engine, Info.name));
409 object->SetProperty("value", CreateJsValue(engine, Info.value));
410 object->SetProperty("resource", CreateJsValue(engine, Info.resource));
411 return objValue;
412 }
413
CreateJsMetadataArray(NativeEngine & engine,const std::vector<AppExecFwk::Metadata> & info)414 NativeValue *CreateJsMetadataArray(NativeEngine &engine, const std::vector<AppExecFwk::Metadata> &info)
415 {
416 IMSA_HILOGI("CreateJsMetadataArray");
417 NativeValue *arrayValue = engine.CreateArray(info.size());
418 NativeArray *array = ConvertNativeValueTo<NativeArray>(arrayValue);
419 uint32_t index = 0;
420 for (const auto &item : info) {
421 array->SetElement(index++, CreateJsMetadata(engine, item));
422 }
423 return arrayValue;
424 }
425
CreateJsExtensionAbilityInfo(NativeEngine & engine,const AppExecFwk::ExtensionAbilityInfo & info)426 NativeValue *CreateJsExtensionAbilityInfo(NativeEngine &engine, const AppExecFwk::ExtensionAbilityInfo &info)
427 {
428 IMSA_HILOGI("CreateJsExtensionAbilityInfo");
429 NativeValue *objValue = engine.CreateObject();
430 NativeObject *object = ConvertNativeValueTo<NativeObject>(objValue);
431 object->SetProperty("bundleName", CreateJsValue(engine, info.bundleName));
432 object->SetProperty("moduleName", CreateJsValue(engine, info.moduleName));
433 object->SetProperty("name", CreateJsValue(engine, info.name));
434 object->SetProperty("labelId", CreateJsValue(engine, info.labelId));
435 object->SetProperty("descriptionId", CreateJsValue(engine, info.descriptionId));
436 object->SetProperty("iconId", CreateJsValue(engine, info.iconId));
437 object->SetProperty("isVisible", CreateJsValue(engine, info.visible));
438 object->SetProperty("extensionAbilityType", CreateJsValue(engine, info.type));
439 NativeValue *permissionArrayValue = engine.CreateArray(info.permissions.size());
440 NativeArray *permissionArray = ConvertNativeValueTo<NativeArray>(permissionArrayValue);
441 if (permissionArray != nullptr) {
442 int index = 0;
443 for (auto permission : info.permissions) {
444 permissionArray->SetElement(index++, CreateJsValue(engine, permission));
445 }
446 }
447 object->SetProperty("permissions", permissionArrayValue);
448 object->SetProperty("applicationInfo", CreateJsApplicationInfo(engine, info.applicationInfo));
449 object->SetProperty("metadata", CreateJsMetadataArray(engine, info.metadata));
450 object->SetProperty("enabled", CreateJsValue(engine, info.enabled));
451 object->SetProperty("readPermission", CreateJsValue(engine, info.readPermission));
452 object->SetProperty("writePermission", CreateJsValue(engine, info.writePermission));
453 return objValue;
454 }
455
CreateJsInputMethodExtensionContext(NativeEngine & engine,std::shared_ptr<InputMethodExtensionContext> context)456 NativeValue *CreateJsInputMethodExtensionContext(
457 NativeEngine &engine, std::shared_ptr<InputMethodExtensionContext> context)
458 {
459 IMSA_HILOGI("CreateJsInputMethodExtensionContext begin");
460 if (context != nullptr) {
461 auto abilityInfo = context->GetAbilityInfo();
462 }
463 NativeValue *objValue = CreateJsExtensionContext(engine, context);
464 NativeObject *object = ConvertNativeValueTo<NativeObject>(objValue);
465
466 std::unique_ptr<JsInputMethodExtensionContext> jsContext = std::make_unique<JsInputMethodExtensionContext>(context);
467 object->SetNativePointer(jsContext.release(), JsInputMethodExtensionContext::Finalizer, nullptr);
468
469 // make handler
470 handler_ = std::make_shared<AppExecFwk::EventHandler>(AppExecFwk::EventRunner::GetMainEventRunner());
471
472 const char *moduleName = "JsInputMethodExtensionContext";
473 BindNativeFunction(engine, *object, "startAbility", moduleName, JsInputMethodExtensionContext::StartAbility);
474 BindNativeFunction(engine, *object, "terminateSelf", moduleName, JsInputMethodExtensionContext::TerminateAbility);
475 BindNativeFunction(engine, *object, "destroy", moduleName, JsInputMethodExtensionContext::TerminateAbility);
476 BindNativeFunction(engine, *object, "connectAbility", moduleName, JsInputMethodExtensionContext::ConnectAbility);
477 BindNativeFunction(
478 engine, *object, "disconnectAbility", moduleName, JsInputMethodExtensionContext::DisconnectAbility);
479 BindNativeFunction(engine, *object, "startAbilityWithAccount", moduleName,
480 JsInputMethodExtensionContext::StartAbilityWithAccount);
481 BindNativeFunction(engine, *object, "connectAbilityWithAccount", moduleName,
482 JsInputMethodExtensionContext::ConnectAbilityWithAccount);
483 return objValue;
484 }
485
JSInputMethodExtensionConnection(NativeEngine & engine)486 JSInputMethodExtensionConnection::JSInputMethodExtensionConnection(NativeEngine &engine) : engine_(engine)
487 {
488 }
489
490 JSInputMethodExtensionConnection::~JSInputMethodExtensionConnection() = default;
491
OnAbilityConnectDone(const AppExecFwk::ElementName & element,const sptr<IRemoteObject> & remoteObject,int resultCode)492 void JSInputMethodExtensionConnection::OnAbilityConnectDone(
493 const AppExecFwk::ElementName &element, const sptr<IRemoteObject> &remoteObject, int resultCode)
494 {
495 IMSA_HILOGI("OnAbilityConnectDone begin, resultCode:%{public}d", resultCode);
496 if (handler_ == nullptr) {
497 IMSA_HILOGI("handler_ nullptr");
498 return;
499 }
500 wptr<JSInputMethodExtensionConnection> connection = this;
501 auto task = [connection, element, remoteObject, resultCode]() {
502 sptr<JSInputMethodExtensionConnection> connectionSptr = connection.promote();
503 if (connectionSptr == nullptr) {
504 IMSA_HILOGE("connectionSptr nullptr");
505 return;
506 }
507 connectionSptr->HandleOnAbilityConnectDone(element, remoteObject, resultCode);
508 };
509 handler_->PostTask(task, "OnAbilityConnectDone");
510 }
511
HandleOnAbilityConnectDone(const AppExecFwk::ElementName & element,const sptr<IRemoteObject> & remoteObject,int resultCode)512 void JSInputMethodExtensionConnection::HandleOnAbilityConnectDone(
513 const AppExecFwk::ElementName &element, const sptr<IRemoteObject> &remoteObject, int resultCode)
514 {
515 IMSA_HILOGI("HandleOnAbilityConnectDone begin, resultCode:%{public}d", resultCode);
516 // wrap ElementName
517 napi_value napiElementName = OHOS::AppExecFwk::WrapElementName(reinterpret_cast<napi_env>(&engine_), element);
518 NativeValue *nativeElementName = reinterpret_cast<NativeValue *>(napiElementName);
519
520 // wrap RemoteObject
521 IMSA_HILOGI("OnAbilityConnectDone begin NAPI_ohos_rpc_CreateJsRemoteObject");
522 napi_value napiRemoteObject =
523 NAPI_ohos_rpc_CreateJsRemoteObject(reinterpret_cast<napi_env>(&engine_), remoteObject);
524 NativeValue *nativeRemoteObject = reinterpret_cast<NativeValue *>(napiRemoteObject);
525 NativeValue *argv[] = { nativeElementName, nativeRemoteObject };
526 if (jsConnectionObject_ == nullptr) {
527 IMSA_HILOGE("jsConnectionObject_ nullptr");
528 return;
529 }
530 NativeValue *value = jsConnectionObject_->Get();
531 NativeObject *obj = ConvertNativeValueTo<NativeObject>(value);
532 if (obj == nullptr) {
533 IMSA_HILOGE("Failed to get object");
534 return;
535 }
536 NativeValue *methodOnConnect = obj->GetProperty("onConnect");
537 if (methodOnConnect == nullptr) {
538 IMSA_HILOGE("Failed to get onConnect from object");
539 return;
540 }
541 IMSA_HILOGI("JSInputMethodExtensionConnection::CallFunction onConnect, success");
542 engine_.CallFunction(value, methodOnConnect, argv, ARGC_TWO);
543 IMSA_HILOGI("OnAbilityConnectDone end");
544 }
545
OnAbilityDisconnectDone(const AppExecFwk::ElementName & element,int resultCode)546 void JSInputMethodExtensionConnection::OnAbilityDisconnectDone(const AppExecFwk::ElementName &element, int resultCode)
547 {
548 IMSA_HILOGI("OnAbilityDisconnectDone begin, resultCode:%{public}d", resultCode);
549 if (handler_ == nullptr) {
550 IMSA_HILOGI("handler_ nullptr");
551 return;
552 }
553 wptr<JSInputMethodExtensionConnection> connection = this;
554 auto task = [connection, element, resultCode]() {
555 sptr<JSInputMethodExtensionConnection> connectionSptr = connection.promote();
556 if (!connectionSptr) {
557 IMSA_HILOGE("connectionSptr nullptr");
558 return;
559 }
560 connectionSptr->HandleOnAbilityDisconnectDone(element, resultCode);
561 };
562 handler_->PostTask(task, "OnAbilityDisconnectDone");
563 }
564
HandleOnAbilityDisconnectDone(const AppExecFwk::ElementName & element,int resultCode)565 void JSInputMethodExtensionConnection::HandleOnAbilityDisconnectDone(
566 const AppExecFwk::ElementName &element, int resultCode)
567 {
568 IMSA_HILOGI("HandleOnAbilityDisconnectDone begin, resultCode:%{public}d", resultCode);
569 napi_value napiElementName = OHOS::AppExecFwk::WrapElementName(reinterpret_cast<napi_env>(&engine_), element);
570 NativeValue *nativeElementName = reinterpret_cast<NativeValue *>(napiElementName);
571 NativeValue *argv[] = { nativeElementName };
572 if (jsConnectionObject_ == nullptr) {
573 IMSA_HILOGE("jsConnectionObject_ nullptr");
574 return;
575 }
576 NativeValue *value = jsConnectionObject_->Get();
577 NativeObject *obj = ConvertNativeValueTo<NativeObject>(value);
578 if (obj == nullptr) {
579 IMSA_HILOGE("Failed to get object");
580 return;
581 }
582
583 NativeValue *method = obj->GetProperty("onDisconnect");
584 if (method == nullptr) {
585 IMSA_HILOGE("Failed to get onDisconnect from object");
586 return;
587 }
588
589 // release connect
590 IMSA_HILOGI("OnAbilityDisconnectDone connects_.size:%{public}zu", connects_.size());
591 std::string bundleName = element.GetBundleName();
592 std::string abilityName = element.GetAbilityName();
593 auto item = std::find_if(connects_.begin(), connects_.end(),
594 [bundleName, abilityName](
595 const std::map<ConnectionKey, sptr<JSInputMethodExtensionConnection>>::value_type &obj) {
596 return (bundleName == obj.first.want.GetBundle()) &&
597 (abilityName == obj.first.want.GetElement().GetAbilityName());
598 });
599 if (item != connects_.end()) {
600 // match bundlename && abilityname
601 connects_.erase(item);
602 IMSA_HILOGI("OnAbilityDisconnectDone erase connects_.size:%{public}zu", connects_.size());
603 }
604 IMSA_HILOGI("OnAbilityDisconnectDone CallFunction success");
605 engine_.CallFunction(value, method, argv, ARGC_ONE);
606 }
607
SetJsConnectionObject(NativeValue * jsConnectionObject)608 void JSInputMethodExtensionConnection::SetJsConnectionObject(NativeValue *jsConnectionObject)
609 {
610 jsConnectionObject_ = std::unique_ptr<NativeReference>(engine_.CreateReference(jsConnectionObject, 1));
611 }
612
CallJsFailed(int32_t errorCode)613 void JSInputMethodExtensionConnection::CallJsFailed(int32_t errorCode)
614 {
615 IMSA_HILOGI("CallJsFailed begin");
616 if (jsConnectionObject_ == nullptr) {
617 IMSA_HILOGE("jsConnectionObject_ nullptr");
618 return;
619 }
620 NativeValue *value = jsConnectionObject_->Get();
621 NativeObject *obj = ConvertNativeValueTo<NativeObject>(value);
622 if (obj == nullptr) {
623 IMSA_HILOGE("Failed to get object");
624 return;
625 }
626
627 NativeValue *method = obj->GetProperty("onFailed");
628 if (method == nullptr) {
629 IMSA_HILOGE("Failed to get onFailed from object");
630 return;
631 }
632 NativeValue *argv[] = { engine_.CreateNumber(errorCode) };
633 IMSA_HILOGI("CallJsFailed CallFunction success");
634 engine_.CallFunction(value, method, argv, ARGC_ONE);
635 IMSA_HILOGI("CallJsFailed end");
636 }
637 } // namespace AbilityRuntime
638 } // namespace OHOS