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