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 <cstddef>
17 #include <cstdint>
18 #include <cstring>
19 #include <optional>
20
21 #include "interfaces/napi/kits/utils/napi_utils.h"
22 #include "js_native_api.h"
23 #include "js_native_api_types.h"
24 #include "napi/native_common.h"
25 #include "native_value.h"
26 #include "node_api.h"
27
28 #if defined(ENABLE_DRAG_FRAMEWORK) && defined(PIXEL_MAP_SUPPORTED)
29 #include "jsnapi.h"
30 #include "pixel_map.h"
31 #include "pixel_map_napi.h"
32
33 #include "base/log/log_wrapper.h"
34 #include "base/memory/referenced.h"
35 #include "base/msdp/device_status/interfaces/innerkits/interaction/include/interaction_manager.h"
36 #include "bridge/common/utils/utils.h"
37 #include "bridge/declarative_frontend/engine/functions/js_drag_function.h"
38 #include "bridge/declarative_frontend/engine/jsi/jsi_declarative_engine.h"
39 #include "bridge/js_frontend/engine/jsi/ark_js_runtime.h"
40 #include "core/common/ace_engine.h"
41 #include "core/common/udmf/udmf_client.h"
42 #include "core/event/ace_events.h"
43 #include "core/gestures/gesture_info.h"
44 #include "frameworks/bridge/common/utils/engine_helper.h"
45 #endif
46
47 namespace OHOS::Ace::Napi {
48 #if defined(ENABLE_DRAG_FRAMEWORK) && defined(PIXEL_MAP_SUPPORTED)
49 namespace {
50 constexpr float PIXELMAP_WIDTH_RATE = -0.5f;
51 constexpr float PIXELMAP_HEIGHT_RATE = -0.2f;
52
53 constexpr int32_t argCount2 = 2;
54 constexpr int32_t argCount3 = 3;
55
56 using DragNotifyMsg = Msdp::DeviceStatus::DragNotifyMsg;
57 using OnDragCallback = std::function<void(const DragNotifyMsg&)>;
58 using StopDragCallback = std::function<void()>;
59 using PixelMapNapiEntry = void* (*)(void*, void*);
60
61 enum class DragState { PENDING, SENDING, REJECT, SUCCESS };
62
63 // the context of drag controller
64 struct DragControllerAsyncCtx {
65 napi_env env = nullptr;
66 size_t argc = 3;
67 napi_value argv[3] { nullptr };
68 napi_ref callbackRef = nullptr;
69 napi_deferred deferred = nullptr;
70 std::shared_ptr<Media::PixelMap> pixmap = nullptr;
71 napi_value customBuilder;
72 int32_t pointerId = -1;
73 RefPtr<OHOS::Ace::UnifiedData> unifiedData;
74 std::string extraParams;
75 int32_t instanceId = -1;
76 int32_t errCode = -1;
77 std::mutex mutex;
78 bool hasHandle = false;
79 int32_t globalX = -1;
80 int32_t globalY = -1;
81 int32_t sourceType = 0;
82 std::mutex dragStateMutex;
83 DragState dragState = DragState::PENDING;
84 };
85 } // namespace
86
CreateCallbackErrorValue(napi_env env,int32_t errCode)87 napi_value CreateCallbackErrorValue(napi_env env, int32_t errCode)
88 {
89 napi_value jsObject = nullptr;
90 napi_value jsValue = nullptr;
91 NAPI_CALL(env, napi_create_int32(env, errCode, &jsValue));
92 NAPI_CALL(env, napi_create_object(env, &jsObject));
93 NAPI_CALL(env, napi_set_named_property(env, jsObject, "code", jsValue));
94 return jsObject;
95 }
96
HandleSuccess(DragControllerAsyncCtx * asyncCtx,const DragNotifyMsg & dragNotifyMsg)97 void HandleSuccess(DragControllerAsyncCtx* asyncCtx, const DragNotifyMsg& dragNotifyMsg)
98 {
99 if (!asyncCtx) {
100 LOGE("DragControllerAsyncContext is null");
101 return;
102 }
103 bool hasHandle = false;
104 {
105 std::lock_guard<std::mutex> lock(asyncCtx->mutex);
106 hasHandle = asyncCtx->hasHandle;
107 asyncCtx->hasHandle = true;
108 }
109 if (hasHandle) {
110 return;
111 }
112 auto container = AceEngine::Get().GetContainer(asyncCtx->instanceId);
113 if (!container) {
114 LOGW("container is null. %{public}d", asyncCtx->instanceId);
115 return;
116 }
117 auto taskExecutor = container->GetTaskExecutor();
118 if (!taskExecutor) {
119 LOGW("taskExecutor is null.");
120 return;
121 }
122 taskExecutor->PostSyncTask(
123 [asyncCtx, dragNotifyMsg]() {
124 // callback result format: {DragEvent, ExtraParams}
125 if (!asyncCtx) {
126 LOGE("DragControllerAsyncContext is null");
127 return;
128 }
129 napi_value result[2] = { nullptr };
130 napi_get_undefined(asyncCtx->env, &result[1]);
131 auto resultCode = dragNotifyMsg.result;
132 LOGI("resultCode = %{public}d", static_cast<int32_t>(resultCode));
133 // do success thing
134 napi_create_object(asyncCtx->env, &result[1]);
135 napi_value eventNapi = nullptr;
136 napi_value globalObj = nullptr;
137 napi_value customDragEvent = nullptr;
138 napi_create_object(asyncCtx->env, &customDragEvent);
139 napi_get_global(asyncCtx->env, &globalObj);
140 if (!globalObj) {
141 LOGE("globalObj is null");
142 return;
143 }
144 napi_get_named_property(asyncCtx->env, globalObj, "DragEvent", &customDragEvent);
145 if (!customDragEvent) {
146 LOGE("customDragEvent is null");
147 return;
148 }
149 napi_status status = napi_new_instance(asyncCtx->env, customDragEvent, 0, nullptr, &eventNapi);
150 if (status != napi_ok) {
151 LOGE("status = %{public}d", status);
152 return;
153 }
154 auto* nativeValue = reinterpret_cast<NativeValue*>(eventNapi);
155 panda::CopyableGlobal<JSValueRef> globalRef = *nativeValue;
156 auto localRef = globalRef.ToLocal();
157 if (localRef->IsNull()) {
158 LOGE("localRef is null");
159 return;
160 }
161 auto* jsDragEvent =
162 static_cast<Framework::JsDragEvent*>(Local<panda::ObjectRef>(localRef)->GetNativePointerField(0));
163 if (!jsDragEvent) {
164 LOGE("jsDragEvent is null");
165 return;
166 }
167 auto dragEvent = AceType::MakeRefPtr<DragEvent>();
168 if (!dragEvent) {
169 LOGE("dragEvent is null");
170 return;
171 }
172 dragEvent->SetResult(static_cast<DragRet>(resultCode));
173 jsDragEvent->SetDragEvent(dragEvent);
174 status = napi_set_named_property(asyncCtx->env, result[1], "event", eventNapi);
175
176 napi_value extraParamsNapi = nullptr;
177 napi_create_string_utf8(
178 asyncCtx->env, asyncCtx->extraParams.c_str(), asyncCtx->extraParams.length(), &extraParamsNapi);
179 napi_set_named_property(asyncCtx->env, result[1], "extraParams", extraParamsNapi);
180 if (asyncCtx->callbackRef) {
181 napi_value ret = nullptr;
182 napi_value napiCallback = nullptr;
183 napi_get_reference_value(asyncCtx->env, asyncCtx->callbackRef, &napiCallback);
184 result[0] = CreateCallbackErrorValue(asyncCtx->env, 0);
185 napi_call_function(asyncCtx->env, nullptr, napiCallback, argCount2, result, &ret);
186 napi_delete_reference(asyncCtx->env, asyncCtx->callbackRef);
187 } else {
188 napi_resolve_deferred(asyncCtx->env, asyncCtx->deferred, result[1]);
189 }
190 },
191 TaskExecutor::TaskType::JS);
192 }
193
HandleFail(DragControllerAsyncCtx * asyncCtx,int32_t errorCode)194 void HandleFail(DragControllerAsyncCtx* asyncCtx, int32_t errorCode)
195 {
196 if (!asyncCtx) {
197 LOGE("DragControllerAsyncContext is null");
198 return;
199 }
200 bool hasHandle = false;
201 {
202 std::lock_guard<std::mutex> lock(asyncCtx->mutex);
203 hasHandle = asyncCtx->hasHandle;
204 asyncCtx->hasHandle = true;
205 }
206 if (hasHandle) {
207 return;
208 }
209 napi_value result[2] = { nullptr };
210 result[0] = CreateCallbackErrorValue(asyncCtx->env, errorCode);
211 if (asyncCtx->callbackRef) {
212 napi_value ret = nullptr;
213 napi_value napiCallback = nullptr;
214 napi_get_reference_value(asyncCtx->env, asyncCtx->callbackRef, &napiCallback);
215 napi_create_object(asyncCtx->env, &result[1]);
216 napi_call_function(asyncCtx->env, nullptr, napiCallback, argCount2, result, &ret);
217 napi_delete_reference(asyncCtx->env, asyncCtx->callbackRef);
218 } else {
219 napi_reject_deferred(asyncCtx->env, asyncCtx->deferred, result[0]);
220 }
221 }
222
OnComplete(DragControllerAsyncCtx * asyncCtx)223 void OnComplete(DragControllerAsyncCtx* asyncCtx)
224 {
225 auto container = AceEngine::Get().GetContainer(asyncCtx->instanceId);
226 if (!container) {
227 LOGW("container is null. %{public}d", asyncCtx->instanceId);
228 return;
229 }
230 auto taskExecutor = container->GetTaskExecutor();
231 if (!taskExecutor) {
232 LOGW("taskExecutor is null.");
233 return;
234 }
235 taskExecutor->PostTask(
236 [asyncCtx]() {
237 if (!asyncCtx) {
238 LOGE("DragControllerAsyncContext is null");
239 return;
240 }
241 DragState dragState = DragState::PENDING;
242 {
243 std::lock_guard<std::mutex> lock(asyncCtx->dragStateMutex);
244 if (asyncCtx->dragState == DragState::PENDING) {
245 asyncCtx->dragState = DragState::SENDING;
246 }
247 dragState = asyncCtx->dragState;
248 }
249 if (dragState == DragState::REJECT) {
250 napi_handle_scope scope = nullptr;
251 napi_open_handle_scope(asyncCtx->env, &scope);
252 HandleFail(asyncCtx, -1);
253 napi_close_handle_scope(asyncCtx->env, scope);
254 return;
255 }
256 if (!asyncCtx->pixmap) {
257 LOGE("The pixmap is null");
258 return;
259 }
260 int32_t dataSize = 1;
261 auto pointerId = asyncCtx->pointerId;
262 std::string udKey;
263 if (asyncCtx->unifiedData) {
264 int32_t ret = UdmfClient::GetInstance()->SetData(asyncCtx->unifiedData, udKey);
265 if (ret != 0) {
266 LOGW("Udmf set data fail, error code is %{public}d", ret);
267 }
268 dataSize = static_cast<int32_t>(asyncCtx->unifiedData->GetSize());
269 }
270 int32_t width = asyncCtx->pixmap->GetWidth();
271 int32_t height = asyncCtx->pixmap->GetHeight();
272
273 Msdp::DeviceStatus::DragData dragData { { asyncCtx->pixmap, width * PIXELMAP_WIDTH_RATE,
274 height * PIXELMAP_HEIGHT_RATE },
275 {}, udKey, asyncCtx->sourceType, dataSize, pointerId, asyncCtx->globalX, asyncCtx->globalY, 0, true };
276
277 OnDragCallback callback = [asyncCtx](const DragNotifyMsg& dragNotifyMsg) {
278 napi_handle_scope scope = nullptr;
279 napi_open_handle_scope(asyncCtx->env, &scope);
280 HandleSuccess(asyncCtx, dragNotifyMsg);
281 napi_close_handle_scope(asyncCtx->env, scope);
282 };
283
284 int32_t ret = Msdp::DeviceStatus::InteractionManager::GetInstance()->StartDrag(dragData, callback);
285 if (ret != 0) {
286 LOGE("drag start error");
287 napi_handle_scope scope = nullptr;
288 napi_open_handle_scope(asyncCtx->env, &scope);
289 HandleFail(asyncCtx, ret);
290 napi_close_handle_scope(asyncCtx->env, scope);
291 return;
292 }
293 LOGI("drag start success");
294 {
295 std::lock_guard<std::mutex> lock(asyncCtx->dragStateMutex);
296 if (asyncCtx->dragState == DragState::SENDING) {
297 asyncCtx->dragState = DragState::SUCCESS;
298 Msdp::DeviceStatus::InteractionManager::GetInstance()->SetDragWindowVisible(true);
299 }
300 }
301 },
302 TaskExecutor::TaskType::JS);
303 }
304
ParseDragItemInfoParam(DragControllerAsyncCtx * asyncCtx,std::string & errMsg)305 bool ParseDragItemInfoParam(DragControllerAsyncCtx* asyncCtx, std::string& errMsg)
306 {
307 if (!asyncCtx) {
308 LOGE("DragControllerAsyncContext is null");
309 errMsg = "DragControllerAsyncContext is null";
310 return false;
311 }
312 napi_valuetype valueType = napi_undefined;
313 napi_typeof(asyncCtx->env, asyncCtx->argv[0], &valueType);
314 if (valueType == napi_function) {
315 asyncCtx->customBuilder = asyncCtx->argv[0];
316 return true;
317 }
318
319 if (valueType != napi_object) {
320 errMsg = "The type of first parameter is incorrect.";
321 return false;
322 }
323 // Parse the DragItemInfo
324 napi_value pixelMapValue;
325 napi_get_named_property(asyncCtx->env, asyncCtx->argv[0], "pixelMap", &pixelMapValue);
326 PixelMapNapiEntry pixelMapNapiEntry = Framework::JsEngine::GetPixelMapNapiEntry();
327 if (pixelMapNapiEntry == nullptr) {
328 LOGW("Failed to parse pixelMap from the first argument.");
329 } else {
330 void* pixmapPtrAddr = pixelMapNapiEntry(asyncCtx->env, pixelMapValue);
331 if (pixmapPtrAddr == nullptr) {
332 LOGW("The pixelMap parsed from the first argument is null");
333 } else {
334 asyncCtx->pixmap = *(reinterpret_cast<std::shared_ptr<Media::PixelMap>*>(pixmapPtrAddr));
335 }
336 }
337
338 napi_get_named_property(asyncCtx->env, asyncCtx->argv[0], "builder", &(asyncCtx->customBuilder));
339 napi_typeof(asyncCtx->env, asyncCtx->customBuilder, &valueType);
340 if (valueType != napi_function) {
341 errMsg = "The type of customBuilder of the first parameter is incorrect.";
342 return false;
343 }
344
345 napi_value extraInfoValue;
346 napi_get_named_property(asyncCtx->env, asyncCtx->argv[0], "extraInfo", &extraInfoValue);
347 napi_typeof(asyncCtx->env, extraInfoValue, &valueType);
348 if (valueType != napi_string) {
349 errMsg = "The type of extraInfo of the first parameter is incorrect.";
350 return false;
351 }
352 GetNapiString(asyncCtx->env, extraInfoValue, asyncCtx->extraParams, valueType);
353 return true;
354 }
355
ParseDragInfoParam(DragControllerAsyncCtx * asyncCtx,std::string & errMsg)356 bool ParseDragInfoParam(DragControllerAsyncCtx* asyncCtx, std::string& errMsg)
357 {
358 if (!asyncCtx) {
359 LOGE("DragControllerAsyncContext is null");
360 errMsg = "DragControllerAsyncContext is null";
361 return false;
362 }
363 napi_valuetype valueType = napi_undefined;
364 napi_typeof(asyncCtx->env, asyncCtx->argv[1], &valueType);
365 if (valueType != napi_object) {
366 errMsg = "The type of second parameter is incorrect.";
367 return false;
368 }
369 napi_value pointerIdNApi = nullptr;
370 napi_status status = napi_ok;
371 napi_get_named_property(asyncCtx->env, asyncCtx->argv[1], "pointerId", &pointerIdNApi);
372 napi_typeof(asyncCtx->env, pointerIdNApi, &valueType);
373 if (valueType != napi_number) {
374 errMsg = "pointerId which type is number must be given";
375 return false;
376 }
377 status = napi_get_value_int32(asyncCtx->env, pointerIdNApi, &asyncCtx->pointerId);
378 if (status != napi_ok) {
379 errMsg = "parse pointerId fail";
380 return false;
381 }
382
383 napi_value dataNApi = nullptr;
384 napi_get_named_property(asyncCtx->env, asyncCtx->argv[1], "data", &dataNApi);
385 napi_typeof(asyncCtx->env, dataNApi, &valueType);
386 if (valueType == napi_object) {
387 auto* nativeValue = reinterpret_cast<NativeValue*>(dataNApi);
388 if (!nativeValue) {
389 errMsg = "parse data fail";
390 return false;
391 }
392 asyncCtx->unifiedData = UdmfClient::GetInstance()->TransformUnifiedData(nativeValue);
393 } else if (valueType != napi_undefined) {
394 errMsg = "data's type is wrong";
395 return false;
396 }
397
398 napi_value extraParamsNApi = nullptr;
399 napi_get_named_property(asyncCtx->env, asyncCtx->argv[1], "extraParams", &extraParamsNApi);
400 napi_typeof(asyncCtx->env, extraParamsNApi, &valueType);
401 if (valueType == napi_string) {
402 GetNapiString(asyncCtx->env, extraParamsNApi, asyncCtx->extraParams, valueType);
403 } else if (valueType != napi_undefined) {
404 errMsg = "extraParams's type is wrong";
405 return false;
406 }
407 return true;
408 }
409
CheckAndParseParams(DragControllerAsyncCtx * asyncCtx,std::string & errMsg)410 bool CheckAndParseParams(DragControllerAsyncCtx* asyncCtx, std::string& errMsg)
411 {
412 // Check the number of the argument
413 if (!asyncCtx) {
414 LOGE("DragControllerAsyncContext is null");
415 errMsg = "DragControllerAsyncContext is null";
416 return false;
417 }
418 if ((asyncCtx->argc != argCount2) && (asyncCtx->argc != argCount3)) {
419 errMsg = "The number of parameters must be 2 or 3.";
420 return false;
421 }
422
423 // Check and parse the first parameter
424 if (!ParseDragItemInfoParam(asyncCtx, errMsg)) {
425 return false;
426 }
427
428 // Check and parse the second parameter
429 return ParseDragInfoParam(asyncCtx, errMsg);
430 }
431
CreateCallback(DragControllerAsyncCtx * asyncCtx,napi_value * result)432 void CreateCallback(DragControllerAsyncCtx* asyncCtx, napi_value* result)
433 {
434 if (!asyncCtx) {
435 LOGE("DragControllerAsyncContext is null");
436 return;
437 }
438 if (asyncCtx->argc == argCount3) {
439 // Create the JsCallback
440 napi_create_reference(asyncCtx->env, asyncCtx->argv[2], 1, &asyncCtx->callbackRef);
441 }
442 if (!asyncCtx->callbackRef) {
443 // Create the promise
444 napi_create_promise(asyncCtx->env, &asyncCtx->deferred, result);
445 } else {
446 napi_get_undefined(asyncCtx->env, result);
447 }
448 }
449
InitializeDragControllerCtx(napi_env env,napi_callback_info info,DragControllerAsyncCtx * asyncCtx)450 void InitializeDragControllerCtx(napi_env env, napi_callback_info info, DragControllerAsyncCtx* asyncCtx)
451 {
452 if (!asyncCtx) {
453 LOGE("DragControllerAsyncContext is null");
454 return;
455 }
456 napi_value thisVar = nullptr;
457 void* data = nullptr;
458 asyncCtx->instanceId = Container::CurrentId();
459 asyncCtx->env = env;
460 // get arguments from JS
461 napi_get_cb_info(asyncCtx->env, info, &(asyncCtx->argc), asyncCtx->argv, &thisVar, &data);
462 }
463
JSExecuteDrag(napi_env env,napi_callback_info info)464 static napi_value JSExecuteDrag(napi_env env, napi_callback_info info)
465 {
466 napi_escapable_handle_scope scope = nullptr;
467 napi_open_escapable_handle_scope(env, &scope);
468
469 auto* asyncCtx = new DragControllerAsyncCtx();
470 InitializeDragControllerCtx(env, info, asyncCtx);
471
472 std::string errMsg;
473 if (!CheckAndParseParams(asyncCtx, errMsg)) {
474 NapiThrow(asyncCtx->env, errMsg, Framework::ERROR_CODE_INTERNAL_ERROR);
475 return nullptr;
476 }
477
478 napi_value result = nullptr;
479 CreateCallback(asyncCtx, &result);
480 auto container = AceEngine::Get().GetContainer(asyncCtx->instanceId);
481 if (!container) {
482 NapiThrow(asyncCtx->env, "container is null", Framework::ERROR_CODE_INTERNAL_ERROR);
483 return nullptr;
484 }
485 StopDragCallback stopDragCallback = [asyncCtx, container]() {
486 if (!asyncCtx) {
487 LOGE("DragControllerAsyncContext is null");
488 return;
489 }
490 if (!container) {
491 LOGE("container is null");
492 return;
493 }
494 bool needPostStopDrag = false;
495 {
496 std::lock_guard<std::mutex> lock(asyncCtx->dragStateMutex);
497 needPostStopDrag = (asyncCtx->dragState == DragState::SENDING);
498 asyncCtx->dragState = DragState::REJECT;
499 }
500 if (needPostStopDrag) {
501 auto taskExecutor = container->GetTaskExecutor();
502 if (!taskExecutor) {
503 LOGE("taskExecutor is null.");
504 return;
505 }
506 taskExecutor->PostTask(
507 [asyncCtx]() {
508 if (!asyncCtx) {
509 LOGE("DragControllerAsyncContext is null");
510 return;
511 }
512 napi_handle_scope scope = nullptr;
513 napi_open_handle_scope(asyncCtx->env, &scope);
514 HandleFail(asyncCtx, -1);
515 napi_close_handle_scope(asyncCtx->env, scope);
516 Msdp::DeviceStatus::InteractionManager::GetInstance()->StopDrag(
517 Msdp::DeviceStatus::DragResult::DRAG_CANCEL, false);
518 Msdp::DeviceStatus::InteractionManager::GetInstance()->SetDragWindowVisible(false);
519 },
520 TaskExecutor::TaskType::JS);
521 }
522 };
523 auto getPointSuccess = container->GetCurPointerEventInfo(
524 asyncCtx->pointerId, asyncCtx->globalX, asyncCtx->globalY, asyncCtx->sourceType, std::move(stopDragCallback));
525 if (!getPointSuccess) {
526 HandleFail(asyncCtx, -1);
527 napi_escape_handle(env, scope, result, &result);
528 napi_close_escapable_handle_scope(env, scope);
529 return result;
530 }
531
532 if (asyncCtx && asyncCtx->pixmap != nullptr) {
533 OnComplete(asyncCtx);
534 } else {
535 auto delegate = EngineHelper::GetCurrentDelegate();
536 if (!delegate) {
537 NapiThrow(env, "ace engine delegate is null", Framework::ERROR_CODE_INTERNAL_ERROR);
538 napi_close_escapable_handle_scope(env, scope);
539 return nullptr;
540 }
541 auto callback = [asyncCtx](std::shared_ptr<Media::PixelMap> pixmap, int32_t errCode) {
542 if (!asyncCtx) {
543 LOGE("DragControllerAsyncContext is null");
544 return;
545 }
546 asyncCtx->pixmap = std::move(pixmap);
547 asyncCtx->errCode = errCode;
548 OnComplete(asyncCtx);
549 };
550 auto builder = [build = asyncCtx->customBuilder, env] {
551 napi_call_function(env, nullptr, build, 0, nullptr, nullptr);
552 };
553 delegate->CreateSnapshot(builder, callback);
554 }
555
556 napi_escape_handle(env, scope, result, &result);
557 napi_close_escapable_handle_scope(env, scope);
558 return result;
559 }
560 #else
561 static napi_value JSExecuteDrag(napi_env env, napi_callback_info info)
562 {
563 napi_escapable_handle_scope scope = nullptr;
564 napi_open_escapable_handle_scope(env, &scope);
565 NapiThrow(env, "The current environment does not enable drag framework or does not support pixmap.",
566 Framework::ERROR_CODE_INTERNAL_ERROR);
567 napi_close_escapable_handle_scope(env, scope);
568 return nullptr;
569 }
570 #endif
571
DragControllerExport(napi_env env,napi_value exports)572 static napi_value DragControllerExport(napi_env env, napi_value exports)
573 {
574 napi_property_descriptor dragControllerDesc[] = {
575 DECLARE_NAPI_FUNCTION("executeDrag", JSExecuteDrag),
576 };
577 NAPI_CALL(env, napi_define_properties(
578 env, exports, sizeof(dragControllerDesc) / sizeof(dragControllerDesc[0]), dragControllerDesc));
579 return exports;
580 }
581
582 static napi_module dragControllerModule = {
583 .nm_version = 1,
584 .nm_flags = 0,
585 .nm_filename = nullptr,
586 .nm_register_func = DragControllerExport,
587 .nm_modname = "arkui.dragController",
588 .nm_priv = ((void*)0),
589 .reserved = { 0 },
590 };
591
DragControllerRegister()592 extern "C" __attribute__((constructor)) void DragControllerRegister()
593 {
594 napi_module_register(&dragControllerModule);
595 }
596 } // namespace OHOS::Ace::Napi
597