1 /*
2  * Copyright (c) 2023 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 "cooperate_context.h"
17 
18 #include <algorithm>
19 
20 #include "display_manager.h"
21 
22 #include "ddm_adapter.h"
23 #include "devicestatus_define.h"
24 #include "dsoftbus_handler.h"
25 #include "utility.h"
26 
27 #undef LOG_TAG
28 #define LOG_TAG "CooperateContext"
29 
30 namespace OHOS {
31 namespace Msdp {
32 namespace DeviceStatus {
33 namespace Cooperate {
34 namespace {
35 const std::string THREAD_NAME { "os_Cooperate_EventHandler" };
36 constexpr double PERCENT { 100.0 };
37 } // namespace
38 
39 class BoardObserver final : public IBoardObserver {
40 public:
BoardObserver(Channel<CooperateEvent>::Sender sender)41     explicit BoardObserver(Channel<CooperateEvent>::Sender sender) : sender_(sender) {}
42     ~BoardObserver() = default;
43     DISALLOW_COPY_AND_MOVE(BoardObserver);
44 
OnBoardOnline(const std::string & networkId)45     void OnBoardOnline(const std::string &networkId) override
46     {
47         FI_HILOGD("\'%{public}s\' is online", Utility::Anonymize(networkId).c_str());
48         auto ret = sender_.Send(CooperateEvent(
49             CooperateEventType::DDM_BOARD_ONLINE,
50             DDMBoardOnlineEvent {
51                 .networkId = networkId
52             }));
53         if (ret != Channel<CooperateEvent>::NO_ERROR) {
54             FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
55         }
56     }
57 
OnBoardOffline(const std::string & networkId)58     void OnBoardOffline(const std::string &networkId) override
59     {
60         FI_HILOGD("\'%{public}s\' is offline", Utility::Anonymize(networkId).c_str());
61         auto ret = sender_.Send(CooperateEvent(
62             CooperateEventType::DDM_BOARD_OFFLINE,
63             DDMBoardOfflineEvent {
64                 .networkId = networkId
65             }));
66         if (ret != Channel<CooperateEvent>::NO_ERROR) {
67             FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
68         }
69     }
70 
71 private:
72     Channel<CooperateEvent>::Sender sender_;
73 };
74 
OnDeviceAdded(std::shared_ptr<IDevice> dev)75 void HotplugObserver::OnDeviceAdded(std::shared_ptr<IDevice> dev)
76 {
77     CHKPV(dev);
78     auto ret = sender_.Send(CooperateEvent(
79         CooperateEventType::INPUT_HOTPLUG_EVENT,
80         InputHotplugEvent {
81             .deviceId = dev->GetId(),
82             .type = InputHotplugType::PLUG,
83             .isKeyboard = dev->IsKeyboard(),
84         }));
85     if (ret != Channel<CooperateEvent>::NO_ERROR) {
86         FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
87     }
88 }
89 
OnDeviceRemoved(std::shared_ptr<IDevice> dev)90 void HotplugObserver::OnDeviceRemoved(std::shared_ptr<IDevice> dev)
91 {
92     CHKPV(dev);
93     auto ret = sender_.Send(CooperateEvent(
94         CooperateEventType::INPUT_HOTPLUG_EVENT,
95         InputHotplugEvent {
96             .deviceId = dev->GetId(),
97             .type = InputHotplugType::UNPLUG,
98             .isKeyboard = dev->IsKeyboard(),
99         }));
100     if (ret != Channel<CooperateEvent>::NO_ERROR) {
101         FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
102     }
103 }
104 
Context(IContext * env)105 Context::Context(IContext *env)
106     : dsoftbus_(env), eventMgr_(env), hotArea_(env), mouseLocation_(env), inputDevMgr_(env),
107       inputEventBuilder_(env), inputEventInterceptor_(env), env_(env)
108 {}
109 
AttachSender(Channel<CooperateEvent>::Sender sender)110 void Context::AttachSender(Channel<CooperateEvent>::Sender sender)
111 {
112     sender_ = sender;
113     dsoftbus_.AttachSender(sender);
114 }
115 
AddObserver(std::shared_ptr<ICooperateObserver> observer)116 void Context::AddObserver(std::shared_ptr<ICooperateObserver> observer)
117 {
118     CHKPV(observer);
119     observers_.insert(observer);
120 }
121 
RemoveObserver(std::shared_ptr<ICooperateObserver> observer)122 void Context::RemoveObserver(std::shared_ptr<ICooperateObserver> observer)
123 {
124     observers_.erase(observer);
125 }
126 
Enable()127 void Context::Enable()
128 {
129     CALL_DEBUG_ENTER;
130     StartEventHandler();
131     EnableDDM();
132     EnableDevMgr();
133     EnableInputDevMgr();
134 }
135 
Disable()136 void Context::Disable()
137 {
138     CALL_DEBUG_ENTER;
139     DisableDevMgr();
140     DisableDDM();
141     DisableInputDevMgr();
142     StopEventHandler();
143 }
144 
StartEventHandler()145 int32_t Context::StartEventHandler()
146 {
147     auto runner = AppExecFwk::EventRunner::Create(THREAD_NAME, AppExecFwk::ThreadMode::FFRT);
148     CHKPR(runner, RET_ERR);
149     eventHandler_ = std::make_shared<AppExecFwk::EventHandler>(runner);
150     return RET_OK;
151 }
152 
StopEventHandler()153 void Context::StopEventHandler()
154 {
155     eventHandler_.reset();
156 }
157 
EnableDDM()158 int32_t Context::EnableDDM()
159 {
160     boardObserver_ = std::make_shared<BoardObserver>(sender_);
161     ddm_.AddBoardObserver(boardObserver_);
162     return ddm_.Enable();
163 }
164 
DisableDDM()165 void Context::DisableDDM()
166 {
167     ddm_.Disable();
168     ddm_.RemoveBoardObserver(boardObserver_);
169     boardObserver_.reset();
170 }
171 
EnableDevMgr()172 int32_t Context::EnableDevMgr()
173 {
174     hotplugObserver_ = std::make_shared<HotplugObserver>(sender_);
175     env_->GetDeviceManager().AddDeviceObserver(hotplugObserver_);
176     return RET_OK;
177 }
178 
DisableDevMgr()179 void Context::DisableDevMgr()
180 {
181     env_->GetDeviceManager().RemoveDeviceObserver(hotplugObserver_);
182     hotplugObserver_.reset();
183 }
184 
EnableInputDevMgr()185 int32_t Context::EnableInputDevMgr()
186 {
187     inputDevMgr_.Enable();
188     return RET_OK;
189 }
190 
DisableInputDevMgr()191 void Context::DisableInputDevMgr()
192 {
193     inputDevMgr_.Disable();
194 }
195 
NormalizedCursorPosition() const196 NormalizedCoordinate Context::NormalizedCursorPosition() const
197 {
198     auto display = Rosen::DisplayManager::GetInstance().GetDefaultDisplay();
199     if (display == nullptr) {
200         FI_HILOGE("No default display");
201         return cursorPos_;
202     }
203     Rectangle displayRect {
204         .width = display->GetWidth(),
205         .height = display->GetHeight(),
206     };
207     if ((displayRect.width <= 0) || (displayRect.height <= 0)) {
208         FI_HILOGE("Invalid display information");
209         return cursorPos_;
210     }
211     return NormalizedCoordinate {
212         .x = static_cast<int32_t>((cursorPos_.x + 1) * PERCENT / displayRect.width),
213         .y = static_cast<int32_t>((cursorPos_.y + 1) * PERCENT / displayRect.height),
214     };
215 }
216 
EnableCooperate(const EnableCooperateEvent & event)217 void Context::EnableCooperate(const EnableCooperateEvent &event)
218 {
219 }
220 
DisableCooperate(const DisableCooperateEvent & event)221 void Context::DisableCooperate(const DisableCooperateEvent &event)
222 {
223 }
224 
StartCooperate(const StartCooperateEvent & event)225 void Context::StartCooperate(const StartCooperateEvent &event)
226 {
227     remoteNetworkId_ = event.remoteNetworkId;
228     startDeviceId_ = event.startDeviceId;
229 }
230 
OnPointerEvent(const InputPointerEvent & event)231 void Context::OnPointerEvent(const InputPointerEvent &event)
232 {
233     if ((event.sourceType == MMI::PointerEvent::SOURCE_TYPE_MOUSE) &&
234         ((event.pointerAction == MMI::PointerEvent::POINTER_ACTION_MOVE) ||
235          (event.pointerAction == MMI::PointerEvent::POINTER_ACTION_PULL_MOVE))) {
236         cursorPos_ = event.position;
237     }
238 }
239 
RemoteStartSuccess(const DSoftbusStartCooperateFinished & event)240 void Context::RemoteStartSuccess(const DSoftbusStartCooperateFinished &event)
241 {
242     remoteNetworkId_ = event.originNetworkId;
243     flag_ = event.extra.flag;
244     SetCursorPosition(event.cursorPos);
245 }
246 
RelayCooperate(const DSoftbusRelayCooperate & event)247 void Context::RelayCooperate(const DSoftbusRelayCooperate &event)
248 {
249     remoteNetworkId_ = event.targetNetworkId;
250 }
251 
UpdateCooperateFlag(const UpdateCooperateFlagEvent & event)252 void Context::UpdateCooperateFlag(const UpdateCooperateFlagEvent &event)
253 {
254     flag_ = ((flag_ & ~event.mask) | (event.flag & event.mask));
255 }
256 
IsAllowCooperate()257 bool Context::IsAllowCooperate()
258 {
259     FI_HILOGI("Notify observers of allow cooperate");
260     return std::all_of(observers_.cbegin(), observers_.cend(), [](const auto &observer) {
261         return observer->IsAllowCooperate();
262     });
263 }
264 
OnStartCooperate(StartCooperateData & data)265 void Context::OnStartCooperate(StartCooperateData &data)
266 {
267     std::for_each(observers_.cbegin(), observers_.cend(), [&data](const auto &observer) {
268         return observer->OnStartCooperate(data);
269     });
270 }
271 
OnRemoteStartCooperate(RemoteStartCooperateData & data)272 void Context::OnRemoteStartCooperate(RemoteStartCooperateData &data)
273 {
274     std::for_each(observers_.cbegin(), observers_.cend(), [&data](const auto &observer) {
275         return observer->OnRemoteStartCooperate(data);
276     });
277 }
278 
OnTransitionOut()279 void Context::OnTransitionOut()
280 {
281     CHKPV(eventHandler_);
282     FI_HILOGI("Notify observers of transition out");
283     for (const auto &observer : observers_) {
284         eventHandler_->PostTask(
285             [observer, remoteNetworkId = Peer(), cursorPos = NormalizedCursorPosition()] {
286                 FI_HILOGI("Notify one observer of transition out");
287                 CHKPV(observer);
288                 observer->OnTransitionOut(remoteNetworkId, cursorPos);
289             });
290     }
291 }
292 
OnTransitionIn()293 void Context::OnTransitionIn()
294 {
295     CHKPV(eventHandler_);
296     FI_HILOGI("Notify observers of transition in");
297     for (const auto &observer : observers_) {
298         eventHandler_->PostTask(
299             [observer, remoteNetworkId = Peer(), cursorPos = NormalizedCursorPosition()] {
300                 FI_HILOGI("Notify one observer of transition in");
301                 CHKPV(observer);
302                 observer->OnTransitionIn(remoteNetworkId, cursorPos);
303             });
304     }
305 }
306 
OnBack()307 void Context::OnBack()
308 {
309     CHKPV(eventHandler_);
310     FI_HILOGI("Notify observers of come back");
311     for (const auto &observer : observers_) {
312         eventHandler_->PostTask(
313             [observer, remoteNetworkId = Peer(), cursorPos = NormalizedCursorPosition()] {
314                 FI_HILOGI("Notify one observer of come back");
315                 CHKPV(observer);
316                 observer->OnBack(remoteNetworkId, cursorPos);
317             });
318     }
319 }
320 
OnRelayCooperation(const std::string & networkId,const NormalizedCoordinate & cursorPos)321 void Context::OnRelayCooperation(const std::string &networkId, const NormalizedCoordinate &cursorPos)
322 {
323     CHKPV(eventHandler_);
324     FI_HILOGI("Notify observers of relay cooperation");
325     for (const auto &observer : observers_) {
326         eventHandler_->PostTask(
327             [observer, networkId, cursorPos] {
328                 FI_HILOGI("Notify one observer of relay cooperation");
329                 CHKPV(observer);
330                 observer->OnRelay(networkId, cursorPos);
331             });
332     }
333 }
334 
CloseDistributedFileConnection(const std::string & remoteNetworkId)335 void Context::CloseDistributedFileConnection(const std::string &remoteNetworkId)
336 {
337     CHKPV(eventHandler_);
338     FI_HILOGI("Notify observers of device offline");
339     for (const auto &observer : observers_) {
340         eventHandler_->PostTask(
341             [observer, remoteNetworkId] {
342                 FI_HILOGI("Notify one observer of device offline, remoteNetworkId:%{public}s",
343                     Utility::Anonymize(remoteNetworkId).c_str());
344                 CHKPV(observer);
345                 observer->CloseDistributedFileConnection(remoteNetworkId);
346             });
347     }
348 }
349 
OnResetCooperation()350 void Context::OnResetCooperation()
351 {
352     CHKPV(eventHandler_);
353     FI_HILOGI("Notify observers of reset cooperation");
354     for (const auto &observer : observers_) {
355         eventHandler_->PostTask(
356             [observer] {
357                 FI_HILOGI("Notify one observer of reset cooperation");
358                 CHKPV(observer);
359                 observer->OnReset();
360             });
361     }
362 }
363 
SetCursorPosition(const Coordinate & cursorPos)364 void Context::SetCursorPosition(const Coordinate &cursorPos)
365 {
366     double xPercent = (PERCENT - std::clamp<double>(cursorPos.x, 0.0, PERCENT)) / PERCENT;
367     double yPercent = std::clamp<double>(cursorPos.y, 0.0, PERCENT) / PERCENT;
368 
369     auto display = Rosen::DisplayManager::GetInstance().GetDefaultDisplay();
370     CHKPV(display);
371     cursorPos_.x = static_cast<int32_t>(xPercent * display->GetWidth());
372     cursorPos_.y = static_cast<int32_t>(yPercent * display->GetHeight());
373     env_->GetInput().SetPointerLocation(cursorPos_.x, cursorPos_.y);
374     FI_HILOGI("Set cursor position (%{private}d,%{private}d)(%{private}d,%{private}d)(%{public}d,%{public}d)",
375         cursorPos.x, cursorPos.y, cursorPos_.x, cursorPos_.y, display->GetWidth(), display->GetHeight());
376 }
377 
UpdateCursorPosition()378 void Context::UpdateCursorPosition()
379 {
380     env_->GetInput().SetPointerLocation(cursorPos_.x, cursorPos_.y);
381     FI_HILOGI("Update cursor position (%{private}d,%{private}d)", cursorPos_.x, cursorPos_.y);
382 }
383 
ResetCursorPosition()384 void Context::ResetCursorPosition()
385 {
386     constexpr Coordinate defaultCursorPos {
387         .x = 50,
388         .y = 50,
389     };
390     SetCursorPosition(defaultCursorPos);
391 }
392 
393 #ifdef ENABLE_PERFORMANCE_CHECK
StartTrace(const std::string & name)394 void Context::StartTrace(const std::string &name)
395 {
396     std::lock_guard guard { lock_ };
397     if (traces_.find(name) != traces_.end()) {
398         return;
399     }
400     traces_.emplace(name, std::chrono::steady_clock::now());
401     FI_HILOGI("[PERF] Start tracing \'%{public}s\'", name.c_str());
402 }
403 
FinishTrace(const std::string & name)404 void Context::FinishTrace(const std::string &name)
405 {
406     std::lock_guard guard { lock_ };
407     if (auto iter = traces_.find(name); iter != traces_.end()) {
408         FI_HILOGI("[PERF] Finish tracing \'%{public}s\', elapsed:%{public}lld ms", name.c_str(),
409             std::chrono::duration_cast<std::chrono::milliseconds>(
410                 std::chrono::steady_clock::now() - iter->second).count());
411         traces_.erase(iter);
412     }
413 }
414 #endif // ENABLE_PERFORMANCE_CHECK
415 
416 } // namespace Cooperate
417 } // namespace DeviceStatus
418 } // namespace Msdp
419 } // namespace OHOS
420