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 #include "drag_controller.h"
16
17 #include <vector>
18
19 #include "display.h"
20 #include "vsync_station.h"
21 #include "wm_common.h"
22 #include "window_helper.h"
23 #include "window_inner_manager.h"
24 #include "window_manager_hilog.h"
25 #include "window_manager_service.h"
26 #include "window_node.h"
27 #include "window_node_container.h"
28 #include "window_property.h"
29
30 namespace OHOS {
31 namespace Rosen {
32 namespace {
33 constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "DragController"};
34 }
35
UpdateDragInfo(uint32_t windowId)36 void DragController::UpdateDragInfo(uint32_t windowId)
37 {
38 PointInfo point;
39 if (!GetHitPoint(windowId, point)) {
40 return;
41 }
42 sptr<WindowNode> dragNode = windowRoot_->GetWindowNode(windowId);
43 if (dragNode == nullptr) {
44 return;
45 }
46 sptr<WindowNode> hitWindowNode = GetHitWindow(dragNode->GetDisplayId(), point);
47 if (hitWindowNode == nullptr) {
48 WLOGFE("Get point failed %{public}d %{public}d", point.x, point.y);
49 return;
50 }
51 auto token = hitWindowNode->GetWindowToken();
52 if (token) {
53 if (hitWindowNode->GetWindowId() == hitWindowId_) {
54 token->UpdateWindowDragInfo(point, DragEvent::DRAG_EVENT_MOVE);
55 return;
56 }
57 token->UpdateWindowDragInfo(point, DragEvent::DRAG_EVENT_IN);
58 }
59 sptr<WindowNode> oldHitWindow = windowRoot_->GetWindowNode(hitWindowId_);
60 if (oldHitWindow != nullptr && oldHitWindow->GetWindowToken()) {
61 oldHitWindow->GetWindowToken()->UpdateWindowDragInfo(point, DragEvent::DRAG_EVENT_OUT);
62 }
63 hitWindowId_ = hitWindowNode->GetWindowId();
64 }
65
StartDrag(uint32_t windowId)66 void DragController::StartDrag(uint32_t windowId)
67 {
68 PointInfo point;
69 if (!GetHitPoint(windowId, point)) {
70 WLOGFE("Get hit point failed");
71 return;
72 }
73 sptr<WindowNode> dragNode = windowRoot_->GetWindowNode(windowId);
74 if (dragNode == nullptr) {
75 return;
76 }
77 sptr<WindowNode> hitWindow = GetHitWindow(dragNode->GetDisplayId(), point);
78 if (hitWindow == nullptr) {
79 WLOGFE("Get point failed %{public}d %{public}d", point.x, point.y);
80 return;
81 }
82 if (hitWindow->GetWindowToken()) {
83 hitWindow->GetWindowToken()->UpdateWindowDragInfo(point, DragEvent::DRAG_EVENT_IN);
84 }
85 hitWindowId_ = windowId;
86 WLOGFI("start Drag");
87 }
88
FinishDrag(uint32_t windowId)89 void DragController::FinishDrag(uint32_t windowId)
90 {
91 sptr<WindowNode> node = windowRoot_->GetWindowNode(windowId);
92 if (node == nullptr) {
93 WLOGFE("get node failed");
94 return;
95 }
96 if (node->GetWindowType() != WindowType::WINDOW_TYPE_DRAGGING_EFFECT) {
97 return;
98 }
99
100 sptr<WindowNode> hitWindow = windowRoot_->GetWindowNode(hitWindowId_);
101 if (hitWindow != nullptr) {
102 auto property = node->GetWindowProperty();
103 PointInfo point = {property->GetWindowRect().posX_ + property->GetHitOffset().x,
104 property->GetWindowRect().posY_ + property->GetHitOffset().y};
105 if (hitWindow->GetWindowToken()) {
106 hitWindow->GetWindowToken()->UpdateWindowDragInfo(point, DragEvent::DRAG_EVENT_END);
107 }
108 }
109 WLOGFI("end drag");
110 }
111
GetHitWindow(DisplayId id,PointInfo point)112 sptr<WindowNode> DragController::GetHitWindow(DisplayId id, PointInfo point)
113 {
114 // Need get display by point
115 if (id == DISPLAY_ID_INVALID) {
116 WLOGFE("Get invalid display");
117 return nullptr;
118 }
119 sptr<WindowNodeContainer> container = windowRoot_->GetOrCreateWindowNodeContainer(id);
120 if (container == nullptr) {
121 WLOGFE("get container failed %{public}" PRIu64"", id);
122 return nullptr;
123 }
124
125 std::vector<sptr<WindowNode>> windowNodes;
126 container->TraverseContainer(windowNodes);
127 for (auto windowNode : windowNodes) {
128 if (windowNode->GetWindowType() >= WindowType::WINDOW_TYPE_PANEL) {
129 continue;
130 }
131 if (WindowHelper::IsPointInTargetRect(point.x, point.y, windowNode->GetWindowRect())) {
132 return windowNode;
133 }
134 }
135 return nullptr;
136 }
137
GetHitPoint(uint32_t windowId,PointInfo & point)138 bool DragController::GetHitPoint(uint32_t windowId, PointInfo& point)
139 {
140 sptr<WindowNode> windowNode = windowRoot_->GetWindowNode(windowId);
141 if (windowNode == nullptr || windowNode->GetWindowType() != WindowType::WINDOW_TYPE_DRAGGING_EFFECT) {
142 WLOGFE("Get hit point failed");
143 return false;
144 }
145 sptr<WindowProperty> property = windowNode->GetWindowProperty();
146 point.x = property->GetWindowRect().posX_ + property->GetHitOffset().x;
147 point.y = property->GetWindowRect().posY_ + property->GetHitOffset().y;
148 return true;
149 }
150
OnInputEvent(std::shared_ptr<MMI::KeyEvent> keyEvent) const151 void DragInputEventListener::OnInputEvent(std::shared_ptr<MMI::KeyEvent> keyEvent) const
152 {
153 if (keyEvent == nullptr) {
154 WLOGFE("KeyEvent is nullptr");
155 return;
156 }
157 uint32_t windowId = static_cast<uint32_t>(keyEvent->GetAgentWindowId());
158 WLOGFD("[WMS] Receive keyEvent, windowId: %{public}u", windowId);
159 keyEvent->MarkProcessed();
160 }
161
OnInputEvent(std::shared_ptr<MMI::AxisEvent> axisEvent) const162 void DragInputEventListener::OnInputEvent(std::shared_ptr<MMI::AxisEvent> axisEvent) const
163 {
164 if (axisEvent == nullptr) {
165 WLOGFE("AxisEvent is nullptr");
166 return;
167 };
168 WLOGFD("[WMS] Receive axisEvent, windowId: %{public}u", axisEvent->GetAgentWindowId());
169 axisEvent->MarkProcessed();
170 }
171
OnInputEvent(std::shared_ptr<MMI::PointerEvent> pointerEvent) const172 void DragInputEventListener::OnInputEvent(std::shared_ptr<MMI::PointerEvent> pointerEvent) const
173 {
174 if (pointerEvent == nullptr) {
175 WLOGFE("PointerEvent is nullptr");
176 return;
177 }
178 uint32_t windowId = static_cast<uint32_t>(pointerEvent->GetAgentWindowId());
179 WLOGFD("[WMS] Receive pointerEvent, windowId: %{public}u", windowId);
180
181 WindowInnerManager::GetInstance().ConsumePointerEvent(pointerEvent);
182 }
183
SetInputEventConsumer()184 void MoveDragController::SetInputEventConsumer()
185 {
186 if (!inputListener_ || !inputEventHandler_) {
187 WLOGFE("InputListener or inputEventHandler is nullptr");
188 return;
189 }
190 MMI::InputManager::GetInstance()->SetWindowInputEventConsumer(inputListener_, inputEventHandler_);
191 }
192
Init()193 bool MoveDragController::Init()
194 {
195 // create handler for input event
196 inputEventHandler_ = std::make_shared<AppExecFwk::EventHandler>(
197 AppExecFwk::EventRunner::Create(INNER_WM_INPUT_THREAD_NAME));
198 if (inputEventHandler_ == nullptr) {
199 return false;
200 }
201 inputListener_ = std::make_shared<DragInputEventListener>(DragInputEventListener());
202 SetInputEventConsumer();
203 VsyncStation::GetInstance().SetIsMainHandlerAvailable(false);
204 VsyncStation::GetInstance().SetVsyncEventHandler(inputEventHandler_);
205 return true;
206 }
207
Stop()208 void MoveDragController::Stop()
209 {
210 if (inputEventHandler_ != nullptr) {
211 inputEventHandler_.reset();
212 }
213 }
214
HandleReadyToMoveOrDrag(uint32_t windowId,sptr<WindowProperty> & windowProperty,sptr<MoveDragProperty> & moveDragProperty)215 void MoveDragController::HandleReadyToMoveOrDrag(uint32_t windowId, sptr<WindowProperty>& windowProperty,
216 sptr<MoveDragProperty>& moveDragProperty)
217 {
218 SetActiveWindowId(windowId);
219 SetWindowProperty(windowProperty);
220 SetDragProperty(moveDragProperty);
221 }
222
HandleEndUpMovingOrDragging(uint32_t windowId)223 void MoveDragController::HandleEndUpMovingOrDragging(uint32_t windowId)
224 {
225 if (activeWindowId_ != windowId) {
226 WLOGFE("end up moving or dragging failed, windowId: %{public}u", windowId);
227 return;
228 }
229 ResetMoveOrDragState();
230 }
231
HandleWindowRemovedOrDestroyed(uint32_t windowId)232 void MoveDragController::HandleWindowRemovedOrDestroyed(uint32_t windowId)
233 {
234 if (GetMoveDragProperty() == nullptr) {
235 return;
236 }
237 if (!(GetMoveDragProperty()->startMoveFlag_ || GetMoveDragProperty()->startDragFlag_)) {
238 return;
239 }
240 VsyncStation::GetInstance().RemoveCallback();
241 ResetMoveOrDragState();
242 }
243
ConvertPointerPosToDisplayGroupPos(DisplayId displayId,int32_t & posX,int32_t & posY)244 void MoveDragController::ConvertPointerPosToDisplayGroupPos(DisplayId displayId, int32_t& posX, int32_t& posY)
245 {
246 if (displayRectMap_.size() <= 1) {
247 return;
248 }
249
250 auto iter = displayRectMap_.find(displayId);
251 if (iter == displayRectMap_.end()) {
252 return;
253 }
254 auto displayRect = iter->second;
255 posX += displayRect.posX_;
256 posY += displayRect.posY_;
257 }
258
HandleDisplayChange(const std::map<DisplayId,Rect> & displayRectMap)259 void MoveDragController::HandleDisplayChange(const std::map<DisplayId, Rect>& displayRectMap)
260 {
261 displayRectMap_.clear();
262 for (auto& elem : displayRectMap) {
263 displayRectMap_.insert(elem);
264 }
265 }
266
ConsumePointerEvent(const std::shared_ptr<MMI::PointerEvent> & pointerEvent)267 void MoveDragController::ConsumePointerEvent(const std::shared_ptr<MMI::PointerEvent>& pointerEvent)
268 {
269 if (pointerEvent == nullptr) {
270 WLOGFE("pointerEvent is nullptr or is handling pointer event");
271 return;
272 }
273 if (pointerEvent->GetPointerAction() == MMI::PointerEvent::POINTER_ACTION_MOVE) {
274 moveEvent_ = pointerEvent;
275 VsyncStation::GetInstance().RequestVsync(vsyncCallback_);
276 } else {
277 WLOGFD("[WMS] Dispatch non-move event, action: %{public}d", pointerEvent->GetPointerAction());
278 HandlePointerEvent(pointerEvent);
279 pointerEvent->MarkProcessed();
280 }
281 }
282
OnReceiveVsync(int64_t timeStamp)283 void MoveDragController::OnReceiveVsync(int64_t timeStamp)
284 {
285 if (moveEvent_ == nullptr) {
286 WLOGFE("moveEvent is nullptr");
287 return;
288 }
289 WLOGFD("[OnReceiveVsync] receive move event, action: %{public}d", moveEvent_->GetPointerAction());
290 HandlePointerEvent(moveEvent_);
291 moveEvent_->MarkProcessed();
292 }
293
GetHotZoneRect()294 Rect MoveDragController::GetHotZoneRect()
295 {
296 auto startPointPosX = moveDragProperty_->startPointPosX_;
297 auto startPointPosY = moveDragProperty_->startPointPosY_;
298 ConvertPointerPosToDisplayGroupPos(moveDragProperty_->targetDisplayId_, startPointPosX, startPointPosY);
299
300 Rect hotZoneRect;
301 const auto& startRectExceptCorner = moveDragProperty_->startRectExceptCorner_;
302 const auto& startRectExceptFrame = moveDragProperty_->startRectExceptFrame_;
303 if ((startPointPosX > startRectExceptCorner.posX_ &&
304 (startPointPosX < startRectExceptCorner.posX_ +
305 static_cast<int32_t>(startRectExceptCorner.width_))) &&
306 (startPointPosY > startRectExceptCorner.posY_ &&
307 (startPointPosY < startRectExceptCorner.posY_ +
308 static_cast<int32_t>(startRectExceptCorner.height_)))) {
309 hotZoneRect = startRectExceptFrame; // drag type: left/right/top/bottom
310 } else {
311 hotZoneRect = startRectExceptCorner; // drag type: left_top/right_top/left_bottom/right_bottom
312 }
313 return hotZoneRect;
314 }
315
HandleDragEvent(int32_t posX,int32_t posY,int32_t pointId,int32_t sourceType)316 void MoveDragController::HandleDragEvent(int32_t posX, int32_t posY, int32_t pointId, int32_t sourceType)
317 {
318 if (moveDragProperty_ == nullptr) {
319 return;
320 }
321 if (!moveDragProperty_->startDragFlag_ ||
322 (pointId != moveDragProperty_->startPointerId_) ||
323 (sourceType != moveDragProperty_->sourceType_)) {
324 return;
325 }
326 auto startPointPosX = moveDragProperty_->startPointPosX_;
327 auto startPointPosY = moveDragProperty_->startPointPosY_;
328 ConvertPointerPosToDisplayGroupPos(moveDragProperty_->targetDisplayId_, startPointPosX, startPointPosY);
329 const auto& startPointRect = moveDragProperty_->startPointRect_;
330 Rect newRect = startPointRect;
331 Rect hotZoneRect = GetHotZoneRect();
332 int32_t diffX = posX - startPointPosX;
333 int32_t diffY = posY - startPointPosY;
334
335 if (startPointPosX <= hotZoneRect.posX_) {
336 if (diffX > static_cast<int32_t>(startPointRect.width_)) {
337 diffX = static_cast<int32_t>(startPointRect.width_);
338 }
339 newRect.posX_ += diffX;
340 newRect.width_ = static_cast<uint32_t>(static_cast<int32_t>(newRect.width_) - diffX);
341 } else if (startPointPosX >= hotZoneRect.posX_ + static_cast<int32_t>(hotZoneRect.width_)) {
342 if (diffX < 0 && (-diffX > static_cast<int32_t>(startPointRect.width_))) {
343 diffX = -(static_cast<int32_t>(startPointRect.width_));
344 }
345 newRect.width_ = static_cast<uint32_t>(static_cast<int32_t>(newRect.width_) + diffX);
346 }
347 if (startPointPosY <= hotZoneRect.posY_) {
348 if (diffY > static_cast<int32_t>(startPointRect.height_)) {
349 diffY = static_cast<int32_t>(startPointRect.height_);
350 }
351 newRect.posY_ += diffY;
352 newRect.height_ = static_cast<uint32_t>(static_cast<int32_t>(newRect.height_) - diffY);
353 } else if (startPointPosY >= hotZoneRect.posY_ + static_cast<int32_t>(hotZoneRect.height_)) {
354 if (diffY < 0 && (-diffY > static_cast<int32_t>(startPointRect.height_))) {
355 diffY = -(static_cast<int32_t>(startPointRect.height_));
356 }
357 newRect.height_ = static_cast<uint32_t>(static_cast<int32_t>(newRect.height_) + diffY);
358 }
359 WLOGFD("[WMS] HandleDragEvent, id: %{public}u, newRect: [%{public}d, %{public}d, %{public}d, %{public}d]",
360 windowProperty_->GetWindowId(), newRect.posX_, newRect.posY_, newRect.width_, newRect.height_);
361 windowProperty_->SetRequestRect(newRect);
362 windowProperty_->SetWindowSizeChangeReason(WindowSizeChangeReason::DRAG);
363 windowProperty_->SetDragType(moveDragProperty_->dragType_);
364 WindowManagerService::GetInstance().UpdateProperty(windowProperty_, PropertyChangeAction::ACTION_UPDATE_RECT, true);
365 }
366
HandleMoveEvent(int32_t posX,int32_t posY,int32_t pointId,int32_t sourceType)367 void MoveDragController::HandleMoveEvent(int32_t posX, int32_t posY, int32_t pointId, int32_t sourceType)
368 {
369 if (moveDragProperty_ == nullptr) {
370 return;
371 }
372 if (!moveDragProperty_->startMoveFlag_ ||
373 (pointId != moveDragProperty_->startPointerId_) ||
374 (sourceType != moveDragProperty_->sourceType_)) {
375 return;
376 }
377 auto startPointPosX = moveDragProperty_->startPointPosX_;
378 auto startPointPosY = moveDragProperty_->startPointPosY_;
379 ConvertPointerPosToDisplayGroupPos(moveDragProperty_->targetDisplayId_, startPointPosX, startPointPosY);
380 int32_t targetX = moveDragProperty_->startPointRect_.posX_ + (posX - startPointPosX);
381 int32_t targetY = moveDragProperty_->startPointRect_.posY_ + (posY - startPointPosY);
382
383 const Rect& oriRect = windowProperty_->GetRequestRect();
384 Rect newRect = { targetX, targetY, oriRect.width_, oriRect.height_ };
385 WLOGFD("[WMS] HandleMoveEvent, id: %{public}u, newRect: [%{public}d, %{public}d, %{public}d, %{public}d]",
386 windowProperty_->GetWindowId(), newRect.posX_, newRect.posY_, newRect.width_, newRect.height_);
387 windowProperty_->SetRequestRect(newRect);
388 windowProperty_->SetWindowSizeChangeReason(WindowSizeChangeReason::MOVE);
389 WindowManagerService::GetInstance().UpdateProperty(windowProperty_, PropertyChangeAction::ACTION_UPDATE_RECT, true);
390 }
391
HandlePointerEvent(const std::shared_ptr<MMI::PointerEvent> & pointerEvent)392 void MoveDragController::HandlePointerEvent(const std::shared_ptr<MMI::PointerEvent>& pointerEvent)
393 {
394 if (windowProperty_) {
395 windowProperty_->UpdatePointerEvent(pointerEvent);
396 }
397 MMI::PointerEvent::PointerItem pointerItem;
398 int32_t pointId = pointerEvent->GetPointerId();
399 int32_t sourceType = pointerEvent->GetSourceType();
400 if (!pointerEvent->GetPointerItem(pointId, pointerItem) ||
401 (sourceType == MMI::PointerEvent::SOURCE_TYPE_MOUSE &&
402 pointerEvent->GetButtonId() != MMI::PointerEvent::MOUSE_BUTTON_LEFT)) {
403 WLOGFW("invalid pointerEvent");
404 return;
405 }
406
407 int32_t pointPosX = pointerItem.GetDisplayX();
408 int32_t pointPosY = pointerItem.GetDisplayY();
409 int32_t action = pointerEvent->GetPointerAction();
410 int32_t targetDisplayId = pointerEvent->GetTargetDisplayId();
411 ConvertPointerPosToDisplayGroupPos(targetDisplayId, pointPosX, pointPosY);
412 switch (action) {
413 case MMI::PointerEvent::POINTER_ACTION_DOWN:
414 case MMI::PointerEvent::POINTER_ACTION_BUTTON_DOWN: {
415 if (pointId == moveDragProperty_->startPointerId_ && sourceType == moveDragProperty_->sourceType_) {
416 moveDragProperty_->startMoveFlag_ = false;
417 moveDragProperty_->startDragFlag_ = false;
418 }
419 WLOGFD("[Server Point Down]: windowId: %{public}u, pointId: %{public}d, sourceType: %{public}d, "
420 "hasPointStarted: %{public}d, startMove: %{public}d, startDrag: %{public}d, targetDisplayId: "
421 "%{public}d, pointPos: [%{public}d, %{public}d]", activeWindowId_, pointId, sourceType,
422 moveDragProperty_->pointEventStarted_, moveDragProperty_->startMoveFlag_,
423 moveDragProperty_->startDragFlag_, targetDisplayId, pointPosX, pointPosY);
424 break;
425 }
426 // ready to move or drag
427 case MMI::PointerEvent::POINTER_ACTION_MOVE: {
428 HandleMoveEvent(pointPosX, pointPosY, pointId, sourceType);
429 HandleDragEvent(pointPosX, pointPosY, pointId, sourceType);
430 break;
431 }
432 // End move or drag
433 case MMI::PointerEvent::POINTER_ACTION_UP:
434 case MMI::PointerEvent::POINTER_ACTION_BUTTON_UP:
435 case MMI::PointerEvent::POINTER_ACTION_CANCEL: {
436 WindowManagerService::GetInstance().NotifyWindowClientPointUp(activeWindowId_, pointerEvent);
437 WLOGFD("[Server Point Up/Cancel]: windowId: %{public}u, action: %{public}d, sourceType: %{public}d",
438 activeWindowId_, action, sourceType);
439 break;
440 }
441 default:
442 break;
443 }
444 }
445
SetDragProperty(const sptr<MoveDragProperty> & moveDragProperty)446 void MoveDragController::SetDragProperty(const sptr<MoveDragProperty>& moveDragProperty)
447 {
448 moveDragProperty_->CopyFrom(moveDragProperty);
449 }
450
SetWindowProperty(const sptr<WindowProperty> & windowProperty)451 void MoveDragController::SetWindowProperty(const sptr<WindowProperty>& windowProperty)
452 {
453 windowProperty_->CopyFrom(windowProperty);
454 }
455
GetMoveDragProperty() const456 const sptr<MoveDragProperty>& MoveDragController::GetMoveDragProperty() const
457 {
458 return moveDragProperty_;
459 }
460
GetWindowProperty() const461 const sptr<WindowProperty>& MoveDragController::GetWindowProperty() const
462 {
463 return windowProperty_;
464 }
465
ResetMoveOrDragState()466 void MoveDragController::ResetMoveOrDragState()
467 {
468 activeWindowId_ = INVALID_WINDOW_ID;
469 auto moveDragProperty = new MoveDragProperty();
470 SetDragProperty(moveDragProperty);
471 }
472
SetActiveWindowId(uint32_t activeWindowId)473 void MoveDragController::SetActiveWindowId(uint32_t activeWindowId)
474 {
475 activeWindowId_ = activeWindowId;
476 }
477
GetActiveWindowId() const478 uint32_t MoveDragController::GetActiveWindowId() const
479 {
480 return activeWindowId_;
481 }
482 }
483 }
484