1 /*
2 * Copyright (c) 2021-2022 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/gesture_recognizer.h"
17
18 #include "base/log/log.h"
19 #include "base/memory/ace_type.h"
20 #include "base/memory/referenced.h"
21 #include "base/utils/utils.h"
22 #include "core/common/container.h"
23 #include "core/components_ng/base/observer_handler.h"
24 #include "core/components_ng/event/response_ctrl.h"
25 #include "core/components_ng/gestures/gesture_referee.h"
26 #include "core/event/axis_event.h"
27 #include "core/event/touch_event.h"
28 #include "core/pipeline_ng/pipeline_context.h"
29
30 namespace OHOS::Ace::NG {
31 namespace {
GetCurrentEventManager()32 RefPtr<EventManager> GetCurrentEventManager()
33 {
34 auto context = PipelineContext::GetCurrentContext();
35 CHECK_NULL_RETURN(context, nullptr);
36
37 return context->GetEventManager();
38 }
39
GetCurrentGestureReferee(const RefPtr<NGGestureRecognizer> & recognizer)40 RefPtr<GestureReferee> GetCurrentGestureReferee(const RefPtr<NGGestureRecognizer>& recognizer)
41 {
42 auto eventManager = GetCurrentEventManager();
43 CHECK_NULL_RETURN(eventManager, nullptr);
44 return eventManager->GetGestureRefereeNG(recognizer);
45 }
46
47 } // namespace
48
ShouldResponse()49 bool NGGestureRecognizer::ShouldResponse()
50 {
51 if (AceType::InstanceOf<RecognizerGroup>(this)) {
52 return true;
53 }
54 auto eventManager = GetCurrentEventManager();
55 CHECK_NULL_RETURN(eventManager, true);
56 auto frameNode = GetAttachedNode();
57 auto ctrl = eventManager->GetResponseCtrl();
58 CHECK_NULL_RETURN(ctrl, true);
59 if (!ctrl->ShouldResponse(frameNode)) {
60 if (refereeState_ != RefereeState::FAIL) {
61 Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
62 }
63 return false;
64 }
65 return true;
66 }
67
IsAllowedType(SourceTool type)68 bool NGGestureRecognizer::IsAllowedType(SourceTool type)
69 {
70 // allow all types by default
71 if (!gestureInfo_) {
72 return true;
73 }
74
75 auto allowedTypes = gestureInfo_->GetAllowedTypes();
76 return allowedTypes.empty() || allowedTypes.find(type) != allowedTypes.end();
77 }
78
OnRejectBridgeObj()79 void NGGestureRecognizer::OnRejectBridgeObj()
80 {
81 if (bridgeObjList_.empty()) {
82 return;
83 }
84 for (const auto& item : bridgeObjList_) {
85 auto bridgeObj = item.Upgrade();
86 if (bridgeObj) {
87 bridgeObj->OnRejected();
88 bridgeObj->OnRejectBridgeObj();
89 }
90 }
91 }
92
HandleEvent(const TouchEvent & point)93 bool NGGestureRecognizer::HandleEvent(const TouchEvent& point)
94 {
95 if (!IsAllowedType(point.sourceTool) && point.type != TouchType::CANCEL) {
96 if (point.type == TouchType::DOWN) {
97 RemoveUnsupportEvent(point.id);
98 }
99 return true;
100 }
101 if (!ShouldResponse() || bridgeMode_) {
102 return true;
103 }
104 auto multiFingerRecognizer = AceType::DynamicCast<MultiFingersRecognizer>(Claim(this));
105 if (multiFingerRecognizer) {
106 multiFingerRecognizer->ResetTouchPointsForSucceedBlock();
107 }
108 return ProcessTouchEvent(point);
109 }
110
ProcessTouchEvent(const TouchEvent & point)111 bool NGGestureRecognizer::ProcessTouchEvent(const TouchEvent& point)
112 {
113 switch (point.type) {
114 case TouchType::MOVE:
115 HandleTouchMoveEvent(point);
116 HandleEventToBridgeObjList(point, bridgeObjList_);
117 break;
118 case TouchType::DOWN:
119 HandleTouchDown(point);
120 break;
121 case TouchType::UP:
122 HandleTouchUp(point);
123 break;
124 case TouchType::CANCEL:
125 HandleTouchCancel(point);
126 break;
127 default:
128 break;
129 }
130 return true;
131 }
132
HandleTouchDown(const TouchEvent & point)133 void NGGestureRecognizer::HandleTouchDown(const TouchEvent& point)
134 {
135 deviceId_ = point.deviceId;
136 deviceType_ = point.sourceType;
137 inputEventType_ = (deviceType_ == SourceType::MOUSE) ? InputEventType::MOUSE_BUTTON : InputEventType::TOUCH_SCREEN;
138
139 auto result = AboutToAddCurrentFingers(point);
140 if (result) {
141 HandleTouchDownEvent(point);
142 HandleEventToBridgeObjList(point, bridgeObjList_);
143 }
144 }
145
HandleTouchUp(const TouchEvent & point)146 void NGGestureRecognizer::HandleTouchUp(const TouchEvent& point)
147 {
148 auto result = AboutToMinusCurrentFingers(point.id);
149 if (result) {
150 HandleTouchUpEvent(point);
151 HandleEventToBridgeObjList(point, bridgeObjList_);
152 currentFingers_--;
153 }
154 }
155
HandleTouchCancel(const TouchEvent & point)156 void NGGestureRecognizer::HandleTouchCancel(const TouchEvent& point)
157 {
158 auto result = AboutToMinusCurrentFingers(point.id);
159 if (result) {
160 HandleTouchCancelEvent(point);
161 HandleEventToBridgeObjList(point, bridgeObjList_);
162 currentFingers_--;
163 }
164 }
165
HandleEvent(const AxisEvent & event)166 bool NGGestureRecognizer::HandleEvent(const AxisEvent& event)
167 {
168 if (!IsAllowedType(event.sourceTool) && event.action != AxisAction::CANCEL) {
169 if (event.action == AxisAction::BEGIN) {
170 RemoveUnsupportEvent(event.id);
171 }
172 return true;
173 }
174 if (!ShouldResponse() || bridgeMode_) {
175 return true;
176 }
177 switch (event.action) {
178 case AxisAction::BEGIN:
179 deviceId_ = event.deviceId;
180 deviceType_ = event.sourceType;
181 inputEventType_ = InputEventType::AXIS;
182 HandleTouchDownEvent(event);
183 break;
184 case AxisAction::UPDATE:
185 HandleTouchMoveEvent(event);
186 break;
187 case AxisAction::END:
188 HandleTouchUpEvent(event);
189 break;
190 default:
191 HandleTouchCancelEvent(event);
192 break;
193 }
194 for (const auto& item : bridgeObjList_) {
195 auto bridgeObj = item.Upgrade();
196 if (bridgeObj) {
197 bridgeObj->HandleBridgeModeEvent(event);
198 }
199 }
200 return true;
201 }
202
HandleBridgeModeEvent(const TouchEvent & point)203 void NGGestureRecognizer::HandleBridgeModeEvent(const TouchEvent& point)
204 {
205 switch (point.type) {
206 case TouchType::MOVE:
207 HandleTouchMoveEvent(point);
208 HandleEventToBridgeObjList(point, bridgeObjList_);
209 break;
210 case TouchType::DOWN: {
211 deviceId_ = point.deviceId;
212 deviceType_ = point.sourceType;
213 if (deviceType_ == SourceType::MOUSE) {
214 inputEventType_ = InputEventType::MOUSE_BUTTON;
215 } else {
216 inputEventType_ = InputEventType::TOUCH_SCREEN;
217 }
218 auto result = AboutToAddCurrentFingers(point);
219 if (result) {
220 HandleTouchDownEvent(point);
221 HandleEventToBridgeObjList(point, bridgeObjList_);
222 }
223 break;
224 }
225 case TouchType::UP: {
226 auto result = AboutToMinusCurrentFingers(point.id);
227 if (result) {
228 HandleTouchUpEvent(point);
229 currentFingers_--;
230 HandleEventToBridgeObjList(point, bridgeObjList_);
231 }
232 break;
233 }
234 case TouchType::CANCEL: {
235 auto result = AboutToMinusCurrentFingers(point.id);
236 if (result) {
237 HandleTouchCancelEvent(point);
238 currentFingers_--;
239 HandleEventToBridgeObjList(point, bridgeObjList_);
240 }
241 break;
242 }
243 default:
244 break;
245 }
246 }
247
HandleEventToBridgeObjList(const TouchEvent & point,const std::list<WeakPtr<NGGestureRecognizer>> & bridgeObjList)248 void NGGestureRecognizer::HandleEventToBridgeObjList(
249 const TouchEvent& point, const std::list<WeakPtr<NGGestureRecognizer>>& bridgeObjList)
250 {
251 for (const auto& item : bridgeObjList) {
252 auto bridgeObj = item.Upgrade();
253 if (bridgeObj) {
254 bridgeObj->HandleBridgeModeEvent(point);
255 }
256 }
257 }
258
HandleBridgeModeEvent(const AxisEvent & event)259 void NGGestureRecognizer::HandleBridgeModeEvent(const AxisEvent& event)
260 {
261 switch (event.action) {
262 case AxisAction::BEGIN:
263 deviceId_ = event.deviceId;
264 deviceType_ = event.sourceType;
265 inputEventType_ = InputEventType::AXIS;
266 HandleTouchDownEvent(event);
267 break;
268 case AxisAction::UPDATE:
269 HandleTouchMoveEvent(event);
270 break;
271 case AxisAction::END:
272 HandleTouchUpEvent(event);
273 break;
274 default:
275 HandleTouchCancelEvent(event);
276 break;
277 }
278 for (const auto& item : bridgeObjList_) {
279 auto bridgeObj = item.Upgrade();
280 if (bridgeObj) {
281 bridgeObj->HandleBridgeModeEvent(event);
282 }
283 }
284 }
285
BatchAdjudicate(const RefPtr<NGGestureRecognizer> & recognizer,GestureDisposal disposal)286 void NGGestureRecognizer::BatchAdjudicate(const RefPtr<NGGestureRecognizer>& recognizer, GestureDisposal disposal)
287 {
288 RefPtr<NGGestureRecognizer> gestureGroup;
289 if (!eventImportGestureGroup_.Invalid()) {
290 gestureGroup = eventImportGestureGroup_.Upgrade();
291 } else {
292 gestureGroup = gestureGroup_.Upgrade();
293 }
294 if (gestureGroup) {
295 gestureGroup->Adjudicate(recognizer, disposal);
296 return;
297 }
298
299 auto referee = GetCurrentGestureReferee(recognizer);
300 if (!referee) {
301 recognizer->OnRejected();
302 return;
303 }
304 referee->Adjudicate(recognizer, disposal);
305 }
306
Transform(PointF & localPointF,const WeakPtr<FrameNode> & node,bool isRealTime,bool isPostEventResult,int32_t postEventNodeId)307 void NGGestureRecognizer::Transform(PointF& localPointF, const WeakPtr<FrameNode>& node, bool isRealTime,
308 bool isPostEventResult, int32_t postEventNodeId)
309 {
310 if (node.Invalid()) {
311 return;
312 }
313
314 std::vector<Matrix4> vTrans {};
315 auto host = node.Upgrade();
316 CHECK_NULL_VOID(host);
317
318 std::function<Matrix4()> getLocalMatrix;
319 if (isRealTime) {
320 getLocalMatrix = [&host]()->Matrix4 {
321 auto context = host->GetRenderContext();
322 CHECK_NULL_RETURN(context, Matrix4::CreateIdentity());
323 return context->GetLocalTransformMatrix();
324 };
325 } else {
326 getLocalMatrix = [&host]()->Matrix4 {
327 return host->GetLocalMatrix();
328 };
329 }
330
331 while (host) {
332 auto localMat = getLocalMatrix();
333 vTrans.emplace_back(localMat);
334 if (host->GetTag() == V2::WINDOW_SCENE_ETS_TAG) {
335 TAG_LOGD(AceLogTag::ACE_GESTURE, "need to break when inject WindowsScene, id:"
336 SEC_PLD(%{public}d) ".", SEC_PARAM(host->GetId()));
337 break;
338 }
339 if ((postEventNodeId == host->GetId()) && isPostEventResult) {
340 TAG_LOGD(AceLogTag::ACE_GESTURE, "need to break when used in NodeContainer, id:"
341 SEC_PLD(%{public}d) ".", SEC_PARAM(host->GetId()));
342 break;
343 }
344 host = host->GetAncestorNodeOfFrame();
345 }
346
347 Point temp(localPointF.GetX(), localPointF.GetY());
348 for (auto iter = vTrans.rbegin(); iter != vTrans.rend(); iter++) {
349 temp = *iter * temp;
350 }
351 localPointF.SetX(temp.GetX());
352 localPointF.SetY(temp.GetY());
353 }
354
SetTransInfo(int transId)355 void NGGestureRecognizer::SetTransInfo(int transId)
356 {
357 transId_ = transId;
358 }
359
AboutToAccept()360 void NGGestureRecognizer::AboutToAccept()
361 {
362 if (AceType::InstanceOf<RecognizerGroup>(this)) {
363 HandleWillAccept();
364 OnAccepted();
365 HandleDidAccept();
366 return;
367 }
368
369 auto eventManager = GetCurrentEventManager();
370 CHECK_NULL_VOID(eventManager);
371 auto frameNode = GetAttachedNode();
372 auto ctrl = eventManager->GetResponseCtrl();
373 CHECK_NULL_VOID(ctrl);
374 if (!ctrl->ShouldResponse(frameNode)) {
375 return;
376 }
377 if (fromCardOrUIExtension_) {
378 eventManager->SetInnerFlag(true);
379 } else {
380 eventManager->SetInnerFlag(false);
381 }
382 ctrl->TrySetFirstResponse(frameNode);
383 HandleWillAccept();
384 OnAccepted();
385 HandleDidAccept();
386 }
387
HandleWillAccept()388 void NGGestureRecognizer::HandleWillAccept()
389 {
390 auto node = GetAttachedNode().Upgrade();
391 if (AceType::InstanceOf<ClickRecognizer>(this)) {
392 auto clickRecognizer = AceType::DynamicCast<ClickRecognizer>(this);
393 CHECK_NULL_VOID(clickRecognizer);
394 GestureEvent gestureEventInfo = clickRecognizer->GetGestureEventInfo();
395 ClickInfo clickInfo = clickRecognizer->GetClickInfo();
396 UIObserverHandler::GetInstance().NotifyWillClick(gestureEventInfo, clickInfo, node);
397 }
398 }
399
HandleDidAccept()400 void NGGestureRecognizer::HandleDidAccept()
401 {
402 auto node = GetAttachedNode().Upgrade();
403 if (AceType::InstanceOf<ClickRecognizer>(this)) {
404 auto clickRecognizer = AceType::DynamicCast<ClickRecognizer>(this);
405 CHECK_NULL_VOID(clickRecognizer);
406 GestureEvent gestureEventInfo = clickRecognizer->GetGestureEventInfo();
407 ClickInfo clickInfo = clickRecognizer->GetClickInfo();
408 UIObserverHandler::GetInstance().NotifyDidClick(gestureEventInfo, clickInfo, node);
409 }
410 }
411
ReconcileGestureInfoFrom(const RefPtr<NGGestureRecognizer> & recognizer)412 void NGGestureRecognizer::ReconcileGestureInfoFrom(const RefPtr<NGGestureRecognizer>& recognizer)
413 {
414 CHECK_NULL_VOID(recognizer);
415 auto currGestureInfo = recognizer->GetGestureInfo();
416 if (gestureInfo_ && currGestureInfo) {
417 gestureInfo_->SetAllowedTypes(currGestureInfo->GetAllowedTypes());
418 }
419 }
420
Dump() const421 RefPtr<GestureSnapshot> NGGestureRecognizer::Dump() const
422 {
423 RefPtr<GestureSnapshot> info = TouchEventTarget::Dump();
424 auto group = gestureGroup_.Upgrade();
425 if (group) {
426 info->parentId = reinterpret_cast<uintptr_t>(AceType::RawPtr(group));
427 }
428 return info;
429 }
430
AddGestureProcedure(const std::string & procedure) const431 void NGGestureRecognizer::AddGestureProcedure(const std::string& procedure) const
432 {
433 auto context = PipelineContext::GetCurrentContext();
434 CHECK_NULL_VOID(context);
435 auto eventMgr = context->GetEventManager();
436 CHECK_NULL_VOID(eventMgr);
437 eventMgr->GetEventTreeRecord(isPostEventResult_ ? EventTreeType::POST_EVENT : EventTreeType::TOUCH)
438 .AddGestureProcedure(reinterpret_cast<uintptr_t>(this), procedure,
439 extraInfo_, TransRefereeState(this->GetRefereeState()),
440 TransGestureDisposal(this->GetGestureDisposal()));
441 }
442
AddGestureProcedure(const TouchEvent & point,const RefPtr<NGGestureRecognizer> & recognizer) const443 void NGGestureRecognizer::AddGestureProcedure(const TouchEvent& point,
444 const RefPtr<NGGestureRecognizer>& recognizer) const
445 {
446 if (!recognizer) {
447 return;
448 }
449 auto context = PipelineContext::GetCurrentContext();
450 CHECK_NULL_VOID(context);
451 auto eventMgr = context->GetEventManager();
452 CHECK_NULL_VOID(eventMgr);
453 eventMgr->GetEventTreeRecord(isPostEventResult_ ? EventTreeType::POST_EVENT : EventTreeType::TOUCH)
454 .AddGestureProcedure(reinterpret_cast<uintptr_t>(AceType::RawPtr(recognizer)),
455 point, recognizer->GetExtraInfo(), TransRefereeState(recognizer->GetRefereeState()),
456 TransGestureDisposal(recognizer->GetGestureDisposal()));
457 }
458
SetGestureGroup(const WeakPtr<NGGestureRecognizer> & gestureGroup)459 bool NGGestureRecognizer::SetGestureGroup(const WeakPtr<NGGestureRecognizer>& gestureGroup)
460 {
461 if (!gestureGroup_.Invalid() && !gestureGroup.Invalid()) {
462 return false;
463 }
464
465 gestureGroup_ = gestureGroup;
466 return true;
467 }
468
SetEventImportGestureGroup(const WeakPtr<NGGestureRecognizer> & gestureGroup)469 void NGGestureRecognizer::SetEventImportGestureGroup(const WeakPtr<NGGestureRecognizer>& gestureGroup)
470 {
471 if (gestureGroup.Invalid()) {
472 return;
473 }
474
475 eventImportGestureGroup_ = gestureGroup;
476 }
477
IsInAttachedNode(const TouchEvent & event,bool isRealTime)478 bool NGGestureRecognizer::IsInAttachedNode(const TouchEvent& event, bool isRealTime)
479 {
480 bool isChildTouchTestResult = false;
481 auto frameNode = GetAttachedNode();
482 if (frameNode.Invalid()) {
483 return true;
484 }
485 auto host = frameNode.Upgrade();
486 CHECK_NULL_RETURN(host, true);
487 auto id = host->GetInspectorIdValue("");
488 isChildTouchTestResult = std::any_of(event.childTouchTestList.begin(), event.childTouchTestList.end(),
489 [id](const std::string& inspectorId) {
490 return inspectorId == id;
491 });
492 if (isChildTouchTestResult) {
493 return true;
494 }
495
496 PointF localPoint(event.x, event.y);
497 if (isRealTime) {
498 NGGestureRecognizer::Transform(localPoint, frameNode, !isPostEventResult_,
499 isPostEventResult_, event.postEventNodeId);
500 } else {
501 NGGestureRecognizer::Transform(localPoint, frameNode, false,
502 isPostEventResult_, event.postEventNodeId);
503 }
504 auto renderContext = host->GetRenderContext();
505 CHECK_NULL_RETURN(renderContext, false);
506 auto paintRect = renderContext->GetPaintRectWithoutTransform();
507 localPoint = localPoint + paintRect.GetOffset();
508 auto responseRegion = host->GetResponseRegionListForRecognizer(static_cast<int32_t>(event.sourceType));
509 auto result = host->InResponseRegionList(localPoint, responseRegion);
510 if (!result) {
511 std::string responseInfo = std::string("responseRegionList = ");
512 for (const auto& item : responseRegion) {
513 responseInfo.append(item.ToString()).append("; ");
514 }
515 TAG_LOGW(AceLogTag::ACE_GESTURE, SEC_PLD(,
516 "%{public}s IsInAttachedNode result is negative, node tag = %{public}s, id = %{public}s, point = "
517 "%{public}s, frameRect = %{public}s, %{public}s"),
518 SEC_PARAM(AceType::TypeName(this), host->GetTag().c_str(), std::to_string(host->GetId()).c_str(),
519 localPoint.ToString().c_str(), host->GetFrameRectWithoutSafeArea().ToString().c_str(),
520 responseInfo.c_str()));
521 }
522 return result;
523 }
524
SetResponseLinkRecognizers(const ResponseLinkResult & responseLinkResult)525 void NGGestureRecognizer::SetResponseLinkRecognizers(const ResponseLinkResult& responseLinkResult)
526 {
527 responseLinkRecognizer_ = responseLinkResult;
528 }
529
IsInResponseLinkRecognizers()530 bool NGGestureRecognizer::IsInResponseLinkRecognizers()
531 {
532 return std::any_of(responseLinkRecognizer_.begin(), responseLinkRecognizer_.end(),
533 [recognizer = Claim(this)](const RefPtr<NGGestureRecognizer>& item) { return item == recognizer; });
534 }
535
AboutToAddCurrentFingers(const TouchEvent & event)536 bool NGGestureRecognizer::AboutToAddCurrentFingers(const TouchEvent& event)
537 {
538 bool isInAttachedNode = IsInAttachedNode(event, !AceType::InstanceOf<ClickRecognizer>(this));
539 if (!isInAttachedNode) {
540 return false;
541 }
542 if (fingersId_.find(event.id) != fingersId_.end()) {
543 auto node = GetAttachedNode().Upgrade();
544 TAG_LOGI(AceLogTag::ACE_GESTURE,
545 "Recognizer has already receive touchId: %{public}d event, "
546 "node tag = %{public}s, id = " SEC_PLD(%{public}s) ".",
547 event.id, node ? node->GetTag().c_str() : "null",
548 SEC_PARAM(node ? std::to_string(node->GetId()).c_str() : "invalid"));
549 return false;
550 }
551 currentFingers_++;
552 return true;
553 }
554
AboutToMinusCurrentFingers(int32_t touchId)555 bool NGGestureRecognizer::AboutToMinusCurrentFingers(int32_t touchId)
556 {
557 if (fingersId_.find(touchId) != fingersId_.end()) {
558 return true;
559 }
560 auto node = GetAttachedNode().Upgrade();
561 TAG_LOGI(AceLogTag::ACE_GESTURE,
562 "Recognizer has already receive touchId: %{public}d up event, "
563 "node tag = %{public}s, id = " SEC_PLD(%{public}s) ".",
564 touchId, node ? node->GetTag().c_str() : "null",
565 SEC_PARAM(node ? std::to_string(node->GetId()).c_str() : "invalid"));
566 return false;
567 }
568 } // namespace OHOS::Ace::NG
569