• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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 <string>
17 #include <uv.h>
18 
19 #include "interfaces/napi/kits/utils/napi_utils.h"
20 #include "napi/native_api.h"
21 #include "napi/native_engine/native_value.h"
22 #include "napi/native_node_api.h"
23 
24 #include "base/subwindow/subwindow_manager.h"
25 #include "base/utils/system_properties.h"
26 #include "bridge/common/utils/engine_helper.h"
27 #include "bridge/js_frontend/engine/common/js_engine.h"
28 
29 namespace OHOS::Ace::Napi {
30 namespace {
31 
32 const int SHOW_DIALOG_BUTTON_NUM_MAX = 3;
33 const int SHOW_ACTION_MENU_BUTTON_NUM_MAX = 6;
34 constexpr char DEFAULT_FONT_COLOR_STRING_VALUE[] = "#ff007dff";
35 
36 #ifdef OHOS_STANDARD_SYSTEM
ContainerIsService()37 bool ContainerIsService()
38 {
39     auto containerId = Container::CurrentId();
40     // Get active container when current instanceid is less than 0
41     if (containerId < 0) {
42         auto container = Container::GetActive();
43         if (container) {
44             containerId = container->GetInstanceId();
45         }
46     }
47     // for pa service
48     return containerId >= MIN_PA_SERVICE_ID || containerId < 0;
49 }
50 #endif
51 
52 } // namespace
53 
GetReturnObject(napi_env env,std::string callbackString)54 napi_value GetReturnObject(napi_env env, std::string callbackString)
55 {
56     napi_value result = nullptr;
57     napi_value returnObj = nullptr;
58     napi_create_object(env, &returnObj);
59     napi_create_string_utf8(env, callbackString.c_str(), NAPI_AUTO_LENGTH, &result);
60     napi_set_named_property(env, returnObj, "errMsg", result);
61     return returnObj;
62 }
63 
GetNapiString(napi_env env,napi_value value,std::string & retStr)64 void GetNapiString(napi_env env, napi_value value, std::string& retStr)
65 {
66     size_t ret = 0;
67     napi_valuetype valueType = napi_undefined;
68     napi_typeof(env, value, &valueType);
69     if (valueType == napi_string) {
70         size_t valueLen = GetParamLen(value) + 1;
71         std::unique_ptr<char[]> titleChar = std::make_unique<char[]>(valueLen);
72         napi_get_value_string_utf8(env, value, titleChar.get(), valueLen, &ret);
73         retStr = titleChar.get();
74     } else if (valueType == napi_object) {
75         int32_t id = 0;
76         int32_t type = 0;
77         std::vector<std::string> params;
78         if (ParseResourceParam(env, value, id, type, params)) {
79             ParseString(id, type, params, retStr);
80         }
81     }
82 }
83 
JSPromptShowToast(napi_env env,napi_callback_info info)84 static napi_value JSPromptShowToast(napi_env env, napi_callback_info info)
85 {
86     size_t requireArgc = 1;
87     size_t argc = 1;
88     napi_value argv = nullptr;
89     napi_value thisVar = nullptr;
90     void* data = nullptr;
91     napi_get_cb_info(env, info, &argc, &argv, &thisVar, &data);
92     if (argc != requireArgc) {
93         NapiThrow(env, "The number of parameters must be equal to 1.", Framework::ERROR_CODE_PARAM_INVALID);
94         return nullptr;
95     }
96 
97     napi_value messageNApi = nullptr;
98     napi_value durationNApi = nullptr;
99     napi_value bottomNApi = nullptr;
100     std::string messageString;
101     std::string bottomString;
102 
103     napi_valuetype valueType = napi_undefined;
104     napi_typeof(env, argv, &valueType);
105     if (valueType == napi_object) {
106         napi_get_named_property(env, argv, "message", &messageNApi);
107         napi_get_named_property(env, argv, "duration", &durationNApi);
108         napi_get_named_property(env, argv, "bottom", &bottomNApi);
109     } else {
110         NapiThrow(env, "The type of parameters is incorrect.", Framework::ERROR_CODE_PARAM_INVALID);
111         return nullptr;
112     }
113     size_t ret = 0;
114     napi_typeof(env, messageNApi, &valueType);
115     if (valueType == napi_string) {
116         size_t messageLen = GetParamLen(messageNApi) + 1;
117         std::unique_ptr<char[]> message = std::make_unique<char[]>(messageLen);
118         napi_get_value_string_utf8(env, messageNApi, message.get(), messageLen, &ret);
119         messageString = message.get();
120     } else if (valueType == napi_object) {
121         int32_t id = 0;
122         int32_t type = 0;
123         std::vector<std::string> params;
124         if (!ParseResourceParam(env, messageNApi, id, type, params)) {
125             LOGE("can not parse resource info from input params.");
126             NapiThrow(env, "Can not parse resource info from input params.", Framework::ERROR_CODE_INTERNAL_ERROR);
127             return nullptr;
128         }
129         if (!ParseString(id, type, params, messageString)) {
130             LOGE("can not get message from resource manager.");
131             NapiThrow(env, "Can not get message from resource manager.", Framework::ERROR_CODE_INTERNAL_ERROR);
132             return nullptr;
133         }
134     } else if (valueType == napi_undefined) {
135         NapiThrow(env, "Required input parameters are missing.", Framework::ERROR_CODE_PARAM_INVALID);
136         return nullptr;
137     } else {
138         LOGE("The parameter type is incorrect.");
139         NapiThrow(env, "The type of message is incorrect.", Framework::ERROR_CODE_PARAM_INVALID);
140         return nullptr;
141     }
142 
143     int32_t duration = -1;
144     std::string durationStr;
145     napi_typeof(env, durationNApi, &valueType);
146     if (valueType == napi_number) {
147         napi_get_value_int32(env, durationNApi, &duration);
148     } else if (valueType == napi_object) {
149         int32_t id = 0;
150         int32_t type = 0;
151         std::vector<std::string> params;
152         if (!ParseResourceParam(env, durationNApi, id, type, params)) {
153             LOGE("can not parse resource info from input params.");
154             NapiThrow(env, "Can not parse resource info from input params.", Framework::ERROR_CODE_INTERNAL_ERROR);
155             return nullptr;
156         }
157         if (!ParseString(id, type, params, durationStr)) {
158             LOGE("can not get message from resource manager.");
159             NapiThrow(env, "Can not get message from resource manager.", Framework::ERROR_CODE_INTERNAL_ERROR);
160             return nullptr;
161         }
162         duration = StringUtils::StringToInt(durationStr);
163     }
164 
165     napi_typeof(env, bottomNApi, &valueType);
166     if (valueType == napi_string) {
167         size_t bottomLen = GetParamLen(bottomNApi) + 1;
168         std::unique_ptr<char[]> bottom = std::make_unique<char[]>(bottomLen);
169         napi_get_value_string_utf8(env, bottomNApi, bottom.get(), bottomLen, &ret);
170         bottomString = bottom.get();
171     } else if (valueType == napi_number) {
172         double bottom = 0.0;
173         napi_get_value_double(env, bottomNApi, &bottom);
174         bottomString = std::to_string(bottom);
175     } else if (valueType == napi_object) {
176         int32_t id = 0;
177         int32_t type = 0;
178         std::vector<std::string> params;
179         if (!ParseResourceParam(env, bottomNApi, id, type, params)) {
180             LOGE("can not parse resource info from input params.");
181             NapiThrow(env, "Can not parse resource info from input params.", Framework::ERROR_CODE_INTERNAL_ERROR);
182             return nullptr;
183         }
184         if (!ParseString(id, type, params, bottomString)) {
185             LOGE("can not get message from resource manager.");
186             NapiThrow(env, "Can not get message from resource manager.", Framework::ERROR_CODE_INTERNAL_ERROR);
187             return nullptr;
188         }
189     }
190 #ifdef OHOS_STANDARD_SYSTEM
191     if (SystemProperties::GetExtSurfaceEnabled() || !ContainerIsService()) {
192         auto delegate = EngineHelper::GetCurrentDelegate();
193         if (!delegate) {
194             LOGE("can not get delegate.");
195             NapiThrow(env, "Can not get delegate.", Framework::ERROR_CODE_INTERNAL_ERROR);
196             return nullptr;
197         }
198         delegate->ShowToast(messageString, duration, bottomString);
199     } else if (SubwindowManager::GetInstance() != nullptr) {
200         SubwindowManager::GetInstance()->ShowToast(messageString, duration, bottomString);
201     }
202 #else
203     auto delegate = EngineHelper::GetCurrentDelegate();
204     if (!delegate) {
205         LOGE("can not get delegate.");
206         NapiThrow(env, "UI execution context not found.", Framework::ERROR_CODE_INTERNAL_ERROR);
207         return nullptr;
208     }
209     delegate->ShowToast(messageString, duration, bottomString);
210 #endif
211 
212     return nullptr;
213 }
214 
215 struct PromptAsyncContext {
216     napi_env env = nullptr;
217     napi_async_work work = nullptr;
218     napi_value titleNApi = nullptr;
219     napi_value messageNApi = nullptr;
220     napi_value buttonsNApi = nullptr;
221     napi_value autoCancel = nullptr;
222     napi_ref callbackSuccess = nullptr;
223     napi_ref callbackCancel = nullptr;
224     napi_ref callbackComplete = nullptr;
225     std::string titleString;
226     std::string messageString;
227     std::vector<ButtonInfo> buttons;
228     bool autoCancelBool = true;
229     std::set<std::string> callbacks;
230     std::string callbackSuccessString;
231     std::string callbackCancelString;
232     std::string callbackCompleteString;
233     napi_deferred deferred = nullptr;
234     napi_ref callbackRef = nullptr;
235     int32_t callbackType = -1;
236     int32_t successType = -1;
237     bool valid = true;
238 };
239 
JSPromptShowDialog(napi_env env,napi_callback_info info)240 static napi_value JSPromptShowDialog(napi_env env, napi_callback_info info)
241 {
242     size_t requireArgc = 1;
243     size_t argc = 2;
244     napi_value argv[3] = { 0 };
245     napi_value thisVar = nullptr;
246     void* data = nullptr;
247     napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
248     if (argc < requireArgc) {
249         NapiThrow(env, "The number of parameters must be greater than or equal to 1.",
250             Framework::ERROR_CODE_PARAM_INVALID);
251         return nullptr;
252     }
253     if (thisVar == nullptr) {
254         LOGE("%{public}s, This argument is nullptr.", __func__);
255         return nullptr;
256     }
257     napi_valuetype valueTypeOfThis = napi_undefined;
258     napi_typeof(env, thisVar, &valueTypeOfThis);
259     if (valueTypeOfThis == napi_undefined) {
260         LOGE("%{public}s, Wrong this value.", __func__);
261         return nullptr;
262     }
263 
264     auto asyncContext = new PromptAsyncContext();
265     asyncContext->env = env;
266     for (size_t i = 0; i < argc; i++) {
267         napi_valuetype valueType = napi_undefined;
268         napi_typeof(env, argv[i], &valueType);
269         if (i == 0) {
270             if (valueType != napi_object) {
271                 delete asyncContext;
272                 asyncContext = nullptr;
273                 NapiThrow(env, "The type of parameters is incorrect.", Framework::ERROR_CODE_PARAM_INVALID);
274                 return nullptr;
275             }
276             napi_get_named_property(env, argv[0], "title", &asyncContext->titleNApi);
277             napi_get_named_property(env, argv[0], "message", &asyncContext->messageNApi);
278             napi_get_named_property(env, argv[0], "buttons", &asyncContext->buttonsNApi);
279             napi_get_named_property(env, argv[0], "autoCancel", &asyncContext->autoCancel);
280             GetNapiString(env, asyncContext->titleNApi, asyncContext->titleString);
281             GetNapiString(env, asyncContext->messageNApi, asyncContext->messageString);
282             bool isBool = false;
283             napi_is_array(env, asyncContext->buttonsNApi, &isBool);
284             napi_typeof(env, asyncContext->buttonsNApi, &valueType);
285             if (valueType == napi_object && isBool) {
286                 uint32_t buttonsLen = 0;
287                 napi_value buttonArray = nullptr;
288                 napi_value textNApi = nullptr;
289                 napi_value colorNApi = nullptr;
290 
291                 uint32_t index = 0;
292                 napi_get_array_length(env, asyncContext->buttonsNApi, &buttonsLen);
293                 uint32_t buttonsLenInt = buttonsLen;
294                 if (buttonsLenInt > SHOW_DIALOG_BUTTON_NUM_MAX) {
295                     buttonsLenInt = SHOW_DIALOG_BUTTON_NUM_MAX;
296                     LOGE("Supports 1 - 3 buttons");
297                 }
298                 for (uint32_t j = 0; j < buttonsLenInt; j++) {
299                     napi_get_element(env, asyncContext->buttonsNApi, index, &buttonArray);
300                     index++;
301                     napi_get_named_property(env, buttonArray, "text", &textNApi);
302                     napi_get_named_property(env, buttonArray, "color", &colorNApi);
303                     std::string textString;
304                     std::string colorString;
305                     GetNapiString(env, textNApi, textString);
306                     GetNapiString(env, colorNApi, colorString);
307                     ButtonInfo buttonInfo = { .text = textString, .textColor = colorString };
308                     asyncContext->buttons.emplace_back(buttonInfo);
309                 }
310             }
311             napi_typeof(env, asyncContext->autoCancel, &valueType);
312             if (valueType == napi_boolean) {
313                 napi_get_value_bool(env, asyncContext->autoCancel, &asyncContext->autoCancelBool);
314             }
315         } else if (valueType == napi_function) {
316             napi_create_reference(env, argv[i], 1, &asyncContext->callbackRef);
317         } else {
318             delete asyncContext;
319             asyncContext = nullptr;
320             NapiThrow(env, "The type of parameters is incorrect.", Framework::ERROR_CODE_PARAM_INVALID);
321             return nullptr;
322         }
323     }
324     napi_value result = nullptr;
325     if (asyncContext->callbackRef == nullptr) {
326         napi_create_promise(env, &asyncContext->deferred, &result);
327     } else {
328         napi_get_undefined(env, &result);
329     }
330     asyncContext->callbacks.emplace("success");
331     asyncContext->callbacks.emplace("cancel");
332 
333     auto callBack = [asyncContext](int32_t callbackType, int32_t successType) {
334         uv_loop_s* loop = nullptr;
335         if (asyncContext == nullptr) {
336             return;
337         }
338 
339         asyncContext->callbackType = callbackType;
340         asyncContext->successType = successType;
341         napi_get_uv_event_loop(asyncContext->env, &loop);
342         uv_work_t* work = new uv_work_t;
343         work->data = (void*)asyncContext;
344         int rev = uv_queue_work(
345             loop, work, [](uv_work_t* work) {},
346             [](uv_work_t* work, int status) {
347                 if (work == nullptr) {
348                     return;
349                 }
350 
351                 PromptAsyncContext* asyncContext = (PromptAsyncContext*)work->data;
352                 if (asyncContext == nullptr) {
353                     LOGE("%{public}s, asyncContext is nullptr.", __func__);
354                     delete work;
355                     work = nullptr;
356                     return;
357                 }
358 
359                 if (!asyncContext->valid) {
360                     LOGE("%{public}s, module exported object is invalid.", __func__);
361                     delete asyncContext;
362                     delete work;
363                     work = nullptr;
364                     return;
365                 }
366 
367                 napi_handle_scope scope = nullptr;
368                 napi_open_handle_scope(asyncContext->env, &scope);
369                 if (scope == nullptr) {
370                     LOGE("%{public}s, open handle scope failed.", __func__);
371                     delete asyncContext;
372                     delete work;
373                     work = nullptr;
374                     return;
375                 }
376 
377                 napi_value ret;
378                 napi_value successIndex = nullptr;
379                 napi_create_int32(asyncContext->env, asyncContext->successType, &successIndex);
380                 napi_value indexObj = nullptr;
381                 napi_create_object(asyncContext->env, &indexObj);
382                 napi_set_named_property(asyncContext->env, indexObj, "index", successIndex);
383                 napi_value result[2] = { 0 };
384                 napi_create_object(asyncContext->env, &result[1]);
385                 napi_set_named_property(asyncContext->env, result[1], "index", successIndex);
386                 bool dialogResult = true;
387                 switch (asyncContext->callbackType) {
388                     case 0:
389                         napi_get_undefined(asyncContext->env, &result[0]);
390                         dialogResult = true;
391                         break;
392                     case 1:
393                         napi_value message = nullptr;
394                         napi_create_string_utf8(asyncContext->env, "cancel", strlen("cancel"), &message);
395                         napi_create_error(asyncContext->env, nullptr, message, &result[0]);
396                         dialogResult = false;
397                         break;
398                 }
399                 if (asyncContext->deferred) {
400                     if (dialogResult) {
401                         napi_resolve_deferred(asyncContext->env, asyncContext->deferred, result[1]);
402                     } else {
403                         napi_reject_deferred(asyncContext->env, asyncContext->deferred, result[0]);
404                     }
405                 } else {
406                     napi_value callback = nullptr;
407                     napi_get_reference_value(asyncContext->env, asyncContext->callbackRef, &callback);
408                     napi_call_function(
409                         asyncContext->env, nullptr, callback, sizeof(result) / sizeof(result[0]), result, &ret);
410                     napi_delete_reference(asyncContext->env, asyncContext->callbackRef);
411                 }
412                 napi_delete_async_work(asyncContext->env, asyncContext->work);
413                 napi_close_handle_scope(asyncContext->env, scope);
414                 delete asyncContext;
415                 delete work;
416                 work = nullptr;
417             });
418         if (rev != 0) {
419             if (work != nullptr) {
420                 delete work;
421                 work = nullptr;
422             }
423         }
424     };
425 
426     napi_wrap(env, thisVar, (void*)asyncContext, [](napi_env env, void* data, void* hint) {
427         PromptAsyncContext* cbInfo = (PromptAsyncContext*)data;
428         if (cbInfo != nullptr) {
429             LOGE("%{public}s, thisVar JavaScript object is ready for garbage-collection.", __func__);
430             cbInfo->valid = false;
431         }
432     }, nullptr, nullptr);
433 #ifdef OHOS_STANDARD_SYSTEM
434     // NG
435     if (SystemProperties::GetExtSurfaceEnabled() || !ContainerIsService()) {
436         auto delegate = EngineHelper::GetCurrentDelegate();
437         if (delegate) {
438             delegate->ShowDialog(asyncContext->titleString, asyncContext->messageString, asyncContext->buttons,
439                 asyncContext->autoCancelBool, std::move(callBack), asyncContext->callbacks);
440         } else {
441             LOGE("delegate is null");
442             // throw internal error
443             napi_value code = nullptr;
444             std::string strCode = std::to_string(Framework::ERROR_CODE_INTERNAL_ERROR);
445             napi_create_string_utf8(env, strCode.c_str(), strCode.length(), &code);
446             napi_value msg = nullptr;
447             std::string strMsg = ErrorToMessage(Framework::ERROR_CODE_INTERNAL_ERROR) + "Can not get delegate.";
448             napi_create_string_utf8(env, strMsg.c_str(), strMsg.length(), &msg);
449             napi_value error = nullptr;
450             napi_create_error(env, code, msg, &error);
451 
452             if (asyncContext->deferred) {
453                 napi_reject_deferred(env, asyncContext->deferred, error);
454             } else {
455                 napi_value ret1;
456                 napi_value callback = nullptr;
457                 napi_get_reference_value(env, asyncContext->callbackRef, &callback);
458                 napi_call_function(env, nullptr, callback, 1, &error, &ret1);
459                 napi_delete_reference(env, asyncContext->callbackRef);
460             }
461         }
462     } else if (SubwindowManager::GetInstance() != nullptr) {
463         SubwindowManager::GetInstance()->ShowDialog(asyncContext->titleString, asyncContext->messageString,
464             asyncContext->buttons, asyncContext->autoCancelBool, std::move(callBack), asyncContext->callbacks);
465     }
466 #else
467     auto delegate = EngineHelper::GetCurrentDelegate();
468     if (delegate) {
469         delegate->ShowDialog(asyncContext->titleString, asyncContext->messageString,
470             asyncContext->buttons, asyncContext->autoCancelBool, std::move(callBack), asyncContext->callbacks);
471     } else {
472         LOGE("delegate is null");
473         // throw internal error
474         napi_value code = nullptr;
475         std::string strCode = std::to_string(Framework::ERROR_CODE_INTERNAL_ERROR);
476         napi_create_string_utf8(env, strCode.c_str(), strCode.length(), &code);
477         napi_value msg = nullptr;
478         std::string strMsg = ErrorToMessage(Framework::ERROR_CODE_INTERNAL_ERROR)
479             + "UI execution context not found.";
480         napi_create_string_utf8(env, strMsg.c_str(), strMsg.length(), &msg);
481         napi_value error = nullptr;
482         napi_create_error(env, code, msg, &error);
483 
484         if (asyncContext->deferred) {
485             napi_reject_deferred(env, asyncContext->deferred, error);
486         } else {
487             napi_value ret1;
488             napi_value callback = nullptr;
489             napi_get_reference_value(env, asyncContext->callbackRef, &callback);
490             napi_call_function(env, nullptr, callback, 1, &error, &ret1);
491             napi_delete_reference(env, asyncContext->callbackRef);
492         }
493     }
494 #endif
495     return result;
496 }
497 
498 struct ShowActionMenuAsyncContext {
499     napi_env env = nullptr;
500     napi_async_work work = nullptr;
501     napi_value titleNApi = nullptr;
502     napi_value buttonsNApi = nullptr;
503     napi_ref callbackSuccess = nullptr;
504     napi_ref callbackFail = nullptr;
505     napi_ref callbackComplete = nullptr;
506     std::string titleString;
507     std::vector<ButtonInfo> buttons;
508     std::string callbackSuccessString;
509     std::string callbackFailString;
510     std::string callbackCompleteString;
511     napi_deferred deferred = nullptr;
512     napi_ref callbackRef = nullptr;
513     int32_t callbackType = -1;
514     int32_t successType = -1;
515     bool valid = true;
516 };
517 
JSPromptShowActionMenu(napi_env env,napi_callback_info info)518 static napi_value JSPromptShowActionMenu(napi_env env, napi_callback_info info)
519 {
520     size_t requireArgc = 1;
521     size_t argc = 2;
522     napi_value argv[3] = { 0 };
523     napi_value thisVar = nullptr;
524     void* data = nullptr;
525     napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
526     if (argc < requireArgc) {
527         NapiThrow(env, "The number of parameters must be greater than or equal to 1.",
528             Framework::ERROR_CODE_PARAM_INVALID);
529         return nullptr;
530     }
531     if (thisVar == nullptr) {
532         LOGE("%{public}s, This argument is nullptr.", __func__);
533         return nullptr;
534     }
535     napi_valuetype valueTypeOfThis = napi_undefined;
536     napi_typeof(env, thisVar, &valueTypeOfThis);
537     if (valueTypeOfThis == napi_undefined) {
538         LOGE("%{public}s, Wrong this value.", __func__);
539         return nullptr;
540     }
541 
542     auto asyncContext = new ShowActionMenuAsyncContext();
543     asyncContext->env = env;
544     for (size_t i = 0; i < argc; i++) {
545         size_t ret = 0;
546         napi_valuetype valueType = napi_undefined;
547         napi_typeof(env, argv[i], &valueType);
548         if (i == 0) {
549             if (valueType != napi_object) {
550                 delete asyncContext;
551                 asyncContext = nullptr;
552                 NapiThrow(env, "The type of parameters is incorrect.", Framework::ERROR_CODE_PARAM_INVALID);
553                 return nullptr;
554             }
555             napi_get_named_property(env, argv[0], "title", &asyncContext->titleNApi);
556             napi_get_named_property(env, argv[0], "buttons", &asyncContext->buttonsNApi);
557             GetNapiString(env, asyncContext->titleNApi, asyncContext->titleString);
558             bool isBool = false;
559             napi_is_array(env, asyncContext->buttonsNApi, &isBool);
560             napi_typeof(env, asyncContext->buttonsNApi, &valueType);
561             if (valueType == napi_object && isBool) {
562                 uint32_t buttonsLen = 0;
563                 napi_value buttonArray = nullptr;
564                 napi_value textNApi = nullptr;
565                 napi_value colorNApi = nullptr;
566                 uint32_t index = 0;
567                 napi_get_array_length(env, asyncContext->buttonsNApi, &buttonsLen);
568                 uint32_t buttonsLenInt = buttonsLen;
569                 if (buttonsLenInt > SHOW_ACTION_MENU_BUTTON_NUM_MAX) {
570                     buttonsLenInt = SHOW_ACTION_MENU_BUTTON_NUM_MAX;
571                     LOGE("Supports 1 - 6 buttons");
572                 }
573                 for (uint32_t j = 0; j < buttonsLenInt; j++) {
574                     napi_get_element(env, asyncContext->buttonsNApi, index, &buttonArray);
575                     index++;
576                     napi_get_named_property(env, buttonArray, "text", &textNApi);
577                     napi_get_named_property(env, buttonArray, "color", &colorNApi);
578                     std::string textString;
579                     std::string colorString;
580                     napi_typeof(env, textNApi, &valueType);
581                     if (valueType == napi_string) {
582                         size_t textLen = GetParamLen(textNApi) + 1;
583                         std::unique_ptr<char[]> text = std::make_unique<char[]>(textLen + 1);
584                         napi_get_value_string_utf8(env, textNApi, text.get(), textLen, &ret);
585                         textString = text.get();
586                     } else if (valueType == napi_object) {
587                         int32_t id = 0;
588                         int32_t type = 0;
589                         std::vector<std::string> params;
590                         if (ParseResourceParam(env, textNApi, id, type, params)) {
591                             ParseString(id, type, params, textString);
592                         }
593                     } else {
594                         delete asyncContext;
595                         asyncContext = nullptr;
596                         if (valueType == napi_undefined) {
597                             NapiThrow(
598                                 env, "Required input parameters are missing.", Framework::ERROR_CODE_PARAM_INVALID);
599                         } else {
600                             NapiThrow(env, "The type of the button text parameter is incorrect.",
601                                 Framework::ERROR_CODE_PARAM_INVALID);
602                         }
603                         return nullptr;
604                     }
605                     napi_typeof(env, colorNApi, &valueType);
606                     if (valueType == napi_string) {
607                         size_t colorLen = GetParamLen(colorNApi) + 1;
608                         char color[colorLen + 1];
609                         napi_get_value_string_utf8(env, colorNApi, color, colorLen, &ret);
610                         colorString = color;
611                     } else if (valueType == napi_object) {
612                         int32_t id = 0;
613                         int32_t type = 0;
614                         std::vector<std::string> params;
615                         if (ParseResourceParam(env, colorNApi, id, type, params)) {
616                             ParseString(id, type, params, colorString);
617                         }
618                     } else if (valueType == napi_undefined) {
619                         colorString = DEFAULT_FONT_COLOR_STRING_VALUE;
620                     } else {
621                         delete asyncContext;
622                         asyncContext = nullptr;
623                         NapiThrow(env, "The type of the button color parameter is incorrect.",
624                             Framework::ERROR_CODE_PARAM_INVALID);
625                         return nullptr;
626                     }
627                     ButtonInfo buttonInfo = { .text = textString, .textColor = colorString };
628                     asyncContext->buttons.emplace_back(buttonInfo);
629                 }
630             } else {
631                 delete asyncContext;
632                 asyncContext = nullptr;
633                 if (valueType == napi_undefined) {
634                     NapiThrow(env, "Required input parameters are missing.", Framework::ERROR_CODE_PARAM_INVALID);
635                 } else {
636                     NapiThrow(
637                         env, "The type of the button parameters is incorrect.", Framework::ERROR_CODE_PARAM_INVALID);
638                 }
639                 return nullptr;
640             }
641         } else if (valueType == napi_function) {
642             napi_create_reference(env, argv[i], 1, &asyncContext->callbackRef);
643         } else {
644             delete asyncContext;
645             asyncContext = nullptr;
646             NapiThrow(env, "The type of parameters is incorrect.", Framework::ERROR_CODE_PARAM_INVALID);
647             return nullptr;
648         }
649     }
650     napi_value result = nullptr;
651     if (asyncContext->callbackRef == nullptr) {
652         napi_create_promise(env, &asyncContext->deferred, &result);
653     } else {
654         napi_get_undefined(env, &result);
655     }
656 
657     auto callBack = [asyncContext](int32_t callbackType, int32_t successType) {
658         uv_loop_s* loop = nullptr;
659         if (asyncContext == nullptr) {
660             return;
661         }
662 
663         asyncContext->callbackType = callbackType;
664         asyncContext->successType = successType;
665         napi_get_uv_event_loop(asyncContext->env, &loop);
666         uv_work_t* work = new uv_work_t;
667         work->data = (void*)asyncContext;
668         int rev = uv_queue_work(
669             loop, work, [](uv_work_t* work) {},
670             [](uv_work_t* work, int status) {
671                 if (work == nullptr) {
672                     return;
673                 }
674 
675                 ShowActionMenuAsyncContext* asyncContext = (ShowActionMenuAsyncContext*)work->data;
676                 if (asyncContext == nullptr) {
677                     LOGE("%{public}s, asyncContext is nullptr.", __func__);
678                     delete work;
679                     work = nullptr;
680                     return;
681                 }
682 
683                 if (!asyncContext->valid) {
684                     LOGE("%{public}s, module exported object is invalid.", __func__);
685                     delete asyncContext;
686                     delete work;
687                     work = nullptr;
688                     return;
689                 }
690 
691                 napi_handle_scope scope = nullptr;
692                 napi_open_handle_scope(asyncContext->env, &scope);
693                 if (scope == nullptr) {
694                     LOGE("%{public}s, open handle scope failed.", __func__);
695                     delete asyncContext;
696                     delete work;
697                     work = nullptr;
698                     return;
699                 }
700 
701                 napi_value ret;
702                 napi_value successIndex = nullptr;
703                 napi_create_int32(asyncContext->env, asyncContext->successType, &successIndex);
704                 asyncContext->callbackSuccessString = "showActionMenu:ok";
705                 napi_value indexObj = GetReturnObject(asyncContext->env, asyncContext->callbackSuccessString);
706                 napi_set_named_property(asyncContext->env, indexObj, "index", successIndex);
707                 napi_value result[2] = { 0 };
708                 napi_create_object(asyncContext->env, &result[1]);
709                 napi_set_named_property(asyncContext->env, result[1], "index", successIndex);
710                 bool dialogResult = true;
711                 switch (asyncContext->callbackType) {
712                     case 0:
713                         napi_get_undefined(asyncContext->env, &result[0]);
714                         dialogResult = true;
715                         break;
716                     case 1:
717                         napi_value message = nullptr;
718                         napi_create_string_utf8(asyncContext->env, "cancel", strlen("cancel"), &message);
719                         napi_create_error(asyncContext->env, nullptr, message, &result[0]);
720                         dialogResult = false;
721                         break;
722                 }
723                 if (asyncContext->deferred) {
724                     if (dialogResult) {
725                         napi_resolve_deferred(asyncContext->env, asyncContext->deferred, result[1]);
726                     } else {
727                         napi_reject_deferred(asyncContext->env, asyncContext->deferred, result[0]);
728                     }
729                 } else {
730                     napi_value callback = nullptr;
731                     napi_get_reference_value(asyncContext->env, asyncContext->callbackRef, &callback);
732                     napi_call_function(
733                         asyncContext->env, nullptr, callback, sizeof(result) / sizeof(result[0]), result, &ret);
734                     napi_delete_reference(asyncContext->env, asyncContext->callbackRef);
735                 }
736                 napi_delete_async_work(asyncContext->env, asyncContext->work);
737                 napi_close_handle_scope(asyncContext->env, scope);
738                 delete asyncContext;
739                 delete work;
740                 work = nullptr;
741             });
742         if (rev != 0) {
743             if (work != nullptr) {
744                 delete work;
745                 work = nullptr;
746             }
747         }
748     };
749 
750     napi_wrap(env, thisVar, (void*)asyncContext, [](napi_env env, void* data, void* hint) {
751         ShowActionMenuAsyncContext* cbInfo = (ShowActionMenuAsyncContext*)data;
752         if (cbInfo != nullptr) {
753             LOGE("%{public}s, thisVar JavaScript object is ready for garbage-collection.", __func__);
754             cbInfo->valid = false;
755         }
756     }, nullptr, nullptr);
757 #ifdef OHOS_STANDARD_SYSTEM
758     if (SystemProperties::GetExtSurfaceEnabled() || !ContainerIsService()) {
759         auto delegate = EngineHelper::GetCurrentDelegate();
760         if (delegate) {
761             delegate->ShowActionMenu(asyncContext->titleString, asyncContext->buttons, std::move(callBack));
762         } else {
763             LOGE("delegate is null");
764             napi_value code = nullptr;
765             std::string strCode = std::to_string(Framework::ERROR_CODE_INTERNAL_ERROR);
766             napi_create_string_utf8(env, strCode.c_str(), strCode.length(), &code);
767             napi_value msg = nullptr;
768             std::string strMsg = ErrorToMessage(Framework::ERROR_CODE_INTERNAL_ERROR) + "Can not get delegate.";
769             napi_create_string_utf8(env, strMsg.c_str(), strMsg.length(), &msg);
770             napi_value error = nullptr;
771             napi_create_error(env, code, msg, &error);
772 
773             if (asyncContext->deferred) {
774                 napi_reject_deferred(env, asyncContext->deferred, error);
775             } else {
776                 napi_value ret1;
777                 napi_value callback = nullptr;
778                 napi_get_reference_value(env, asyncContext->callbackRef, &callback);
779                 napi_call_function(env, nullptr, callback, 1, &error, &ret1);
780                 napi_delete_reference(env, asyncContext->callbackRef);
781             }
782         }
783     } else if (SubwindowManager::GetInstance() != nullptr) {
784         SubwindowManager::GetInstance()->ShowActionMenu(
785             asyncContext->titleString, asyncContext->buttons, std::move(callBack));
786     }
787 #else
788     auto delegate = EngineHelper::GetCurrentDelegate();
789     if (delegate) {
790         delegate->ShowActionMenu(asyncContext->titleString, asyncContext->buttons, std::move(callBack));
791     } else {
792         LOGE("delegate is null");
793         napi_value code = nullptr;
794         std::string strCode = std::to_string(Framework::ERROR_CODE_INTERNAL_ERROR);
795         napi_create_string_utf8(env, strCode.c_str(), strCode.length(), &code);
796         napi_value msg = nullptr;
797         std::string strMsg = ErrorToMessage(Framework::ERROR_CODE_INTERNAL_ERROR)
798             + "UI execution context not found.";
799         napi_create_string_utf8(env, strMsg.c_str(), strMsg.length(), &msg);
800         napi_value error = nullptr;
801         napi_create_error(env, code, msg, &error);
802 
803         if (asyncContext->deferred) {
804             napi_reject_deferred(env, asyncContext->deferred, error);
805         } else {
806             napi_value ret1;
807             napi_value callback = nullptr;
808             napi_get_reference_value(env, asyncContext->callbackRef, &callback);
809             napi_call_function(env, nullptr, callback, 1, &error, &ret1);
810             napi_delete_reference(env, asyncContext->callbackRef);
811         }
812     }
813 #endif
814     return result;
815 }
816 
PromptExport(napi_env env,napi_value exports)817 static napi_value PromptExport(napi_env env, napi_value exports)
818 {
819     napi_property_descriptor promptDesc[] = {
820         DECLARE_NAPI_FUNCTION("showToast", JSPromptShowToast),
821         DECLARE_NAPI_FUNCTION("showDialog", JSPromptShowDialog),
822         DECLARE_NAPI_FUNCTION("showActionMenu", JSPromptShowActionMenu),
823     };
824     NAPI_CALL(env, napi_define_properties(env, exports, sizeof(promptDesc) / sizeof(promptDesc[0]), promptDesc));
825     return exports;
826 }
827 
828 static napi_module promptModule = {
829     .nm_version = 1,
830     .nm_flags = 0,
831     .nm_filename = nullptr,
832     .nm_register_func = PromptExport,
833     .nm_modname = "prompt",
834     .nm_priv = ((void*)0),
835     .reserved = { 0 },
836 };
837 
838 static napi_module promptActionModule = {
839     .nm_version = 1,
840     .nm_flags = 0,
841     .nm_filename = nullptr,
842     .nm_register_func = PromptExport,
843     .nm_modname = "promptAction",
844     .nm_priv = ((void*)0),
845     .reserved = { 0 },
846 };
847 
PromptRegister()848 extern "C" __attribute__((constructor)) void PromptRegister()
849 {
850     napi_module_register(&promptModule);
851     napi_module_register(&promptActionModule);
852 }
853 
854 } // namespace OHOS::Ace::Napi
855