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