1 /*
2  * Copyright (c) 2020-2021 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 "dock/pointer_input_device.h"
17 
18 #include "components/root_view.h"
19 #include "components/ui_tree_manager.h"
20 #include "core/render_manager.h"
21 #if ENABLE_AOD
22 #include "events/aod_callback.h"
23 #endif
24 #include "gfx_utils/graphic_log.h"
25 #include "gfx_utils/graphic_math.h"
26 #if ENABLE_WINDOW
27 #include "window/window.h"
28 #endif
29 
30 namespace OHOS {
DispatchEvent(const DeviceData & data)31 void PointerInputDevice::DispatchEvent(const DeviceData& data)
32 {
33     curPos_ = data.point;
34 #if ENABLE_WINDOW
35     Window* window = RenderManager::GetInstance().GetWindowById(data.winId);
36     if (window == nullptr) {
37         return;
38     }
39     curPos_.x = curPos_.x - window->GetRect().GetLeft();
40     curPos_.y = curPos_.y - window->GetRect().GetTop();
41     UIViewGroup* rootView = window->GetRootView();
42 #else
43     UIViewGroup* rootView = RootView::GetInstance();
44 #endif
45     if (rootView == nullptr) {
46         GRAPHIC_LOGE("No valid rootview to dispatch input event!\n");
47         return;
48     }
49 
50     if (data.state == STATE_PRESS) {
51         DispatchPressEvent(rootView);
52     } else {
53         DispatchReleaseEvent(rootView);
54     }
55     dragLastPos_ = lastPos_;
56     lastPos_ = curPos_;
57 }
58 
DispatchPressEvent(UIViewGroup * rootView)59 void PointerInputDevice::DispatchPressEvent(UIViewGroup* rootView)
60 {
61     // first time to press
62     if (!pressState_) {
63         rootView->GetTargetView(curPos_, &touchableView_, &targetView_);
64         if (touchableView_ == nullptr) {
65             GRAPHIC_LOGD("PointerInputDevice::DispatchPressEvent cannot find target view!\n");
66             return;
67         }
68         draggableView_ = GetDraggableView(touchableView_);
69         pressState_ = true;
70         pressTimeStamp_ = HALTick::GetInstance().GetTime();
71         lastPos_ = curPos_;
72         dragLastPos_ = lastPos_;
73         return;
74     }
75     uint32_t elapse = HALTick::GetInstance().GetElapseTime(pressTimeStamp_);
76     DispatchDragStartEvent();
77     DispatchDragEvent();
78     if (!isDragging_ && (touchableView_ != nullptr) && !cancelSent_) {
79         UIView* tempView = nullptr;
80         rootView->GetTargetView(curPos_, &tempView, &targetView_);
81         if (tempView != touchableView_) {
82             DispatchCancelEvent();
83         } else {
84             if (!pressSent_ && (elapse > INDEV_PRESS_TIME_IN_DRAG)) {
85                 PressEvent evt(curPos_);
86                 UIView* parent = touchableView_->GetParent();
87                 if (!touchableView_->OnPressEvent(evt)) {
88                     while (parent != nullptr) {
89                         PressEvent evtParent(curPos_);
90                         if (parent->OnPressEvent(evtParent)) {
91                             break;
92                         }
93                         parent = parent->GetParent();
94                     }
95                 }
96                 pressSent_ = true;
97             }
98             DispatchLongPressEvent(elapse);
99         }
100     }
101 }
102 
ProcessReleaseEvent()103 bool PointerInputDevice::ProcessReleaseEvent()
104 {
105     UIView* parent = touchableView_->GetParent();
106     // reissue press event.
107     if (!pressSent_) {
108         PressEvent evtPress(curPos_);
109         if (!touchableView_->OnPressEvent(evtPress)) {
110             while (parent != nullptr) {
111                 PressEvent evtPressParent(curPos_);
112                 if (parent->OnPressEvent(evtPressParent)) {
113                     break;
114                 }
115                 parent = parent->GetParent();
116             }
117         }
118         pressSent_ = true;
119         return false;
120     } else {
121         ReleaseEvent evtRelease(curPos_);
122         if (!touchableView_->OnReleaseEvent(evtRelease)) {
123             while (parent != nullptr) {
124                 ReleaseEvent evtReleaseParent(curPos_);
125                 if (parent->OnReleaseEvent(evtReleaseParent)) {
126                     break;
127                 }
128                 parent = parent->GetParent();
129             }
130         }
131 
132         if (pressSent_ && needClick_) {
133             ClickEvent evt(curPos_);
134             parent = touchableView_->GetParent();
135             if (!touchableView_->OnClickEvent(evt)) {
136                 while (parent != nullptr) {
137 #if ENABLE_AOD
138                     OnClickEventHappen(parent);
139 #endif
140                     ClickEvent evtParent(curPos_);
141                     if (parent->OnClickEvent(evtParent)) {
142                         break;
143                     }
144                     parent = parent->GetParent();
145                 }
146             }
147 #if ENABLE_AOD
148             OnClickEventHappen(*touchableView_);
149 #endif
150         }
151     }
152     return true;
153 }
154 
DispatchReleaseEvent(UIViewGroup * rootView)155 void PointerInputDevice::DispatchReleaseEvent(UIViewGroup* rootView)
156 {
157     if (!pressState_) {
158         return;
159     }
160 
161     DispatchDragStartEvent();
162     DispatchDragEndEvent();
163     if (!isDragging_ && (touchableView_ != nullptr) && !cancelSent_) {
164         UIView* tempView = nullptr;
165         rootView->GetTargetView(curPos_, &tempView, &targetView_);
166         if (tempView != touchableView_) {
167             DispatchCancelEvent();
168         } else {
169             if (!ProcessReleaseEvent()) {
170                 return;
171             }
172         }
173     }
174     isDragging_ = false;
175     pressState_ = false;
176     pressSent_ = false;
177     cancelSent_ = false;
178     longPressSent_ = false;
179     needClick_ = true;
180     touchableView_ = nullptr;
181 }
182 
DispatchDragStartEvent()183 void PointerInputDevice::DispatchDragStartEvent()
184 {
185     if (draggableView_ == nullptr) {
186         return;
187     }
188     dragStep_.x = curPos_.x - lastPos_.x;
189     dragStep_.y = curPos_.y - lastPos_.y;
190     dragLen_.x += dragStep_.x;
191     dragLen_.y += dragStep_.y;
192     if (!isDragging_) {
193         if ((MATH_ABS(dragLen_.x) >= INDEV_DRAG_LIMIT) || (MATH_ABS(dragLen_.y) >= INDEV_DRAG_LIMIT)) {
194             if ((touchableView_ != nullptr) && !cancelSent_) {
195                 DispatchCancelEvent();
196             }
197             // Send Drag Begin Event.
198             DragEvent evt(curPos_, lastPos_, dragLen_);
199             UIView* parent = draggableView_->GetParent();
200             if (!draggableView_->OnDragStartEvent(evt)) {
201                 while (parent != nullptr) {
202                     DragEvent evtParent(curPos_, lastPos_, dragLen_);
203                     if (parent->OnDragStartEvent(evtParent)) {
204                         break;
205                     }
206                     parent = parent->GetParent();
207                 }
208             }
209             dragLastPos_ = lastPos_;
210             isDragging_ = true;
211         }
212     }
213 }
214 
DispatchDragEvent()215 void PointerInputDevice::DispatchDragEvent()
216 {
217     if ((draggableView_ == nullptr) || !isDragging_) {
218         return;
219     }
220     if ((dragStep_.x != 0) || (dragStep_.y != 0)) {
221         DragEvent evt(curPos_, lastPos_, dragLen_);
222         UIView* parent = draggableView_->GetParent();
223         if (!draggableView_->OnDragEvent(evt)) {
224             while (parent != nullptr) {
225                 DragEvent evtParent(curPos_, lastPos_, dragLen_);
226                 if (parent->OnDragEvent(evtParent)) {
227                     break;
228                 }
229                 parent = parent->GetParent();
230             }
231         }
232     }
233 }
234 
DispatchDragEndEvent()235 void PointerInputDevice::DispatchDragEndEvent()
236 {
237     if (draggableView_ == nullptr) {
238         return;
239     }
240 
241     if (isDragging_) {
242         DragEvent evt(curPos_, lastPos_, dragLen_);
243         UIView* parent = draggableView_->GetParent();
244         evt.SetPreLastPoint(dragLastPos_);
245         if (!draggableView_->OnDragEndEvent(evt)) {
246             while (parent != nullptr) {
247                 DragEvent evtParent(curPos_, lastPos_, dragLen_);
248                 if (parent->OnDragEndEvent(evtParent)) {
249                     break;
250                 }
251                 parent = parent->GetParent();
252             }
253         }
254 #if ENABLE_AOD
255         OnDragEndEventHappen(*draggableView_);
256 #endif
257     }
258     dragLen_ = {0, 0};
259     dragStep_ = {0, 0};
260     draggableView_ = nullptr;
261 }
262 
DispatchLongPressEvent(uint32_t elapse)263 void PointerInputDevice::DispatchLongPressEvent(uint32_t elapse)
264 {
265     if (!longPressSent_ && (elapse > INDEV_LONG_PRESS_TIME)) {
266         longPressSent_ = true;
267         LongPressEvent evt(curPos_, pressTimeStamp_);
268         bool isConsumed = touchableView_->OnLongPressEvent(evt);
269         if (touchableView_->GetOnLongPressListener() != nullptr) {
270             needClick_ = false;
271         }
272         UIView* parent = touchableView_->GetParent();
273 #if ENABLE_AOD
274         OnLongPressEventHappen(*touchableView_);
275 #endif
276         if (!isConsumed) {
277             while (parent != nullptr) {
278                 LongPressEvent evtParent(curPos_, pressTimeStamp_);
279                 isConsumed = parent->OnLongPressEvent(evtParent);
280                 if (needClick_ && (parent->GetOnLongPressListener() != nullptr)) {
281                     needClick_ = false;
282                 }
283 #if ENABLE_AOD
284                 OnLongPressEventHappen(*parent);
285 #endif
286                 if (isConsumed) {
287                     break;
288                 }
289                 parent = parent->GetParent();
290             }
291         }
292     }
293 }
294 
DispatchCancelEvent()295 void PointerInputDevice::DispatchCancelEvent()
296 {
297     CancelEvent evt(lastPos_);
298     UIView* parent = touchableView_->GetParent();
299     if (!touchableView_->OnCancelEvent(evt)) {
300         while (parent != nullptr) {
301             CancelEvent evtParent(lastPos_);
302             if (parent->OnCancelEvent(evtParent)) {
303                 break;
304             }
305             parent = parent->GetParent();
306         }
307     }
308     cancelSent_ = true;
309 }
310 
UpdateEventViews(UIView * view)311 void PointerInputDevice::UpdateEventViews(UIView* view)
312 {
313     // view should not be nullptr
314     // invalid touchable and draggable view will be reset to nullptr
315     if ((touchableView_ != nullptr) && RootView::FindSubView(*view, touchableView_)) {
316         touchableView_ = nullptr;
317     }
318 
319     if ((draggableView_ != nullptr) && RootView::FindSubView(*view, draggableView_)) {
320         draggableView_ = nullptr;
321         dragLastPos_ = curPos_;
322         dragLen_ = {0, 0};
323         dragStep_ = {0, 0};
324         isDragging_ = false;
325     }
326 }
327 
OnViewLifeEvent()328 void PointerInputDevice::OnViewLifeEvent()
329 {
330     UIView* view;
331     UITreeManager::ViewLifeEvent event;
332     UITreeManager::GetInstance().GetLastEvent(view, event);
333 
334     if ((event != UITreeManager::REMOVE) || (view == nullptr)) {
335         return;
336     }
337     UpdateEventViews(view);
338 }
339 
340 } // namespace OHOS
341