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_free.h"
17
18#include "devicestatus_define.h"
19#include "utility.h"
20
21#undef LOG_TAG
22#define LOG_TAG "CooperateFree"
23
24namespace OHOS {
25namespace Msdp {
26namespace DeviceStatus {
27namespace Cooperate {
28
29CooperateFree::CooperateFree(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
37CooperateFree::~CooperateFree()
38{
39    Initial::RemoveChains(initial_);
40}
41
42void CooperateFree::OnEvent(Context &context, const CooperateEvent &event)
43{
44    current_->OnEvent(context, event);
45}
46
47void CooperateFree::OnEnterState(Context &context)
48{
49    CALL_INFO_TRACE;
50}
51
52void CooperateFree::OnLeaveState(Context &context)
53{
54    CALL_INFO_TRACE;
55    UpdateCooperateFlagEvent event {
56        .mask = COOPERATE_FLAG_HIDE_CURSOR,
57    };
58    context.UpdateCooperateFlag(event);
59}
60
61void CooperateFree::SetPointerVisible(Context &context)
62{
63    CHKPV(env_);
64    bool hasLocalPointerDevice = env_->GetDeviceManager().HasLocalPointerDevice();
65    bool visible = !context.NeedHideCursor() && hasLocalPointerDevice;
66    FI_HILOGI("Set pointer visible:%{public}s, HasLocalPointerDevice:%{public}s",
67        visible ? "true" : "false", hasLocalPointerDevice ? "true" : "false");
68    env_->GetInput().SetPointerVisibility(visible, PRIORITY);
69}
70
71void CooperateFree::UnchainConnections(Context &context, const StopCooperateEvent &event) const
72{
73    CALL_DEBUG_ENTER;
74    if (event.isUnchained) {
75        FI_HILOGI("Unchain all connections");
76        context.dsoftbus_.CloseAllSessions();
77        context.eventMgr_.OnUnchain(event);
78    }
79}
80
81void CooperateFree::OnSetCooperatePriv(uint32_t priv)
82{
83    CALL_DEBUG_ENTER;
84    env_->GetDragManager().SetCooperatePriv(priv);
85}
86
87CooperateFree::Initial::Initial(CooperateFree &parent)
88    : ICooperateStep(parent, nullptr), parent_(parent)
89{
90    AddHandler(CooperateEventType::START, [this](Context &context, const CooperateEvent &event) {
91        this->OnStart(context, event);
92    });
93    AddHandler(CooperateEventType::STOP, [this](Context &context, const CooperateEvent &event) {
94        this->OnStop(context, event);
95    });
96    AddHandler(CooperateEventType::APP_CLOSED, [this](Context &context, const CooperateEvent &event) {
97        this->OnAppClosed(context, event);
98    });
99    AddHandler(CooperateEventType::DSOFTBUS_START_COOPERATE, [this](Context &context, const CooperateEvent &event) {
100        this->OnRemoteStart(context, event);
101    });
102    AddHandler(CooperateEventType::INPUT_POINTER_EVENT, [this](Context &context, const CooperateEvent &event) {
103        this->OnPointerEvent(context, event);
104    });
105}
106
107void CooperateFree::Initial::OnProgress(Context &context, const CooperateEvent &event)
108{}
109
110void CooperateFree::Initial::OnReset(Context &context, const CooperateEvent &event)
111{}
112
113void CooperateFree::Initial::BuildChains(std::shared_ptr<Initial> initial, CooperateFree &parent)
114{}
115
116void CooperateFree::Initial::RemoveChains(std::shared_ptr<Initial> initial)
117{}
118
119void CooperateFree::Initial::OnStart(Context &context, const CooperateEvent &event)
120{
121    CALL_INFO_TRACE;
122    StartCooperateEvent notice = std::get<StartCooperateEvent>(event.event);
123    FI_HILOGI("[start cooperation] With \'%{public}s\'", Utility::Anonymize(notice.remoteNetworkId).c_str());
124    context.StartCooperate(notice);
125    context.eventMgr_.StartCooperate(notice);
126
127    int32_t ret = context.dsoftbus_.OpenSession(context.Peer());
128    if (ret != RET_OK) {
129        FI_HILOGE("[start cooperation] Failed to connect to \'%{public}s\'",
130            Utility::Anonymize(context.Peer()).c_str());
131        int32_t errNum = (ret == RET_ERR ? static_cast<int32_t>(CoordinationErrCode::OPEN_SESSION_FAILED) : ret);
132        DSoftbusStartCooperateFinished failNotice {
133            .success = false,
134            .errCode = errNum
135        };
136        context.eventMgr_.StartCooperateFinish(failNotice);
137        return;
138    }
139    DSoftbusStartCooperate startNotice {
140        .originNetworkId = context.Local(),
141        .success = true,
142        .cursorPos = context.NormalizedCursorPosition(),
143    };
144    context.OnStartCooperate(startNotice.extra);
145    context.dsoftbus_.StartCooperate(context.Peer(), startNotice);
146    context.inputEventInterceptor_.Enable(context);
147    context.eventMgr_.StartCooperateFinish(startNotice);
148    FI_HILOGI("[start cooperation] Cooperation with \'%{public}s\' established",
149        Utility::Anonymize(context.Peer()).c_str());
150    TransiteTo(context, CooperateState::COOPERATE_STATE_OUT);
151    context.OnTransitionOut();
152#ifdef ENABLE_PERFORMANCE_CHECK
153    std::ostringstream ss;
154    ss << "start_cooperation_with_ " << Utility::Anonymize(context.Peer()).c_str();
155    context.FinishTrace(ss.str());
156#endif // ENABLE_PERFORMANCE_CHECK
157}
158
159void CooperateFree::Initial::OnStop(Context &context, const CooperateEvent &event)
160{
161    CALL_DEBUG_ENTER;
162    StopCooperateEvent param = std::get<StopCooperateEvent>(event.event);
163    context.eventMgr_.StopCooperate(param);
164    DSoftbusStopCooperateFinished notice {
165        .normal = true,
166    };
167    context.eventMgr_.StopCooperateFinish(notice);
168    parent_.UnchainConnections(context, param);
169}
170
171void CooperateFree::Initial::OnAppClosed(Context &context, const CooperateEvent &event)
172{
173    FI_HILOGI("[app closed] Close all connections");
174    context.dsoftbus_.CloseAllSessions();
175}
176
177void CooperateFree::Initial::OnRemoteStart(Context &context, const CooperateEvent &event)
178{
179    CALL_INFO_TRACE;
180    DSoftbusStartCooperate notice = std::get<DSoftbusStartCooperate>(event.event);
181    context.OnRemoteStartCooperate(notice.extra);
182    parent_.OnSetCooperatePriv(notice.extra.priv);
183    context.eventMgr_.RemoteStart(notice);
184    context.RemoteStartSuccess(notice);
185    context.inputEventBuilder_.Enable(context);
186    context.eventMgr_.RemoteStartFinish(notice);
187    context.inputDevMgr_.AddVirtualInputDevice(context.Peer());
188    FI_HILOGI("[remote start] Cooperation with \'%{public}s\' established", Utility::Anonymize(context.Peer()).c_str());
189    TransiteTo(context, CooperateState::COOPERATE_STATE_IN);
190    context.OnTransitionIn();
191}
192
193void CooperateFree::Initial::OnPointerEvent(Context &context, const CooperateEvent &event)
194{
195    CALL_DEBUG_ENTER;
196    InputPointerEvent notice = std::get<InputPointerEvent>(event.event);
197    if (InputEventBuilder::IsLocalEvent(notice) && context.NeedHideCursor()) {
198        UpdateCooperateFlagEvent event {
199            .mask = COOPERATE_FLAG_HIDE_CURSOR,
200        };
201        context.UpdateCooperateFlag(event);
202        parent_.SetPointerVisible(context);
203    }
204}
205} // namespace Cooperate
206} // namespace DeviceStatus
207} // namespace Msdp
208} // namespace OHOS
209