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