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