1/*
2 * Copyright (c) 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 "mouse_location.h"
17
18#include "devicestatus_define.h"s
19#include "dsoftbus_handler.h"
20#include "utility.h"
21
22#undef LOG_TAG
23#define LOG_TAG "MouseLocation"
24
25namespace OHOS {
26namespace Msdp {
27namespace DeviceStatus {
28namespace Cooperate {
29
30MouseLocation::MouseLocation(IContext *context) : context_(context) {}
31
32void MouseLocation::AddListener(const RegisterEventListenerEvent &event)
33{
34    CALL_INFO_TRACE;
35    std::lock_guard<std::mutex> guard(mutex_);
36    localNetworkId_ = IDSoftbusAdapter::GetLocalNetworkId();
37    if (event.networkId == localNetworkId_) {
38        FI_HILOGI("Add local mouse location listener");
39        localListeners_.insert(event.pid);
40        return;
41    }
42    FI_HILOGI("Add remote mouse location listener, networkId:%{public}s", Utility::Anonymize(event.networkId).c_str());
43    DSoftbusSubscribeMouseLocation softbusEvent {
44        .networkId = localNetworkId_,
45        .remoteNetworkId = event.networkId,
46    };
47    if (SubscribeMouseLocation(softbusEvent) != RET_OK) {
48        FI_HILOGE("SubscribeMouseLocation failed, networkId:%{public}s", Utility::Anonymize(event.networkId).c_str());
49        return;
50    }
51    listeners_[event.networkId].insert(event.pid);
52}
53
54void MouseLocation::RemoveListener(const UnregisterEventListenerEvent &event)
55{
56    CALL_INFO_TRACE;
57    std::lock_guard<std::mutex> guard(mutex_);
58    localNetworkId_ = IDSoftbusAdapter::GetLocalNetworkId();
59    if (event.networkId == localNetworkId_) {
60        FI_HILOGI("Remove local mouse location listener");
61        localListeners_.erase(event.pid);
62        return;
63    }
64    DSoftbusUnSubscribeMouseLocation softbusEvent {
65        .networkId = localNetworkId_,
66        .remoteNetworkId = event.networkId,
67    };
68    if (UnSubscribeMouseLocation(softbusEvent) != RET_OK) {
69        FI_HILOGE("UnSubscribeMouseLocation failed, networkId:%{public}s", Utility::Anonymize(event.networkId).c_str());
70    }
71    if (listeners_.find(event.networkId) == listeners_.end()) {
72        FI_HILOGE("No listener for networkId:%{public}s", Utility::Anonymize(event.networkId).c_str());
73        return;
74    }
75    listeners_[event.networkId].erase(event.pid);
76    if (listeners_[event.networkId].empty()) {
77        listeners_.erase(event.networkId);
78    }
79}
80
81void MouseLocation::OnClientDied(const ClientDiedEvent &event)
82{
83    CALL_INFO_TRACE;
84    std::lock_guard<std::mutex> guard(mutex_);
85    localNetworkId_ = IDSoftbusAdapter::GetLocalNetworkId();
86    FI_HILOGI("Remove client died listener, pid: %{public}d", event.pid);
87    localListeners_.erase(event.pid);
88    for (auto it = listeners_.begin(); it != listeners_.end();) {
89        it->second.erase(event.pid);
90        if (it->second.empty()) {
91            DSoftbusUnSubscribeMouseLocation softbusEvent {
92                .networkId = localNetworkId_,
93                .remoteNetworkId = it->first,
94            };
95            UnSubscribeMouseLocation(softbusEvent);
96            it = listeners_.erase(it);
97        } else {
98            ++it;
99        }
100    }
101}
102
103void MouseLocation::OnSoftbusSessionClosed(const DSoftbusSessionClosed &notice)
104{
105    CALL_INFO_TRACE;
106    std::lock_guard<std::mutex> guard(mutex_);
107    FI_HILOGI("Session to %{public}s closed", Utility::Anonymize(notice.networkId).c_str());
108    if (remoteSubscribers_.find(notice.networkId) != remoteSubscribers_.end()) {
109        remoteSubscribers_.erase(notice.networkId);
110        FI_HILOGI("Remove remote subscribers from %{public}s", Utility::Anonymize(notice.networkId).c_str());
111    }
112    if (listeners_.find(notice.networkId) != listeners_.end()) {
113        listeners_.erase(notice.networkId);
114        FI_HILOGI("Remove listeners listen to %{public}s", Utility::Anonymize(notice.networkId).c_str());
115    }
116}
117
118void MouseLocation::OnSubscribeMouseLocation(const DSoftbusSubscribeMouseLocation &notice)
119{
120    CALL_INFO_TRACE;
121    std::lock_guard<std::mutex> guard(mutex_);
122    CHKPV(context_);
123    remoteSubscribers_.insert(notice.networkId);
124    FI_HILOGI("Add subscriber for networkId:%{public}s successfully", Utility::Anonymize(notice.networkId).c_str());
125    DSoftbusReplySubscribeMouseLocation event = {
126        .networkId = notice.remoteNetworkId,
127        .remoteNetworkId = notice.networkId,
128        .result = true,
129    };
130    FI_HILOGI("ReplySubscribeMouseLocation from networkId:%{public}s to networkId:%{public}s",
131        Utility::Anonymize(event.networkId).c_str(), Utility::Anonymize(event.remoteNetworkId).c_str());
132    ReplySubscribeMouseLocation(event);
133}
134
135void MouseLocation::OnUnSubscribeMouseLocation(const DSoftbusUnSubscribeMouseLocation &notice)
136{
137    CALL_INFO_TRACE;
138    std::lock_guard<std::mutex> guard(mutex_);
139    localNetworkId_ = IDSoftbusAdapter::GetLocalNetworkId();
140    if (remoteSubscribers_.find(notice.networkId) == remoteSubscribers_.end()) {
141        FI_HILOGE("No subscriber for networkId:%{public}s stored in remote subscriber",
142            Utility::Anonymize(notice.networkId).c_str());
143        return;
144    }
145    remoteSubscribers_.erase(notice.networkId);
146    DSoftbusReplyUnSubscribeMouseLocation event = {
147        .networkId = notice.remoteNetworkId,
148        .remoteNetworkId = notice.networkId,
149        .result = true,
150    };
151    FI_HILOGI("ReplyUnSubscribeMouseLocation from networkId:%{public}s to networkId:%{public}s",
152        Utility::Anonymize(event.networkId).c_str(), Utility::Anonymize(event.remoteNetworkId).c_str());
153    ReplyUnSubscribeMouseLocation(event);
154}
155
156void MouseLocation::OnReplySubscribeMouseLocation(const DSoftbusReplySubscribeMouseLocation &notice)
157{
158    CALL_INFO_TRACE;
159    std::lock_guard<std::mutex> guard(mutex_);
160    if (notice.result) {
161        FI_HILOGI("SubscribeMouseLocation of networkId:%{public}s successfully, localNetworkId:%{public}s",
162            Utility::Anonymize(notice.networkId).c_str(), Utility::Anonymize(notice.remoteNetworkId).c_str());
163    } else {
164        FI_HILOGI("SubscribeMouseLocation of networkId:%{public}s failed, localNetworkId:%{public}s",
165            Utility::Anonymize(notice.networkId).c_str(), Utility::Anonymize(notice.remoteNetworkId).c_str());
166    }
167}
168
169void MouseLocation::OnReplyUnSubscribeMouseLocation(const DSoftbusReplyUnSubscribeMouseLocation &notice)
170{
171    CALL_INFO_TRACE;
172    std::lock_guard<std::mutex> guard(mutex_);
173    if (notice.result) {
174        FI_HILOGI("UnSubscribeMouseLocation of networkId:%{public}s successfully, localNetworkId:%{public}s",
175            Utility::Anonymize(notice.networkId).c_str(), Utility::Anonymize(notice.remoteNetworkId).c_str());
176    } else {
177        FI_HILOGI("UnSubscribeMouseLocation of networkId:%{public}s failed, localNetworkId:%{public}s",
178            Utility::Anonymize(notice.networkId).c_str(), Utility::Anonymize(notice.remoteNetworkId).c_str());
179    }
180}
181
182void MouseLocation::OnRemoteMouseLocation(const DSoftbusSyncMouseLocation &notice)
183{
184    CALL_DEBUG_ENTER;
185    std::lock_guard<std::mutex> guard(mutex_);
186    if (listeners_.find(notice.networkId) == listeners_.end()) {
187        FI_HILOGE("No listener for networkId:%{public}s stored in listeners",
188            Utility::Anonymize(notice.networkId).c_str());
189        return;
190    }
191    LocationInfo locationInfo {
192        .displayX = notice.mouseLocation.displayX,
193        .displayY = notice.mouseLocation.displayY,
194        .displayWidth = notice.mouseLocation.displayWidth,
195        .displayHeight = notice.mouseLocation.displayHeight
196        };
197    for (auto pid : listeners_[notice.networkId]) {
198        ReportMouseLocationToListener(notice.networkId, locationInfo, pid);
199    }
200}
201
202void MouseLocation::ProcessData(std::shared_ptr<MMI::PointerEvent> pointerEvent)
203{
204    CALL_DEBUG_ENTER;
205    std::lock_guard<std::mutex> guard(mutex_);
206    CHKPV(pointerEvent);
207    if (auto sourceType = pointerEvent->GetSourceType(); sourceType != MMI::PointerEvent::SOURCE_TYPE_MOUSE) {
208        FI_HILOGD("Unexpected sourceType:%{public}d", static_cast<int32_t>(sourceType));
209        return;
210    }
211    LocationInfo locationInfo;
212    TransferToLocationInfo(pointerEvent, locationInfo);
213    if (HasLocalListener()) {
214        for (auto pid : localListeners_) {
215            ReportMouseLocationToListener(localNetworkId_, locationInfo, pid);
216        }
217    }
218    if (!HasRemoteSubscriber()) {
219        FI_HILOGD("No remote subscriber");
220        return;
221    }
222    for (const auto &networkId : remoteSubscribers_) {
223        SyncLocationToRemote(networkId, locationInfo);
224    }
225}
226
227void MouseLocation::SyncLocationToRemote(const std::string &remoteNetworkId, const LocationInfo &locationInfo)
228{
229    CALL_DEBUG_ENTER;
230    DSoftbusSyncMouseLocation softbusEvent {
231        .networkId = localNetworkId_,
232        .remoteNetworkId = remoteNetworkId,
233        .mouseLocation = {
234            .displayX = locationInfo.displayX,
235            .displayY = locationInfo.displayY,
236            .displayWidth = locationInfo.displayWidth,
237            .displayHeight = locationInfo.displayHeight,
238        },
239    };
240    SyncMouseLocation(softbusEvent);
241}
242
243int32_t MouseLocation::ReplySubscribeMouseLocation(const DSoftbusReplySubscribeMouseLocation &event)
244{
245    CALL_INFO_TRACE;
246    NetPacket packet(MessageId::DSOFTBUS_REPLY_SUBSCRIBE_MOUSE_LOCATION);
247    packet << event.networkId << event.remoteNetworkId << event.result;
248    if (packet.ChkRWError()) {
249        FI_HILOGE("Failed to write data packet");
250        return RET_ERR;
251    }
252    if (SendPacket(event.remoteNetworkId, packet) != RET_OK) {
253        FI_HILOGE("SendPacket failed");
254        return RET_ERR;
255    }
256    return RET_OK;
257}
258
259int32_t MouseLocation::ReplyUnSubscribeMouseLocation(const DSoftbusReplyUnSubscribeMouseLocation &event)
260{
261    CALL_INFO_TRACE;
262    NetPacket packet(MessageId::DSOFTBUS_REPLY_UNSUBSCRIBE_MOUSE_LOCATION);
263    packet << event.networkId << event.remoteNetworkId << event.result;
264    if (packet.ChkRWError()) {
265        FI_HILOGE("Failed to write data packet");
266        return RET_ERR;
267    }
268    if (SendPacket(event.remoteNetworkId, packet) != RET_OK) {
269        FI_HILOGE("SendPacket failed");
270        return RET_ERR;
271    }
272    return RET_OK;
273}
274
275int32_t MouseLocation::SubscribeMouseLocation(const DSoftbusSubscribeMouseLocation &event)
276{
277    CALL_INFO_TRACE;
278    NetPacket packet(MessageId::DSOFTBUS_SUBSCRIBE_MOUSE_LOCATION);
279    packet << event.networkId << event.remoteNetworkId;
280    if (packet.ChkRWError()) {
281        FI_HILOGE("Failed to write data packet");
282        return RET_ERR;
283    }
284    if (SendPacket(event.remoteNetworkId, packet) != RET_OK) {
285        FI_HILOGE("SendPacket failed");
286        return RET_ERR;
287    }
288    return RET_OK;
289}
290
291int32_t MouseLocation::UnSubscribeMouseLocation(const DSoftbusUnSubscribeMouseLocation &event)
292{
293    CALL_INFO_TRACE;
294    NetPacket packet(MessageId::DSOFTBUS_UNSUBSCRIBE_MOUSE_LOCATION);
295    packet << event.networkId << event.remoteNetworkId;
296    if (packet.ChkRWError()) {
297        FI_HILOGE("Failed to write data packet");
298        return RET_ERR;
299    }
300    if (SendPacket(event.remoteNetworkId, packet) != RET_OK) {
301        FI_HILOGE("SendPacket failed");
302        return RET_ERR;
303    }
304    return RET_OK;
305}
306
307int32_t MouseLocation::SyncMouseLocation(const DSoftbusSyncMouseLocation &event)
308{
309    CALL_DEBUG_ENTER;
310    NetPacket packet(MessageId::DSOFTBUS_MOUSE_LOCATION);
311    packet << event.networkId << event.remoteNetworkId << event.mouseLocation.displayX <<
312        event.mouseLocation.displayY << event.mouseLocation.displayWidth << event.mouseLocation.displayHeight;
313    if (packet.ChkRWError()) {
314        FI_HILOGE("Failed to write data packet");
315        return RET_ERR;
316    }
317    if (SendPacket(event.remoteNetworkId, packet) != RET_OK) {
318        FI_HILOGE("SendPacket failed");
319        return RET_ERR;
320    }
321    return RET_OK;
322}
323
324void MouseLocation::ReportMouseLocationToListener(const std::string &networkId, const LocationInfo &locationInfo,
325    int32_t pid)
326{
327    CALL_DEBUG_ENTER;
328    CHKPV(context_);
329    auto session = context_->GetSocketSessionManager().FindSessionByPid(pid);
330    CHKPV(session);
331    NetPacket pkt(MessageId::MOUSE_LOCATION_ADD_LISTENER);
332    pkt << networkId << locationInfo.displayX << locationInfo.displayY <<
333        locationInfo.displayWidth << locationInfo.displayHeight;
334    if (pkt.ChkRWError()) {
335        FI_HILOGE("Packet write data failed");
336        return;
337    }
338    if (!session->SendMsg(pkt)) {
339        FI_HILOGE("Sending failed");
340        return;
341    }
342}
343
344void MouseLocation::TransferToLocationInfo(std::shared_ptr<MMI::PointerEvent> pointerEvent, LocationInfo &locationInfo)
345{
346    CALL_DEBUG_ENTER;
347    CHKPV(pointerEvent);
348    MMI::PointerEvent::PointerItem pointerItem;
349    if (!pointerEvent->GetPointerItem(pointerEvent->GetPointerId(), pointerItem)) {
350        FI_HILOGE("Corrupted pointer event");
351        return;
352    }
353    auto display = Rosen::DisplayManager::GetInstance().GetDefaultDisplay();
354    CHKPV(display);
355    locationInfo = {
356        .displayX = pointerItem.GetDisplayX(),
357        .displayY = pointerItem.GetDisplayY(),
358        .displayWidth = display->GetWidth(),
359        .displayHeight = display->GetHeight(),
360    };
361}
362
363bool MouseLocation::HasRemoteSubscriber()
364{
365    CALL_DEBUG_ENTER;
366    return !remoteSubscribers_.empty();
367}
368
369bool MouseLocation::HasLocalListener()
370{
371    CALL_DEBUG_ENTER;
372    return !localListeners_.empty();
373}
374
375int32_t MouseLocation::SendPacket(const std::string &remoteNetworkId, NetPacket &packet)
376{
377    CALL_DEBUG_ENTER;
378    CHKPR(context_, RET_ERR);
379    if (!context_->GetDSoftbus().HasSessionExisted(remoteNetworkId)) {
380        FI_HILOGE("No session connected to %{public}s", Utility::Anonymize(remoteNetworkId).c_str());
381        return RET_ERR;
382    }
383    if (context_->GetDSoftbus().SendPacket(remoteNetworkId, packet) != RET_OK) {
384        FI_HILOGE("SendPacket failed to %{public}s", Utility::Anonymize(remoteNetworkId).c_str());
385        return RET_ERR;
386    }
387    return RET_OK;
388}
389
390} // namespace Cooperate
391} // namespace DeviceStatus
392} // namespace Msdp
393} // namespace OHOS
394