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 "input_window_monitor.h"
17
18#include <ipc_skeleton.h>
19#include <ability_manager_client.h>
20
21#include "display_group_info.h"
22#include "display_manager_service_inner.h"
23#include "dm_common.h"
24#include "window_helper.h"
25#include "window_manager_hilog.h"
26#include "window_inner_manager.h"
27
28namespace OHOS {
29namespace Rosen {
30namespace {
31constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "InputMonitor"};
32}
33static inline void convertRectsToMmiRects(const std::vector<Rect>& rects, std::vector<MMI::Rect>& mmiRects)
34{
35    for (const auto& rect : rects) {
36        mmiRects.emplace_back(
37            MMI::Rect{ rect.posX_, rect.posY_, static_cast<int32_t>(rect.width_), static_cast<int32_t>(rect.height_) });
38    }
39}
40
41void InputWindowMonitor::UpdateInputWindow(uint32_t windowId)
42{
43    if (windowRoot_ == nullptr) {
44        WLOGFE("windowRoot is null.");
45        return;
46    }
47    sptr<WindowNode> windowNode = windowRoot_->GetWindowNode(windowId);
48    if (windowNode == nullptr) {
49        WLOGFE("window node could not be found.");
50        return;
51    }
52    if (INPUT_WINDOW_TYPE_SKIPPED.find(windowNode->GetWindowProperty()->GetWindowType()) !=
53        INPUT_WINDOW_TYPE_SKIPPED.end()) {
54        return;
55    }
56    DisplayId displayId = windowNode->GetDisplayId();
57    UpdateInputWindowByDisplayId(displayId);
58}
59
60void InputWindowMonitor::UpdateInputWindowByDisplayId(DisplayId displayId)
61{
62    if (displayId == DISPLAY_ID_INVALID) {
63        return;
64    }
65    auto container = windowRoot_->GetOrCreateWindowNodeContainer(displayId);
66    if (container == nullptr) {
67        WLOGFE("can not get window node container.");
68        return;
69    }
70    auto displayInfos = DisplayGroupInfo::GetInstance().GetAllDisplayInfo();
71    if (displayInfos.empty()) {
72        return;
73    }
74    UpdateDisplayGroupInfo(container, displayGroupInfo_);
75    UpdateDisplayInfo(displayInfos, displayGroupInfo_.displaysInfo);
76    std::vector<sptr<WindowNode>> windowNodes;
77    container->TraverseContainer(windowNodes);
78    TraverseWindowNodes(windowNodes, displayGroupInfo_.windowsInfo);
79    WLOGFD("update display info to IMS, displayId: %{public}" PRIu64"", displayId);
80    auto task = [displayGroupInfo = displayGroupInfo_]() {
81        MMI::InputManager::GetInstance()->UpdateDisplayInfo(displayGroupInfo);
82    };
83    WindowInnerManager::GetInstance().PostTask(std::move(task), "wms:UpdateDisplayInfoBydisplayId");
84}
85
86void InputWindowMonitor::UpdateDisplayGroupInfo(const sptr<WindowNodeContainer>& windowNodeContainer,
87                                                MMI::DisplayGroupInfo& displayGroupInfo)
88{
89    const Rect&& rect = windowNodeContainer->GetDisplayGroupRect();
90    displayGroupInfo.width = static_cast<int32_t>(rect.width_);
91    displayGroupInfo.height = static_cast<int32_t>(rect.height_);
92    displayGroupInfo.focusWindowId = static_cast<int32_t>(windowNodeContainer->GetFocusWindow());
93    displayGroupInfo.windowsInfo.clear();
94    displayGroupInfo.displaysInfo.clear();
95}
96
97void InputWindowMonitor::UpdateDisplayInfo(const std::vector<sptr<DisplayInfo>>& displayInfos,
98                                           std::vector<MMI::DisplayInfo>& displayInfoVector)
99{
100    for (auto& displayInfo : displayInfos) {
101        if (displayInfo == nullptr) {
102            continue;
103        }
104        uint32_t displayWidth = static_cast<uint32_t>(displayInfo->GetWidth());
105        uint32_t displayHeight = static_cast<uint32_t>(displayInfo->GetHeight());
106        int32_t offsetX = displayInfo->GetOffsetX();
107        int32_t offsetY = displayInfo->GetOffsetY();
108        if (displayInfo->GetWaterfallDisplayCompressionStatus()) {
109            displayWidth = static_cast<uint32_t>(
110                static_cast<int32_t>(displayWidth) + offsetX * 2); // 2: Get full width;
111            displayHeight = static_cast<uint32_t>(
112                static_cast<int32_t>(displayHeight) + offsetY * 2); // 2: Get full height;
113            offsetX = 0;
114            offsetY = 0;
115        }
116        if (displayInfo->GetRotation() == Rotation::ROTATION_90 ||
117            displayInfo->GetRotation() == Rotation::ROTATION_270) {
118            std::swap(displayWidth, displayHeight);
119        }
120        MMI::DisplayInfo display = {
121            .id = static_cast<int32_t>(displayInfo->GetDisplayId()),
122            .x = offsetX,
123            .y = offsetY,
124            .width = static_cast<int32_t>(displayWidth),
125            .height = static_cast<int32_t>(displayHeight),
126            .dpi = displayInfo->GetDpi(),
127            .name = "display " + std::to_string(displayInfo->GetDisplayId()),
128            .uniq = "default" + std::to_string(displayInfo->GetDisplayId()),
129            .direction = GetDisplayDirectionForMmi(displayInfo->GetRotation()),
130            .displayDirection = GetDisplayDirectionForMmi(displayInfo->GetRotation()),
131        };
132        auto displayIter = std::find_if(displayInfoVector.begin(), displayInfoVector.end(),
133            [&display](MMI::DisplayInfo& displayInfoTmp) {
134            return displayInfoTmp.id == display.id;
135        });
136        if (displayIter != displayInfoVector.end()) {
137            *displayIter = display;
138        } else {
139            displayInfoVector.emplace_back(display);
140        }
141        WLOGFD("UpdateDisplayInfo, displayId: %{public}d, displayRect: "
142            "[%{public}d, %{public}d, %{public}u, %{public}u]",
143            display.id, display.x, display.y, display.width, display.height);
144    }
145}
146
147void InputWindowMonitor::TransformWindowRects(const sptr<WindowNode>& windowNode, Rect& areaRect,
148                                              std::vector<Rect>& touchHotAreas, std::vector<Rect>& pointerHotAreas)
149{
150    if (windowNode->GetWindowProperty()->isNeedComputerTransform()) {
151        windowNode->ComputeTransform();
152        for (Rect& rect : touchHotAreas) {
153            rect = WindowHelper::TransformRect(windowNode->GetWindowProperty()->GetTransformMat(), rect);
154        }
155        for (Rect& rect : pointerHotAreas) {
156            rect = WindowHelper::TransformRect(windowNode->GetWindowProperty()->GetTransformMat(), rect);
157        }
158        WLOGD("Area rect before tranform: [%{public}d, %{public}d, %{public}u, %{public}u]",
159            areaRect.posX_, areaRect.posY_, areaRect.width_, areaRect.height_);
160        areaRect = WindowHelper::TransformRect(windowNode->GetWindowProperty()->GetTransformMat(), areaRect);
161        WLOGD("Area rect after tranform: [%{public}d, %{public}d, %{public}u, %{public}u]",
162            areaRect.posX_, areaRect.posY_, areaRect.width_, areaRect.height_);
163    }
164}
165
166void InputWindowMonitor::TraverseWindowNodes(const std::vector<sptr<WindowNode>>& windowNodes,
167                                             std::vector<MMI::WindowInfo>& windowsInfo)
168{
169    std::map<uint32_t, sptr<WindowNode>> dialogWindowMap;
170    for (const auto& windowNode: windowNodes) {
171        if (windowNode->GetWindowType() != WindowType::WINDOW_TYPE_DIALOG) {
172            continue;
173        }
174        sptr<WindowNode> callerNode =
175            windowRoot_->FindMainWindowWithToken(windowNode->dialogTargetToken_);
176        if (callerNode != nullptr) {
177            dialogWindowMap.insert(std::make_pair(callerNode->GetWindowId(), windowNode));
178        }
179    }
180    for (const auto& windowNode: windowNodes) {
181        if (INPUT_WINDOW_TYPE_SKIPPED.find(windowNode->GetWindowType()) != INPUT_WINDOW_TYPE_SKIPPED.end()) {
182            WLOGI("skip node[id:%{public}u, type:%{public}d]", windowNode->GetWindowId(), windowNode->GetWindowType());
183            continue;
184        }
185
186        std::vector<Rect> touchHotAreas;
187        std::vector<Rect> pointerHotAreas;
188        windowNode->GetTouchHotAreas(touchHotAreas);
189        windowNode->GetPointerHotAreas(pointerHotAreas);
190        Rect areaRect = windowNode->GetWindowRect();
191
192        TransformWindowRects(windowNode, areaRect, touchHotAreas, pointerHotAreas);
193
194        MMI::WindowInfo windowInfo = {
195            .id = static_cast<int32_t>(windowNode->GetWindowId()),
196            .pid = windowNode->GetInputEventCallingPid(),
197            .uid = windowNode->GetCallingUid(),
198            .area = MMI::Rect { areaRect.posX_, areaRect.posY_,
199                static_cast<int32_t>(areaRect.width_), static_cast<int32_t>(areaRect.height_) },
200            .agentWindowId = static_cast<int32_t>(windowNode->GetWindowId()),
201        };
202
203        auto iter = (windowNode->GetParentId() == INVALID_WINDOW_ID) ?
204            dialogWindowMap.find(windowNode->GetWindowId()) : dialogWindowMap.find(windowNode->GetParentId());
205        if (iter != dialogWindowMap.end()) {
206            windowInfo.agentWindowId = static_cast<int32_t>(iter->second->GetWindowId());
207        }
208        convertRectsToMmiRects(touchHotAreas, windowInfo.defaultHotAreas);
209        convertRectsToMmiRects(pointerHotAreas, windowInfo.pointerHotAreas);
210        if (!windowNode->GetWindowProperty()->GetTouchable()) {
211            WLOGFD("window is not touchable: %{public}u", windowNode->GetWindowId());
212            windowInfo.flags |= MMI::WindowInfo::FLAG_BIT_UNTOUCHABLE;
213        }
214        windowsInfo.emplace_back(windowInfo);
215    }
216}
217
218MMI::Direction InputWindowMonitor::GetDisplayDirectionForMmi(Rotation rotation)
219{
220    MMI::Direction direction = MMI::DIRECTION0;
221    switch (rotation) {
222        case Rotation::ROTATION_0:
223            direction = MMI::DIRECTION0;
224            break;
225        case Rotation::ROTATION_90:
226            direction = MMI::DIRECTION90;
227            break;
228        case Rotation::ROTATION_180:
229            direction = MMI::DIRECTION180;
230            break;
231        case Rotation::ROTATION_270:
232            direction = MMI::DIRECTION270;
233            break;
234        default:
235            break;
236    }
237    return direction;
238}
239}
240}
241