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_engine/impl/ark/ark_native_engine.h"
26 #include "native_value.h"
27 #include "core/common/udmf/data_load_params.h"
28
29 #if defined(ENABLE_DRAG_FRAMEWORK) && defined(PIXEL_MAP_SUPPORTED)
30 #include "jsnapi.h"
31 #include "pixel_map.h"
32 #include "pixel_map_napi.h"
33 #include "interaction_manager.h"
34
35 #include "adapter/ohos/capability/interaction/start_drag_listener_impl.h"
36 #include "base/log/log_wrapper.h"
37 #include "base/memory/referenced.h"
38 #include "base/geometry/ng/offset_t.h"
39 #include "base/subwindow/subwindow.h"
40 #include "base/utils/utils.h"
41 #include "bridge/common/utils/utils.h"
42 #include "bridge/declarative_frontend/engine/functions/js_drag_function.h"
43 #include "bridge/declarative_frontend/engine/jsi/jsi_declarative_engine.h"
44 #include "bridge/js_frontend/engine/jsi/ark_js_runtime.h"
45 #include "core/common/ace_engine.h"
46 #include "core/common/container_scope.h"
47 #include "core/common/udmf/udmf_client.h"
48 #include "core/components/common/layout/grid_system_manager.h"
49 #include "core/components_ng/manager/drag_drop/drag_drop_func_wrapper.h"
50 #include "core/components_ng/manager/drag_drop/drag_drop_controller_func_wrapper.h"
51 #include "core/components_ng/manager/drag_drop/drag_drop_manager.h"
52 #include "core/event/ace_events.h"
53 #include "core/pipeline_ng/pipeline_context.h"
54 #include "frameworks/bridge/common/utils/engine_helper.h"
55 #include "frameworks/base/json/json_util.h"
56 #include "frameworks/core/event/pointer_event.h"
57 #include "drag_preview.h"
58 #endif
59 namespace OHOS::Ace::Napi {
60 class DragAction;
61 static constexpr uint32_t DRAG_STARTED = 0;
62 static constexpr uint32_t DRAG_ENDED = 1;
63 #if defined(ENABLE_DRAG_FRAMEWORK) && defined(PIXEL_MAP_SUPPORTED)
64 namespace {
65 constexpr float PIXELMAP_WIDTH_RATE = -0.5f;
66 constexpr float PIXELMAP_HEIGHT_RATE = -0.2f;
67 constexpr size_t STR_BUFFER_SIZE = 1024;
68 constexpr int32_t PARAMETER_NUM = 2;
69 constexpr int32_t ARG_COUNT_3 = 3;
70 constexpr int32_t SOURCE_TYPE_MOUSE = 1;
71 constexpr int32_t MOUSE_POINTER_ID = 1001;
72 constexpr int32_t SOURCE_TOOL_PEN = 1;
73 constexpr int32_t SOURCE_TYPE_TOUCH = 2;
74 constexpr int32_t PEN_POINTER_ID = 102;
75 constexpr int32_t CREATE_PIXELMAP_DELAY_TIME = 80;
76
77 using DragNotifyMsg = Msdp::DeviceStatus::DragNotifyMsg;
78 using DragRet = OHOS::Ace::DragRet;
79 using OnDragCallback = std::function<void(const DragNotifyMsg&)>;
80 using StopDragCallback = std::function<void()>;
81 using PixelMapNapiEntry = void* (*)(void*, void*);
82
83 enum class DragState { PENDING, SENDING, REJECT, SUCCESS };
84 enum class DragStatus { STARTED, ENDED };
85 enum class ParameterType { CUSTOMBUILDER, DRAGITEMINFO, DRAGITEMINFO_ARRAY, MIX, ERROR };
86
87 // the context of drag controller
88 struct DragControllerAsyncCtx {
89 napi_env env = nullptr;
90 size_t argc = ARG_COUNT_3;
91 napi_value argv[ARG_COUNT_3] { nullptr };
92 napi_ref callbackRef = nullptr;
93 napi_deferred deferred = nullptr;
94 std::shared_ptr<Media::PixelMap> pixelMap = nullptr;
95 std::vector<std::shared_ptr<Media::PixelMap>> pixelMapList;
96 bool isArray = false;
97 bool isSwitchedToSubWindow = false;
98 napi_value customBuilder;
99 std::vector<napi_ref> customBuilderList;
100 RefPtr<OHOS::Ace::UnifiedData> unifiedData;
101 RefPtr<OHOS::Ace::DataLoadParams> dataLoadParams;
102 std::string extraParams;
103 int32_t instanceId = -1;
104 int32_t errCode = -1;
105 int32_t badgeNumber = 1;
106 std::mutex mutex;
107 bool hasHandle = false;
108 DragPointerEvent dragPointerEvent;
109 float windowScale = 1.0f;
110 float dipScale = 0.0;
111 int parseBuilderCount = 0;
112 std::mutex dragStateMutex;
113 DragState dragState = DragState::PENDING;
114 DimensionOffset touchPoint = DimensionOffset(0.0_vp, 0.0_vp);
115 bool hasTouchPoint = false;
116 DragAction *dragAction = nullptr;
117 NG::DragPreviewOption dragPreviewOption;
118 ~DragControllerAsyncCtx();
119 };
120 } // namespace
121
122 void OnMultipleComplete(std::shared_ptr<DragControllerAsyncCtx> asyncCtx);
123 void OnComplete(std::shared_ptr<DragControllerAsyncCtx> asyncCtx);
124 bool GetPixelMapByCustom(std::shared_ptr<DragControllerAsyncCtx> asyncCtx);
125 bool GetPixelMapArrayByCustom(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,
126 napi_value customBuilder, int arrayLength);
127 ParameterType getParameterType(std::shared_ptr<DragControllerAsyncCtx> asyncCtx);
128 void SetMouseDragMonitorState(std::shared_ptr<DragControllerAsyncCtx> asyncCtx, bool state);
129 void HandleExecuteDrag(napi_env env, std::shared_ptr<DragControllerAsyncCtx> asyncCtx);
130 bool TryToStartDrag(std::shared_ptr<DragControllerAsyncCtx> asyncCtx);
131 void ExecuteHandleOnDragStart(std::shared_ptr<DragControllerAsyncCtx> asyncCtx);
132
133 class DragAction {
134 public:
DragAction(std::shared_ptr<DragControllerAsyncCtx> asyncCtx)135 DragAction(std::shared_ptr<DragControllerAsyncCtx> asyncCtx) : asyncCtx_(asyncCtx) {}
~DragAction()136 ~DragAction()
137 {
138 if (asyncCtx_) {
139 asyncCtx_->dragAction = nullptr;
140 }
141 CHECK_NULL_VOID(env_);
142 for (auto& item : cbList_) {
143 napi_delete_reference(env_, item);
144 }
145 }
146
OnNapiCallback(napi_value resultArg)147 void OnNapiCallback(napi_value resultArg)
148 {
149 std::vector<napi_value> cbList(cbList_.size());
150 for (auto& cbRef : cbList_) {
151 napi_value cb = nullptr;
152 napi_get_reference_value(env_, cbRef, &cb);
153 cbList.push_back(cb);
154 }
155 for (auto& cb : cbList) {
156 napi_call_function(env_, nullptr, cb, 1, &resultArg, nullptr);
157 }
158 }
159
NapiSerializer(napi_env & env,napi_value & result)160 void NapiSerializer(napi_env& env, napi_value& result)
161 {
162 napi_wrap(
163 env, result, this,
164 [](napi_env env, void* data, void* hint) {
165 DragAction* dragAction = static_cast<DragAction*>(data);
166 if (dragAction != nullptr) {
167 dragAction->DeleteRef();
168 delete dragAction;
169 }
170 },
171 nullptr, nullptr);
172
173 /* insert callback functions */
174 const char* funName = "on";
175 napi_value funcValue = nullptr;
176 napi_create_function(env, funName, NAPI_AUTO_LENGTH, On, nullptr, &funcValue);
177 napi_set_named_property(env, result, funName, funcValue);
178
179 funName = "off";
180 napi_create_function(env, funName, NAPI_AUTO_LENGTH, Off, nullptr, &funcValue);
181 napi_set_named_property(env, result, funName, funcValue);
182
183 funName = "startDrag";
184 napi_create_function(env, funName, NAPI_AUTO_LENGTH, StartDrag, nullptr, &funcValue);
185 napi_set_named_property(env, result, funName, funcValue);
186 }
187
DeleteRef()188 void DeleteRef()
189 {
190 CHECK_NULL_VOID(asyncCtx_);
191 for (auto customBuilderValue : asyncCtx_->customBuilderList) {
192 if (customBuilderValue == nullptr) {
193 continue;
194 }
195 napi_delete_reference(asyncCtx_->env, customBuilderValue);
196 }
197 asyncCtx_->dragAction = nullptr;
198 asyncCtx_ = nullptr;
199 }
200
On(napi_env env,napi_callback_info info)201 static napi_value On(napi_env env, napi_callback_info info)
202 {
203 TAG_LOGI(AceLogTag::ACE_DRAG, "drag action On function called.");
204 napi_handle_scope scope = nullptr;
205 napi_open_handle_scope(env, &scope);
206 CHECK_NULL_RETURN(scope, nullptr);
207 napi_value thisVar = nullptr;
208 napi_value cb = nullptr;
209 size_t argc = ParseArgs(env, info, thisVar, cb);
210 if (argc != ARG_COUNT_2 || thisVar == nullptr || cb == nullptr) {
211 TAG_LOGE(AceLogTag::ACE_DRAG, "Invalid arguments");
212 napi_close_handle_scope(env, scope);
213 return nullptr;
214 }
215 napi_valuetype valueType = napi_undefined;
216 napi_typeof(env, cb, &valueType);
217 if (valueType != napi_function) {
218 NapiThrow(env, "Check param failed", ERROR_CODE_PARAM_INVALID);
219 napi_close_handle_scope(env, scope);
220 return nullptr;
221 }
222 DragAction* dragAction = ConvertDragAction(env, thisVar);
223 if (!dragAction) {
224 NapiThrow(env, "convert drag action failed.", ERROR_CODE_PARAM_INVALID);
225 napi_close_handle_scope(env, scope);
226 return nullptr;
227 }
228 auto iter = dragAction->FindCbList(cb);
229 if (iter != dragAction->cbList_.end()) {
230 NapiThrow(env, "get js callback function error.", ERROR_CODE_PARAM_INVALID);
231 napi_close_handle_scope(env, scope);
232 return nullptr;
233 }
234 napi_ref ref = nullptr;
235 napi_create_reference(env, cb, 1, &ref);
236 dragAction->cbList_.emplace_back(ref);
237 napi_close_handle_scope(env, scope);
238 return nullptr;
239 }
240
Off(napi_env env,napi_callback_info info)241 static napi_value Off(napi_env env, napi_callback_info info)
242 {
243 TAG_LOGI(AceLogTag::ACE_DRAG, "drag action Off function called.");
244 napi_handle_scope scope = nullptr;
245 napi_open_handle_scope(env, &scope);
246 CHECK_NULL_RETURN(scope, nullptr);
247 napi_value thisVar = nullptr;
248 napi_value cb = nullptr;
249 size_t argc = ParseArgs(env, info, thisVar, cb);
250 DragAction* dragAction = ConvertDragAction(env, thisVar);
251 if (!dragAction) {
252 NapiThrow(env, "convert drag action failed.", ERROR_CODE_PARAM_INVALID);
253 napi_close_handle_scope(env, scope);
254 return nullptr;
255 }
256 if (argc == 1) {
257 for (const auto& item : dragAction->cbList_) {
258 napi_delete_reference(dragAction->env_, item);
259 }
260 dragAction->cbList_.clear();
261 } else {
262 NAPI_ASSERT(env, (argc == ARG_COUNT_2 && dragAction != nullptr && cb != nullptr), "Invalid arguments");
263 napi_valuetype valueType = napi_undefined;
264 napi_typeof(env, cb, &valueType);
265 if (valueType != napi_function) {
266 NapiThrow(env, "Check param failed", ERROR_CODE_PARAM_INVALID);
267 napi_close_handle_scope(env, scope);
268 return nullptr;
269 }
270 auto iter = dragAction->FindCbList(cb);
271 if (iter != dragAction->cbList_.end()) {
272 napi_delete_reference(dragAction->env_, *iter);
273 dragAction->cbList_.erase(iter);
274 }
275 }
276 napi_close_handle_scope(env, scope);
277 return nullptr;
278 }
279
StartDrag(napi_env env,napi_callback_info info)280 static napi_value StartDrag(napi_env env, napi_callback_info info)
281 {
282 TAG_LOGI(AceLogTag::ACE_DRAG, "drag action StartDrag function called.");
283 napi_escapable_handle_scope scope = nullptr;
284 napi_open_escapable_handle_scope(env, &scope);
285 CHECK_NULL_RETURN(scope, nullptr);
286 napi_value thisVar = nullptr;
287 napi_value cb = nullptr;
288 size_t argc = ParseArgs(env, info, thisVar, cb);
289 if (argc != 0 || thisVar == nullptr) {
290 TAG_LOGE(AceLogTag::ACE_DRAG, "Invalid arguments");
291 napi_close_escapable_handle_scope(env, scope);
292 return nullptr;
293 }
294 DragAction* dragAction = ConvertDragAction(env, thisVar);
295 if (!dragAction) {
296 NapiThrow(env, "convert drag action failed.", ERROR_CODE_INTERNAL_ERROR);
297 napi_close_escapable_handle_scope(env, scope);
298 return nullptr;
299 }
300 if (dragAction->asyncCtx_ == nullptr) {
301 NapiThrow(env, "drag action must be recreated for each dragging", ERROR_CODE_INTERNAL_ERROR);
302 napi_close_escapable_handle_scope(env, scope);
303 return nullptr;
304 }
305 napi_value promiseResult = nullptr;
306 napi_status status = napi_create_promise(env, &dragAction->asyncCtx_->deferred, &promiseResult);
307 if (status != napi_ok) {
308 NapiThrow(env, "ace engine delegate is null", ERROR_CODE_INTERNAL_ERROR);
309 napi_close_escapable_handle_scope(env, scope);
310 return nullptr;
311 }
312
313 SetMouseDragMonitorState(dragAction->asyncCtx_, true);
314 dragAction->StartDragInternal(dragAction->asyncCtx_);
315 napi_escape_handle(env, scope, promiseResult, &promiseResult);
316 napi_close_escapable_handle_scope(env, scope);
317 return promiseResult;
318 }
319
FindCbList(napi_value cb)320 std::list<napi_ref>::iterator FindCbList(napi_value cb)
321 {
322 return std::find_if(cbList_.begin(), cbList_.end(), [env = env_, cb](const napi_ref& item) -> bool {
323 bool result = false;
324 napi_value refItem;
325 napi_get_reference_value(env, item, &refItem);
326 napi_strict_equals(env, refItem, cb, &result);
327 return result;
328 });
329 }
330
331 private:
Initialize(napi_env env,napi_value thisVar)332 void Initialize(napi_env env, napi_value thisVar)
333 {
334 env_ = env;
335 }
336
ParseArgs(napi_env & env,napi_callback_info & info,napi_value & thisVar,napi_value & cb)337 static size_t ParseArgs(napi_env& env, napi_callback_info& info, napi_value& thisVar, napi_value& cb)
338 {
339 size_t argc = ARG_COUNT_2;
340 napi_value argv[ARG_COUNT_2] = { 0 };
341 void* data = nullptr;
342 napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
343 if (argc == 0) {
344 return argc;
345 }
346 NAPI_ASSERT_BASE(env, argc > 0, "too few parameter", 0);
347
348 napi_valuetype napiType;
349 NAPI_CALL_BASE(env, napi_typeof(env, argv[0], &napiType), 0);
350 NAPI_ASSERT_BASE(env, napiType == napi_string, "parameter 1 should be string", 0);
351 char type[STR_BUFFER_SIZE] = { 0 };
352 size_t len = 0;
353 napi_get_value_string_utf8(env, argv[0], type, STR_BUFFER_SIZE, &len);
354 NAPI_ASSERT_BASE(env, len < STR_BUFFER_SIZE, "condition string too long", 0);
355 NAPI_ASSERT_BASE(env, strcmp("statusChange", type) == 0, "type mismatch('change')", 0);
356 if (argc <= 1) {
357 return argc;
358 }
359 NAPI_CALL_BASE(env, napi_typeof(env, argv[1], &napiType), 0);
360 NAPI_ASSERT_BASE(env, napiType == napi_function, "type mismatch for parameter 2", 0);
361 cb = argv[1];
362 return argc;
363 }
364
ConvertDragAction(napi_env env,napi_value thisVar)365 static DragAction* ConvertDragAction(napi_env env, napi_value thisVar)
366 {
367 DragAction* dragAction = nullptr;
368 napi_unwrap(env, thisVar, (void**)&dragAction);
369 if (dragAction) {
370 dragAction->Initialize(env, thisVar);
371 }
372 return dragAction;
373 }
374
StartDragInternal(std::shared_ptr<DragControllerAsyncCtx> dragCtx)375 void StartDragInternal(std::shared_ptr<DragControllerAsyncCtx> dragCtx)
376 {
377 CHECK_NULL_VOID(dragCtx);
378 ParameterType parameterType = getParameterType(dragCtx);
379 TAG_LOGI(AceLogTag::ACE_DRAG, "parameter type is %{public}d", static_cast<int32_t>(parameterType));
380 if (parameterType == ParameterType::DRAGITEMINFO_ARRAY) {
381 OnMultipleComplete(dragCtx);
382 } else if (parameterType == ParameterType::MIX) {
383 int32_t arrayLenth = static_cast<int32_t>(dragCtx->customBuilderList.size());
384 for (auto customBuilderValue: dragCtx->customBuilderList) {
385 napi_value cb = nullptr;
386 napi_get_reference_value(dragCtx->env, customBuilderValue, &cb);
387 GetPixelMapArrayByCustom(dragCtx, cb, arrayLenth);
388 }
389 } else {
390 NapiThrow(dragCtx->env, "parameter parsing failed.", ERROR_CODE_PARAM_INVALID);
391 }
392 }
393
394 napi_env env_ = nullptr;
395 std::list<napi_ref> cbList_;
396 std::shared_ptr<DragControllerAsyncCtx> asyncCtx_;
397 };
398
~DragControllerAsyncCtx()399 DragControllerAsyncCtx::~DragControllerAsyncCtx()
400 {
401 if (!dragAction) {
402 dragAction = nullptr;
403 }
404 }
405
IsExecutingWithDragAction(std::shared_ptr<DragControllerAsyncCtx> asyncCtx)406 bool IsExecutingWithDragAction(std::shared_ptr<DragControllerAsyncCtx> asyncCtx)
407 {
408 CHECK_NULL_RETURN(asyncCtx, false);
409 return (asyncCtx->isArray && asyncCtx->argc == ARG_COUNT_2);
410 }
411
CreateCallbackErrorValue(napi_env env,int32_t errCode,const std::string & errMsg="")412 napi_value CreateCallbackErrorValue(napi_env env, int32_t errCode, const std::string& errMsg = "")
413 {
414 napi_value code = nullptr;
415 std::string strCode = std::to_string(errCode);
416 napi_create_string_utf8(env, strCode.c_str(), strCode.length(), &code);
417 napi_value msg = nullptr;
418 napi_create_string_utf8(env, errMsg.c_str(), errMsg.length(), &msg);
419 napi_value error = nullptr;
420 napi_create_error(env, code, msg, &error);
421 return error;
422 }
423
ConvertToPx(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,const Dimension & dimension,double size)424 double ConvertToPx(std::shared_ptr<DragControllerAsyncCtx> asyncCtx, const Dimension& dimension, double size)
425 {
426 auto unit = dimension.Unit();
427 auto value = dimension.Value();
428 if (unit == DimensionUnit::PERCENT) {
429 return value * size;
430 }
431 if (unit == DimensionUnit::NONE || unit == DimensionUnit::PX) {
432 return value;
433 }
434 auto container = AceEngine::Get().GetContainer(asyncCtx->instanceId);
435 if (!container) {
436 return 0.0;
437 }
438 auto pipeline = container->GetPipelineContext();
439 CHECK_NULL_RETURN(pipeline, 0.0);
440 if (unit == DimensionUnit::VP) {
441 return value * pipeline->GetDipScale();
442 }
443 if (unit == DimensionUnit::FP) {
444 return value * pipeline->GetDipScale() * pipeline->GetFontScale();
445 }
446 if (unit == DimensionUnit::LPX) {
447 return value * pipeline->GetLogicScale();
448 }
449 return 0.0;
450 }
451
HandleDimensionType(napi_value parameterNapi,napi_env env)452 static std::optional<Dimension> HandleDimensionType(napi_value parameterNapi, napi_env env)
453 {
454 size_t ret = 0;
455 std::string parameterStr;
456 napi_valuetype valueType = napi_undefined;
457 napi_typeof(env, parameterNapi, &valueType);
458 Dimension parameter;
459 if (valueType == napi_number) {
460 double parameterValue;
461 napi_get_value_double(env, parameterNapi, ¶meterValue);
462 parameter.SetValue(parameterValue);
463 parameter.SetUnit(DimensionUnit::VP);
464 } else if (valueType == napi_string) {
465 size_t parameterLen = GetParamLen(env, parameterNapi) + 1;
466 std::unique_ptr<char[]> parameterTemp = std::make_unique<char[]>(parameterLen);
467 napi_get_value_string_utf8(env, parameterNapi, parameterTemp.get(), parameterLen, &ret);
468 parameterStr = parameterTemp.get();
469 parameter = StringUtils::StringToDimensionWithUnit(parameterStr, DimensionUnit::VP);
470 } else if (valueType == napi_object) {
471 ResourceInfo recv;
472 if (!ParseResourceParam(env, parameterNapi, recv)) {
473 return std::nullopt;
474 }
475 if (!ParseString(recv, parameterStr)) {
476 return std::nullopt;
477 }
478 parameter = StringUtils::StringToDimensionWithUnit(parameterStr, DimensionUnit::VP);
479 } else {
480 return std::nullopt;
481 }
482 return parameter;
483 }
484
CallBackForJs(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,napi_value result)485 void CallBackForJs(std::shared_ptr<DragControllerAsyncCtx> asyncCtx, napi_value result)
486 {
487 CHECK_NULL_VOID(asyncCtx);
488 CHECK_NULL_VOID(result);
489
490 if (IsExecutingWithDragAction(asyncCtx) && asyncCtx->dragAction) {
491 asyncCtx->dragAction->OnNapiCallback(result);
492 if (asyncCtx->deferred != nullptr) {
493 napi_value promiseResult = nullptr;
494 napi_get_undefined(asyncCtx->env, &promiseResult);
495 napi_resolve_deferred(asyncCtx->env, asyncCtx->deferred, promiseResult);
496 }
497 } else {
498 napi_value resultVal[PARAMETER_NUM] = { nullptr };
499 napi_get_undefined(asyncCtx->env, &resultVal[0]);
500 napi_get_undefined(asyncCtx->env, &resultVal[1]);
501 resultVal[1] = result;
502 if (asyncCtx->callbackRef) {
503 napi_value ret = nullptr;
504 napi_value napiCallback = nullptr;
505 napi_get_reference_value(asyncCtx->env, asyncCtx->callbackRef, &napiCallback);
506 napi_call_function(asyncCtx->env, nullptr, napiCallback, PARAMETER_NUM, resultVal, &ret);
507 napi_delete_reference(asyncCtx->env, asyncCtx->callbackRef);
508 } else {
509 napi_resolve_deferred(asyncCtx->env, asyncCtx->deferred, resultVal[1]);
510 }
511 }
512 asyncCtx->deferred = nullptr;
513 asyncCtx->hasHandle = false;
514 }
515
TranslateDragResult(Msdp::DeviceStatus::DragResult dragResult)516 DragRet TranslateDragResult(Msdp::DeviceStatus::DragResult dragResult)
517 {
518 switch (dragResult) {
519 case Msdp::DeviceStatus::DragResult::DRAG_SUCCESS:
520 return DragRet::DRAG_SUCCESS;
521 case Msdp::DeviceStatus::DragResult::DRAG_FAIL:
522 return DragRet::DRAG_FAIL;
523 case Msdp::DeviceStatus::DragResult::DRAG_CANCEL:
524 return DragRet::DRAG_CANCEL;
525 default:
526 return DragRet::DRAG_FAIL;
527 }
528 }
SetDragEventForJs(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,const napi_value & eventNapi,const DragNotifyMsg & dragNotifyMsg)529 bool SetDragEventForJs(
530 std::shared_ptr<DragControllerAsyncCtx> asyncCtx, const napi_value& eventNapi, const DragNotifyMsg& dragNotifyMsg)
531 {
532 CHECK_NULL_RETURN(asyncCtx, false);
533 auto localRef = NapiValueToLocalValue(eventNapi);
534 if (localRef->IsNull()) {
535 TAG_LOGE(AceLogTag::ACE_DRAG, "napi value convert to local value failed.");
536 return false;
537 }
538 auto vm = reinterpret_cast<NativeEngine*>(asyncCtx->env)->GetEcmaVm();
539 auto* jsDragEvent =
540 static_cast<Framework::JsDragEvent*>(Local<panda::ObjectRef>(localRef)->GetNativePointerField(vm, 0));
541 CHECK_NULL_RETURN(jsDragEvent, false);
542 auto dragEvent = AceType::MakeRefPtr<DragEvent>();
543 if (!dragEvent) {
544 TAG_LOGE(AceLogTag::ACE_DRAG, "create dragEvent failed.");
545 return false;
546 }
547 dragEvent->SetResult(TranslateDragResult(dragNotifyMsg.result));
548 dragEvent->SetDragBehavior(static_cast<DragBehavior>(dragNotifyMsg.dragBehavior));
549 jsDragEvent->SetDragEvent(dragEvent);
550 return true;
551 }
552
GetCallBackDataForJs(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,const DragNotifyMsg & dragNotifyMsg,const DragStatus dragStatus)553 void GetCallBackDataForJs(std::shared_ptr<DragControllerAsyncCtx> asyncCtx, const DragNotifyMsg& dragNotifyMsg,
554 const DragStatus dragStatus)
555 {
556 CHECK_NULL_VOID(asyncCtx);
557 napi_handle_scope scope = nullptr;
558 napi_open_handle_scope(asyncCtx->env, &scope);
559 napi_value result = nullptr;
560 napi_get_undefined(asyncCtx->env, &result);
561 napi_create_object(asyncCtx->env, &result);
562 napi_value eventNapi = nullptr;
563 napi_value globalObj = nullptr;
564 napi_value customDragEvent = nullptr;
565 napi_create_object(asyncCtx->env, &customDragEvent);
566 napi_get_global(asyncCtx->env, &globalObj);
567 napi_get_named_property(asyncCtx->env, globalObj, "DragEvent", &customDragEvent);
568 napi_status status = napi_new_instance(asyncCtx->env, customDragEvent, 0, nullptr, &eventNapi);
569 if (status != napi_ok) {
570 TAG_LOGE(AceLogTag::ACE_DRAG,
571 "create new instance dragEvent failed, return value is %{public}d", status);
572 napi_close_handle_scope(asyncCtx->env, scope);
573 return;
574 }
575 if (!SetDragEventForJs(asyncCtx, eventNapi, dragNotifyMsg)) {
576 TAG_LOGE(AceLogTag::ACE_DRAG, "set dragEvent for JS failed.");
577 napi_close_handle_scope(asyncCtx->env, scope);
578 return;
579 }
580 napi_set_named_property(asyncCtx->env, result, "event", eventNapi);
581
582 napi_value extraParamsNapi = nullptr;
583 napi_create_string_utf8(
584 asyncCtx->env, asyncCtx->extraParams.c_str(), asyncCtx->extraParams.length(), &extraParamsNapi);
585 napi_set_named_property(asyncCtx->env, result, "extraParams", extraParamsNapi);
586
587 if (asyncCtx->isArray) {
588 napi_value dragStatusValue = nullptr;
589 napi_create_int32(asyncCtx->env, static_cast<int32_t>(dragStatus), &dragStatusValue);
590 napi_set_named_property(asyncCtx->env, result, "status", dragStatusValue);
591 }
592
593 CallBackForJs(asyncCtx, result);
594 napi_close_handle_scope(asyncCtx->env, scope);
595 }
596
SetMouseDragMonitorState(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,bool state)597 void SetMouseDragMonitorState(std::shared_ptr<DragControllerAsyncCtx> asyncCtx, bool state)
598 {
599 if (asyncCtx->dragPointerEvent.sourceType != SOURCE_TYPE_MOUSE) {
600 return;
601 }
602 auto ret = InteractionInterface::GetInstance()->SetMouseDragMonitorState(state);
603 if (ret != 0) {
604 TAG_LOGW(AceLogTag::ACE_DRAG, "Set mouse drag monitor state %{public}d failed, return value is %{public}d",
605 state, ret);
606 return;
607 }
608 TAG_LOGI(AceLogTag::ACE_DRAG, "Set mouse drag monitor state %{public}d success", state);
609 }
610
HandleExecuteDrag(napi_env env,std::shared_ptr<DragControllerAsyncCtx> asyncCtx)611 void HandleExecuteDrag(napi_env env, std::shared_ptr<DragControllerAsyncCtx> asyncCtx)
612 {
613 ParameterType parameterType = getParameterType(asyncCtx);
614 if (parameterType == ParameterType::DRAGITEMINFO) {
615 OnComplete(asyncCtx);
616 } else if (parameterType == ParameterType::CUSTOMBUILDER) {
617 GetPixelMapByCustom(asyncCtx);
618 } else {
619 NapiThrow(env, "parameter parsing error.", ERROR_CODE_PARAM_INVALID);
620 }
621 }
622
HandleSuccess(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,const DragNotifyMsg & dragNotifyMsg,const DragStatus dragStatus)623 void HandleSuccess(std::shared_ptr<DragControllerAsyncCtx> asyncCtx, const DragNotifyMsg& dragNotifyMsg,
624 const DragStatus dragStatus)
625 {
626 TAG_LOGI(AceLogTag::ACE_DRAG, "drag notify message result is %{public}d.", dragNotifyMsg.result);
627 CHECK_NULL_VOID(asyncCtx);
628 bool hasHandle = false;
629 {
630 std::lock_guard<std::mutex> lock(asyncCtx->mutex);
631 hasHandle = asyncCtx->hasHandle;
632 asyncCtx->hasHandle = true;
633 }
634 if (hasHandle) {
635 return;
636 }
637 auto container = AceEngine::Get().GetContainer(asyncCtx->instanceId);
638 CHECK_NULL_VOID(container);
639 auto taskExecutor = container->GetTaskExecutor();
640 CHECK_NULL_VOID(taskExecutor);
641 if (dragStatus == DragStatus::ENDED) {
642 auto pipelineContext = container->GetPipelineContext();
643 CHECK_NULL_VOID(pipelineContext);
644 pipelineContext->ResetDragging();
645 taskExecutor->PostTask(
646 [asyncCtx, dragNotifyMsg, dragStatus]() {
647 CHECK_NULL_VOID(asyncCtx);
648 GetCallBackDataForJs(asyncCtx, dragNotifyMsg, dragStatus);
649 },
650 TaskExecutor::TaskType::JS, "ArkUIDragHandleSuccess", PriorityType::VIP);
651 return;
652 }
653 taskExecutor->PostSyncTask(
654 [asyncCtx, dragNotifyMsg, dragStatus]() {
655 CHECK_NULL_VOID(asyncCtx);
656 GetCallBackDataForJs(asyncCtx, dragNotifyMsg, dragStatus);
657 },
658 TaskExecutor::TaskType::JS, "ArkUIDragHandleSuccess");
659 }
660
HandleFail(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,int32_t errorCode,const std::string & errMsg="")661 void HandleFail(std::shared_ptr<DragControllerAsyncCtx> asyncCtx, int32_t errorCode, const std::string& errMsg = "")
662 {
663 CHECK_NULL_VOID(asyncCtx);
664 bool hasHandle = false;
665 {
666 std::lock_guard<std::mutex> lock(asyncCtx->mutex);
667 hasHandle = asyncCtx->hasHandle;
668 asyncCtx->hasHandle = true;
669 }
670 if (hasHandle) {
671 return;
672 }
673 napi_value result[PARAMETER_NUM] = { nullptr };
674 result[0] = CreateCallbackErrorValue(asyncCtx->env, errorCode, errMsg);
675 if (asyncCtx->callbackRef) {
676 napi_value ret = nullptr;
677 napi_value napiCallback = nullptr;
678 napi_get_reference_value(asyncCtx->env, asyncCtx->callbackRef, &napiCallback);
679 napi_create_object(asyncCtx->env, &result[1]);
680 napi_call_function(asyncCtx->env, nullptr, napiCallback, PARAMETER_NUM, result, &ret);
681 napi_delete_reference(asyncCtx->env, asyncCtx->callbackRef);
682 } else {
683 napi_reject_deferred(asyncCtx->env, asyncCtx->deferred, result[0]);
684 }
685 }
686
HandleDragEnd(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,const DragNotifyMsg & dragNotifyMsg)687 void HandleDragEnd(std::shared_ptr<DragControllerAsyncCtx> asyncCtx, const DragNotifyMsg& dragNotifyMsg)
688 {
689 TAG_LOGI(AceLogTag::ACE_DRAG, "handleDragEnd notify message result is %{public}d.", dragNotifyMsg.result);
690 CHECK_NULL_VOID(asyncCtx);
691 auto container = AceEngine::Get().GetContainer(asyncCtx->instanceId);
692 CHECK_NULL_VOID(container);
693 auto pipelineContext = container->GetPipelineContext();
694 CHECK_NULL_VOID(pipelineContext);
695 pipelineContext->ResetDragging();
696 auto taskExecutor = container->GetTaskExecutor();
697 CHECK_NULL_VOID(taskExecutor);
698 taskExecutor->PostTask(
699 [asyncCtx, dragNotifyMsg]() {
700 CHECK_NULL_VOID(asyncCtx);
701 GetCallBackDataForJs(asyncCtx, dragNotifyMsg, DragStatus::ENDED);
702 },
703 TaskExecutor::TaskType::JS, "ArkUIDragHandleDragEnd", PriorityType::VIP);
704 }
705
HandleOnDragStart(std::shared_ptr<DragControllerAsyncCtx> asyncCtx)706 void HandleOnDragStart(std::shared_ptr<DragControllerAsyncCtx> asyncCtx)
707 {
708 ContainerScope scope(asyncCtx->instanceId);
709 auto container = Container::CurrentSafely();
710 CHECK_NULL_VOID(container);
711 auto pipelineContext = container->GetPipelineContext();
712 CHECK_NULL_VOID(pipelineContext);
713 pipelineContext->OnDragEvent({ asyncCtx->dragPointerEvent.displayX, asyncCtx->dragPointerEvent.displayY },
714 DragEventAction::DRAG_EVENT_START_FOR_CONTROLLER);
715 }
716
CopyMediaPixelMap(const RefPtr<PixelMap> & pixelMap)717 std::shared_ptr<Media::PixelMap> CopyMediaPixelMap(const RefPtr<PixelMap>& pixelMap)
718 {
719 CHECK_NULL_RETURN(pixelMap, nullptr);
720 OHOS::Media::InitializationOptions opts;
721 auto mediaPixelMap = pixelMap->GetPixelMapSharedPtr();
722 std::unique_ptr<Media::PixelMap> uniquePixelMap = Media::PixelMap::Create(*mediaPixelMap, opts);
723 CHECK_NULL_RETURN(uniquePixelMap, nullptr);
724 Media::PixelMap* pixelMapRelease = uniquePixelMap.release();
725 CHECK_NULL_RETURN(pixelMapRelease, nullptr);
726 std::shared_ptr<Media::PixelMap> newPixelMap(pixelMapRelease);
727 CHECK_NULL_RETURN(newPixelMap, nullptr);
728 return newPixelMap;
729 }
730
GetShadowInfo(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,Msdp::DeviceStatus::ShadowInfo & shadowInfo,RefPtr<PixelMap> refPixelMap,float scale)731 bool GetShadowInfo(std::shared_ptr<DragControllerAsyncCtx> asyncCtx, Msdp::DeviceStatus::ShadowInfo& shadowInfo,
732 RefPtr<PixelMap> refPixelMap, float scale)
733 {
734 CHECK_NULL_RETURN(asyncCtx, false);
735 auto pixelMapDuplicated = CopyMediaPixelMap(refPixelMap);
736 if (!pixelMapDuplicated) {
737 TAG_LOGW(AceLogTag::ACE_DRAG, "duplicate PixelMap failed!");
738 pixelMapDuplicated = asyncCtx->pixelMap;
739 }
740 CHECK_NULL_RETURN(pixelMapDuplicated, false);
741 pixelMapDuplicated->scale(scale, scale, Media::AntiAliasingOption::HIGH);
742 int32_t width = pixelMapDuplicated->GetWidth();
743 int32_t height = pixelMapDuplicated->GetHeight();
744 CHECK_NULL_RETURN(pixelMapDuplicated, false);
745 double x = ConvertToPx(asyncCtx, asyncCtx->touchPoint.GetX(), width);
746 double y = ConvertToPx(asyncCtx, asyncCtx->touchPoint.GetY(), height);
747 if (!asyncCtx->hasTouchPoint) {
748 x = -width * PIXELMAP_WIDTH_RATE;
749 y = -height * PIXELMAP_HEIGHT_RATE;
750 } else if (x < 0 || y < 0 || x > static_cast<double>(width) || y > static_cast<double>(height)) {
751 napi_handle_scope scope = nullptr;
752 napi_open_handle_scope(asyncCtx->env, &scope);
753 HandleFail(asyncCtx, ERROR_CODE_PARAM_INVALID, "touchPoint's coordinate out of range");
754 napi_close_handle_scope(asyncCtx->env, scope);
755 return false;
756 }
757 shadowInfo = { pixelMapDuplicated, -x, -y };
758 return true;
759 }
760
SetIsDragging(const RefPtr<Container> & container,bool isDragging)761 static void SetIsDragging(const RefPtr<Container>& container, bool isDragging)
762 {
763 CHECK_NULL_VOID(container);
764 auto pipelineContext = container->GetPipelineContext();
765 CHECK_NULL_VOID(pipelineContext);
766 pipelineContext->SetIsDragging(isDragging);
767 }
768
JudgeCoordinateCanDrag(Msdp::DeviceStatus::ShadowInfo & shadowInfo)769 bool JudgeCoordinateCanDrag(Msdp::DeviceStatus::ShadowInfo& shadowInfo)
770 {
771 CHECK_NULL_RETURN(shadowInfo.pixelMap, false);
772 int32_t x = -shadowInfo.x;
773 int32_t y = -shadowInfo.y;
774 int32_t width = shadowInfo.pixelMap->GetWidth();
775 int32_t height = shadowInfo.pixelMap->GetHeight();
776 if (x < 0 || y < 0 || x > width || y > height) {
777 return false;
778 }
779 return true;
780 }
781
SetUnifiedData(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,std::string & udKey,DragSummaryInfo & dragSummaryInfo)782 int32_t SetUnifiedData(std::shared_ptr<DragControllerAsyncCtx> asyncCtx, std::string& udKey,
783 DragSummaryInfo& dragSummaryInfo)
784 {
785 int32_t dataSize = 1;
786 int32_t ret = 1;
787 CHECK_NULL_RETURN(asyncCtx, dataSize);
788 if (asyncCtx->dataLoadParams) {
789 ret = UdmfClient::GetInstance()->SetDelayInfo(asyncCtx->dataLoadParams, udKey);
790 if (ret != 0) {
791 TAG_LOGI(AceLogTag::ACE_DRAG, "udmf set delayInfo failed, return value is %{public}d", ret);
792 }
793 auto recodeCount = asyncCtx->dataLoadParams->GetRecordCount();
794 dataSize = (recodeCount == 0 || recodeCount > INT32_MAX) ? 1 : static_cast<int32_t>(recodeCount);
795 }
796 if (asyncCtx->unifiedData) {
797 ret = UdmfClient::GetInstance()->SetData(asyncCtx->unifiedData, udKey);
798 if (ret != 0) {
799 TAG_LOGI(AceLogTag::ACE_DRAG, "udmf set data failed, return value is %{public}d", ret);
800 }
801 dataSize = static_cast<int32_t>(asyncCtx->unifiedData->GetSize());
802 }
803 if (ret == 0) {
804 ret = UdmfClient::GetInstance()->GetSummary(udKey, dragSummaryInfo);
805 if (ret != 0) {
806 TAG_LOGI(AceLogTag::ACE_DRAG, "get summary failed, return value is %{public}d", ret);
807 }
808 }
809 return dataSize;
810 }
811
EnvelopedDragData(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,std::optional<Msdp::DeviceStatus::DragData> & dragData,std::vector<Msdp::DeviceStatus::ShadowInfo> & shadowInfos)812 bool EnvelopedDragData(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,
813 std::optional<Msdp::DeviceStatus::DragData>& dragData, std::vector<Msdp::DeviceStatus::ShadowInfo>& shadowInfos)
814 {
815 auto container = AceEngine::Get().GetContainer(asyncCtx->instanceId);
816 CHECK_NULL_RETURN(container, false);
817 if (shadowInfos.empty()) {
818 napi_handle_scope scope = nullptr;
819 napi_open_handle_scope(asyncCtx->env, &scope);
820 HandleFail(asyncCtx, ERROR_CODE_PARAM_INVALID, "shadowInfo array is empty");
821 napi_close_handle_scope(asyncCtx->env, scope);
822 TAG_LOGE(AceLogTag::ACE_DRAG, "shadowInfo array is empty");
823 return false;
824 }
825 if (!JudgeCoordinateCanDrag(shadowInfos[0])) {
826 napi_handle_scope scope = nullptr;
827 napi_open_handle_scope(asyncCtx->env, &scope);
828 HandleFail(asyncCtx, ERROR_CODE_PARAM_INVALID, "touchPoint's coordinate out of range");
829 napi_close_handle_scope(asyncCtx->env, scope);
830 TAG_LOGE(AceLogTag::ACE_DRAG, "touchPoint's coordinate out of range");
831 return false;
832 }
833 if (!container->GetLastMovingPointerPosition(asyncCtx->dragPointerEvent)) {
834 napi_handle_scope scope = nullptr;
835 napi_open_handle_scope(asyncCtx->env, &scope);
836 HandleFail(asyncCtx, ERROR_CODE_INTERNAL_ERROR, "can not find current pointerId or not in press");
837 napi_close_handle_scope(asyncCtx->env, scope);
838 TAG_LOGE(AceLogTag::ACE_DRAG, "can not find current pointerId or not in press");
839 return false;
840 }
841 std::string udKey;
842 DragSummaryInfo dragSummaryInfo;
843 int32_t dataSize = SetUnifiedData(asyncCtx, udKey, dragSummaryInfo);
844 int32_t recordSize = (dataSize != 0 ? dataSize : static_cast<int32_t>(shadowInfos.size()));
845 auto badgeNumber = asyncCtx->dragPreviewOption.GetCustomerBadgeNumber();
846 if (badgeNumber.has_value()) {
847 recordSize = badgeNumber.value();
848 TAG_LOGI(AceLogTag::ACE_DRAG, "Use custom badge number, value is %{public}d", recordSize);
849 }
850 auto windowId = container->GetWindowId();
851 auto arkExtraInfoJson = JsonUtil::Create(true);
852 arkExtraInfoJson->Put("dip_scale", asyncCtx->dipScale);
853 arkExtraInfoJson->Put("event_id", asyncCtx->dragPointerEvent.pointerEventId);
854 NG::DragDropFuncWrapper::UpdateExtraInfo(arkExtraInfoJson, asyncCtx->dragPreviewOption);
855 dragData = { shadowInfos, {}, udKey, asyncCtx->extraParams, arkExtraInfoJson->ToString(),
856 asyncCtx->dragPointerEvent.sourceType, recordSize, asyncCtx->dragPointerEvent.pointerId,
857 asyncCtx->dragPointerEvent.displayX, asyncCtx->dragPointerEvent.displayY,
858 asyncCtx->dragPointerEvent.displayId, windowId, true, false, dragSummaryInfo.summary, false,
859 dragSummaryInfo.detailedSummary, dragSummaryInfo.summaryFormat, dragSummaryInfo.version,
860 dragSummaryInfo.totalSize };
861 return true;
862 }
863
864 #ifdef CROSS_PLATFORM
TranslateDragResult(Ace::DragRet ret)865 Msdp::DeviceStatus::DragResult TranslateDragResult(Ace::DragRet ret)
866 {
867 switch (ret) {
868 case Ace::DragRet::DRAG_SUCCESS:
869 return Msdp::DeviceStatus::DragResult::DRAG_SUCCESS;
870 case Ace::DragRet::DRAG_FAIL:
871 return Msdp::DeviceStatus::DragResult::DRAG_FAIL;
872 case Ace::DragRet::DRAG_CANCEL:
873 return Msdp::DeviceStatus::DragResult::DRAG_CANCEL;
874 default:
875 TAG_LOGW(AceLogTag::ACE_DRAG, "translate drag result unknown type %{public}d", static_cast<int32_t>(ret));
876 return Msdp::DeviceStatus::DragResult::DRAG_EXCEPTION;
877 }
878 }
879
TranslateDragBehavior(Ace::DragBehavior ret)880 Msdp::DeviceStatus::DragBehavior TranslateDragBehavior(Ace::DragBehavior ret)
881 {
882 switch (ret) {
883 case Ace::DragBehavior::UNKNOWN:
884 return Msdp::DeviceStatus::DragBehavior::UNKNOWN;
885 case Ace::DragBehavior::COPY:
886 return Msdp::DeviceStatus::DragBehavior::COPY;
887 case Ace::DragBehavior::MOVE:
888 return Msdp::DeviceStatus::DragBehavior::MOVE;
889 default:
890 TAG_LOGW(AceLogTag::ACE_DRAG, "translate drag behavior unknown type %{public}d", static_cast<int32_t>(ret));
891 return Msdp::DeviceStatus::DragBehavior::UNKNOWN;
892 }
893 }
894
StartDrag(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,const Msdp::DeviceStatus::DragData & dragData,bool isStartDragService)895 int32_t StartDrag(std::shared_ptr<DragControllerAsyncCtx> asyncCtx, const Msdp::DeviceStatus::DragData& dragData,
896 bool isStartDragService)
897 {
898 OHOS::Ace::DragDataCore dragDataCore { {}, {}, dragData.udKey, dragData.extraInfo, dragData.filterInfo,
899 MMI::PointerEvent::SOURCE_TYPE_TOUCHSCREEN, dragData.dragNum, dragData.pointerId,
900 dragData.displayX, dragData.displayY, dragData.displayId, dragData.mainWindow, dragData.hasCanceledAnimation,
901 dragData.hasCoordinateCorrected, dragData.summarys };
902 for (const auto& shadowInfo : dragData.shadowInfos) {
903 auto pixelMap = shadowInfo.pixelMap;
904 if (pixelMap) {
905 dragDataCore.shadowInfos.push_back(
906 { OHOS::Ace::PixelMap::CreatePixelMap(reinterpret_cast<void*>(&pixelMap)), shadowInfo.x,
907 shadowInfo.y });
908 } else {
909 dragDataCore.shadowInfos.push_back({ nullptr, shadowInfo.x, shadowInfo.y });
910 }
911 }
912 auto callback = [asyncCtx, isStartDragService](const OHOS::Ace::DragNotifyMsg& msg) {
913 DragNotifyMsg dragNotifyMsg = DragNotifyMsg();
914 dragNotifyMsg.displayX = msg.displayX;
915 dragNotifyMsg.displayY = msg.displayY;
916 dragNotifyMsg.targetPid = msg.targetPid;
917 dragNotifyMsg.result = TranslateDragResult(msg.result);
918 dragNotifyMsg.dragBehavior = TranslateDragBehavior(msg.dragBehavior);
919 if (isStartDragService) {
920 HandleDragEnd(asyncCtx, dragNotifyMsg);
921 } else {
922 HandleSuccess(asyncCtx, dragNotifyMsg, DragStatus::ENDED);
923 }
924 };
925 auto interactionInterface = OHOS::Ace::InteractionInterface::GetInstance();
926 int32_t ret = interactionInterface->StartDrag(dragDataCore, callback);
927 interactionInterface->SetDragWindowVisible(true);
928 return ret;
929 }
930 #endif
931
LogDragInfoInner(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,const Msdp::DeviceStatus::DragData & dragData)932 void LogDragInfoInner(std::shared_ptr<DragControllerAsyncCtx> asyncCtx, const Msdp::DeviceStatus::DragData& dragData)
933 {
934 auto pixelMap = dragData.shadowInfos[0].pixelMap;
935 std::string summarys = NG::DragDropFuncWrapper::GetSummaryString(dragData.summarys);
936 TAG_LOGI(AceLogTag::ACE_DRAG,
937 "dragData, pixelMap width %{public}d height %{public}d, udkey %{public}s, recordSize %{public}d, "
938 "extraParams length %{public}d, pointerId %{public}d, summary %{public}s, eventId %{public}d",
939 pixelMap->GetWidth(), pixelMap->GetHeight(),
940 NG::DragDropFuncWrapper::GetAnonyString(dragData.udKey).c_str(), dragData.dragNum,
941 static_cast<int32_t>(asyncCtx->extraParams.length()), asyncCtx->dragPointerEvent.pointerId,
942 summarys.c_str(), asyncCtx->dragPointerEvent.pointerEventId);
943 }
944
CreatePreviewNodeAndScale(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,NG::PreparedInfoForDrag & data,NG::PreparedAsyncCtxForAnimate & asyncCtxData,Msdp::DeviceStatus::ShadowInfo & shadowInfo,std::shared_ptr<Media::PixelMap> pixelMap)945 bool CreatePreviewNodeAndScale(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,
946 NG::PreparedInfoForDrag& data, NG::PreparedAsyncCtxForAnimate& asyncCtxData,
947 Msdp::DeviceStatus::ShadowInfo& shadowInfo, std::shared_ptr<Media::PixelMap> pixelMap)
948 {
949 CHECK_NULL_RETURN(asyncCtx, false);
950 auto container = AceEngine::Get().GetContainer(asyncCtx->instanceId);
951 auto pipeline = container->GetPipelineContext();
952 CHECK_NULL_RETURN(pipeline, false);
953 auto dragNodePipeline = AceType::DynamicCast<NG::PipelineContext>(pipeline);
954 CHECK_NULL_RETURN(dragNodePipeline, false);
955 auto scaleData =
956 NG::DragControllerFuncWrapper::GetScaleInfo(asyncCtx->instanceId, pixelMap->GetWidth(), pixelMap->GetHeight());
957 CHECK_NULL_RETURN(scaleData, false);
958 auto scale = asyncCtx->windowScale;
959 CHECK_NULL_RETURN(pixelMap, false);
960 RefPtr<PixelMap> refPixelMap = PixelMap::CreatePixelMap(reinterpret_cast<void*>(&pixelMap));
961 CHECK_NULL_RETURN(refPixelMap, false);
962 auto badgeNumber = asyncCtx->dragPreviewOption.GetCustomerBadgeNumber();
963 if (badgeNumber.has_value()) {
964 asyncCtx->badgeNumber = badgeNumber.value();
965 }
966 data = { false, asyncCtx->badgeNumber, 1.0f, false,
967 NG::OffsetF(), NG::DragControllerFuncWrapper::GetUpdateDragMovePosition(asyncCtx->instanceId), refPixelMap };
968 NG::DragControllerFuncWrapper::ResetContextMenuDragPosition(asyncCtx->instanceId);
969 if (scaleData->isNeedScale && asyncCtx->dragPreviewOption.isScaleEnabled) {
970 auto overlayManager = dragNodePipeline->GetOverlayManager();
971 auto imageNode = overlayManager->GetPixelMapContentNode();
972 scale = scaleData->scale * asyncCtx->windowScale;
973 data.previewScale = scale;
974 NG::DragControllerFuncWrapper::CreatePreviewNode(imageNode, data, asyncCtxData);
975 CHECK_NULL_RETURN(imageNode, false);
976 data.imageNode = imageNode;
977 data.dragPreviewOffsetToScreen = NG::DragControllerFuncWrapper::GetOriginNodeOffset(data, asyncCtxData);
978 }
979 auto result = GetShadowInfo(asyncCtx, shadowInfo, refPixelMap, scale);
980 if (!result) {
981 return false;
982 }
983 asyncCtxData = {asyncCtx->instanceId, asyncCtx->hasTouchPoint, asyncCtx->dragPointerEvent,
984 asyncCtx->dragPreviewOption, asyncCtx->touchPoint, asyncCtx->pixelMapList};
985 return true;
986 }
987
HideDragPreviewWindow(std::shared_ptr<DragControllerAsyncCtx> asyncCtx)988 void HideDragPreviewWindow(std::shared_ptr<DragControllerAsyncCtx> asyncCtx)
989 {
990 auto container = Container::CurrentSafely();
991 CHECK_NULL_VOID(container);
992 auto taskExecutor = container->GetTaskExecutor();
993 CHECK_NULL_VOID(taskExecutor);
994 taskExecutor->PostTask([asyncCtx]() { NG::DragControllerFuncWrapper::HideDragPreviewWindow(asyncCtx->instanceId); },
995 TaskExecutor::TaskType::UI, "ArkUIHideDragPreviewWindow", PriorityType::VIP);
996 }
997
StartDragService(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,int32_t & ret)998 void StartDragService(std::shared_ptr<DragControllerAsyncCtx> asyncCtx, int32_t& ret)
999 {
1000 CHECK_NULL_VOID(asyncCtx);
1001 auto container = AceEngine::Get().GetContainer(asyncCtx->instanceId);
1002 CHECK_NULL_VOID(container);
1003 auto pipeline = container->GetPipelineContext();
1004 CHECK_NULL_VOID(pipeline);
1005 NG::PreparedInfoForDrag data;
1006 NG::PreparedAsyncCtxForAnimate asyncCtxData;
1007 std::vector<Msdp::DeviceStatus::ShadowInfo> shadowInfos;
1008 Msdp::DeviceStatus::ShadowInfo shadowInfo;
1009 asyncCtxData = {asyncCtx->instanceId, asyncCtx->hasTouchPoint, asyncCtx->dragPointerEvent,
1010 asyncCtx->dragPreviewOption, asyncCtx->touchPoint, asyncCtx->pixelMapList};
1011 auto subWindow = NG::DragControllerFuncWrapper::SubWindowShow(pipeline);
1012 for (auto& pixelMap: asyncCtx->pixelMapList) {
1013 if (!pixelMap) {
1014 TAG_LOGD(AceLogTag::ACE_DRAG, "Skipping null pixelMap");
1015 continue;
1016 }
1017 auto ret = CreatePreviewNodeAndScale(asyncCtx, data, asyncCtxData, shadowInfo, pixelMap);
1018 if (!ret) {
1019 return;
1020 }
1021 shadowInfos.push_back(shadowInfo);
1022 }
1023 std::optional<Msdp::DeviceStatus::DragData> dragData;
1024 if (!EnvelopedDragData(asyncCtx, dragData, shadowInfos)) {
1025 return;
1026 }
1027 OnDragCallback callback = [asyncCtx](const DragNotifyMsg& dragNotifyMsg) {
1028 HideDragPreviewWindow(asyncCtx);
1029 HandleDragEnd(asyncCtx, dragNotifyMsg);
1030 };
1031 NG::DragDropFuncWrapper::SetDraggingPointerAndPressedState(
1032 asyncCtx->dragPointerEvent.pointerId, asyncCtx->instanceId);
1033 NG::DragDropFuncWrapper::SetExtraInfo(asyncCtx->instanceId, asyncCtx->extraParams);
1034 LogDragInfoInner(asyncCtx, dragData.value());
1035 #ifdef CROSS_PLATFORM
1036 ret = StartDrag(asyncCtx, dragData.value(), true);
1037 #else
1038 ret = Msdp::DeviceStatus::InteractionManager::GetInstance()->StartDrag(dragData.value(),
1039 std::make_shared<OHOS::Ace::StartDragListenerImpl>(callback));
1040 #endif
1041 if (ret == 0) {
1042 asyncCtxData.dragPointerEvent = asyncCtx->dragPointerEvent;
1043 if (NG::DragControllerFuncWrapper::TryDoDragStartAnimation(subWindow, data, asyncCtxData)) {
1044 asyncCtx->isSwitchedToSubWindow = true;
1045 }
1046 }
1047 }
1048
OnMultipleComplete(std::shared_ptr<DragControllerAsyncCtx> asyncCtx)1049 void OnMultipleComplete(std::shared_ptr<DragControllerAsyncCtx> asyncCtx)
1050 {
1051 auto container = AceEngine::Get().GetContainer(asyncCtx->instanceId);
1052 CHECK_NULL_VOID(container);
1053 auto taskExecutor = container->GetTaskExecutor();
1054 CHECK_NULL_VOID(taskExecutor);
1055 auto windowScale = container->GetWindowScale();
1056 asyncCtx->windowScale = windowScale;
1057 taskExecutor->PostTask(
1058 [asyncCtx]() {
1059 CHECK_NULL_VOID(asyncCtx);
1060 ContainerScope scope(asyncCtx->instanceId);
1061 DragState dragState = DragState::PENDING;
1062 {
1063 std::lock_guard<std::mutex> lock(asyncCtx->dragStateMutex);
1064 if (asyncCtx->dragState == DragState::PENDING) {
1065 asyncCtx->dragState = DragState::SENDING;
1066 }
1067 dragState = asyncCtx->dragState;
1068 }
1069 if (dragState == DragState::REJECT) {
1070 napi_handle_scope scope = nullptr;
1071 napi_open_handle_scope(asyncCtx->env, &scope);
1072 HandleFail(asyncCtx, ERROR_CODE_INTERNAL_ERROR, "drag state is reject.");
1073 SetMouseDragMonitorState(asyncCtx, false);
1074 napi_close_handle_scope(asyncCtx->env, scope);
1075 return;
1076 }
1077 int32_t ret = 0;
1078 StartDragService(asyncCtx, ret);
1079 if (ret != 0) {
1080 napi_handle_scope scope = nullptr;
1081 napi_open_handle_scope(asyncCtx->env, &scope);
1082 HandleFail(asyncCtx, ERROR_CODE_INTERNAL_ERROR, "msdp start drag failed.");
1083 napi_close_handle_scope(asyncCtx->env, scope);
1084 return;
1085 }
1086 HandleSuccess(asyncCtx, DragNotifyMsg {}, DragStatus::STARTED);
1087 auto container = AceEngine::Get().GetContainer(asyncCtx->instanceId);
1088 CHECK_NULL_VOID(container);
1089 SetIsDragging(container, true);
1090 TAG_LOGI(AceLogTag::ACE_DRAG, "msdp start drag successfully");
1091 ExecuteHandleOnDragStart(asyncCtx);
1092 },
1093 TaskExecutor::TaskType::JS, "ArkUIDragMultipleComplete", PriorityType::VIP);
1094 }
1095
OnComplete(std::shared_ptr<DragControllerAsyncCtx> asyncCtx)1096 void OnComplete(std::shared_ptr<DragControllerAsyncCtx> asyncCtx)
1097 {
1098 auto container = AceEngine::Get().GetContainer(asyncCtx->instanceId);
1099 CHECK_NULL_VOID(container);
1100 auto taskExecutor = container->GetTaskExecutor();
1101 CHECK_NULL_VOID(taskExecutor);
1102 auto windowScale = container->GetWindowScale();
1103 asyncCtx->windowScale = windowScale;
1104 taskExecutor->PostTask(
1105 [asyncCtx]() {
1106 CHECK_NULL_VOID(asyncCtx);
1107 ContainerScope scope(asyncCtx->instanceId);
1108 DragState dragState = DragState::PENDING;
1109 {
1110 std::lock_guard<std::mutex> lock(asyncCtx->dragStateMutex);
1111 if (asyncCtx->dragState == DragState::PENDING) {
1112 asyncCtx->dragState = DragState::SENDING;
1113 }
1114 dragState = asyncCtx->dragState;
1115 }
1116 if (dragState == DragState::REJECT) {
1117 napi_handle_scope scope = nullptr;
1118 napi_open_handle_scope(asyncCtx->env, &scope);
1119 HandleFail(asyncCtx, ERROR_CODE_INTERNAL_ERROR, "drag state is reject.");
1120 napi_close_handle_scope(asyncCtx->env, scope);
1121 return;
1122 }
1123 if (!TryToStartDrag(asyncCtx)) {
1124 TAG_LOGW(AceLogTag::ACE_DRAG, "msdp start drag failed.");
1125 return;
1126 }
1127 auto container = AceEngine::Get().GetContainer(asyncCtx->instanceId);
1128 CHECK_NULL_VOID(container);
1129 SetIsDragging(container, true);
1130 TAG_LOGI(AceLogTag::ACE_DRAG, "msdp start drag successfully");
1131 ExecuteHandleOnDragStart(asyncCtx);
1132 },
1133 TaskExecutor::TaskType::JS, "ArkUIDragComplete", PriorityType::VIP);
1134 }
1135
ExecuteHandleOnDragStart(std::shared_ptr<DragControllerAsyncCtx> asyncCtx)1136 void ExecuteHandleOnDragStart(std::shared_ptr<DragControllerAsyncCtx> asyncCtx)
1137 {
1138 CHECK_NULL_VOID(asyncCtx);
1139 {
1140 std::lock_guard<std::mutex> lock(asyncCtx->dragStateMutex);
1141 if (asyncCtx->dragState == DragState::SENDING) {
1142 asyncCtx->dragState = DragState::SUCCESS;
1143 if (!asyncCtx->isSwitchedToSubWindow) {
1144 Msdp::DeviceStatus::InteractionManager::GetInstance()->SetDragWindowVisible(true);
1145 }
1146 napi_handle_scope scope = nullptr;
1147 napi_open_handle_scope(asyncCtx->env, &scope);
1148 HandleOnDragStart(asyncCtx);
1149 napi_close_handle_scope(asyncCtx->env, scope);
1150 }
1151 }
1152 }
1153
PrepareDragData(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,Msdp::DeviceStatus::DragData & dragData,Msdp::DeviceStatus::ShadowInfo & shadowInfo)1154 bool PrepareDragData(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,
1155 Msdp::DeviceStatus::DragData& dragData, Msdp::DeviceStatus::ShadowInfo& shadowInfo)
1156 {
1157 CHECK_NULL_RETURN(asyncCtx, false);
1158 CHECK_NULL_RETURN(asyncCtx->pixelMap, false);
1159 int32_t dataSize = 1;
1160 std::string udKey;
1161 DragSummaryInfo dragSummaryInfo;
1162 dataSize = SetUnifiedData(asyncCtx, udKey, dragSummaryInfo);
1163 auto badgeNumber = asyncCtx->dragPreviewOption.GetCustomerBadgeNumber();
1164 if (badgeNumber.has_value()) {
1165 dataSize = badgeNumber.value();
1166 }
1167 auto container = AceEngine::Get().GetContainer(asyncCtx->instanceId);
1168 CHECK_NULL_RETURN(container, false);
1169 if (!container->GetLastMovingPointerPosition(asyncCtx->dragPointerEvent)) {
1170 napi_handle_scope scope = nullptr;
1171 napi_open_handle_scope(asyncCtx->env, &scope);
1172 HandleFail(asyncCtx, ERROR_CODE_INTERNAL_ERROR, "can not find current pointerId or not in press");
1173 napi_close_handle_scope(asyncCtx->env, scope);
1174 return false;
1175 }
1176 auto arkExtraInfoJson = JsonUtil::Create(true);
1177 arkExtraInfoJson->Put("dip_scale", asyncCtx->dipScale);
1178 arkExtraInfoJson->Put("event_id", asyncCtx->dragPointerEvent.pointerEventId);
1179 NG::DragDropFuncWrapper::UpdateExtraInfo(arkExtraInfoJson, asyncCtx->dragPreviewOption);
1180 auto windowId = container->GetWindowId();
1181 dragData = { { shadowInfo }, {}, udKey, asyncCtx->extraParams,
1182 arkExtraInfoJson->ToString(), asyncCtx->dragPointerEvent.sourceType, dataSize,
1183 asyncCtx->dragPointerEvent.pointerId, asyncCtx->dragPointerEvent.displayX,
1184 asyncCtx->dragPointerEvent.displayY, asyncCtx->dragPointerEvent.displayId,
1185 windowId, true, false, dragSummaryInfo.summary, false, dragSummaryInfo.detailedSummary,
1186 dragSummaryInfo.summaryFormat, dragSummaryInfo.version, dragSummaryInfo.totalSize };
1187 return true;
1188 }
1189
TryToStartDrag(std::shared_ptr<DragControllerAsyncCtx> asyncCtx)1190 bool TryToStartDrag(std::shared_ptr<DragControllerAsyncCtx> asyncCtx)
1191 {
1192 CHECK_NULL_RETURN(asyncCtx, false);
1193 auto container = AceEngine::Get().GetContainer(asyncCtx->instanceId);
1194 CHECK_NULL_RETURN(container, false);
1195 auto pipeline = container->GetPipelineContext();
1196 CHECK_NULL_RETURN(pipeline, false);
1197 NG::PreparedInfoForDrag data;
1198 NG::PreparedAsyncCtxForAnimate asyncCtxData;
1199 Msdp::DeviceStatus::ShadowInfo shadowInfo;
1200 asyncCtxData = {asyncCtx->instanceId, asyncCtx->hasTouchPoint, asyncCtx->dragPointerEvent,
1201 asyncCtx->dragPreviewOption, asyncCtx->touchPoint, asyncCtx->pixelMapList};
1202 auto subWindow = NG::DragControllerFuncWrapper::SubWindowShow(pipeline);
1203 auto ret = CreatePreviewNodeAndScale(asyncCtx, data, asyncCtxData, shadowInfo, asyncCtx->pixelMap);
1204 if (!ret) {
1205 return false;
1206 }
1207 Msdp::DeviceStatus::DragData dragData;
1208 if (!PrepareDragData(asyncCtx, dragData, shadowInfo)) {
1209 TAG_LOGW(AceLogTag::ACE_DRAG, "prepare drag data failed!");
1210 return false;
1211 }
1212 OnDragCallback callback = [asyncCtx](const DragNotifyMsg& dragNotifyMsg) {
1213 HideDragPreviewWindow(asyncCtx);
1214 HandleSuccess(asyncCtx, dragNotifyMsg, DragStatus::ENDED);
1215 };
1216 NG::DragDropFuncWrapper::SetDraggingPointerAndPressedState(
1217 asyncCtx->dragPointerEvent.pointerId, asyncCtx->instanceId);
1218 LogDragInfoInner(asyncCtx, dragData);
1219 #ifdef CROSS_PLATFORM
1220 int32_t result = StartDrag(asyncCtx, dragData, false);
1221 #else
1222 int32_t result = Msdp::DeviceStatus::InteractionManager::GetInstance()->StartDrag(dragData,
1223 std::make_shared<OHOS::Ace::StartDragListenerImpl>(callback));
1224 #endif
1225 if (result != 0) {
1226 napi_handle_scope scope = nullptr;
1227 napi_open_handle_scope(asyncCtx->env, &scope);
1228 HandleFail(asyncCtx, ERROR_CODE_INTERNAL_ERROR, "msdp start drag failed.");
1229 napi_close_handle_scope(asyncCtx->env, scope);
1230 return false;
1231 }
1232 if (NG::DragControllerFuncWrapper::TryDoDragStartAnimation(subWindow, data, asyncCtxData)) {
1233 asyncCtx->isSwitchedToSubWindow = true;
1234 }
1235 return true;
1236 }
1237
ParseTouchPoint(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,napi_valuetype & valueType)1238 bool ParseTouchPoint(std::shared_ptr<DragControllerAsyncCtx> asyncCtx, napi_valuetype& valueType)
1239 {
1240 napi_value touchPointNapi = nullptr;
1241 napi_get_named_property(asyncCtx->env, asyncCtx->argv[1], "touchPoint", &touchPointNapi);
1242 napi_typeof(asyncCtx->env, touchPointNapi, &valueType);
1243 if (valueType == napi_object) {
1244 napi_value xNapi = nullptr;
1245 napi_get_named_property(asyncCtx->env, touchPointNapi, "x", &xNapi);
1246 std::optional<Dimension> dx = HandleDimensionType(xNapi, asyncCtx->env);
1247 if (dx == std::nullopt) {
1248 return false;
1249 }
1250 napi_value yNapi = nullptr;
1251 napi_get_named_property(asyncCtx->env, touchPointNapi, "y", &yNapi);
1252 std::optional<Dimension> dy = HandleDimensionType(yNapi, asyncCtx->env);
1253 if (dy == std::nullopt) {
1254 return false;
1255 }
1256 asyncCtx->touchPoint = DimensionOffset(dx.value(), dy.value());
1257 } else {
1258 return false;
1259 }
1260 return true;
1261 }
1262
ParseDataLoadParams(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,napi_valuetype & valueType)1263 bool ParseDataLoadParams(std::shared_ptr<DragControllerAsyncCtx> asyncCtx, napi_valuetype& valueType)
1264 {
1265 CHECK_NULL_RETURN(asyncCtx, false);
1266 napi_value dataLoadParamsNApi = nullptr;
1267 napi_get_named_property(asyncCtx->env, asyncCtx->argv[1], "dataLoadParams", &dataLoadParamsNApi);
1268 napi_typeof(asyncCtx->env, dataLoadParamsNApi, &valueType);
1269 if (valueType == napi_object) {
1270 auto dataLoadParams = UdmfClient::GetInstance()->TransformDataLoadParams(asyncCtx->env, dataLoadParamsNApi);
1271 CHECK_NULL_RETURN(dataLoadParams, false);
1272 asyncCtx->dataLoadParams = dataLoadParams;
1273 asyncCtx->unifiedData = nullptr;
1274 return true;
1275 }
1276 return false;
1277 }
1278
ParseDragItemInfoParam(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,std::string & errMsg)1279 bool ParseDragItemInfoParam(std::shared_ptr<DragControllerAsyncCtx> asyncCtx, std::string& errMsg)
1280 {
1281 CHECK_NULL_RETURN(asyncCtx, false);
1282 napi_valuetype valueType = napi_undefined;
1283 napi_typeof(asyncCtx->env, asyncCtx->argv[0], &valueType);
1284 if (valueType == napi_function) {
1285 asyncCtx->customBuilder = asyncCtx->argv[0];
1286 return true;
1287 }
1288
1289 if (valueType != napi_object) {
1290 errMsg = "The type of first parameter is incorrect.";
1291 return false;
1292 }
1293 // Parse the DragItemInfo
1294 napi_value pixelMapValue;
1295 napi_get_named_property(asyncCtx->env, asyncCtx->argv[0], "pixelMap", &pixelMapValue);
1296 PixelMapNapiEntry pixelMapNapiEntry = Framework::JsEngine::GetPixelMapNapiEntry();
1297 if (pixelMapNapiEntry == nullptr) {
1298 TAG_LOGW(AceLogTag::ACE_DRAG, "failed to parse pixelMap from the first argument");
1299 } else {
1300 void* pixmapPtrAddr = pixelMapNapiEntry(asyncCtx->env, pixelMapValue);
1301 if (pixmapPtrAddr == nullptr) {
1302 napi_get_named_property(asyncCtx->env, asyncCtx->argv[0], "builder", &(asyncCtx->customBuilder));
1303 napi_typeof(asyncCtx->env, asyncCtx->customBuilder, &valueType);
1304 if (valueType != napi_function) {
1305 errMsg = "The first parameter is not a pixelMap or customBuilder.";
1306 return false;
1307 }
1308 } else {
1309 asyncCtx->pixelMap = *(reinterpret_cast<std::shared_ptr<Media::PixelMap>*>(pixmapPtrAddr));
1310 }
1311 }
1312
1313 napi_value extraInfoValue;
1314 napi_get_named_property(asyncCtx->env, asyncCtx->argv[0], "extraInfo", &extraInfoValue);
1315 napi_typeof(asyncCtx->env, extraInfoValue, &valueType);
1316 if (valueType == napi_string) {
1317 GetNapiString(asyncCtx->env, extraInfoValue, asyncCtx->extraParams, valueType);
1318 } else if (valueType != napi_undefined) {
1319 errMsg = "The type of extraInfo of the first parameter is incorrect.";
1320 return false;
1321 }
1322 return true;
1323 }
1324
GetPixelMapByCustom(std::shared_ptr<DragControllerAsyncCtx> asyncCtx)1325 bool GetPixelMapByCustom(std::shared_ptr<DragControllerAsyncCtx> asyncCtx)
1326 {
1327 CHECK_NULL_RETURN(asyncCtx, false);
1328 napi_escapable_handle_scope scope = nullptr;
1329 napi_open_escapable_handle_scope(asyncCtx->env, &scope);
1330 auto delegate = EngineHelper::GetCurrentDelegateSafely();
1331 if (!delegate) {
1332 NapiThrow(asyncCtx->env, "ace engine delegate is null", ERROR_CODE_INTERNAL_ERROR);
1333 napi_close_escapable_handle_scope(asyncCtx->env, scope);
1334 return false;
1335 }
1336 auto callback = [asyncCtx](std::shared_ptr<Media::PixelMap> pixelMap, int32_t errCode,
1337 std::function<void()> finishCallback) {
1338 CHECK_NULL_VOID(asyncCtx);
1339 auto container = AceEngine::Get().GetContainer(asyncCtx->instanceId);
1340 CHECK_NULL_VOID(container);
1341 auto taskExecutor = container->GetTaskExecutor();
1342 CHECK_NULL_VOID(taskExecutor);
1343 taskExecutor->PostTask(
1344 [finishCallback]() {
1345 CHECK_NULL_VOID(finishCallback);
1346 finishCallback();
1347 },
1348 TaskExecutor::TaskType::JS, "ArkUIGetPixelMapByCustom");
1349 CHECK_NULL_VOID(pixelMap);
1350 asyncCtx->errCode = errCode;
1351 asyncCtx->pixelMap = std::move(pixelMap);
1352 OnComplete(asyncCtx);
1353 };
1354 auto builder = [build = asyncCtx->customBuilder, env = asyncCtx->env] {
1355 napi_call_function(env, nullptr, build, 0, nullptr, nullptr);
1356 };
1357 NG::SnapshotParam param;
1358 param.delay = CREATE_PIXELMAP_DELAY_TIME;
1359 param.checkImageStatus = true;
1360 param.options.waitUntilRenderFinished = true;
1361 delegate->CreateSnapshot(builder, callback, true, param);
1362 napi_close_escapable_handle_scope(asyncCtx->env, scope);
1363 return true;
1364 }
1365
GetPixelMapArrayByCustom(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,napi_value customBuilder,int arrayLength)1366 bool GetPixelMapArrayByCustom(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,
1367 napi_value customBuilder, int arrayLength)
1368 {
1369 CHECK_NULL_RETURN(asyncCtx, false);
1370 napi_escapable_handle_scope scope = nullptr;
1371 napi_open_escapable_handle_scope(asyncCtx->env, &scope);
1372
1373 auto delegate = EngineHelper::GetCurrentDelegateSafely();
1374 if (!delegate) {
1375 NapiThrow(asyncCtx->env, "ace engine delegate is null", ERROR_CODE_INTERNAL_ERROR);
1376 napi_close_escapable_handle_scope(asyncCtx->env, scope);
1377 return false;
1378 }
1379 auto callback = [asyncCtx, arrayLength](
1380 std::shared_ptr<Media::PixelMap> pixelMap, int32_t errCode, std::function<void()> finishCallback) {
1381 CHECK_NULL_VOID(asyncCtx);
1382 auto container = AceEngine::Get().GetContainer(asyncCtx->instanceId);
1383 CHECK_NULL_VOID(container);
1384 auto taskExecutor = container->GetTaskExecutor();
1385 CHECK_NULL_VOID(taskExecutor);
1386 taskExecutor->PostTask(
1387 [finishCallback]() {
1388 CHECK_NULL_VOID(finishCallback);
1389 finishCallback();
1390 },
1391 TaskExecutor::TaskType::JS, "ArkUIGetPixelMapArrayByCustom");
1392 CHECK_NULL_VOID(pixelMap);
1393 asyncCtx->errCode = errCode;
1394 asyncCtx->pixelMapList.push_back(std::move(pixelMap));
1395 asyncCtx->parseBuilderCount++;
1396 if (asyncCtx->parseBuilderCount == arrayLength) {
1397 OnMultipleComplete(asyncCtx);
1398 }
1399 };
1400 auto builder = [build = customBuilder, env = asyncCtx->env] {
1401 napi_call_function(env, nullptr, build, 0, nullptr, nullptr);
1402 };
1403 NG::SnapshotParam param;
1404 param.delay = CREATE_PIXELMAP_DELAY_TIME;
1405 param.checkImageStatus = true;
1406 param.options.waitUntilRenderFinished = true;
1407 delegate->CreateSnapshot(builder, callback, true, param);
1408 napi_close_escapable_handle_scope(asyncCtx->env, scope);
1409 return true;
1410 }
1411
ParseExtraInfo(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,std::string & errMsg,napi_value element)1412 bool ParseExtraInfo(std::shared_ptr<DragControllerAsyncCtx> asyncCtx, std::string& errMsg, napi_value element)
1413 {
1414 CHECK_NULL_RETURN(asyncCtx, false);
1415 napi_value extraInfoValue;
1416 napi_get_named_property(asyncCtx->env, element, "extraInfo", &extraInfoValue);
1417 napi_valuetype valueType = napi_undefined;
1418 napi_typeof(asyncCtx->env, extraInfoValue, &valueType);
1419 if (valueType != napi_string && valueType != napi_undefined) {
1420 errMsg = "The type of extraInfo of the first parameter is incorrect.";
1421 return false;
1422 }
1423 GetNapiString(asyncCtx->env, extraInfoValue, asyncCtx->extraParams, valueType);
1424 return true;
1425 }
1426
ParsePixelMapAndBuilder(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,std::string & errMsg,napi_value element)1427 bool ParsePixelMapAndBuilder(std::shared_ptr<DragControllerAsyncCtx> asyncCtx, std::string& errMsg, napi_value element)
1428 {
1429 CHECK_NULL_RETURN(asyncCtx, false);
1430 napi_value pixelMapValue;
1431 napi_get_named_property(asyncCtx->env, element, "pixelMap", &pixelMapValue);
1432 PixelMapNapiEntry pixelMapNapiEntry = Framework::JsEngine::GetPixelMapNapiEntry();
1433 if (pixelMapNapiEntry == nullptr) {
1434 TAG_LOGW(AceLogTag::ACE_DRAG, "failed to parse pixelMap from the first argument");
1435 } else {
1436 void* pixmapPtrAddr = pixelMapNapiEntry(asyncCtx->env, pixelMapValue);
1437 if (pixmapPtrAddr == nullptr) {
1438 TAG_LOGW(AceLogTag::ACE_DRAG, "the pixelMap parsed from the first argument is null");
1439 napi_value customBuilderValue;
1440 napi_get_named_property(asyncCtx->env, element, "builder", &customBuilderValue);
1441 napi_valuetype valueType = napi_undefined;
1442 napi_typeof(asyncCtx->env, customBuilderValue, &valueType);
1443 if (valueType != napi_function) {
1444 errMsg = "The type of customBuilder of the first parameter is incorrect.";
1445 return false;
1446 }
1447 napi_ref ref = nullptr;
1448 napi_create_reference(asyncCtx->env, customBuilderValue, 1, &ref);
1449 asyncCtx->customBuilderList.push_back(ref);
1450 } else {
1451 asyncCtx->pixelMapList.push_back(*(reinterpret_cast<std::shared_ptr<Media::PixelMap>*>(pixmapPtrAddr)));
1452 }
1453 }
1454 return true;
1455 }
1456
ParseDragItemListInfoParam(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,std::string & errMsg)1457 bool ParseDragItemListInfoParam(std::shared_ptr<DragControllerAsyncCtx> asyncCtx, std::string& errMsg)
1458 {
1459 CHECK_NULL_RETURN(asyncCtx, false);
1460 bool isParseSucess;
1461 uint32_t arrayLength = 0;
1462 napi_get_array_length(asyncCtx->env, asyncCtx->argv[0], &arrayLength);
1463 for (size_t i = 0; i < arrayLength; i++) {
1464 bool hasElement = false;
1465 napi_has_element(asyncCtx->env, asyncCtx->argv[0], i, &hasElement);
1466 napi_value element = nullptr;
1467 napi_get_element(asyncCtx->env, asyncCtx->argv[0], i, &element);
1468 napi_valuetype valueType = napi_undefined;
1469 napi_typeof(asyncCtx->env, element, &valueType);
1470 if (valueType == napi_function) {
1471 napi_ref ref = nullptr;
1472 napi_create_reference(asyncCtx->env, element, 1, &ref);
1473 asyncCtx->customBuilderList.push_back(ref);
1474 isParseSucess = true;
1475 continue;
1476 }
1477 if (valueType != napi_object) {
1478 errMsg = "The type of first parameter is incorrect";
1479 isParseSucess = false;
1480 break;
1481 }
1482 if (!ParseExtraInfo(asyncCtx, errMsg, element)) {
1483 errMsg = "The type of first parameter is incorrect by extraInfo";
1484 isParseSucess = false;
1485 break;
1486 }
1487 if (!ParsePixelMapAndBuilder(asyncCtx, errMsg, element)) {
1488 errMsg = "The type of first parameter is incorrect by pixelMap or builder";
1489 isParseSucess = false;
1490 break;
1491 }
1492 isParseSucess = true;
1493 continue;
1494 }
1495 return isParseSucess;
1496 }
1497
ParseDragParam(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,std::string & errMsg)1498 bool ParseDragParam(std::shared_ptr<DragControllerAsyncCtx> asyncCtx, std::string& errMsg)
1499 {
1500 CHECK_NULL_RETURN(asyncCtx, false);
1501 napi_valuetype valueType = napi_undefined;
1502 napi_typeof(asyncCtx->env, asyncCtx->argv[0], &valueType);
1503 if (valueType == napi_function) {
1504 asyncCtx->customBuilder = asyncCtx->argv[0];
1505 return true;
1506 }
1507 if (valueType != napi_object) {
1508 errMsg = "The type of first parameter is incorrect.";
1509 return false;
1510 }
1511
1512 bool isArray = false;
1513 napi_is_array(asyncCtx->env, asyncCtx->argv[0], &isArray);
1514 if (isArray) {
1515 TAG_LOGI(AceLogTag::ACE_DRAG, "drag controller is multi object drag.");
1516 asyncCtx->isArray = true;
1517 return ParseDragItemListInfoParam(asyncCtx, errMsg);
1518 }
1519 asyncCtx->isArray = false;
1520 return ParseDragItemInfoParam(asyncCtx, errMsg);
1521 }
1522
ApplyPreviewOptionsFromModifier(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,napi_value modifierObj,NG::DragPreviewOption & option)1523 bool ApplyPreviewOptionsFromModifier(
1524 std::shared_ptr<DragControllerAsyncCtx> asyncCtx, napi_value modifierObj, NG::DragPreviewOption& option)
1525 {
1526 CHECK_NULL_RETURN(asyncCtx, false);
1527 napi_valuetype valueType = napi_undefined;
1528 napi_typeof(asyncCtx->env, modifierObj, &valueType);
1529 if (valueType == napi_undefined) {
1530 return true;
1531 }
1532 if (valueType != napi_object) {
1533 return false;
1534 }
1535
1536 napi_value globalObj = nullptr;
1537 napi_get_global(asyncCtx->env, &globalObj);
1538 napi_value globalFunc = nullptr;
1539 napi_get_named_property(asyncCtx->env, globalObj, "applyImageModifierToNode", &globalFunc);
1540 napi_typeof(asyncCtx->env, globalFunc, &valueType);
1541 if (globalFunc == nullptr || valueType != napi_function) {
1542 return false;
1543 }
1544
1545 auto applyOnNodeSync =
1546 [modifierObj, globalFunc, asyncCtx](WeakPtr<NG::FrameNode> frameNode) {
1547 // convert nodeptr to js value
1548 auto nodePtr = frameNode.Upgrade();
1549 const size_t size = 64; // fake size for gc
1550 napi_value nodeJsValue = nullptr;
1551 napi_create_external_with_size(
1552 asyncCtx->env, static_cast<void*>(AceType::RawPtr(nodePtr)),
1553 [](napi_env env, void* data, void* hint) {}, static_cast<void*>(AceType::RawPtr(nodePtr)),
1554 &nodeJsValue, size);
1555 if (nodeJsValue == nullptr) {
1556 return;
1557 }
1558 // apply modifier
1559 napi_value ret;
1560 napi_value params[2];
1561 params[0] = modifierObj;
1562 params[1] = nodeJsValue;
1563 napi_call_function(asyncCtx->env, nullptr, globalFunc, 2, params, &ret);
1564 };
1565
1566 NG::DragDropFuncWrapper::UpdateDragPreviewOptionsFromModifier(applyOnNodeSync, option);
1567 return true;
1568 }
1569
GetNamedPropertyModifier(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,napi_value previewOptionsNApi,std::string & errMsg)1570 bool GetNamedPropertyModifier(
1571 std::shared_ptr<DragControllerAsyncCtx> asyncCtx, napi_value previewOptionsNApi, std::string& errMsg)
1572 {
1573 napi_value modifierObj = nullptr;
1574 napi_get_named_property(asyncCtx->env, previewOptionsNApi, "modifier", &modifierObj);
1575 if (!ApplyPreviewOptionsFromModifier(asyncCtx, modifierObj, asyncCtx->dragPreviewOption)) {
1576 errMsg = "apply modifier failed.";
1577 return false;
1578 }
1579 return true;
1580 }
1581
SetDragPreviewOptionMode(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,napi_value & modeNApi,std::string & errMsg,bool & isAuto)1582 bool SetDragPreviewOptionMode(std::shared_ptr<DragControllerAsyncCtx> asyncCtx, napi_value& modeNApi,
1583 std::string& errMsg, bool& isAuto)
1584 {
1585 napi_valuetype valueType = napi_undefined;
1586 napi_typeof(asyncCtx->env, modeNApi, &valueType);
1587 if (valueType == napi_undefined) {
1588 return true;
1589 } else if (valueType != napi_number) {
1590 errMsg = "mode type is wrong";
1591 return false;
1592 } else if (isAuto) {
1593 return true;
1594 }
1595
1596 int32_t dragPreviewMode = 0;
1597 napi_get_value_int32(asyncCtx->env, modeNApi, &dragPreviewMode);
1598 auto mode = static_cast<NG::DragPreviewMode>(dragPreviewMode);
1599 switch (mode) {
1600 case NG::DragPreviewMode::AUTO:
1601 asyncCtx->dragPreviewOption.ResetDragPreviewMode();
1602 isAuto = true;
1603 break;
1604 case NG::DragPreviewMode::DISABLE_SCALE:
1605 asyncCtx->dragPreviewOption.isScaleEnabled = false;
1606 break;
1607 case NG::DragPreviewMode::ENABLE_DEFAULT_SHADOW:
1608 asyncCtx->dragPreviewOption.isDefaultShadowEnabled = true;
1609 break;
1610 case NG::DragPreviewMode::ENABLE_DEFAULT_RADIUS:
1611 asyncCtx->dragPreviewOption.isDefaultRadiusEnabled = true;
1612 break;
1613 default:
1614 break;
1615 }
1616 return true;
1617 }
1618
ParseDragPreviewMode(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,napi_value & previewOptionsNApi,std::string & errMsg)1619 bool ParseDragPreviewMode(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,
1620 napi_value& previewOptionsNApi, std::string& errMsg)
1621 {
1622 napi_value modeNApi = nullptr;
1623 napi_get_named_property(asyncCtx->env, previewOptionsNApi, "mode", &modeNApi);
1624 bool isArray = false;
1625 bool isAuto = false;
1626 napi_is_array(asyncCtx->env, modeNApi, &isArray);
1627 if (isArray) {
1628 uint32_t arrayLength = 0;
1629 napi_get_array_length(asyncCtx->env, modeNApi, &arrayLength);
1630 for (size_t i = 0; i < arrayLength; i++) {
1631 bool hasElement = false;
1632 napi_has_element(asyncCtx->env, modeNApi, i, &hasElement);
1633 if (!hasElement) {
1634 continue;
1635 }
1636 napi_value element = nullptr;
1637 napi_get_element(asyncCtx->env, modeNApi, i, &element);
1638 if (!SetDragPreviewOptionMode(asyncCtx, element, errMsg, isAuto)) {
1639 return false;
1640 }
1641 }
1642 } else if (!SetDragPreviewOptionMode(asyncCtx, modeNApi, errMsg, isAuto)) {
1643 return false;
1644 }
1645 NG::DragDropFuncWrapper::UpdatePreviewOptionDefaultAttr(asyncCtx->dragPreviewOption);
1646 return true;
1647 }
1648
GetCurrentDipScale(std::shared_ptr<DragControllerAsyncCtx> asyncCtx)1649 void GetCurrentDipScale(std::shared_ptr<DragControllerAsyncCtx> asyncCtx)
1650 {
1651 auto container = AceEngine::Get().GetContainer(asyncCtx->instanceId);
1652 CHECK_NULL_VOID(container);
1653 auto pipeline = container->GetPipelineContext();
1654 CHECK_NULL_VOID(pipeline);
1655 asyncCtx->dipScale = pipeline->GetDipScale();
1656 }
1657
ParsePreviewOptions(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,napi_valuetype & valueType,std::string & errMsg)1658 bool ParsePreviewOptions(
1659 std::shared_ptr<DragControllerAsyncCtx> asyncCtx, napi_valuetype& valueType, std::string& errMsg)
1660 {
1661 CHECK_NULL_RETURN(asyncCtx, false);
1662 napi_handle_scope scope = nullptr;
1663 napi_open_handle_scope(asyncCtx->env, &scope);
1664 asyncCtx->dragPreviewOption.isNumber = false;
1665 asyncCtx->dragPreviewOption.isShowBadge = true;
1666 napi_value previewOptionsNApi = nullptr;
1667 napi_get_named_property(asyncCtx->env, asyncCtx->argv[1], "previewOptions", &previewOptionsNApi);
1668 napi_typeof(asyncCtx->env, previewOptionsNApi, &valueType);
1669 if (valueType == napi_object) {
1670 if (!ParseDragPreviewMode(asyncCtx, previewOptionsNApi, errMsg)) {
1671 napi_close_handle_scope(asyncCtx->env, scope);
1672 return false;
1673 }
1674
1675 napi_value numberBadgeNApi = nullptr;
1676 napi_get_named_property(asyncCtx->env, previewOptionsNApi, "numberBadge", &numberBadgeNApi);
1677 napi_typeof(asyncCtx->env, numberBadgeNApi, &valueType);
1678 if (valueType == napi_number) {
1679 int64_t number = 0;
1680 napi_get_value_int64(asyncCtx->env, numberBadgeNApi, &number);
1681 if (number < 0 || number > INT_MAX) {
1682 asyncCtx->dragPreviewOption.isNumber = false;
1683 asyncCtx->dragPreviewOption.isShowBadge = true;
1684 } else {
1685 asyncCtx->dragPreviewOption.isNumber = true;
1686 asyncCtx->dragPreviewOption.isShowBadge = false;
1687 asyncCtx->dragPreviewOption.badgeNumber = number;
1688 }
1689 } else if (valueType == napi_boolean) {
1690 asyncCtx->dragPreviewOption.isNumber = false;
1691 napi_get_value_bool(asyncCtx->env, numberBadgeNApi, &asyncCtx->dragPreviewOption.isShowBadge);
1692 } else if (valueType != napi_undefined) {
1693 errMsg = "numberBadge type is wrong.";
1694 napi_close_handle_scope(asyncCtx->env, scope);
1695 return false;
1696 }
1697
1698 if (!(GetNamedPropertyModifier(asyncCtx, previewOptionsNApi, errMsg))) {
1699 napi_close_handle_scope(asyncCtx->env, scope);
1700 return false;
1701 }
1702 } else if (valueType != napi_undefined) {
1703 errMsg = "previewOptions type is wrong";
1704 napi_close_handle_scope(asyncCtx->env, scope);
1705 return false;
1706 }
1707 napi_close_handle_scope(asyncCtx->env, scope);
1708 return true;
1709 }
1710
ParseDragInfoParam(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,std::string & errMsg)1711 bool ParseDragInfoParam(std::shared_ptr<DragControllerAsyncCtx> asyncCtx, std::string& errMsg)
1712 {
1713 CHECK_NULL_RETURN(asyncCtx, false);
1714 napi_valuetype valueType = napi_undefined;
1715 napi_typeof(asyncCtx->env, asyncCtx->argv[1], &valueType);
1716 if (valueType != napi_object) {
1717 errMsg = "The type of second parameter is incorrect.";
1718 return false;
1719 }
1720 napi_value pointerIdNApi = nullptr;
1721 napi_status status = napi_ok;
1722 napi_get_named_property(asyncCtx->env, asyncCtx->argv[1], "pointerId", &pointerIdNApi);
1723 napi_typeof(asyncCtx->env, pointerIdNApi, &valueType);
1724 if (valueType != napi_number) {
1725 errMsg = "pointerId which type is number must be given";
1726 return false;
1727 }
1728 status = napi_get_value_int32(asyncCtx->env, pointerIdNApi, &asyncCtx->dragPointerEvent.pointerId);
1729 if (status != napi_ok) {
1730 errMsg = "parse pointerId fail";
1731 return false;
1732 }
1733
1734 napi_value dataNApi = nullptr;
1735 napi_get_named_property(asyncCtx->env, asyncCtx->argv[1], "data", &dataNApi);
1736 napi_typeof(asyncCtx->env, dataNApi, &valueType);
1737 if (valueType == napi_object) {
1738 asyncCtx->unifiedData = UdmfClient::GetInstance()->TransformUnifiedData(dataNApi);
1739 } else if (valueType != napi_undefined) {
1740 errMsg = "data's type is wrong";
1741 return false;
1742 }
1743
1744 napi_value extraParamsNApi = nullptr;
1745 napi_get_named_property(asyncCtx->env, asyncCtx->argv[1], "extraParams", &extraParamsNApi);
1746 napi_typeof(asyncCtx->env, extraParamsNApi, &valueType);
1747 if (valueType == napi_string) {
1748 GetNapiString(asyncCtx->env, extraParamsNApi, asyncCtx->extraParams, valueType);
1749 } else if (valueType != napi_undefined) {
1750 errMsg = "extraParams's type is wrong";
1751 return false;
1752 }
1753
1754 if (!ParsePreviewOptions(asyncCtx, valueType, errMsg)) {
1755 return false;
1756 }
1757
1758 GetCurrentDipScale(asyncCtx);
1759 asyncCtx->hasTouchPoint = ParseTouchPoint(asyncCtx, valueType);
1760
1761 ParseDataLoadParams(asyncCtx, valueType);
1762 return true;
1763 }
1764
CheckAndParseParams(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,std::string & errMsg)1765 bool CheckAndParseParams(std::shared_ptr<DragControllerAsyncCtx> asyncCtx, std::string& errMsg)
1766 {
1767 // Check the number of the argument
1768 CHECK_NULL_RETURN(asyncCtx, false);
1769 if ((asyncCtx->argc != ARG_COUNT_2) && (asyncCtx->argc != ARG_COUNT_3)) {
1770 errMsg = "The number of parameters must be 2 or 3.";
1771 return false;
1772 }
1773
1774 // Check and parse the first parameter
1775 if (!ParseDragParam(asyncCtx, errMsg)) {
1776 return false;
1777 }
1778
1779 // Check and parse the second parameter
1780 return ParseDragInfoParam(asyncCtx, errMsg);
1781 }
1782
CreateCallback(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,napi_value * result)1783 void CreateCallback(std::shared_ptr<DragControllerAsyncCtx> asyncCtx, napi_value* result)
1784 {
1785 CHECK_NULL_VOID(asyncCtx);
1786 if (asyncCtx->argc == ARG_COUNT_3) {
1787 // Create the JsCallback
1788 napi_create_reference(asyncCtx->env, asyncCtx->argv[2], 1, &asyncCtx->callbackRef);
1789 }
1790 if (!asyncCtx->callbackRef) {
1791 // Create the promise
1792 napi_create_promise(asyncCtx->env, &asyncCtx->deferred, result);
1793 } else {
1794 napi_get_undefined(asyncCtx->env, result);
1795 }
1796 }
1797
InitializeDragControllerCtx(napi_env env,napi_callback_info info,std::shared_ptr<DragControllerAsyncCtx> asyncCtx)1798 void InitializeDragControllerCtx(napi_env env, napi_callback_info info,
1799 std::shared_ptr<DragControllerAsyncCtx> asyncCtx)
1800 {
1801 CHECK_NULL_VOID(asyncCtx);
1802 napi_value thisVar = nullptr;
1803 void* data = nullptr;
1804 asyncCtx->instanceId = Container::CurrentIdSafely();
1805 asyncCtx->env = env;
1806 // get arguments from JS
1807 napi_get_cb_info(asyncCtx->env, info, &(asyncCtx->argc), asyncCtx->argv, &thisVar, &data);
1808 }
1809
getParameterType(std::shared_ptr<DragControllerAsyncCtx> asyncCtx)1810 ParameterType getParameterType(std::shared_ptr<DragControllerAsyncCtx> asyncCtx)
1811 {
1812 CHECK_NULL_RETURN(asyncCtx, ParameterType::ERROR);
1813 if (asyncCtx->pixelMap != nullptr) {
1814 return ParameterType::DRAGITEMINFO;
1815 }
1816 if (asyncCtx->customBuilder != nullptr) {
1817 return ParameterType::CUSTOMBUILDER;
1818 }
1819 if (!asyncCtx->pixelMapList.empty() && asyncCtx->customBuilderList.empty()) {
1820 return ParameterType::DRAGITEMINFO_ARRAY;
1821 }
1822 if (!asyncCtx->customBuilderList.empty() || !asyncCtx->pixelMapList.empty()) {
1823 return ParameterType::MIX;
1824 } else {
1825 return ParameterType::ERROR;
1826 }
1827 }
1828
HandleStopDragCallback(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,const RefPtr<Container> & container)1829 void HandleStopDragCallback(std::shared_ptr<DragControllerAsyncCtx> asyncCtx, const RefPtr<Container>& container)
1830 {
1831 CHECK_NULL_VOID(asyncCtx);
1832 CHECK_NULL_VOID(container);
1833 bool needPostStopDrag = false;
1834 {
1835 std::lock_guard<std::mutex> lock(asyncCtx->dragStateMutex);
1836 needPostStopDrag = (asyncCtx->dragState == DragState::SENDING);
1837 asyncCtx->dragState = DragState::REJECT;
1838 }
1839 if (needPostStopDrag) {
1840 auto pipelineContext = container->GetPipelineContext();
1841 CHECK_NULL_VOID(pipelineContext);
1842 pipelineContext->ResetDragging();
1843 auto taskExecutor = container->GetTaskExecutor();
1844 CHECK_NULL_VOID(taskExecutor);
1845 auto windowId = container->GetWindowId();
1846 taskExecutor->PostTask(
1847 [asyncCtx, windowId]() {
1848 CHECK_NULL_VOID(asyncCtx);
1849 napi_handle_scope scope = nullptr;
1850 napi_open_handle_scope(asyncCtx->env, &scope);
1851 HandleFail(asyncCtx, ERROR_CODE_INTERNAL_ERROR, "drag state error, stop drag.");
1852 napi_close_handle_scope(asyncCtx->env, scope);
1853 TAG_LOGI(AceLogTag::ACE_DRAG,
1854 "drag state is reject, stop drag, windowId is %{public}d.", windowId);
1855 Msdp::DeviceStatus::DragDropResult dropResult { Msdp::DeviceStatus::DragResult::DRAG_CANCEL, false,
1856 windowId, Msdp::DeviceStatus::DragBehavior::UNKNOWN };
1857 Msdp::DeviceStatus::InteractionManager::GetInstance()->StopDrag(dropResult);
1858 Msdp::DeviceStatus::InteractionManager::GetInstance()->SetDragWindowVisible(false);
1859 },
1860 TaskExecutor::TaskType::JS, "ArkUIDragStop", PriorityType::VIP);
1861 }
1862 }
1863
ConfirmCurPointerEventInfo(std::shared_ptr<DragControllerAsyncCtx> asyncCtx,const RefPtr<Container> & container)1864 bool ConfirmCurPointerEventInfo(std::shared_ptr<DragControllerAsyncCtx> asyncCtx, const RefPtr<Container>& container)
1865 {
1866 CHECK_NULL_RETURN(asyncCtx, false);
1867 CHECK_NULL_RETURN(container, false);
1868 StopDragCallback stopDragCallback = [asyncCtx, container]() {
1869 HandleStopDragCallback(asyncCtx, container);
1870 };
1871 bool getPointSuccess = container->GetCurPointerEventInfo(
1872 asyncCtx->dragPointerEvent, std::move(stopDragCallback));
1873 if (asyncCtx->dragPointerEvent.sourceType == SOURCE_TYPE_MOUSE) {
1874 asyncCtx->dragPointerEvent.pointerId = MOUSE_POINTER_ID;
1875 } else if (asyncCtx->dragPointerEvent.sourceType == SOURCE_TYPE_TOUCH &&
1876 static_cast<int32_t>(asyncCtx->dragPointerEvent.sourceTool) == SOURCE_TOOL_PEN) {
1877 asyncCtx->dragPointerEvent.pointerId = PEN_POINTER_ID;
1878 }
1879 return getPointSuccess;
1880 }
1881
CheckDragging(const RefPtr<Container> & container)1882 static bool CheckDragging(const RefPtr<Container>& container)
1883 {
1884 CHECK_NULL_RETURN(container, false);
1885 auto pipelineContext = container->GetPipelineContext();
1886 if (!pipelineContext || !pipelineContext->IsDragging()) {
1887 return false;
1888 }
1889 return true;
1890 }
1891
JSExecuteDrag(napi_env env,napi_callback_info info)1892 static napi_value JSExecuteDrag(napi_env env, napi_callback_info info)
1893 {
1894 TAG_LOGI(AceLogTag::ACE_DRAG, "executeDrag fuction called.");
1895 napi_escapable_handle_scope scope = nullptr;
1896 napi_open_escapable_handle_scope(env, &scope);
1897
1898 auto dragAsyncContext = std::make_shared<DragControllerAsyncCtx>();
1899 if (dragAsyncContext == nullptr) {
1900 NapiThrow(env, "create drag controller async context failed.", ERROR_CODE_INTERNAL_ERROR);
1901 napi_close_escapable_handle_scope(env, scope);
1902 return nullptr;
1903 }
1904 InitializeDragControllerCtx(env, info, dragAsyncContext);
1905
1906 std::string errMsg;
1907 if (!CheckAndParseParams(dragAsyncContext, errMsg)) {
1908 NapiThrow(env, errMsg, ERROR_CODE_PARAM_INVALID);
1909 napi_close_escapable_handle_scope(env, scope);
1910 return nullptr;
1911 }
1912 napi_value result = nullptr;
1913 CreateCallback(dragAsyncContext, &result);
1914 auto container = AceEngine::Get().GetContainer(dragAsyncContext->instanceId);
1915 if (!container) {
1916 NapiThrow(env, "get container failed.", ERROR_CODE_INTERNAL_ERROR);
1917 napi_close_escapable_handle_scope(env, scope);
1918 return nullptr;
1919 }
1920 if (CheckDragging(container)) {
1921 NapiThrow(env, "only one drag is allowed at the same time", ERROR_CODE_INTERNAL_ERROR);
1922 napi_close_escapable_handle_scope(env, scope);
1923 return nullptr;
1924 }
1925 auto getPointSuccess = ConfirmCurPointerEventInfo(dragAsyncContext, container);
1926 if (!getPointSuccess) {
1927 NapiThrow(env, "confirm current point info failed.", ERROR_CODE_INTERNAL_ERROR);
1928 napi_escape_handle(env, scope, result, &result);
1929 napi_close_escapable_handle_scope(env, scope);
1930 return result;
1931 }
1932 SetMouseDragMonitorState(dragAsyncContext, true);
1933 HandleExecuteDrag(env, dragAsyncContext);
1934 napi_escape_handle(env, scope, result, &result);
1935 napi_close_escapable_handle_scope(env, scope);
1936 return result;
1937 }
1938
JSCreateDragAction(napi_env env,napi_callback_info info)1939 static napi_value JSCreateDragAction(napi_env env, napi_callback_info info)
1940 {
1941 napi_escapable_handle_scope scope = nullptr;
1942 napi_open_escapable_handle_scope(env, &scope);
1943
1944 auto dragAsyncContext = std::make_shared<DragControllerAsyncCtx>();
1945 if (dragAsyncContext == nullptr) {
1946 NapiThrow(env, "create drag controller async context failed.", ERROR_CODE_INTERNAL_ERROR);
1947 napi_close_escapable_handle_scope(env, scope);
1948 return nullptr;
1949 }
1950 InitializeDragControllerCtx(env, info, dragAsyncContext);
1951
1952 std::string errMsg = "";
1953 if (!CheckAndParseParams(dragAsyncContext, errMsg)) {
1954 NapiThrow(env, errMsg, ERROR_CODE_PARAM_INVALID);
1955 napi_close_escapable_handle_scope(env, scope);
1956 return nullptr;
1957 }
1958
1959 auto container = AceEngine::Get().GetContainer(dragAsyncContext->instanceId);
1960 if (!container) {
1961 NapiThrow(env, "get container failed.", ERROR_CODE_INTERNAL_ERROR);
1962 napi_close_escapable_handle_scope(env, scope);
1963 return nullptr;
1964 }
1965
1966 if (CheckDragging(container)) {
1967 NapiThrow(env, "only one dragAction is allowed at the same time", ERROR_CODE_INTERNAL_ERROR);
1968 napi_close_escapable_handle_scope(env, scope);
1969 return nullptr;
1970 }
1971
1972 auto getPointSuccess = ConfirmCurPointerEventInfo(dragAsyncContext, container);
1973 if (!getPointSuccess) {
1974 NapiThrow(env, "confirm pointer info failed", ERROR_CODE_PARAM_INVALID);
1975 napi_close_escapable_handle_scope(env, scope);
1976 return nullptr;
1977 }
1978
1979 napi_value result = nullptr;
1980 napi_create_object(env, &result);
1981 DragAction* dragAction = new DragAction(dragAsyncContext);
1982 dragAction->NapiSerializer(env, result);
1983 if (!result) {
1984 dragAction->DeleteRef();
1985 delete dragAction;
1986 napi_close_escapable_handle_scope(env, scope);
1987 return nullptr;
1988 }
1989 dragAsyncContext->dragAction = dragAction;
1990 napi_escape_handle(env, scope, result, &result);
1991 napi_close_escapable_handle_scope(env, scope);
1992 return result;
1993 }
1994
JSGetDragPreview(napi_env env,napi_callback_info info)1995 static napi_value JSGetDragPreview(napi_env env, napi_callback_info info)
1996 {
1997 DragPreview* dragPreview = new DragPreview();
1998 napi_value result = nullptr;
1999 napi_create_object(env, &result);
2000 dragPreview->NapiSerializer(env, result);
2001 if (!result) {
2002 delete dragPreview;
2003 return nullptr;
2004 }
2005 return result;
2006 }
2007 #else
2008
JSGetDragPreview(napi_env env,napi_callback_info info)2009 static napi_value JSGetDragPreview(napi_env env, napi_callback_info info)
2010 {
2011 napi_escapable_handle_scope scope = nullptr;
2012 napi_open_escapable_handle_scope(env, &scope);
2013 NapiThrow(env, "The current environment does not enable drag framework or does not support drag preview.",
2014 ERROR_CODE_INTERNAL_ERROR);
2015 napi_close_escapable_handle_scope(env, scope);
2016 return nullptr;
2017 }
2018
JSExecuteDrag(napi_env env,napi_callback_info info)2019 static napi_value JSExecuteDrag(napi_env env, napi_callback_info info)
2020 {
2021 napi_escapable_handle_scope scope = nullptr;
2022 napi_open_escapable_handle_scope(env, &scope);
2023 NapiThrow(env, "The current environment does not enable drag framework or does not support pixelMap.",
2024 ERROR_CODE_INTERNAL_ERROR);
2025 napi_close_escapable_handle_scope(env, scope);
2026 return nullptr;
2027 }
2028
JSCreateDragAction(napi_env env,napi_callback_info info)2029 static napi_value JSCreateDragAction(napi_env env, napi_callback_info info)
2030 {
2031 napi_escapable_handle_scope scope = nullptr;
2032 napi_open_escapable_handle_scope(env, &scope);
2033 NapiThrow(env, "The current environment does not enable drag framework or does not support pixelMap.",
2034 ERROR_CODE_INTERNAL_ERROR);
2035 napi_close_escapable_handle_scope(env, scope);
2036 return nullptr;
2037 }
2038 #endif
2039
2040 // The default empty implementation function setForegroundColor for dragPreview.
JsDragPreviewSetForegroundColor(napi_env env,napi_callback_info info)2041 static napi_value JsDragPreviewSetForegroundColor(napi_env env, napi_callback_info info)
2042 {
2043 return nullptr;
2044 }
2045
2046 // The default empty implementation function animate for dragPreview.
JsDragPreviewAnimate(napi_env env,napi_callback_info info)2047 static napi_value JsDragPreviewAnimate(napi_env env, napi_callback_info info)
2048 {
2049 return nullptr;
2050 }
2051
2052 // The default empty constructor for dragPreview.
DragPreviewConstructor(napi_env env,napi_callback_info info)2053 static napi_value DragPreviewConstructor(napi_env env, napi_callback_info info)
2054 {
2055 napi_value thisArg = nullptr;
2056 void* data = nullptr;
2057 napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, &data);
2058 napi_value global = nullptr;
2059 napi_get_global(env, &global);
2060 return thisArg;
2061 }
2062
DragControllerExport(napi_env env,napi_value exports)2063 static napi_value DragControllerExport(napi_env env, napi_value exports)
2064 {
2065 napi_value dragStatus = nullptr;
2066 napi_create_object(env, &dragStatus);
2067 napi_value prop = nullptr;
2068 napi_create_uint32(env, DRAG_STARTED, &prop);
2069 napi_set_named_property(env, dragStatus, "STARTED", prop);
2070 napi_create_uint32(env, DRAG_ENDED, &prop);
2071 napi_set_named_property(env, dragStatus, "ENDED", prop);
2072
2073 napi_property_descriptor dragPreviewDesc[] = {
2074 DECLARE_NAPI_FUNCTION("setForegroundColor", JsDragPreviewSetForegroundColor),
2075 DECLARE_NAPI_FUNCTION("animate", JsDragPreviewAnimate),
2076 };
2077 napi_value classDragPreview = nullptr;
2078 napi_define_class(env, "DragPreview", NAPI_AUTO_LENGTH, DragPreviewConstructor, nullptr,
2079 sizeof(dragPreviewDesc) / sizeof(*dragPreviewDesc), dragPreviewDesc, &classDragPreview);
2080
2081 napi_property_descriptor dragControllerDesc[] = {
2082 DECLARE_NAPI_FUNCTION("executeDrag", JSExecuteDrag),
2083 DECLARE_NAPI_FUNCTION("getDragPreview", JSGetDragPreview),
2084 DECLARE_NAPI_FUNCTION("createDragAction", JSCreateDragAction),
2085 DECLARE_NAPI_PROPERTY("DragStatus", dragStatus),
2086 DECLARE_NAPI_PROPERTY("DragPreview", classDragPreview),
2087 };
2088 NAPI_CALL(env, napi_define_properties(
2089 env, exports, sizeof(dragControllerDesc) / sizeof(dragControllerDesc[0]), dragControllerDesc));
2090 return exports;
2091 }
2092
2093 static napi_module dragControllerModule = {
2094 .nm_version = 1,
2095 .nm_flags = 0,
2096 .nm_filename = nullptr,
2097 .nm_register_func = DragControllerExport,
2098 .nm_modname = "arkui.dragController",
2099 .nm_priv = ((void*)0),
2100 .reserved = { 0 },
2101 };
2102
DragControllerRegister()2103 extern "C" __attribute__((constructor)) void DragControllerRegister()
2104 {
2105 napi_module_register(&dragControllerModule);
2106 }
2107 } // namespace OHOS::Ace::Napi
2108