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