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
30namespace OHOS {
31void 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
59void 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
103bool 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
155void 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
183void 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
215void 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
235void 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
263void 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
295void 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
311void 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
328void 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