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