1 /*
2  * Copyright (c) 2021-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 "core/components_ng/gestures/recognizers/long_press_recognizer.h"
17 
18 #include "base/perf/socperf_client.h"
19 #include "base/thread/frame_trace_adapter.h"
20 #include "base/utils/time_util.h"
21 #include "base/utils/utils.h"
22 #include "core/components/common/layout/constants.h"
23 #include "core/components_ng/base/frame_node.h"
24 #include "core/components_ng/event/gesture_event_hub.h"
25 #include "core/components_ng/gestures/base_gesture_event.h"
26 #include "core/components_ng/gestures/gesture_referee.h"
27 #include "core/components_ng/gestures/recognizers/gesture_recognizer.h"
28 #include "core/components_ng/gestures/recognizers/multi_fingers_recognizer.h"
29 #include "core/event/ace_events.h"
30 #include "core/pipeline_ng/pipeline_context.h"
31 
32 namespace OHOS::Ace::NG {
33 namespace {
34 constexpr double MAX_THRESHOLD = 15.0;
35 constexpr int32_t MAX_LONGPRESS_FINGERS = 10;
36 constexpr int32_t DEFAULT_LONGPRESS_FINGERS = 1;
37 constexpr int32_t DEFAULT_LONGPRESS_DURATION = 500;
38 } // namespace
39 
LongPressRecognizer(int32_t duration,int32_t fingers,bool repeat,bool isForDrag,bool isDisableMouseLeft)40 LongPressRecognizer::LongPressRecognizer(
41     int32_t duration, int32_t fingers, bool repeat, bool isForDrag, bool isDisableMouseLeft)
42     : MultiFingersRecognizer(fingers), duration_(duration), repeat_(repeat), isForDrag_(isForDrag),
43       isDisableMouseLeft_(isDisableMouseLeft)
44 {
45     if (fingers_ > MAX_LONGPRESS_FINGERS || fingers_ < DEFAULT_LONGPRESS_FINGERS) {
46         fingers_ = DEFAULT_LONGPRESS_FINGERS;
47     }
48     if (duration_ <= 0) {
49         duration_ = DEFAULT_LONGPRESS_DURATION;
50     }
51 }
52 
OnAccepted()53 void LongPressRecognizer::OnAccepted()
54 {
55     int64_t acceptTime = GetSysTimestamp();
56     int64_t inputTime = acceptTime;
57     if (firstInputTime_.has_value()) {
58         inputTime = static_cast<int64_t>(firstInputTime_.value().time_since_epoch().count());
59     }
60     if (SystemProperties::GetTraceInputEventEnabled()) {
61         ACE_SCOPED_TRACE("UserEvent InputTime:%lld AcceptTime:%lld InputType:LongPressGesture",
62             static_cast<long long>(inputTime), static_cast<long long>(acceptTime));
63     }
64 
65     auto node = GetAttachedNode().Upgrade();
66     TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW, "LongPress accepted, tag = %{public}s",
67         node ? node->GetTag().c_str() : "null");
68     if (onAccessibilityEventFunc_) {
69         onAccessibilityEventFunc_(AccessibilityEventType::LONG_PRESS);
70     }
71     refereeState_ = RefereeState::SUCCEED;
72     if (onLongPress_ && !touchPoints_.empty()) {
73         TouchEvent trackPoint = touchPoints_.begin()->second;
74         PointF localPoint(trackPoint.GetOffset().GetX(), trackPoint.GetOffset().GetY());
75         NGGestureRecognizer::Transform(localPoint, GetAttachedNode(), false,
76             isPostEventResult_, trackPoint.postEventNodeId);
77         LongPressInfo info(trackPoint.id);
78         info.SetTimeStamp(time_);
79         info.SetScreenLocation(trackPoint.GetScreenOffset());
80         info.SetGlobalLocation(trackPoint.GetOffset()).SetLocalLocation(Offset(localPoint.GetX(), localPoint.GetY()));
81         info.SetTarget(GetEventTarget().value_or(EventTarget()));
82         onLongPress_(info);
83     }
84 
85     UpdateFingerListInfo();
86     SendCallbackMsg(onActionUpdate_, false);
87     SendCallbackMsg(onAction_, false, true);
88     if (repeat_) {
89         StartRepeatTimer();
90     }
91 }
92 
OnRejected()93 void LongPressRecognizer::OnRejected()
94 {
95     if (refereeState_ == RefereeState::SUCCEED) {
96         return;
97     }
98     SendRejectMsg();
99     refereeState_ = RefereeState::FAIL;
100     firstInputTime_.reset();
101 }
102 
ThumbnailTimer(int32_t time)103 void LongPressRecognizer::ThumbnailTimer(int32_t time)
104 {
105     auto context = PipelineContext::GetCurrentContext();
106     CHECK_NULL_VOID(context);
107     if (!callback_) {
108         return;
109     }
110     auto&& callback = [weakPtr = AceType::WeakClaim(this), customCallback = callback_]() {
111         auto refPtr = weakPtr.Upgrade();
112         if (!refPtr) {
113             return;
114         }
115         if (refPtr->refereeState_ == RefereeState::DETECTING) {
116             customCallback(Offset(refPtr->globalPoint_.GetX(), refPtr->globalPoint_.GetY()));
117         }
118     };
119     thumbnailTimer_.Reset(callback);
120     auto taskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
121     taskExecutor.PostDelayedTask(thumbnailTimer_, time, "ArkUIGestureLongPressThumbnailTimer");
122 }
123 
HandleTouchDownEvent(const TouchEvent & event)124 void LongPressRecognizer::HandleTouchDownEvent(const TouchEvent& event)
125 {
126     TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW, "Id:%{public}d, LongPress %{public}d down, state: %{public}d",
127         event.touchEventId, event.id, refereeState_);
128     extraInfo_ = "";
129     if (!firstInputTime_.has_value()) {
130         firstInputTime_ = event.time;
131     }
132 
133     if (isDisableMouseLeft_ && event.sourceType == SourceType::MOUSE) {
134         TAG_LOGI(AceLogTag::ACE_GESTURE, "Mouse left button is disabled for long press recognizer");
135         extraInfo_ += "Reject: mouse left button disabled.";
136         Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
137         return;
138     }
139 
140     if (!IsInAttachedNode(event)) {
141         extraInfo_ += "Reject: not in attached node.";
142         Adjudicate(Claim(this), GestureDisposal::REJECT);
143         return;
144     }
145     int32_t curDuration = duration_;
146 #if defined(OHOS_STANDARD_SYSTEM) && !defined(PREVIEW)
147     if (!IsPostEventResult()) {
148         int64_t currentTimeStamp = GetSysTimestamp();
149         int64_t eventTimeStamp = static_cast<int64_t>(event.time.time_since_epoch().count());
150         if (currentTimeStamp > eventTimeStamp) {
151             // nanoseconds to millisceond.
152             curDuration = curDuration - static_cast<int32_t>((currentTimeStamp - eventTimeStamp) / (1000 * 1000));
153             curDuration = curDuration < 0 ? 0 : curDuration;
154         }
155     }
156 #endif
157 
158     if (isForDrag_ && event.sourceType == SourceType::MOUSE) {
159         curDuration = 0;
160     }
161     if ((touchRestrict_.forbiddenType & TouchRestrict::LONG_PRESS) == TouchRestrict::LONG_PRESS) {
162         extraInfo_ += "Reject: long press forbidden.";
163         Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
164         return;
165     }
166     if (fingersId_.find(event.id) == fingersId_.end()) {
167         fingersId_.insert(event.id);
168     }
169     globalPoint_ = Point(event.x, event.y);
170     touchPoints_[event.id] = event;
171     lastTouchEvent_ = event;
172     UpdateFingerListInfo();
173     if (GetValidFingersCount() == fingers_) {
174         refereeState_ = RefereeState::DETECTING;
175         if (useCatchMode_) {
176             DeadlineTimer(curDuration, true);
177         } else {
178             DeadlineTimer(curDuration, false);
179         }
180     } else {
181         PrintCurrentFingersInfo();
182     }
183 
184     ThumbnailTimer(thumbnailDeadline);
185 }
186 
HandleTouchUpEvent(const TouchEvent & event)187 void LongPressRecognizer::HandleTouchUpEvent(const TouchEvent& event)
188 {
189     TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW, "Id:%{public}d, LongPress %{public}d up, state: %{public}d",
190         event.touchEventId, event.id, refereeState_);
191     auto context = PipelineContext::GetCurrentContext();
192     CHECK_NULL_VOID(context);
193     context->RemoveGestureTask(task_);
194     if (fingersId_.find(event.id) != fingersId_.end()) {
195         fingersId_.erase(event.id);
196     }
197     if (touchPoints_.find(event.id) != touchPoints_.end()) {
198         touchPoints_.erase(event.id);
199     }
200     lastTouchEvent_ = event;
201     if (refereeState_ == RefereeState::SUCCEED) {
202         SendCallbackMsg(onActionUpdate_, false);
203         if (static_cast<int32_t>(touchPoints_.size()) == 0) {
204             SendCallbackMsg(onActionEnd_, false);
205             int64_t overTime = GetSysTimestamp();
206             int64_t inputTime = overTime;
207             if (firstInputTime_.has_value()) {
208                 inputTime = static_cast<int64_t>(firstInputTime_.value().time_since_epoch().count());
209             }
210             if (SystemProperties::GetTraceInputEventEnabled()) {
211                 ACE_SCOPED_TRACE("UserEvent InputTime:%lld OverTime:%lld InputType:LongPressGesture",
212                     static_cast<long long>(inputTime), static_cast<long long>(overTime));
213             }
214             firstInputTime_.reset();
215         }
216     } else {
217         extraInfo_ += "Reject: received up but not succeed.";
218         Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
219     }
220 }
221 
HandleTouchMoveEvent(const TouchEvent & event)222 void LongPressRecognizer::HandleTouchMoveEvent(const TouchEvent& event)
223 {
224     lastTouchEvent_.pressedKeyCodes_ = event.pressedKeyCodes_;
225     if (static_cast<int32_t>(touchPoints_.size()) < fingers_) {
226         return;
227     }
228     if (IsRefereeFinished()) {
229         return;
230     }
231     Offset offset = event.GetOffset() - touchPoints_[event.id].GetOffset();
232     if (offset.GetDistance() > MAX_THRESHOLD) {
233         extraInfo_ += "Reject: move over max threshold.";
234         Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
235         return;
236     }
237     lastTouchEvent_ = event;
238     UpdateFingerListInfo();
239     time_ = event.time;
240 }
241 
HandleTouchCancelEvent(const TouchEvent & event)242 void LongPressRecognizer::HandleTouchCancelEvent(const TouchEvent& event)
243 {
244     TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW, "Id:%{public}d, LongPress %{public}d cancel, TPS:%{public}d",
245         event.touchEventId, event.id, static_cast<int32_t>(touchPoints_.size()));
246     if (refereeState_ == RefereeState::FAIL) {
247         return;
248     }
249     lastTouchEvent_ = event;
250     if (touchPoints_.find(event.id) != touchPoints_.end()) {
251         touchPoints_.erase(event.id);
252     }
253     if (refereeState_ == RefereeState::SUCCEED && static_cast<int32_t>(touchPoints_.size()) == 0) {
254         SendCancelMsg();
255         refereeState_ = RefereeState::READY;
256         extraInfo_ += "Reject: received cancel and succeed.";
257     } else {
258         extraInfo_ += "Reject: received cancel but not succeed.";
259         Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
260     }
261 }
262 
HandleOverdueDeadline(bool isCatchMode)263 void LongPressRecognizer::HandleOverdueDeadline(bool isCatchMode)
264 {
265     if (refereeState_ != RefereeState::DETECTING) {
266         return;
267     }
268     if (!isCatchMode) {
269         OnAccepted();
270         return;
271     }
272     if (gestureInfo_ && gestureInfo_->GetType() == GestureTypeName::DRAG) {
273         auto dragEventActuator = GetDragEventActuator();
274         CHECK_NULL_VOID(dragEventActuator);
275         if (dragEventActuator->IsDragUserReject()) {
276             TAG_LOGI(AceLogTag::ACE_GESTURE, "Drag long press reject because of user's reject");
277             extraInfo_ += "Reject: user reject.";
278             Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
279             return;
280         }
281     }
282     auto onGestureJudgeBeginResult = TriggerGestureJudgeCallback();
283     if (onGestureJudgeBeginResult == GestureJudgeResult::REJECT) {
284         TAG_LOGI(AceLogTag::ACE_GESTURE, "Long press reject as judge result is reject");
285         extraInfo_ += "Reject: judge reject.";
286         Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
287         if (gestureInfo_ && gestureInfo_->GetType() == GestureTypeName::DRAG) {
288             auto dragEventActuator = GetDragEventActuator();
289             CHECK_NULL_VOID(dragEventActuator);
290             dragEventActuator->SetIsDragUserReject(true);
291         }
292         return;
293     }
294     Adjudicate(AceType::Claim(this), GestureDisposal::ACCEPT);
295 }
296 
DeadlineTimer(int32_t time,bool isCatchMode)297 void LongPressRecognizer::DeadlineTimer(int32_t time, bool isCatchMode)
298 {
299     auto context = PipelineContext::GetCurrentContext();
300     CHECK_NULL_VOID(context);
301 
302     auto&& callback = [weakPtr = AceType::WeakClaim(this), isCatchMode]() {
303         auto refPtr = weakPtr.Upgrade();
304         if (refPtr) {
305             refPtr->HandleOverdueDeadline(isCatchMode);
306         }
307     };
308     task_ = { WeakClaim(this), GetSysTimestamp(), time, callback };
309     context->AddGestureTask(task_);
310 
311     auto&& flushCallback = []() {
312         auto context = PipelineContext::GetCurrentContext();
313         CHECK_NULL_VOID(context);
314         context->RequestFrame();
315     };
316     deadlineTimer_.Reset(flushCallback);
317     auto taskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
318     taskExecutor.PostDelayedTask(deadlineTimer_, time, "ArkUIGestureLongPressDeadlineTimer");
319 }
320 
DoRepeat()321 void LongPressRecognizer::DoRepeat()
322 {
323     if (static_cast<int32_t>(touchPoints_.size()) < fingers_) {
324         return;
325     }
326     if (refereeState_ == RefereeState::SUCCEED) {
327         SendCallbackMsg(onAction_, true, true);
328         StartRepeatTimer();
329     }
330 }
331 
StartRepeatTimer()332 void LongPressRecognizer::StartRepeatTimer()
333 {
334     auto context = PipelineContext::GetCurrentContext();
335     CHECK_NULL_VOID(context);
336 
337     auto&& callback = [weakPtr = AceType::WeakClaim(this)]() {
338         auto refPtr = weakPtr.Upgrade();
339         if (refPtr) {
340             refPtr->DoRepeat();
341         }
342     };
343     timer_.Reset(callback);
344     auto taskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
345     taskExecutor.PostDelayedTask(timer_, duration_, "ArkUIGestureLongPressRepeatTimer");
346 }
347 
ConvertPxToVp(double offset) const348 double LongPressRecognizer::ConvertPxToVp(double offset) const
349 {
350     auto context = PipelineContext::GetCurrentContext();
351     CHECK_NULL_RETURN(context, offset);
352 
353     double vpOffset = context->ConvertPxToVp(Dimension(offset, DimensionUnit::PX));
354     return vpOffset;
355 }
356 
SendCallbackMsg(const std::unique_ptr<GestureEventFunc> & callback,bool isRepeat,bool isOnAction)357 void LongPressRecognizer::SendCallbackMsg(
358     const std::unique_ptr<GestureEventFunc>& callback, bool isRepeat, bool isOnAction)
359 {
360     if (gestureInfo_ && gestureInfo_->GetDisposeTag()) {
361         return;
362     }
363     if (callback && *callback) {
364         GestureEvent info;
365         info.SetTimeStamp(time_);
366         info.SetRepeat(isRepeat);
367         info.SetFingerList(fingerList_);
368         info.SetSourceDevice(deviceType_);
369         info.SetDeviceId(deviceId_);
370         info.SetTargetDisplayId(lastTouchEvent_.targetDisplayId);
371         info.SetGlobalPoint(globalPoint_);
372         info.SetScreenLocation(lastTouchEvent_.GetScreenOffset());
373         info.SetGlobalLocation(lastTouchEvent_.GetOffset())
374             .SetLocalLocation(lastTouchEvent_.GetOffset() - coordinateOffset_);
375         info.SetTarget(GetEventTarget().value_or(EventTarget()));
376         info.SetForce(lastTouchEvent_.force);
377         if (lastTouchEvent_.tiltX.has_value()) {
378             info.SetTiltX(lastTouchEvent_.tiltX.value());
379         }
380         if (lastTouchEvent_.tiltY.has_value()) {
381             info.SetTiltY(lastTouchEvent_.tiltY.value());
382         }
383         info.SetSourceTool(lastTouchEvent_.sourceTool);
384         info.SetPointerEvent(lastPointEvent_);
385         Platform::UpdatePressedKeyCodes(lastTouchEvent_.pressedKeyCodes_);
386         info.SetPressedKeyCodes(lastTouchEvent_.pressedKeyCodes_);
387         info.SetInputEventType(inputEventType_);
388         // callback may be overwritten in its invoke so we copy it first
389         auto callbackFunction = *callback;
390         callbackFunction(info);
391         if (isOnAction && longPressRecorder_ && *longPressRecorder_) {
392             (*longPressRecorder_)(info);
393         }
394     }
395 }
396 
OnResetStatus()397 void LongPressRecognizer::OnResetStatus()
398 {
399     MultiFingersRecognizer::OnResetStatus();
400     timer_.Cancel();
401     deadlineTimer_.Cancel();
402     auto context = PipelineContext::GetCurrentContext();
403     CHECK_NULL_VOID(context);
404     context->RemoveGestureTask(task_);
405 }
406 
ReconcileFrom(const RefPtr<NGGestureRecognizer> & recognizer)407 bool LongPressRecognizer::ReconcileFrom(const RefPtr<NGGestureRecognizer>& recognizer)
408 {
409     RefPtr<LongPressRecognizer> curr = AceType::DynamicCast<LongPressRecognizer>(recognizer);
410     if (!curr) {
411         ResetStatus();
412         return false;
413     }
414 
415     if (curr->duration_ != duration_ || curr->fingers_ != fingers_ || curr->repeat_ != repeat_ ||
416         curr->priorityMask_ != priorityMask_) {
417         if (refereeState_ == RefereeState::SUCCEED && static_cast<int32_t>(touchPoints_.size()) > 0) {
418             SendCancelMsg();
419         }
420         ResetStatus();
421         return false;
422     }
423 
424     onAction_ = std::move(curr->onAction_);
425     onActionEnd_ = std::move(curr->onActionEnd_);
426     onActionCancel_ = std::move(curr->onActionCancel_);
427     ReconcileGestureInfoFrom(recognizer);
428     return true;
429 }
430 
GetLongPressActionFunc()431 GestureEventFunc LongPressRecognizer::GetLongPressActionFunc()
432 {
433     auto callback = [weak = WeakClaim(this)](GestureEvent& info) {
434         auto longPressRecognizer = weak.Upgrade();
435         CHECK_NULL_VOID(longPressRecognizer);
436         if (longPressRecognizer->onActionUpdate_) {
437             (*(longPressRecognizer->onActionUpdate_))(info);
438         }
439         if (longPressRecognizer->onAction_) {
440             (*(longPressRecognizer->onAction_))(info);
441         }
442         if (longPressRecognizer->onActionUpdate_) {
443             (*(longPressRecognizer->onActionUpdate_))(info);
444         }
445         if (longPressRecognizer->onActionEnd_) {
446             (*(longPressRecognizer->onActionEnd_))(info);
447         }
448     };
449     return callback;
450 }
451 
Dump() const452 RefPtr<GestureSnapshot> LongPressRecognizer::Dump() const
453 {
454     RefPtr<GestureSnapshot> info = NGGestureRecognizer::Dump();
455     std::stringstream oss;
456     oss << "duration: " << duration_ << ", "
457         << "isForDrag: " << isForDrag_ << ", "
458         << "repeat: " << repeat_ << ", "
459         << "fingers: " << fingers_ << ", "
460         << DumpGestureInfo();
461     info->customInfo = oss.str();
462     return info;
463 }
464 
PrintCurrentFingersInfo() const465 void LongPressRecognizer::PrintCurrentFingersInfo() const
466 {
467     std::string log = "Fingers number = ";
468     log += std::to_string(GetValidFingersCount());
469     log += " fingers_ = ";
470     log += std::to_string(fingers_);
471     log += ". ";
472     for (const auto& iter : touchPoints_) {
473         log += "Event id = ";
474         log += std::to_string(iter.first);
475         log += ", event type = ";
476         log += std::to_string(static_cast<int32_t>(iter.second.type));
477         log += "; ";
478     }
479     TAG_LOGI(AceLogTag::ACE_GESTURE, "Finger info : %{public}s", log.c_str());
480 }
481 
TriggerGestureJudgeCallback()482 GestureJudgeResult LongPressRecognizer::TriggerGestureJudgeCallback()
483 {
484     auto targetComponent = GetTargetComponent();
485     CHECK_NULL_RETURN(targetComponent, GestureJudgeResult::CONTINUE);
486     auto gestureRecognizerJudgeFunc = targetComponent->GetOnGestureRecognizerJudgeBegin();
487     auto callback = targetComponent->GetOnGestureJudgeBeginCallback();
488     if (!callback && !gestureRecognizerJudgeFunc) {
489         return GestureJudgeResult::CONTINUE;
490     }
491     auto info = std::make_shared<LongPressGestureEvent>();
492     info->SetTimeStamp(time_);
493     info->SetDeviceId(deviceId_);
494     info->SetRepeat(repeat_);
495     info->SetFingerList(fingerList_);
496     TouchEvent trackPoint = {};
497     if (!touchPoints_.empty()) {
498         trackPoint = touchPoints_.begin()->second;
499     }
500     info->SetSourceDevice(deviceType_);
501     info->SetTarget(GetEventTarget().value_or(EventTarget()));
502     info->SetForce(trackPoint.force);
503     if (gestureInfo_) {
504         gestureInfo_->SetInputEventType(inputEventType_);
505     }
506     if (trackPoint.tiltX.has_value()) {
507         info->SetTiltX(trackPoint.tiltX.value());
508     }
509     if (trackPoint.tiltY.has_value()) {
510         info->SetTiltY(trackPoint.tiltY.value());
511     }
512     info->SetSourceTool(trackPoint.sourceTool);
513     if (gestureRecognizerJudgeFunc) {
514         return gestureRecognizerJudgeFunc(info, Claim(this), responseLinkRecognizer_);
515     }
516     return callback(gestureInfo_, info);
517 }
518 
GetDragEventActuator()519 RefPtr<DragEventActuator> LongPressRecognizer::GetDragEventActuator()
520 {
521     auto targetComponent = GetTargetComponent();
522     CHECK_NULL_RETURN(targetComponent, nullptr);
523     auto uiNode = targetComponent->GetUINode().Upgrade();
524     CHECK_NULL_RETURN(uiNode, nullptr);
525     auto frameNode = AceType::DynamicCast<FrameNode>(uiNode);
526     CHECK_NULL_RETURN(frameNode, nullptr);
527     auto gestureEventHub = frameNode->GetOrCreateGestureEventHub();
528     CHECK_NULL_RETURN(gestureEventHub, nullptr);
529     return gestureEventHub->GetDragEventActuator();
530 }
531 
532 } // namespace OHOS::Ace::NG
533