/* * Copyright (c) 2020-2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "dock/pointer_input_device.h" #include "components/root_view.h" #include "components/ui_tree_manager.h" #include "core/render_manager.h" #if ENABLE_AOD #include "events/aod_callback.h" #endif #include "gfx_utils/graphic_log.h" #include "gfx_utils/graphic_math.h" #if ENABLE_WINDOW #include "window/window.h" #endif namespace OHOS { void PointerInputDevice::DispatchEvent(const DeviceData& data) { curPos_ = data.point; #if ENABLE_WINDOW Window* window = RenderManager::GetInstance().GetWindowById(data.winId); if (window == nullptr) { return; } curPos_.x = curPos_.x - window->GetRect().GetLeft(); curPos_.y = curPos_.y - window->GetRect().GetTop(); UIViewGroup* rootView = window->GetRootView(); #else UIViewGroup* rootView = RootView::GetInstance(); #endif if (rootView == nullptr) { GRAPHIC_LOGE("No valid rootview to dispatch input event!\n"); return; } if (data.state == STATE_PRESS) { DispatchPressEvent(rootView); } else { DispatchReleaseEvent(rootView); } dragLastPos_ = lastPos_; lastPos_ = curPos_; } void PointerInputDevice::DispatchPressEvent(UIViewGroup* rootView) { // first time to press if (!pressState_) { rootView->GetTargetView(curPos_, &touchableView_, &targetView_); if (touchableView_ == nullptr) { GRAPHIC_LOGD("PointerInputDevice::DispatchPressEvent cannot find target view!\n"); return; } draggableView_ = GetDraggableView(touchableView_); pressState_ = true; pressTimeStamp_ = HALTick::GetInstance().GetTime(); lastPos_ = curPos_; dragLastPos_ = lastPos_; return; } uint32_t elapse = HALTick::GetInstance().GetElapseTime(pressTimeStamp_); DispatchDragStartEvent(); DispatchDragEvent(); if (!isDragging_ && (touchableView_ != nullptr) && !cancelSent_) { UIView* tempView = nullptr; rootView->GetTargetView(curPos_, &tempView, &targetView_); if (tempView != touchableView_) { DispatchCancelEvent(); } else { if (!pressSent_ && (elapse > INDEV_PRESS_TIME_IN_DRAG)) { PressEvent evt(curPos_); UIView* parent = touchableView_->GetParent(); if (!touchableView_->OnPressEvent(evt)) { while (parent != nullptr) { PressEvent evtParent(curPos_); if (parent->OnPressEvent(evtParent)) { break; } parent = parent->GetParent(); } } pressSent_ = true; } DispatchLongPressEvent(elapse); } } } bool PointerInputDevice::ProcessReleaseEvent() { UIView* parent = touchableView_->GetParent(); // reissue press event. if (!pressSent_) { PressEvent evtPress(curPos_); if (!touchableView_->OnPressEvent(evtPress)) { while (parent != nullptr) { PressEvent evtPressParent(curPos_); if (parent->OnPressEvent(evtPressParent)) { break; } parent = parent->GetParent(); } } pressSent_ = true; return false; } else { ReleaseEvent evtRelease(curPos_); if (!touchableView_->OnReleaseEvent(evtRelease)) { while (parent != nullptr) { ReleaseEvent evtReleaseParent(curPos_); if (parent->OnReleaseEvent(evtReleaseParent)) { break; } parent = parent->GetParent(); } } if (pressSent_ && needClick_) { ClickEvent evt(curPos_); parent = touchableView_->GetParent(); if (!touchableView_->OnClickEvent(evt)) { while (parent != nullptr) { #if ENABLE_AOD OnClickEventHappen(parent); #endif ClickEvent evtParent(curPos_); if (parent->OnClickEvent(evtParent)) { break; } parent = parent->GetParent(); } } #if ENABLE_AOD OnClickEventHappen(*touchableView_); #endif } } return true; } void PointerInputDevice::DispatchReleaseEvent(UIViewGroup* rootView) { if (!pressState_) { return; } DispatchDragStartEvent(); DispatchDragEndEvent(); if (!isDragging_ && (touchableView_ != nullptr) && !cancelSent_) { UIView* tempView = nullptr; rootView->GetTargetView(curPos_, &tempView, &targetView_); if (tempView != touchableView_) { DispatchCancelEvent(); } else { if (!ProcessReleaseEvent()) { return; } } } isDragging_ = false; pressState_ = false; pressSent_ = false; cancelSent_ = false; longPressSent_ = false; needClick_ = true; touchableView_ = nullptr; } void PointerInputDevice::DispatchDragStartEvent() { if (draggableView_ == nullptr) { return; } dragStep_.x = curPos_.x - lastPos_.x; dragStep_.y = curPos_.y - lastPos_.y; dragLen_.x += dragStep_.x; dragLen_.y += dragStep_.y; if (!isDragging_) { if ((MATH_ABS(dragLen_.x) >= INDEV_DRAG_LIMIT) || (MATH_ABS(dragLen_.y) >= INDEV_DRAG_LIMIT)) { if ((touchableView_ != nullptr) && !cancelSent_) { DispatchCancelEvent(); } // Send Drag Begin Event. DragEvent evt(curPos_, lastPos_, dragLen_); UIView* parent = draggableView_->GetParent(); if (!draggableView_->OnDragStartEvent(evt)) { while (parent != nullptr) { DragEvent evtParent(curPos_, lastPos_, dragLen_); if (parent->OnDragStartEvent(evtParent)) { break; } parent = parent->GetParent(); } } dragLastPos_ = lastPos_; isDragging_ = true; } } } void PointerInputDevice::DispatchDragEvent() { if ((draggableView_ == nullptr) || !isDragging_) { return; } if ((dragStep_.x != 0) || (dragStep_.y != 0)) { DragEvent evt(curPos_, lastPos_, dragLen_); UIView* parent = draggableView_->GetParent(); if (!draggableView_->OnDragEvent(evt)) { while (parent != nullptr) { DragEvent evtParent(curPos_, lastPos_, dragLen_); if (parent->OnDragEvent(evtParent)) { break; } parent = parent->GetParent(); } } } } void PointerInputDevice::DispatchDragEndEvent() { if (draggableView_ == nullptr) { return; } if (isDragging_) { DragEvent evt(curPos_, lastPos_, dragLen_); UIView* parent = draggableView_->GetParent(); evt.SetPreLastPoint(dragLastPos_); if (!draggableView_->OnDragEndEvent(evt)) { while (parent != nullptr) { DragEvent evtParent(curPos_, lastPos_, dragLen_); if (parent->OnDragEndEvent(evtParent)) { break; } parent = parent->GetParent(); } } #if ENABLE_AOD OnDragEndEventHappen(*draggableView_); #endif } dragLen_ = {0, 0}; dragStep_ = {0, 0}; draggableView_ = nullptr; } void PointerInputDevice::DispatchLongPressEvent(uint32_t elapse) { if (!longPressSent_ && (elapse > INDEV_LONG_PRESS_TIME)) { longPressSent_ = true; LongPressEvent evt(curPos_, pressTimeStamp_); bool isConsumed = touchableView_->OnLongPressEvent(evt); if (touchableView_->GetOnLongPressListener() != nullptr) { needClick_ = false; } UIView* parent = touchableView_->GetParent(); #if ENABLE_AOD OnLongPressEventHappen(*touchableView_); #endif if (!isConsumed) { while (parent != nullptr) { LongPressEvent evtParent(curPos_, pressTimeStamp_); isConsumed = parent->OnLongPressEvent(evtParent); if (needClick_ && (parent->GetOnLongPressListener() != nullptr)) { needClick_ = false; } #if ENABLE_AOD OnLongPressEventHappen(*parent); #endif if (isConsumed) { break; } parent = parent->GetParent(); } } } } void PointerInputDevice::DispatchCancelEvent() { CancelEvent evt(lastPos_); UIView* parent = touchableView_->GetParent(); if (!touchableView_->OnCancelEvent(evt)) { while (parent != nullptr) { CancelEvent evtParent(lastPos_); if (parent->OnCancelEvent(evtParent)) { break; } parent = parent->GetParent(); } } cancelSent_ = true; } void PointerInputDevice::UpdateEventViews(UIView* view) { // view should not be nullptr // invalid touchable and draggable view will be reset to nullptr if ((touchableView_ != nullptr) && RootView::FindSubView(*view, touchableView_)) { touchableView_ = nullptr; } if ((draggableView_ != nullptr) && RootView::FindSubView(*view, draggableView_)) { draggableView_ = nullptr; dragLastPos_ = curPos_; dragLen_ = {0, 0}; dragStep_ = {0, 0}; isDragging_ = false; } } void PointerInputDevice::OnViewLifeEvent() { UIView* view; UITreeManager::ViewLifeEvent event; UITreeManager::GetInstance().GetLastEvent(view, event); if ((event != UITreeManager::REMOVE) || (view == nullptr)) { return; } UpdateEventViews(view); } } // namespace OHOS