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
24namespace OHOS {
25namespace Msdp {
26namespace DeviceStatus {
27namespace Cooperate {
28
29CooperateOut::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
37CooperateOut::~CooperateOut()
38{
39    Initial::RemoveChains(initial_);
40}
41
42void CooperateOut::OnEvent(Context &context, const CooperateEvent &event)
43{
44    current_->OnEvent(context, event);
45}
46
47void CooperateOut::OnEnterState(Context &context)
48{
49    CALL_INFO_TRACE;
50    env_->GetInput().SetPointerVisibility(false);
51}
52
53void CooperateOut::OnLeaveState(Context &context)
54{
55    CALL_INFO_TRACE;
56    SetPointerVisible(context);
57}
58
59void 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
69void CooperateOut::Initial::BuildChains(std::shared_ptr<Initial> self, CooperateOut &parent)
70{}
71
72void CooperateOut::Initial::RemoveChains(std::shared_ptr<Initial> self)
73{}
74
75CooperateOut::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
125void CooperateOut::Initial::OnDisable(Context &context, const CooperateEvent &event)
126{
127    FI_HILOGI("[disable cooperation] Stop cooperation");
128    parent_.StopCooperate(context, event);
129}
130
131void 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
145void 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
164void 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
186void 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
215void 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
231void 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
259void 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
269void 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
277void 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
290void 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
301void 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
312void 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
324void CooperateOut::Initial::OnProgress(Context &context, const CooperateEvent &event)
325{}
326
327void CooperateOut::Initial::OnReset(Context &context, const CooperateEvent &event)
328{}
329
330void 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
342void 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