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