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_transfer_station.h"
17
18#include <thread>
19#include <event_handler.h>
20#include "window_manager_hilog.h"
21#include "wm_common_inner.h"
22#include "gtx_input_event_sender.h"
23#include <hitrace_meter.h>
24
25namespace OHOS {
26namespace Rosen {
27namespace {
28constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "InputTransferStation"};
29}
30WM_IMPLEMENT_SINGLE_INSTANCE(InputTransferStation)
31
32InputTransferStation::~InputTransferStation()
33{
34    std::lock_guard<std::mutex> lock(mtx_);
35    destroyed_ = true;
36}
37
38void InputEventListener::OnInputEvent(std::shared_ptr<MMI::KeyEvent> keyEvent) const
39{
40    if (keyEvent == nullptr) {
41        TLOGE(WmsLogTag::WMS_INPUT_KEY_FLOW, "KeyEvent is nullptr");
42        return;
43    }
44    HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "IEL:KeyEvent id:%d", keyEvent->GetId());
45    uint32_t windowId = static_cast<uint32_t>(keyEvent->GetAgentWindowId());
46    static uint32_t eventId = 0;
47    TLOGI(WmsLogTag::WMS_INPUT_KEY_FLOW, "eid:%{public}d,InputId:%{public}d,wid:%{public}u",
48        eventId++, keyEvent->GetId(), windowId);
49    auto channel = InputTransferStation::GetInstance().GetInputChannel(windowId);
50    if (channel == nullptr) {
51        keyEvent->MarkProcessed();
52        TLOGE(WmsLogTag::WMS_INPUT_KEY_FLOW,
53            "WindowInputChannel is nullptr InputTracking id:%{public}d windowId:%{public}u",
54            keyEvent->GetId(), windowId);
55        return;
56    }
57    channel->HandleKeyEvent(keyEvent);
58}
59
60void InputEventListener::OnInputEvent(std::shared_ptr<MMI::AxisEvent> axisEvent) const
61{
62    if (axisEvent == nullptr) {
63        TLOGE(WmsLogTag::WMS_INPUT_KEY_FLOW, "AxisEvent is nullptr");
64        return;
65    }
66    TLOGD(WmsLogTag::WMS_INPUT_KEY_FLOW, "Receive axisEvent, windowId: %{public}d", axisEvent->GetAgentWindowId());
67    axisEvent->MarkProcessed();
68}
69
70void InputEventListener::OnInputEvent(std::shared_ptr<MMI::PointerEvent> pointerEvent) const
71{
72    if (pointerEvent == nullptr) {
73        TLOGE(WmsLogTag::WMS_INPUT_KEY_FLOW, "PointerEvent is nullptr");
74        return;
75    }
76    HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "IEL:PointerEvent id:%d action:%d",
77        pointerEvent->GetId(), pointerEvent->GetPointerAction());
78    // If handling input event at server, client will receive pointEvent that the winId is -1, intercept log error
79    uint32_t invalidId = static_cast<uint32_t>(-1);
80    uint32_t windowId = static_cast<uint32_t>(pointerEvent->GetAgentWindowId());
81    int32_t action = pointerEvent->GetPointerAction();
82    if (action != MMI::PointerEvent::POINTER_ACTION_MOVE) {
83        static uint32_t eventId = 0;
84        TLOGI(WmsLogTag::WMS_INPUT_KEY_FLOW, "eid:%{public}d,InputId:%{public}d"
85            ",wid:%{public}u,action:%{public}d", eventId++, pointerEvent->GetId(), windowId,
86            pointerEvent->GetPointerAction());
87    }
88    auto channel = InputTransferStation::GetInstance().GetInputChannel(windowId);
89    if (channel == nullptr) {
90        if (windowId != invalidId) {
91            TLOGE(WmsLogTag::WMS_INPUT_KEY_FLOW, "WindowInputChannel is nullptr InputTracking id:%{public}d "
92                "windowId:%{public}u",
93                pointerEvent->GetId(), windowId);
94        }
95        pointerEvent->MarkProcessed();
96        return;
97    }
98    channel->HandlePointerEvent(pointerEvent);
99    GtxInputEventSender::GetInstance().SetTouchEvent(channel->GetWindowRect(), pointerEvent);
100}
101
102void InputTransferStation::AddInputWindow(const sptr<Window>& window)
103{
104    if (IsRegisterToMMI()) {
105        return;
106    }
107
108    uint32_t windowId = window->GetWindowId();
109    TLOGD(WmsLogTag::WMS_EVENT, "Add input window, windowId: %{public}u", windowId);
110
111    // INPUT_WINDOW_TYPE_SKIPPED should not set input consumer
112    if (INPUT_WINDOW_TYPE_SKIPPED.find(window->GetType()) != INPUT_WINDOW_TYPE_SKIPPED.end()) {
113        TLOGW(WmsLogTag::WMS_EVENT, "skip window for InputConsumer [id:%{public}u, type:%{public}d]",
114            windowId, window->GetType());
115        return;
116    }
117    sptr<WindowInputChannel> inputChannel = new WindowInputChannel(window);
118    std::lock_guard<std::mutex> lock(mtx_);
119    if (destroyed_) {
120        TLOGW(WmsLogTag::WMS_EVENT, "Already destroyed");
121        return;
122    }
123    windowInputChannels_.insert(std::make_pair(windowId, inputChannel));
124    if (inputListener_ == nullptr) {
125        TLOGD(WmsLogTag::WMS_EVENT, "Init input listener, IsMainHandlerAvailable: %{public}u",
126            window->IsMainHandlerAvailable());
127        std::shared_ptr<MMI::IInputEventConsumer> listener = std::make_shared<InputEventListener>(InputEventListener());
128        auto mainEventRunner = AppExecFwk::EventRunner::GetMainEventRunner();
129        if (mainEventRunner != nullptr && window->IsMainHandlerAvailable()) {
130            TLOGD(WmsLogTag::WMS_EVENT, "MainEventRunner is available");
131            eventHandler_ = std::make_shared<AppExecFwk::EventHandler>(mainEventRunner);
132        } else {
133            TLOGD(WmsLogTag::WMS_EVENT, "MainEventRunner is not available");
134            eventHandler_ = AppExecFwk::EventHandler::Current();
135            auto curThreadId = std::this_thread::get_id();
136            if (!eventHandler_ || (mainEventRunner != nullptr &&
137                mainEventRunner->GetThreadId() == *(reinterpret_cast<uint64_t*>(&curThreadId)))) {
138                eventHandler_ = std::make_shared<AppExecFwk::EventHandler>(
139                    AppExecFwk::EventRunner::Create(INPUT_AND_VSYNC_THREAD));
140            }
141        }
142        MMI::InputManager::GetInstance()->SetWindowInputEventConsumer(listener, eventHandler_);
143        TLOGI(WmsLogTag::WMS_EVENT, "SetWindowInputEventConsumer success, windowid:%{public}u", windowId);
144        inputListener_ = listener;
145    }
146}
147
148void InputTransferStation::RemoveInputWindow(uint32_t windowId)
149{
150    TLOGD(WmsLogTag::WMS_EVENT, "Remove input window, windowId: %{public}u", windowId);
151    sptr<WindowInputChannel> inputChannel = nullptr;
152    {
153        std::lock_guard<std::mutex> lock(mtx_);
154        if (destroyed_) {
155            WLOGFW("Already destroyed");
156            return;
157        }
158        auto iter = windowInputChannels_.find(windowId);
159        if (iter != windowInputChannels_.end()) {
160            inputChannel = iter->second;
161            windowInputChannels_.erase(windowId);
162        }
163    }
164    if (inputChannel != nullptr) {
165        inputChannel->Destroy();
166    } else {
167        TLOGE(WmsLogTag::WMS_EVENT, "Can not find windowId: %{public}u", windowId);
168    }
169}
170
171sptr<WindowInputChannel> InputTransferStation::GetInputChannel(uint32_t windowId)
172{
173    std::lock_guard<std::mutex> lock(mtx_);
174    if (destroyed_) {
175        TLOGW(WmsLogTag::WMS_EVENT, "Already destroyed");
176        return nullptr;
177    }
178    auto iter = windowInputChannels_.find(windowId);
179    if (iter == windowInputChannels_.end()) {
180        return nullptr;
181    }
182    return iter->second;
183}
184}
185}
186