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