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 "render_touch_listener.h"
17 
18 #include "core/components/touch_listener/touch_listener_component.h"
19 #include "core/event/ace_event_helper.h"
20 
21 namespace OHOS::Ace {
22 
RenderTouchListener()23 RenderTouchListener::RenderTouchListener() : rawRecognizer_(AceType::MakeRefPtr<RawRecognizer>()) {}
24 
Create()25 RefPtr<RenderNode> RenderTouchListener::Create()
26 {
27     return AceType::MakeRefPtr<RenderTouchListener>();
28 }
29 
Update(const RefPtr<Component> & component)30 void RenderTouchListener::Update(const RefPtr<Component>& component)
31 {
32     auto touchComponent = AceType::DynamicCast<TouchListenerComponent>(component);
33     ACE_DCHECK(touchComponent);
34     responseRegion_ = touchComponent->GetResponseRegion();
35     isResponseRegion_ = touchComponent->IsResponseRegion();
36     auto context = context_.Upgrade();
37     if (context && context->GetIsDeclarative()) {
38         onTouchEventCallback_ = AceSyncEvent<void(const std::shared_ptr<TouchEventInfo>&)>::Create(
39             touchComponent->GetOnTouchId(), context_);
40         return;
41     }
42 
43     for (uint32_t eventStage = 0; eventStage < EventStage::SIZE; eventStage++) {
44         for (uint32_t touchEventType = 0; touchEventType < EventType::SIZE; touchEventType++) {
45             auto& onEventId = touchComponent->GetEvent(EventAction::ON, eventStage, touchEventType);
46             if (!onEventId.IsEmpty()) {
47                 rawRecognizer_->SetOnEventCallback(
48                     AceAsyncEvent<void(const TouchEventInfo&)>::Create(onEventId, context_), eventStage,
49                     touchEventType);
50             }
51             auto& catchEventId = touchComponent->GetEvent(EventAction::CATCH, eventStage, touchEventType);
52             if (!catchEventId.IsEmpty()) {
53                 rawRecognizer_->SetCatchEventCallback(
54                     AceAsyncEvent<void()>::Create(catchEventId, context_), eventStage, touchEventType);
55             }
56         }
57 
58         auto& onEventId = touchComponent->GetSwipeEvent(EventAction::ON, eventStage);
59         if (!onEventId.IsEmpty()) {
60             if (!swipeRecognizer_) {
61                 swipeRecognizer_ = AceType::MakeRefPtr<SwipeRecognizer>();
62             }
63             swipeRecognizer_->SetSwipeCallback(
64                 AceAsyncEvent<void(const SwipeEventInfo&)>::Create(onEventId, context_), eventStage);
65         }
66         auto& catchEventId = touchComponent->GetSwipeEvent(EventAction::CATCH, eventStage);
67         if (!catchEventId.IsEmpty()) {
68             if (!swipeRecognizer_) {
69                 swipeRecognizer_ = AceType::MakeRefPtr<SwipeRecognizer>();
70             }
71             swipeRecognizer_->SetCatchEventCallback(
72                 AceAsyncEvent<void(const SwipeEventInfo&)>::Create(catchEventId, context_), eventStage);
73         }
74     }
75     touchable_ = touchComponent->IsTouchable();
76     isVisible_ = touchComponent->IsVisible();
77     interceptTouchEvent_ = !touchable_;
78 
79     if (!touchComponent->GetEvent(EventAction::CATCH, EventStage::CAPTURE, EventType::TOUCH_DOWN).IsEmpty()) {
80         EventMarker eventMarker("catchEvent");
81         auto event = AceAsyncEvent<void()>::Create(eventMarker, context_);
82         rawRecognizer_->SetCatchEventCallback(event, EventStage::CAPTURE, EventType::TOUCH_UP);
83         rawRecognizer_->SetCatchEventCallback(event, EventStage::CAPTURE, EventType::TOUCH_MOVE);
84     }
85 }
86 
OnTouchTestHit(const Offset & coordinateOffset,const TouchRestrict & touchRestrict,TouchTestResult & result)87 void RenderTouchListener::OnTouchTestHit(
88     const Offset& coordinateOffset, const TouchRestrict& touchRestrict, TouchTestResult& result)
89 {
90     auto context = context_.Upgrade();
91     if (context && context->GetIsDeclarative()) {
92         coordinateOffset_ = coordinateOffset;
93         result.emplace_back(Claim(this));
94         return;
95     }
96     rawRecognizer_->SetCoordinateOffset(coordinateOffset);
97     result.emplace_back(rawRecognizer_);
98     if (swipeRecognizer_) {
99         result.emplace_back(swipeRecognizer_);
100     }
101 }
102 
GetVisible() const103 bool RenderTouchListener::GetVisible() const
104 {
105     return RenderNode::GetVisible() && isVisible_;
106 }
107 
DispatchEvent(const TouchEvent & point)108 bool RenderTouchListener::DispatchEvent(const TouchEvent& point)
109 {
110     return true;
111 }
112 
HandleEvent(const TouchEvent & point)113 bool RenderTouchListener::HandleEvent(const TouchEvent& point)
114 {
115     bool isPropagation = true;
116     auto context = context_.Upgrade();
117     if (context && context->GetIsDeclarative()) {
118         if (point.type == TouchType::DOWN) {
119             touchPointMap_[point.id] = point;
120             isPropagation = TriggerTouchCallBack(point);
121         } else if (point.type == TouchType::UP) {
122             isPropagation = TriggerTouchCallBack(point);
123             touchPointMap_.erase(point.id);
124         } else {
125             for (const auto& pointPair : touchPointMap_) {
126                 if (pointPair.first == point.id && (pointPair.second.x != point.x || pointPair.second.y != point.y)) {
127                     touchPointMap_[point.id] = point;
128                     isPropagation = TriggerTouchCallBack(point);
129                     break;
130                 }
131             }
132         }
133     }
134     return isPropagation;
135 }
136 
TriggerTouchCallBack(const TouchEvent & changedPoint)137 bool RenderTouchListener::TriggerTouchCallBack(const TouchEvent& changedPoint)
138 {
139     LOGI("Trigger touch callback");
140     if (!onTouchEventCallback_ && !onTouchFocusEventCallback_) {
141         return true;
142     }
143     auto event = std::make_shared<TouchEventInfo>("touchEvent");
144     event->SetTimeStamp(changedPoint.time);
145     TouchLocationInfo changedInfo("onTouch", changedPoint.id);
146     float localX = changedPoint.x - coordinateOffset_.GetX();
147     float localY = changedPoint.y - coordinateOffset_.GetY();
148     changedInfo.SetLocalLocation(Offset(localX, localY));
149     changedInfo.SetGlobalLocation(Offset(changedPoint.x, changedPoint.y));
150     changedInfo.SetScreenLocation(Offset(changedPoint.screenX, changedPoint.screenY));
151     changedInfo.SetTouchType(changedPoint.type);
152     changedInfo.SetForce(changedPoint.force);
153     if (changedPoint.tiltX.has_value()) {
154         changedInfo.SetTiltX(changedPoint.tiltX.value());
155     }
156     if (changedPoint.tiltY.has_value()) {
157         changedInfo.SetTiltY(changedPoint.tiltY.value());
158     }
159     changedInfo.SetSourceTool(changedPoint.sourceTool);
160     event->AddChangedTouchLocationInfo(std::move(changedInfo));
161 
162     // all fingers collection
163     for (const auto& pointPair : touchPointMap_) {
164         float globalX = pointPair.second.x;
165         float globalY = pointPair.second.y;
166         float screenX = pointPair.second.screenX;
167         float screenY = pointPair.second.screenY;
168         float localX = pointPair.second.x - coordinateOffset_.GetX();
169         float localY = pointPair.second.y - coordinateOffset_.GetY();
170         TouchLocationInfo info("onTouch", pointPair.second.id);
171         info.SetGlobalLocation(Offset(globalX, globalY));
172         info.SetLocalLocation(Offset(localX, localY));
173         info.SetScreenLocation(Offset(screenX, screenY));
174         info.SetTouchType(pointPair.second.type);
175         info.SetForce(pointPair.second.force);
176         if (pointPair.second.tiltX.has_value()) {
177             info.SetTiltX(pointPair.second.tiltX.value());
178         }
179         if (pointPair.second.tiltY.has_value()) {
180             info.SetTiltY(pointPair.second.tiltY.value());
181         }
182         info.SetSourceTool(pointPair.second.sourceTool);
183         event->AddTouchLocationInfo(std::move(info));
184     }
185     event->SetSourceDevice(changedPoint.sourceType);
186     event->SetForce(changedPoint.force);
187     if (changedPoint.tiltX.has_value()) {
188         event->SetTiltX(changedPoint.tiltX.value());
189     }
190     if (changedPoint.tiltY.has_value()) {
191         event->SetTiltY(changedPoint.tiltY.value());
192     }
193     event->SetSourceTool(changedPoint.sourceTool);
194     if (onTouchEventCallback_) {
195         onTouchEventCallback_(event);
196     }
197     if (onTouchFocusEventCallback_ && changedPoint.type == TouchType::DOWN) {
198         onTouchFocusEventCallback_();
199     }
200     return event->IsStopPropagation() ? false : true;
201 }
202 
203 } // namespace OHOS::Ace