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_out.h"
17 
18 #include "devicestatus_define.h"
19 #include "utility.h"
20 
21 #undef LOG_TAG
22 #define LOG_TAG "CooperateOut"
23 
24 namespace OHOS {
25 namespace Msdp {
26 namespace DeviceStatus {
27 namespace Cooperate {
28 
CooperateOut(IStateMachine & parent,IContext * env)29 CooperateOut::CooperateOut(IStateMachine &parent, IContext *env)
30     : ICooperateState(parent), env_(env)
31 {
32     initial_ = std::make_shared<Initial>(*this);
33     Initial::BuildChains(initial_, *this);
34     current_ = initial_;
35 }
36 
~CooperateOut()37 CooperateOut::~CooperateOut()
38 {
39     CHKPV(initial_);
40     Initial::RemoveChains(initial_);
41 }
42 
OnEvent(Context & context,const CooperateEvent & event)43 void CooperateOut::OnEvent(Context &context, const CooperateEvent &event)
44 {
45     current_->OnEvent(context, event);
46 }
47 
OnEnterState(Context & context)48 void CooperateOut::OnEnterState(Context &context)
49 {
50     CALL_INFO_TRACE;
51     env_->GetInput().SetPointerVisibility(false);
52 }
53 
OnLeaveState(Context & context)54 void CooperateOut::OnLeaveState(Context &context)
55 {
56     CALL_INFO_TRACE;
57     SetPointerVisible(context);
58 }
59 
SetPointerVisible(Context & context)60 void CooperateOut::SetPointerVisible(Context &context)
61 {
62     CHKPV(env_);
63     bool hasLocalPointerDevice =  env_->GetDeviceManager().HasLocalPointerDevice();
64     bool visible = !context.NeedHideCursor() && hasLocalPointerDevice;
65     FI_HILOGI("Set pointer visible:%{public}s, HasLocalPointerDevice:%{public}s",
66         visible ? "true" : "false", hasLocalPointerDevice ? "true" : "false");
67     env_->GetInput().SetPointerVisibility(visible, PRIORITY);
68 }
69 
OnSetCooperatePriv(uint32_t priv)70 void CooperateOut::OnSetCooperatePriv(uint32_t priv)
71 {
72     CALL_DEBUG_ENTER;
73     env_->GetDragManager().SetCooperatePriv(priv);
74 }
75 
BuildChains(std::shared_ptr<Initial> self,CooperateOut & parent)76 void CooperateOut::Initial::BuildChains(std::shared_ptr<Initial> self, CooperateOut &parent)
77 {}
78 
RemoveChains(std::shared_ptr<Initial> self)79 void CooperateOut::Initial::RemoveChains(std::shared_ptr<Initial> self)
80 {}
81 
Initial(CooperateOut & parent)82 CooperateOut::Initial::Initial(CooperateOut &parent)
83     : ICooperateStep(parent, nullptr), parent_(parent)
84 {
85     AddHandler(CooperateEventType::DISABLE, [this](Context &context, const CooperateEvent &event) {
86         this->OnDisable(context, event);
87     });
88     AddHandler(CooperateEventType::START, [this](Context &context, const CooperateEvent &event) {
89         this->OnStart(context, event);
90     });
91     AddHandler(CooperateEventType::STOP, [this](Context &context, const CooperateEvent &event) {
92         this->OnStop(context, event);
93     });
94     AddHandler(CooperateEventType::APP_CLOSED, [this](Context &context, const CooperateEvent &event) {
95         this->OnAppClosed(context, event);
96     });
97     AddHandler(CooperateEventType::INPUT_HOTPLUG_EVENT, [this](Context &context, const CooperateEvent &event) {
98         this->OnHotplug(context, event);
99     });
100     AddHandler(CooperateEventType::INPUT_POINTER_EVENT, [this](Context &context, const CooperateEvent &event) {
101         this->OnPointerEvent(context, event);
102     });
103     AddHandler(CooperateEventType::DDM_BOARD_OFFLINE, [this](Context &context, const CooperateEvent &event) {
104         this->OnBoardOffline(context, event);
105     });
106     AddHandler(CooperateEventType::DDP_COOPERATE_SWITCH_CHANGED,
107         [this](Context &context, const CooperateEvent &event) {
108             this->OnSwitchChanged(context, event);
109     });
110     AddHandler(CooperateEventType::DSOFTBUS_SESSION_CLOSED,
111         [this](Context &context, const CooperateEvent &event) {
112             this->OnSoftbusSessionClosed(context, event);
113     });
114     AddHandler(CooperateEventType::DSOFTBUS_COME_BACK,
115         [this](Context &context, const CooperateEvent &event) {
116             this->OnComeBack(context, event);
117     });
118     AddHandler(CooperateEventType::DSOFTBUS_START_COOPERATE,
119         [this](Context &context, const CooperateEvent &event) {
120             this->OnRemoteStart(context, event);
121     });
122     AddHandler(CooperateEventType::DSOFTBUS_STOP_COOPERATE,
123         [this](Context &context, const CooperateEvent &event) {
124             this->OnRemoteStop(context, event);
125     });
126     AddHandler(CooperateEventType::DSOFTBUS_RELAY_COOPERATE,
127         [this](Context &context, const CooperateEvent &event) {
128             this->OnRelay(context, event);
129     });
130 }
131 
OnDisable(Context & context,const CooperateEvent & event)132 void CooperateOut::Initial::OnDisable(Context &context, const CooperateEvent &event)
133 {
134     FI_HILOGI("[disable cooperation] Stop cooperation");
135     parent_.StopCooperate(context, event);
136 }
137 
OnStart(Context & context,const CooperateEvent & event)138 void CooperateOut::Initial::OnStart(Context &context, const CooperateEvent &event)
139 {
140     StartCooperateEvent param = std::get<StartCooperateEvent>(event.event);
141 
142     context.eventMgr_.StartCooperate(param);
143     FI_HILOGI("[start] Start cooperation with \'%{public}s\', report success when out",
144         Utility::Anonymize(context.Peer()).c_str());
145     DSoftbusStartCooperateFinished failNotice {
146         .success = false,
147         .errCode = static_cast<int32_t>(CoordinationErrCode::UNEXPECTED_START_CALL)
148     };
149     context.eventMgr_.StartCooperateFinish(failNotice);
150 }
151 
OnStop(Context & context,const CooperateEvent & event)152 void CooperateOut::Initial::OnStop(Context &context, const CooperateEvent &event)
153 {
154     StopCooperateEvent param = std::get<StopCooperateEvent>(event.event);
155 
156     context.eventMgr_.StopCooperate(param);
157     FI_HILOGI("[stop] Stop cooperation with \'%{public}s\', unchain:%{public}d",
158         Utility::Anonymize(context.Peer()).c_str(), param.isUnchained);
159     parent_.StopCooperate(context, event);
160 
161     DSoftbusStopCooperateFinished notice {
162         .normal = true,
163     };
164     context.eventMgr_.StopCooperateFinish(notice);
165 
166     parent_.UnchainConnections(context, param);
167 }
168 
OnComeBack(Context & context,const CooperateEvent & event)169 void CooperateOut::Initial::OnComeBack(Context &context, const CooperateEvent &event)
170 {
171     CALL_INFO_TRACE;
172     DSoftbusComeBack notice = std::get<DSoftbusComeBack>(event.event);
173 
174     if (!context.IsPeer(notice.networkId)) {
175         return;
176     }
177     FI_HILOGI("[come back] From \'%{public}s\'", Utility::Anonymize(notice.networkId).c_str());
178     context.OnRemoteStartCooperate(notice.extra);
179     parent_.OnSetCooperatePriv(notice.extra.priv);
180     DSoftbusStartCooperate startEvent {
181         .networkId = notice.networkId,
182     };
183     context.eventMgr_.RemoteStart(startEvent);
184     context.inputEventInterceptor_.Disable();
185 
186     context.RemoteStartSuccess(notice);
187     context.eventMgr_.RemoteStartFinish(notice);
188     TransiteTo(context, CooperateState::COOPERATE_STATE_FREE);
189     context.OnBack();
190 }
191 
OnRemoteStart(Context & context,const CooperateEvent & event)192 void CooperateOut::Initial::OnRemoteStart(Context &context, const CooperateEvent &event)
193 {
194     DSoftbusStartCooperate notice = std::get<DSoftbusStartCooperate>(event.event);
195 
196     if (context.IsLocal(notice.networkId)) {
197         return;
198     }
199     FI_HILOGI("[remote start] Request from \'%{public}s\'", Utility::Anonymize(notice.networkId).c_str());
200     if (context.IsPeer(notice.networkId)) {
201         FI_HILOGI("[remote start] Reset on request from peer");
202         parent_.StopCooperate(context, event);
203         return;
204     }
205     context.OnRemoteStartCooperate(notice.extra);
206     context.eventMgr_.RemoteStart(notice);
207     context.inputEventInterceptor_.Disable();
208 
209     DSoftbusStopCooperate stopNotice {};
210     context.dsoftbus_.StopCooperate(context.Peer(), stopNotice);
211 
212     context.RemoteStartSuccess(notice);
213     context.inputEventBuilder_.Enable(context);
214     context.eventMgr_.RemoteStartFinish(notice);
215     FI_HILOGI("[remote start] Cooperation with \'%{public}s\' established", Utility::Anonymize(context.Peer()).c_str());
216     TransiteTo(context, CooperateState::COOPERATE_STATE_IN);
217     context.OnTransitionIn();
218 }
219 
OnRemoteStop(Context & context,const CooperateEvent & event)220 void CooperateOut::Initial::OnRemoteStop(Context &context, const CooperateEvent &event)
221 {
222     DSoftbusStopCooperate notice = std::get<DSoftbusStopCooperate>(event.event);
223 
224     if (!context.IsPeer(notice.networkId)) {
225         return;
226     }
227     FI_HILOGI("[remote stop] Notification from \'%{public}s\'", Utility::Anonymize(notice.networkId).c_str());
228     context.eventMgr_.RemoteStop(notice);
229     context.inputEventInterceptor_.Disable();
230     context.ResetCursorPosition();
231     context.eventMgr_.RemoteStopFinish(notice);
232     TransiteTo(context, CooperateState::COOPERATE_STATE_FREE);
233     context.OnResetCooperation();
234 }
235 
OnRelay(Context & context,const CooperateEvent & event)236 void CooperateOut::Initial::OnRelay(Context &context, const CooperateEvent &event)
237 {
238     DSoftbusRelayCooperate notice = std::get<DSoftbusRelayCooperate>(event.event);
239     if (!context.IsPeer(notice.networkId)) {
240         return;
241     }
242     DSoftbusRelayCooperateFinished resp {
243         .targetNetworkId = notice.targetNetworkId,
244     };
245 
246     int32_t ret = context.dsoftbus_.OpenSession(notice.targetNetworkId);
247     if (ret != RET_OK) {
248         FI_HILOGE("[relay cooperate] Failed to connect to \'%{public}s\'",
249             Utility::Anonymize(notice.targetNetworkId).c_str());
250         resp.normal = false;
251         context.dsoftbus_.RelayCooperateFinish(notice.networkId, resp);
252         return;
253     }
254 
255     resp.normal = true;
256     context.dsoftbus_.RelayCooperateFinish(notice.networkId, resp);
257 
258     context.RelayCooperate(notice);
259     context.inputEventInterceptor_.Update(context);
260     FI_HILOGI("[relay cooperate] Relay cooperation to \'%{public}s\'", Utility::Anonymize(context.Peer()).c_str());
261     context.OnRelayCooperation(context.Peer(), context.NormalizedCursorPosition());
262 }
263 
OnHotplug(Context & context,const CooperateEvent & event)264 void CooperateOut::Initial::OnHotplug(Context &context, const CooperateEvent &event)
265 {
266     InputHotplugEvent notice = std::get<InputHotplugEvent>(event.event);
267     if (notice.deviceId != context.StartDeviceId()) {
268         return;
269     }
270     FI_HILOGI("Stop cooperation on unplug of dedicated pointer");
271     parent_.StopCooperate(context, event);
272 }
273 
OnAppClosed(Context & context,const CooperateEvent & event)274 void CooperateOut::Initial::OnAppClosed(Context &context, const CooperateEvent &event)
275 {
276     FI_HILOGI("[app closed] Close all connections");
277     context.dsoftbus_.CloseAllSessions();
278     FI_HILOGI("[app closed] Stop cooperation");
279     parent_.StopCooperate(context, event);
280 }
281 
OnPointerEvent(Context & context,const CooperateEvent & event)282 void CooperateOut::Initial::OnPointerEvent(Context &context, const CooperateEvent &event)
283 {
284     InputPointerEvent notice = std::get<InputPointerEvent>(event.event);
285 
286     if ((notice.sourceType != MMI::PointerEvent::SOURCE_TYPE_MOUSE) ||
287         (notice.deviceId == context.StartDeviceId())) {
288         return;
289     }
290     FI_HILOGI("Stop cooperation on operation of undedicated pointer");
291     parent_.StopCooperate(context, event);
292 }
293 
OnBoardOffline(Context & context,const CooperateEvent & event)294 void CooperateOut::Initial::OnBoardOffline(Context &context, const CooperateEvent &event)
295 {
296     DDMBoardOfflineEvent notice = std::get<DDMBoardOfflineEvent>(event.event);
297 
298     if (!context.IsPeer(notice.networkId)) {
299         return;
300     }
301     FI_HILOGI("[board offline] Peer(\'%{public}s\') is offline", Utility::Anonymize(notice.networkId).c_str());
302     parent_.StopCooperate(context, event);
303 }
304 
OnSwitchChanged(Context & context,const CooperateEvent & event)305 void CooperateOut::Initial::OnSwitchChanged(Context &context, const CooperateEvent &event)
306 {
307     DDPCooperateSwitchChanged notice = std::get<DDPCooperateSwitchChanged>(event.event);
308 
309     if (!context.IsPeer(notice.networkId) || notice.normal) {
310         return;
311     }
312     FI_HILOGI("[switch off] Peer(\'%{public}s\') switch off", Utility::Anonymize(notice.networkId).c_str());
313     parent_.StopCooperate(context, event);
314 }
315 
OnSoftbusSessionClosed(Context & context,const CooperateEvent & event)316 void CooperateOut::Initial::OnSoftbusSessionClosed(Context &context, const CooperateEvent &event)
317 {
318     DSoftbusSessionClosed notice = std::get<DSoftbusSessionClosed>(event.event);
319 
320     if (!context.IsPeer(notice.networkId)) {
321         return;
322     }
323     FI_HILOGI("[dsoftbus session closed] Disconnected with \'%{public}s\'",
324         Utility::Anonymize(notice.networkId).c_str());
325     parent_.StopCooperate(context, event);
326 }
327 
OnProgress(Context & context,const CooperateEvent & event)328 void CooperateOut::Initial::OnProgress(Context &context, const CooperateEvent &event)
329 {}
330 
OnReset(Context & context,const CooperateEvent & event)331 void CooperateOut::Initial::OnReset(Context &context, const CooperateEvent &event)
332 {}
333 
StopCooperate(Context & context,const CooperateEvent & event)334 void CooperateOut::StopCooperate(Context &context, const CooperateEvent &event)
335 {
336     context.inputEventInterceptor_.Disable();
337 
338     DSoftbusStopCooperate notice {};
339     context.dsoftbus_.StopCooperate(context.Peer(), notice);
340 
341     context.ResetCursorPosition();
342     TransiteTo(context, CooperateState::COOPERATE_STATE_FREE);
343     context.OnResetCooperation();
344 }
345 
UnchainConnections(Context & context,const StopCooperateEvent & event) const346 void CooperateOut::UnchainConnections(Context &context, const StopCooperateEvent &event) const
347 {
348     if (event.isUnchained) {
349         FI_HILOGI("Unchain all connections");
350         context.dsoftbus_.CloseAllSessions();
351         context.eventMgr_.OnUnchain(event);
352     }
353 }
354 } // namespace Cooperate
355 } // namespace DeviceStatus
356 } // namespace Msdp
357 } // namespace OHOS
358