• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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