• 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 == 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