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
OnRejectBridgeObj()68 void NGGestureRecognizer::OnRejectBridgeObj()
69 {
70 if (bridgeObjList_.empty()) {
71 return;
72 }
73 for (const auto& item : bridgeObjList_) {
74 auto bridgeObj = item.Upgrade();
75 if (bridgeObj) {
76 bridgeObj->OnRejected();
77 bridgeObj->OnRejectBridgeObj();
78 }
79 }
80 }
81
HandleEvent(const TouchEvent & point)82 bool NGGestureRecognizer::HandleEvent(const TouchEvent& point)
83 {
84 if (!ShouldResponse()) {
85 return true;
86 }
87 if (bridgeMode_) {
88 return true;
89 }
90 switch (point.type) {
91 case TouchType::MOVE:
92 HandleTouchMoveEvent(point);
93 HandleEventToBridgeObjList(point, bridgeObjList_);
94 break;
95 case TouchType::DOWN: {
96 deviceId_ = point.deviceId;
97 deviceType_ = point.sourceType;
98 if (deviceType_ == SourceType::MOUSE) {
99 inputEventType_ = InputEventType::MOUSE_BUTTON;
100 } else {
101 inputEventType_ = InputEventType::TOUCH_SCREEN;
102 }
103 auto result = AboutToAddCurrentFingers(point);
104 if (result) {
105 HandleTouchDownEvent(point);
106 HandleEventToBridgeObjList(point, bridgeObjList_);
107 }
108 break;
109 }
110 case TouchType::UP: {
111 auto result = AboutToMinusCurrentFingers(point.id);
112 if (result) {
113 HandleTouchUpEvent(point);
114 HandleEventToBridgeObjList(point, bridgeObjList_);
115 currentFingers_--;
116 }
117 break;
118 }
119 case TouchType::CANCEL: {
120 auto result = AboutToMinusCurrentFingers(point.id);
121 if (result) {
122 HandleTouchCancelEvent(point);
123 HandleEventToBridgeObjList(point, bridgeObjList_);
124 currentFingers_--;
125 }
126 break;
127 }
128 default:
129 break;
130 }
131 return true;
132 }
133
HandleEvent(const AxisEvent & event)134 bool NGGestureRecognizer::HandleEvent(const AxisEvent& event)
135 {
136 if (!ShouldResponse()) {
137 return true;
138 }
139 if (bridgeMode_) {
140 return true;
141 }
142 switch (event.action) {
143 case AxisAction::BEGIN:
144 deviceId_ = event.deviceId;
145 deviceType_ = event.sourceType;
146 inputEventType_ = InputEventType::AXIS;
147 HandleTouchDownEvent(event);
148 break;
149 case AxisAction::UPDATE:
150 HandleTouchMoveEvent(event);
151 break;
152 case AxisAction::END:
153 HandleTouchUpEvent(event);
154 break;
155 default:
156 HandleTouchCancelEvent(event);
157 break;
158 }
159 for (const auto& item : bridgeObjList_) {
160 auto bridgeObj = item.Upgrade();
161 if (bridgeObj) {
162 bridgeObj->HandleBridgeModeEvent(event);
163 }
164 }
165 return true;
166 }
167
HandleBridgeModeEvent(const TouchEvent & point)168 void NGGestureRecognizer::HandleBridgeModeEvent(const TouchEvent& point)
169 {
170 switch (point.type) {
171 case TouchType::MOVE:
172 HandleTouchMoveEvent(point);
173 HandleEventToBridgeObjList(point, bridgeObjList_);
174 break;
175 case TouchType::DOWN: {
176 deviceId_ = point.deviceId;
177 deviceType_ = point.sourceType;
178 if (deviceType_ == SourceType::MOUSE) {
179 inputEventType_ = InputEventType::MOUSE_BUTTON;
180 } else {
181 inputEventType_ = InputEventType::TOUCH_SCREEN;
182 }
183 auto result = AboutToAddCurrentFingers(point);
184 if (result) {
185 HandleTouchDownEvent(point);
186 HandleEventToBridgeObjList(point, bridgeObjList_);
187 }
188 break;
189 }
190 case TouchType::UP: {
191 auto result = AboutToMinusCurrentFingers(point.id);
192 if (result) {
193 HandleTouchUpEvent(point);
194 currentFingers_--;
195 HandleEventToBridgeObjList(point, bridgeObjList_);
196 }
197 break;
198 }
199 case TouchType::CANCEL: {
200 auto result = AboutToMinusCurrentFingers(point.id);
201 if (result) {
202 HandleTouchCancelEvent(point);
203 currentFingers_--;
204 HandleEventToBridgeObjList(point, bridgeObjList_);
205 }
206 break;
207 }
208 default:
209 break;
210 }
211 }
212
HandleEventToBridgeObjList(const TouchEvent & point,const std::list<WeakPtr<NGGestureRecognizer>> & bridgeObjList)213 void NGGestureRecognizer::HandleEventToBridgeObjList(
214 const TouchEvent& point, const std::list<WeakPtr<NGGestureRecognizer>>& bridgeObjList)
215 {
216 for (const auto& item : bridgeObjList) {
217 auto bridgeObj = item.Upgrade();
218 if (bridgeObj) {
219 bridgeObj->HandleBridgeModeEvent(point);
220 }
221 }
222 }
223
HandleBridgeModeEvent(const AxisEvent & event)224 void NGGestureRecognizer::HandleBridgeModeEvent(const AxisEvent& event)
225 {
226 switch (event.action) {
227 case AxisAction::BEGIN:
228 deviceId_ = event.deviceId;
229 deviceType_ = event.sourceType;
230 inputEventType_ = InputEventType::AXIS;
231 HandleTouchDownEvent(event);
232 break;
233 case AxisAction::UPDATE:
234 HandleTouchMoveEvent(event);
235 break;
236 case AxisAction::END:
237 HandleTouchUpEvent(event);
238 break;
239 default:
240 HandleTouchCancelEvent(event);
241 break;
242 }
243 for (const auto& item : bridgeObjList_) {
244 auto bridgeObj = item.Upgrade();
245 if (bridgeObj) {
246 bridgeObj->HandleBridgeModeEvent(event);
247 }
248 }
249 }
250
BatchAdjudicate(const RefPtr<NGGestureRecognizer> & recognizer,GestureDisposal disposal)251 void NGGestureRecognizer::BatchAdjudicate(const RefPtr<NGGestureRecognizer>& recognizer, GestureDisposal disposal)
252 {
253 RefPtr<NGGestureRecognizer> gestureGroup;
254 if (!eventImportGestureGroup_.Invalid()) {
255 gestureGroup = eventImportGestureGroup_.Upgrade();
256 } else {
257 gestureGroup = gestureGroup_.Upgrade();
258 }
259 if (gestureGroup) {
260 gestureGroup->Adjudicate(recognizer, disposal);
261 return;
262 }
263
264 auto referee = GetCurrentGestureReferee(recognizer);
265 if (!referee) {
266 recognizer->OnRejected();
267 return;
268 }
269 referee->Adjudicate(recognizer, disposal);
270 }
271
Transform(PointF & localPointF,const WeakPtr<FrameNode> & node,bool isRealTime,bool isPostEventResult,int32_t postEventNodeId)272 void NGGestureRecognizer::Transform(PointF& localPointF, const WeakPtr<FrameNode>& node, bool isRealTime,
273 bool isPostEventResult, int32_t postEventNodeId)
274 {
275 if (node.Invalid()) {
276 return;
277 }
278
279 std::vector<Matrix4> vTrans {};
280 auto host = node.Upgrade();
281 CHECK_NULL_VOID(host);
282
283 std::function<Matrix4()> getLocalMatrix;
284 if (isRealTime) {
285 getLocalMatrix = [&host]()->Matrix4 {
286 auto context = host->GetRenderContext();
287 CHECK_NULL_RETURN(context, Matrix4::CreateIdentity());
288 return context->GetLocalTransformMatrix();
289 };
290 } else {
291 getLocalMatrix = [&host]()->Matrix4 {
292 return host->GetLocalMatrix();
293 };
294 }
295
296 while (host) {
297 auto localMat = getLocalMatrix();
298 vTrans.emplace_back(localMat);
299 if (host->GetTag() == V2::WINDOW_SCENE_ETS_TAG) {
300 break;
301 }
302 if ((postEventNodeId == host->GetId()) && isPostEventResult) {
303 TAG_LOGD(AceLogTag::ACE_GESTURE, "need to break when used in NodeContainer, id:%{public}d", host->GetId());
304 break;
305 }
306 host = host->GetAncestorNodeOfFrame();
307 }
308
309 Point temp(localPointF.GetX(), localPointF.GetY());
310 for (auto iter = vTrans.rbegin(); iter != vTrans.rend(); iter++) {
311 temp = *iter * temp;
312 }
313 localPointF.SetX(temp.GetX());
314 localPointF.SetY(temp.GetY());
315 }
316
SetTransInfo(int transId)317 void NGGestureRecognizer::SetTransInfo(int transId)
318 {
319 transId_ = transId;
320 }
321
AboutToAccept()322 void NGGestureRecognizer::AboutToAccept()
323 {
324 if (AceType::InstanceOf<RecognizerGroup>(this)) {
325 HandleWillAccept();
326 OnAccepted();
327 HandleDidAccept();
328 return;
329 }
330
331 auto eventManager = GetCurrentEventManager();
332 CHECK_NULL_VOID(eventManager);
333 auto frameNode = GetAttachedNode();
334 auto ctrl = eventManager->GetResponseCtrl();
335 CHECK_NULL_VOID(ctrl);
336 if (!ctrl->ShouldResponse(frameNode)) {
337 return;
338 }
339 if (fromCardOrUIExtension_) {
340 eventManager->SetInnerFlag(true);
341 } else {
342 eventManager->SetInnerFlag(false);
343 }
344 ctrl->TrySetFirstResponse(frameNode);
345 HandleWillAccept();
346 OnAccepted();
347 HandleDidAccept();
348 }
349
HandleWillAccept()350 void NGGestureRecognizer::HandleWillAccept()
351 {
352 auto node = GetAttachedNode().Upgrade();
353 if (AceType::InstanceOf<ClickRecognizer>(this)) {
354 auto clickRecognizer = AceType::DynamicCast<ClickRecognizer>(this);
355 CHECK_NULL_VOID(clickRecognizer);
356 GestureEvent gestureEventInfo = clickRecognizer->GetGestureEventInfo();
357 ClickInfo clickInfo = clickRecognizer->GetClickInfo();
358 UIObserverHandler::GetInstance().NotifyWillClick(gestureEventInfo, clickInfo, node);
359 }
360 }
361
HandleDidAccept()362 void NGGestureRecognizer::HandleDidAccept()
363 {
364 auto node = GetAttachedNode().Upgrade();
365 if (AceType::InstanceOf<ClickRecognizer>(this)) {
366 auto clickRecognizer = AceType::DynamicCast<ClickRecognizer>(this);
367 CHECK_NULL_VOID(clickRecognizer);
368 GestureEvent gestureEventInfo = clickRecognizer->GetGestureEventInfo();
369 ClickInfo clickInfo = clickRecognizer->GetClickInfo();
370 UIObserverHandler::GetInstance().NotifyDidClick(gestureEventInfo, clickInfo, node);
371 }
372 }
373
Dump() const374 RefPtr<GestureSnapshot> NGGestureRecognizer::Dump() const
375 {
376 RefPtr<GestureSnapshot> info = TouchEventTarget::Dump();
377 auto group = gestureGroup_.Upgrade();
378 if (group) {
379 info->parentId = reinterpret_cast<uintptr_t>(AceType::RawPtr(group));
380 }
381 return info;
382 }
383
AddGestureProcedure(const std::string & procedure) const384 void NGGestureRecognizer::AddGestureProcedure(const std::string& procedure) const
385 {
386 auto context = PipelineContext::GetCurrentContext();
387 CHECK_NULL_VOID(context);
388 auto eventMgr = context->GetEventManager();
389 CHECK_NULL_VOID(eventMgr);
390 eventMgr->GetEventTreeRecord(isPostEventResult_ ? EventTreeType::POST_EVENT : EventTreeType::TOUCH)
391 .AddGestureProcedure(reinterpret_cast<uintptr_t>(this), procedure, TransRefereeState(this->GetRefereeState()),
392 TransGestureDisposal(this->GetGestureDisposal()));
393 }
394
AddGestureProcedure(const TouchEvent & point,const RefPtr<NGGestureRecognizer> & recognizer) const395 void NGGestureRecognizer::AddGestureProcedure(const TouchEvent& point,
396 const RefPtr<NGGestureRecognizer>& recognizer) const
397 {
398 if (!recognizer) {
399 return;
400 }
401 auto context = PipelineContext::GetCurrentContext();
402 CHECK_NULL_VOID(context);
403 auto eventMgr = context->GetEventManager();
404 CHECK_NULL_VOID(eventMgr);
405 eventMgr->GetEventTreeRecord(isPostEventResult_ ? EventTreeType::POST_EVENT : EventTreeType::TOUCH)
406 .AddGestureProcedure(reinterpret_cast<uintptr_t>(AceType::RawPtr(recognizer)), point,
407 TransRefereeState(recognizer->GetRefereeState()), TransGestureDisposal(recognizer->GetGestureDisposal()));
408 }
409
SetGestureGroup(const WeakPtr<NGGestureRecognizer> & gestureGroup)410 bool NGGestureRecognizer::SetGestureGroup(const WeakPtr<NGGestureRecognizer>& gestureGroup)
411 {
412 if (!gestureGroup_.Invalid() && !gestureGroup.Invalid()) {
413 return false;
414 }
415
416 gestureGroup_ = gestureGroup;
417 return true;
418 }
419
SetEventImportGestureGroup(const WeakPtr<NGGestureRecognizer> & gestureGroup)420 void NGGestureRecognizer::SetEventImportGestureGroup(const WeakPtr<NGGestureRecognizer>& gestureGroup)
421 {
422 if (gestureGroup.Invalid()) {
423 return;
424 }
425
426 eventImportGestureGroup_ = gestureGroup;
427 }
428
IsInAttachedNode(const TouchEvent & event,bool isRealTime)429 bool NGGestureRecognizer::IsInAttachedNode(const TouchEvent& event, bool isRealTime)
430 {
431 bool isChildTouchTestResult = false;
432 auto frameNode = GetAttachedNode();
433 if (frameNode.Invalid()) {
434 return true;
435 }
436 auto host = frameNode.Upgrade();
437 CHECK_NULL_RETURN(host, true);
438 auto id = host->GetInspectorIdValue("");
439 isChildTouchTestResult = std::any_of(event.childTouchTestList.begin(), event.childTouchTestList.end(),
440 [id](const std::string& inspectorId) {
441 return inspectorId == id;
442 });
443 if (isChildTouchTestResult) {
444 return true;
445 }
446
447 PointF localPoint(event.x, event.y);
448 if (isRealTime) {
449 NGGestureRecognizer::Transform(localPoint, frameNode, !isPostEventResult_,
450 isPostEventResult_, event.postEventNodeId);
451 } else {
452 NGGestureRecognizer::Transform(localPoint, frameNode, false,
453 isPostEventResult_, event.postEventNodeId);
454 }
455 auto renderContext = host->GetRenderContext();
456 CHECK_NULL_RETURN(renderContext, false);
457 auto paintRect = renderContext->GetPaintRectWithoutTransform();
458 localPoint = localPoint + paintRect.GetOffset();
459 auto responseRegion = host->GetResponseRegionListForRecognizer(static_cast<int32_t>(event.sourceType));
460 auto result = host->InResponseRegionList(localPoint, responseRegion);
461 if (!result) {
462 std::string responseInfo = std::string("responseRegionList = ");
463 for (const auto& item : responseRegion) {
464 responseInfo.append(item.ToString()).append("; ");
465 }
466 TAG_LOGI(AceLogTag::ACE_GESTURE,
467 "%{public}s IsInAttachedNode result is negative, node tag = %{public}s, id = %{public}s, point = "
468 "%{public}s, frameRect = %{public}s, %{public}s",
469 AceType::TypeName(this), host->GetTag().c_str(), std::to_string(host->GetId()).c_str(),
470 localPoint.ToString().c_str(), host->GetFrameRectWithoutSafeArea().ToString().c_str(),
471 responseInfo.c_str());
472 }
473 return result;
474 }
475
SetResponseLinkRecognizers(const ResponseLinkResult & responseLinkResult)476 void NGGestureRecognizer::SetResponseLinkRecognizers(const ResponseLinkResult& responseLinkResult)
477 {
478 responseLinkRecognizer_ = responseLinkResult;
479 }
480
IsInResponseLinkRecognizers()481 bool NGGestureRecognizer::IsInResponseLinkRecognizers()
482 {
483 return std::any_of(responseLinkRecognizer_.begin(), responseLinkRecognizer_.end(),
484 [recognizer = Claim(this)](const RefPtr<NGGestureRecognizer>& item) { return item == recognizer; });
485 }
486
AboutToAddCurrentFingers(const TouchEvent & event)487 bool NGGestureRecognizer::AboutToAddCurrentFingers(const TouchEvent& event)
488 {
489 bool isInAttachedNode = IsInAttachedNode(event, !AceType::InstanceOf<ClickRecognizer>(this));
490 if (!isInAttachedNode) {
491 return false;
492 }
493 if (fingersId_.find(event.id) != fingersId_.end()) {
494 auto node = GetAttachedNode().Upgrade();
495 TAG_LOGI(AceLogTag::ACE_GESTURE,
496 "Recognizer has already receive touchId: %{public}d event, node tag = %{public}s, id = %{public}s",
497 event.id, node ? node->GetTag().c_str() : "null",
498 node ? std::to_string(node->GetId()).c_str() : "invalid");
499 return false;
500 }
501 currentFingers_++;
502 return true;
503 }
504
AboutToMinusCurrentFingers(int32_t touchId)505 bool NGGestureRecognizer::AboutToMinusCurrentFingers(int32_t touchId)
506 {
507 if (fingersId_.find(touchId) != fingersId_.end()) {
508 return true;
509 }
510 auto node = GetAttachedNode().Upgrade();
511 TAG_LOGI(AceLogTag::ACE_GESTURE,
512 "Recognizer has already receive touchId: %{public}d up event, node tag = %{public}s, id = %{public}s",
513 touchId, node ? node->GetTag().c_str() : "null",
514 node ? std::to_string(node->GetId()).c_str() : "invalid");
515 return false;
516 }
517 } // namespace OHOS::Ace::NG
518