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,bool isLimitFingerCount)40 LongPressRecognizer::LongPressRecognizer(
41 int32_t duration, int32_t fingers, bool repeat, bool isForDrag, bool isDisableMouseLeft, bool isLimitFingerCount)
42 : MultiFingersRecognizer(fingers, isLimitFingerCount), 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 if (isLimitFingerCount_ && static_cast<int32_t>(touchPoints_.size()) == fingers_) {
203 SendCallbackMsg(onAction_, false, true);
204 }
205 SendCallbackMsg(onActionUpdate_, false);
206 if (static_cast<int32_t>(touchPoints_.size()) == 0) {
207 SendCallbackMsg(onActionEnd_, false);
208 int64_t overTime = GetSysTimestamp();
209 int64_t inputTime = overTime;
210 if (firstInputTime_.has_value()) {
211 inputTime = static_cast<int64_t>(firstInputTime_.value().time_since_epoch().count());
212 }
213 if (SystemProperties::GetTraceInputEventEnabled()) {
214 ACE_SCOPED_TRACE("UserEvent InputTime:%lld OverTime:%lld InputType:LongPressGesture",
215 static_cast<long long>(inputTime), static_cast<long long>(overTime));
216 }
217 firstInputTime_.reset();
218 }
219 } else {
220 extraInfo_ += "Reject: received up but not succeed.";
221 Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
222 }
223 }
224
HandleTouchMoveEvent(const TouchEvent & event)225 void LongPressRecognizer::HandleTouchMoveEvent(const TouchEvent& event)
226 {
227 lastTouchEvent_.pressedKeyCodes_ = event.pressedKeyCodes_;
228 if (static_cast<int32_t>(touchPoints_.size()) < fingers_) {
229 return;
230 }
231 if (IsRefereeFinished()) {
232 return;
233 }
234 Offset offset = event.GetOffset() - touchPoints_[event.id].GetOffset();
235 if (offset.GetDistance() > MAX_THRESHOLD) {
236 extraInfo_ += "Reject: move over max threshold.";
237 Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
238 return;
239 }
240 touchPoints_[event.id].operatingHand = event.operatingHand;
241 lastTouchEvent_ = event;
242 UpdateFingerListInfo();
243 time_ = event.time;
244 }
245
HandleTouchCancelEvent(const TouchEvent & event)246 void LongPressRecognizer::HandleTouchCancelEvent(const TouchEvent& event)
247 {
248 TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW, "Id:%{public}d, LongPress %{public}d cancel, TPS:%{public}d",
249 event.touchEventId, event.id, static_cast<int32_t>(touchPoints_.size()));
250 if (refereeState_ == RefereeState::FAIL) {
251 return;
252 }
253 lastTouchEvent_ = event;
254 if (touchPoints_.find(event.id) != touchPoints_.end()) {
255 touchPoints_.erase(event.id);
256 }
257 if (refereeState_ == RefereeState::SUCCEED && static_cast<int32_t>(touchPoints_.size()) == 0) {
258 SendCancelMsg();
259 refereeState_ = RefereeState::READY;
260 extraInfo_ += "Reject: received cancel and succeed.";
261 } else {
262 extraInfo_ += "Reject: received cancel but not succeed.";
263 Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
264 }
265 }
266
HandleOverdueDeadline(bool isCatchMode)267 void LongPressRecognizer::HandleOverdueDeadline(bool isCatchMode)
268 {
269 if (refereeState_ != RefereeState::DETECTING) {
270 return;
271 }
272 if (!isCatchMode) {
273 OnAccepted();
274 return;
275 }
276 if (gestureInfo_ && gestureInfo_->GetType() == GestureTypeName::DRAG) {
277 auto dragEventActuator = GetDragEventActuator();
278 CHECK_NULL_VOID(dragEventActuator);
279 if (dragEventActuator->IsDragUserReject()) {
280 TAG_LOGI(AceLogTag::ACE_GESTURE, "Drag long press reject because of user's reject");
281 extraInfo_ += "Reject: user reject.";
282 Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
283 return;
284 }
285 }
286 auto onGestureJudgeBeginResult = TriggerGestureJudgeCallback();
287 if (onGestureJudgeBeginResult == GestureJudgeResult::REJECT) {
288 TAG_LOGI(AceLogTag::ACE_GESTURE, "Long press reject as judge result is reject");
289 extraInfo_ += "Reject: judge reject.";
290 Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
291 if (gestureInfo_ && gestureInfo_->GetType() == GestureTypeName::DRAG) {
292 auto dragEventActuator = GetDragEventActuator();
293 CHECK_NULL_VOID(dragEventActuator);
294 dragEventActuator->SetIsDragUserReject(true);
295 }
296 return;
297 }
298 if (CheckLimitFinger()) {
299 Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
300 return;
301 }
302 Adjudicate(AceType::Claim(this), GestureDisposal::ACCEPT);
303 }
304
DeadlineTimer(int32_t time,bool isCatchMode)305 void LongPressRecognizer::DeadlineTimer(int32_t time, bool isCatchMode)
306 {
307 auto context = PipelineContext::GetCurrentContext();
308 CHECK_NULL_VOID(context);
309
310 auto&& callback = [weakPtr = AceType::WeakClaim(this), isCatchMode]() {
311 auto refPtr = weakPtr.Upgrade();
312 if (refPtr) {
313 refPtr->HandleOverdueDeadline(isCatchMode);
314 }
315 };
316 task_ = { WeakClaim(this), GetSysTimestamp(), time, callback };
317 context->AddGestureTask(task_);
318
319 auto&& flushCallback = []() {
320 auto context = PipelineContext::GetCurrentContext();
321 CHECK_NULL_VOID(context);
322 context->RequestFrame();
323 };
324 deadlineTimer_.Reset(flushCallback);
325 auto taskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
326 taskExecutor.PostDelayedTask(deadlineTimer_, time, "ArkUIGestureLongPressDeadlineTimer");
327 }
328
DoRepeat()329 void LongPressRecognizer::DoRepeat()
330 {
331 if (static_cast<int32_t>(touchPoints_.size()) < fingers_) {
332 return;
333 }
334 if (static_cast<int32_t>(touchPoints_.size()) > fingers_ && isLimitFingerCount_) {
335 return;
336 }
337 if (refereeState_ == RefereeState::SUCCEED) {
338 SendCallbackMsg(onAction_, true, true);
339 StartRepeatTimer();
340 }
341 }
342
StartRepeatTimer()343 void LongPressRecognizer::StartRepeatTimer()
344 {
345 auto context = PipelineContext::GetCurrentContext();
346 CHECK_NULL_VOID(context);
347
348 auto&& callback = [weakPtr = AceType::WeakClaim(this)]() {
349 auto refPtr = weakPtr.Upgrade();
350 if (refPtr) {
351 refPtr->DoRepeat();
352 }
353 };
354 timer_.Reset(callback);
355 auto taskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
356 taskExecutor.PostDelayedTask(timer_, duration_, "ArkUIGestureLongPressRepeatTimer");
357 }
358
ConvertPxToVp(double offset) const359 double LongPressRecognizer::ConvertPxToVp(double offset) const
360 {
361 auto context = PipelineContext::GetCurrentContext();
362 CHECK_NULL_RETURN(context, offset);
363
364 double vpOffset = context->ConvertPxToVp(Dimension(offset, DimensionUnit::PX));
365 return vpOffset;
366 }
367
SendCallbackMsg(const std::unique_ptr<GestureEventFunc> & callback,bool isRepeat,bool isOnAction)368 void LongPressRecognizer::SendCallbackMsg(
369 const std::unique_ptr<GestureEventFunc>& callback, bool isRepeat, bool isOnAction)
370 {
371 if (gestureInfo_ && gestureInfo_->GetDisposeTag()) {
372 return;
373 }
374 if (callback && *callback) {
375 GestureEvent info;
376 info.SetTimeStamp(time_);
377 info.SetRepeat(isRepeat);
378 info.SetFingerList(fingerList_);
379 info.SetSourceDevice(deviceType_);
380 info.SetDeviceId(deviceId_);
381 info.SetTargetDisplayId(lastTouchEvent_.targetDisplayId);
382 info.SetGlobalPoint(globalPoint_);
383 info.SetScreenLocation(lastTouchEvent_.GetScreenOffset());
384 info.SetGlobalLocation(lastTouchEvent_.GetOffset())
385 .SetLocalLocation(lastTouchEvent_.GetOffset() - coordinateOffset_);
386 info.SetTarget(GetEventTarget().value_or(EventTarget()));
387 info.SetForce(lastTouchEvent_.force);
388 if (lastTouchEvent_.tiltX.has_value()) {
389 info.SetTiltX(lastTouchEvent_.tiltX.value());
390 }
391 if (lastTouchEvent_.tiltY.has_value()) {
392 info.SetTiltY(lastTouchEvent_.tiltY.value());
393 }
394 info.SetSourceTool(lastTouchEvent_.sourceTool);
395 info.SetPointerEvent(lastPointEvent_);
396 Platform::UpdatePressedKeyCodes(lastTouchEvent_.pressedKeyCodes_);
397 info.SetPressedKeyCodes(lastTouchEvent_.pressedKeyCodes_);
398 info.SetInputEventType(inputEventType_);
399 // callback may be overwritten in its invoke so we copy it first
400 auto callbackFunction = *callback;
401 callbackFunction(info);
402 if (isOnAction && longPressRecorder_ && *longPressRecorder_) {
403 (*longPressRecorder_)(info);
404 }
405 }
406 }
407
OnResetStatus()408 void LongPressRecognizer::OnResetStatus()
409 {
410 MultiFingersRecognizer::OnResetStatus();
411 timer_.Cancel();
412 deadlineTimer_.Cancel();
413 auto context = PipelineContext::GetCurrentContext();
414 CHECK_NULL_VOID(context);
415 context->RemoveGestureTask(task_);
416 }
417
ReconcileFrom(const RefPtr<NGGestureRecognizer> & recognizer)418 bool LongPressRecognizer::ReconcileFrom(const RefPtr<NGGestureRecognizer>& recognizer)
419 {
420 RefPtr<LongPressRecognizer> curr = AceType::DynamicCast<LongPressRecognizer>(recognizer);
421 if (!curr) {
422 ResetStatus();
423 return false;
424 }
425
426 if (curr->duration_ != duration_ || curr->fingers_ != fingers_ || curr->repeat_ != repeat_ ||
427 curr->priorityMask_ != priorityMask_) {
428 if (refereeState_ == RefereeState::SUCCEED && static_cast<int32_t>(touchPoints_.size()) > 0) {
429 SendCancelMsg();
430 }
431 ResetStatus();
432 return false;
433 }
434
435 onAction_ = std::move(curr->onAction_);
436 onActionEnd_ = std::move(curr->onActionEnd_);
437 onActionCancel_ = std::move(curr->onActionCancel_);
438 ReconcileGestureInfoFrom(recognizer);
439 return true;
440 }
441
GetLongPressActionFunc()442 GestureEventFunc LongPressRecognizer::GetLongPressActionFunc()
443 {
444 auto callback = [weak = WeakClaim(this)](GestureEvent& info) {
445 auto longPressRecognizer = weak.Upgrade();
446 CHECK_NULL_VOID(longPressRecognizer);
447 if (longPressRecognizer->onActionUpdate_) {
448 (*(longPressRecognizer->onActionUpdate_))(info);
449 }
450 if (longPressRecognizer->onAction_) {
451 (*(longPressRecognizer->onAction_))(info);
452 }
453 if (longPressRecognizer->onActionUpdate_) {
454 (*(longPressRecognizer->onActionUpdate_))(info);
455 }
456 if (longPressRecognizer->onActionEnd_) {
457 (*(longPressRecognizer->onActionEnd_))(info);
458 }
459 };
460 return callback;
461 }
462
Dump() const463 RefPtr<GestureSnapshot> LongPressRecognizer::Dump() const
464 {
465 RefPtr<GestureSnapshot> info = NGGestureRecognizer::Dump();
466 std::stringstream oss;
467 oss << "duration: " << duration_ << ", "
468 << "isForDrag: " << isForDrag_ << ", "
469 << "repeat: " << repeat_ << ", "
470 << "fingers: " << fingers_ << ", "
471 << DumpGestureInfo();
472 info->customInfo = oss.str();
473 return info;
474 }
475
PrintCurrentFingersInfo() const476 void LongPressRecognizer::PrintCurrentFingersInfo() const
477 {
478 std::string log = "Fingers number = ";
479 log += std::to_string(GetValidFingersCount());
480 log += " fingers_ = ";
481 log += std::to_string(fingers_);
482 log += ". ";
483 for (const auto& iter : touchPoints_) {
484 log += "Event id = ";
485 log += std::to_string(iter.first);
486 log += ", event type = ";
487 log += std::to_string(static_cast<int32_t>(iter.second.type));
488 log += "; ";
489 }
490 TAG_LOGI(AceLogTag::ACE_GESTURE, "Finger info : %{public}s", log.c_str());
491 }
492
TriggerGestureJudgeCallback()493 GestureJudgeResult LongPressRecognizer::TriggerGestureJudgeCallback()
494 {
495 auto targetComponent = GetTargetComponent();
496 CHECK_NULL_RETURN(targetComponent, GestureJudgeResult::CONTINUE);
497 auto gestureRecognizerJudgeFunc = targetComponent->GetOnGestureRecognizerJudgeBegin();
498 auto callback = targetComponent->GetOnGestureJudgeBeginCallback();
499 if (!callback && !gestureRecognizerJudgeFunc) {
500 return GestureJudgeResult::CONTINUE;
501 }
502 auto info = std::make_shared<LongPressGestureEvent>();
503 info->SetTimeStamp(time_);
504 info->SetDeviceId(deviceId_);
505 info->SetRepeat(repeat_);
506 info->SetFingerList(fingerList_);
507 TouchEvent trackPoint = {};
508 if (!touchPoints_.empty()) {
509 trackPoint = touchPoints_.begin()->second;
510 }
511 info->SetSourceDevice(deviceType_);
512 info->SetTarget(GetEventTarget().value_or(EventTarget()));
513 info->SetForce(trackPoint.force);
514 if (gestureInfo_) {
515 gestureInfo_->SetInputEventType(inputEventType_);
516 }
517 if (trackPoint.tiltX.has_value()) {
518 info->SetTiltX(trackPoint.tiltX.value());
519 }
520 if (trackPoint.tiltY.has_value()) {
521 info->SetTiltY(trackPoint.tiltY.value());
522 }
523 info->SetSourceTool(trackPoint.sourceTool);
524 if (gestureRecognizerJudgeFunc) {
525 return gestureRecognizerJudgeFunc(info, Claim(this), responseLinkRecognizer_);
526 }
527 return callback(gestureInfo_, info);
528 }
529
GetDragEventActuator()530 RefPtr<DragEventActuator> LongPressRecognizer::GetDragEventActuator()
531 {
532 auto targetComponent = GetTargetComponent();
533 CHECK_NULL_RETURN(targetComponent, nullptr);
534 auto uiNode = targetComponent->GetUINode().Upgrade();
535 CHECK_NULL_RETURN(uiNode, nullptr);
536 auto frameNode = AceType::DynamicCast<FrameNode>(uiNode);
537 CHECK_NULL_RETURN(frameNode, nullptr);
538 auto gestureEventHub = frameNode->GetOrCreateGestureEventHub();
539 CHECK_NULL_RETURN(gestureEventHub, nullptr);
540 return gestureEventHub->GetDragEventActuator();
541 }
542
543 } // namespace OHOS::Ace::NG
544