• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 "fusion_device_profile_adapter.h"
17 
18 #include <set>
19 
20 #include "distributed_device_profile_client.h"
21 #include "singleton.h"
22 
23 #include "devicestatus_define.h"
24 #include "json_parser.h"
25 
26 #undef LOG_TAG
27 #define LOG_TAG "FusionDeviceProfileAdapter"
28 
29 using namespace OHOS;
30 using namespace OHOS::DeviceProfile;
31 
32 namespace {
33 const std::string SERVICE_ID { "deviceStatus" };
34 } // namespace
35 
36 class ProfileEventCallback final : public IProfileEventCallback {
37 public:
38     explicit ProfileEventCallback(CICrossStateListener* listener);
39     ~ProfileEventCallback();
40 
41     void OnProfileChanged(const ProfileChangeNotification &changeNotification) override;
42     bool SupportProfileEvent(const ProfileEvent &event) const;
43     void AddProfileEvent(const ProfileEvent &event);
44     void RemoveProfileEvents(const std::list<ProfileEvent> &profileEvents);
45 
HasProfileEvent() const46     bool HasProfileEvent() const
47     {
48         return !profileEvents_.empty();
49     }
50 
51 private:
52     CICrossStateListener* listener_ { nullptr };
53     std::set<ProfileEvent> profileEvents_;
54 };
55 
56 class FusionDeviceProfileAdapter {
57     DECLARE_DELAYED_REF_SINGLETON(FusionDeviceProfileAdapter);
58 
59 public:
60     int32_t UpdateCrossSwitchState(bool switchState);
61     int32_t SyncCrossSwitchState(bool switchState, const std::vector<std::string> &deviceIds);
62     bool GetCrossSwitchState(const std::string &deviceId);
63     int32_t RegisterCrossStateListener(const std::string &deviceId,
64         const std::shared_ptr<ProfileEventCallback> &callback);
65     int32_t UnregisterCrossStateListener(const std::string &deviceId);
66 
67 private:
68     void SaveSubscribeInfos(const std::string &deviceId,
69                             const std::shared_ptr<ProfileEventCallback> &callback,
70                             std::list<SubscribeInfo> &subscribeInfos);
71     void RemoveFailedSubscriptions(const std::string &deviceId, const std::list<ProfileEvent> &failedEvents);
72 
73 private:
74     std::map<std::string, std::shared_ptr<ProfileEventCallback>> callbacks_;
75     const std::string characteristicsName_ = "currentStatus";
76 };
77 
ProfileEventCallback(CICrossStateListener * listener)78 ProfileEventCallback::ProfileEventCallback(CICrossStateListener* listener)
79 {
80     if ((listener != nullptr) && (listener->clone != nullptr)) {
81         listener_ = listener->clone(listener);
82     }
83 }
84 
~ProfileEventCallback()85 ProfileEventCallback::~ProfileEventCallback()
86 {
87     if ((listener_ != nullptr) && (listener_->destruct != nullptr)) {
88         listener_->destruct(listener_);
89     }
90 }
91 
OnProfileChanged(const ProfileChangeNotification & changeNotification)92 void ProfileEventCallback::OnProfileChanged(const ProfileChangeNotification &changeNotification)
93 {
94     CALL_INFO_TRACE;
95     if (listener_ == nullptr || listener_->onUpdate == nullptr) {
96         FI_HILOGE("listener_ is nullptr or onUpdate is nullptr");
97         return;
98     }
99     std::string deviceId = changeNotification.GetDeviceId();
100     bool switchState = DelayedRefSingleton<FusionDeviceProfileAdapter>::GetInstance().GetCrossSwitchState(deviceId);
101     listener_->onUpdate(listener_, deviceId.c_str(), switchState);
102 }
103 
SupportProfileEvent(const ProfileEvent & event) const104 bool ProfileEventCallback::SupportProfileEvent(const ProfileEvent &event) const
105 {
106     return (profileEvents_.find(event) != profileEvents_.cend());
107 }
108 
AddProfileEvent(const ProfileEvent & event)109 void ProfileEventCallback::AddProfileEvent(const ProfileEvent &event)
110 {
111     auto ret = profileEvents_.insert(event);
112     if (!ret.second) {
113         FI_HILOGW("Profile event is duplicate");
114     }
115 }
116 
RemoveProfileEvents(const std::list<ProfileEvent> & profileEvents)117 void ProfileEventCallback::RemoveProfileEvents(const std::list<ProfileEvent> &profileEvents)
118 {
119     for (const auto &event : profileEvents) {
120         profileEvents_.erase(event);
121     }
122 }
123 
FusionDeviceProfileAdapter()124 FusionDeviceProfileAdapter::FusionDeviceProfileAdapter()
125 {}
126 
~FusionDeviceProfileAdapter()127 FusionDeviceProfileAdapter::~FusionDeviceProfileAdapter()
128 {}
129 
UpdateCrossSwitchState(bool switchState)130 int32_t FusionDeviceProfileAdapter::UpdateCrossSwitchState(bool switchState)
131 {
132     CALL_DEBUG_ENTER;
133     const std::string SERVICE_TYPE = "deviceStatus";
134     ServiceCharacteristicProfile profile;
135     profile.SetServiceId(SERVICE_ID);
136     profile.SetServiceType(SERVICE_TYPE);
137     cJSON* data = cJSON_CreateObject();
138     CHKPR(data, RET_ERR);
139     cJSON_AddItemToObject(data, characteristicsName_.c_str(), cJSON_CreateNumber(switchState));
140     char* smsg = cJSON_Print(data);
141     cJSON_Delete(data);
142     CHKPR(smsg, RET_ERR);
143     profile.SetCharacteristicProfileJson(smsg);
144     cJSON_free(smsg);
145     return DistributedDeviceProfileClient::GetInstance().PutDeviceProfile(profile);
146 }
147 
SyncCrossSwitchState(bool switchState,const std::vector<std::string> & deviceIds)148 int32_t FusionDeviceProfileAdapter::SyncCrossSwitchState(bool switchState, const std::vector<std::string> &deviceIds)
149 {
150     CALL_DEBUG_ENTER;
151     const std::string SERVICE_TYPE = "deviceStatus";
152     ServiceCharacteristicProfile profile;
153     profile.SetServiceId(SERVICE_ID);
154     profile.SetServiceType(SERVICE_TYPE);
155     cJSON* data = cJSON_CreateObject();
156     CHKPR(data, RET_ERR);
157     cJSON_AddItemToObject(data, characteristicsName_.c_str(), cJSON_CreateNumber(switchState));
158     char* smsg = cJSON_Print(data);
159     cJSON_Delete(data);
160     CHKPR(smsg, RET_ERR);
161     profile.SetCharacteristicProfileJson(smsg);
162     cJSON_free(smsg);
163 
164     int32_t ret = DistributedDeviceProfileClient::GetInstance().PutDeviceProfile(profile);
165     if (ret != 0) {
166         FI_HILOGE("Put device profile failed, ret:%{public}d", ret);
167         return ret;
168     }
169     return ret;
170 }
171 
GetCrossSwitchState(const std::string & deviceId)172 bool FusionDeviceProfileAdapter::GetCrossSwitchState(const std::string &deviceId)
173 {
174     CALL_DEBUG_ENTER;
175     ServiceCharacteristicProfile profile;
176 
177     DistributedDeviceProfileClient::GetInstance().GetDeviceProfile(deviceId, SERVICE_ID, profile);
178     std::string jsonData = profile.GetCharacteristicProfileJson();
179     JsonParser parser;
180     parser.json = cJSON_Parse(jsonData.c_str());
181     if (!cJSON_IsObject(parser.json)) {
182         FI_HILOGE("parser json is not object");
183         return false;
184     }
185     cJSON* state = cJSON_GetObjectItemCaseSensitive(parser.json, characteristicsName_.c_str());
186     if (!cJSON_IsNumber(state)) {
187         FI_HILOGE("State is not number type");
188         return false;
189     }
190     return (static_cast<bool>(state->valueint));
191 }
192 
RegisterCrossStateListener(const std::string & deviceId,const std::shared_ptr<ProfileEventCallback> & callback)193 int32_t FusionDeviceProfileAdapter::RegisterCrossStateListener(const std::string &deviceId,
194     const std::shared_ptr<ProfileEventCallback> &callback)
195 {
196     CALL_DEBUG_ENTER;
197     CHKPR(callback, RET_ERR);
198     std::list<std::string> serviceIds;
199     serviceIds.emplace_back(SERVICE_ID);
200 
201     ExtraInfo extraInfo;
202     extraInfo["deviceId"] = deviceId;
203     extraInfo["serviceIds"] = serviceIds;
204 
205     SubscribeInfo changeEventInfo;
206     changeEventInfo.profileEvent = ProfileEvent::EVENT_PROFILE_CHANGED;
207     changeEventInfo.extraInfo = std::move(extraInfo);
208 
209     std::list<SubscribeInfo> subscribeInfos;
210     subscribeInfos.emplace_back(changeEventInfo);
211 
212     SubscribeInfo syncEventInfo;
213     syncEventInfo.profileEvent = ProfileEvent::EVENT_SYNC_COMPLETED;
214     subscribeInfos.emplace_back(syncEventInfo);
215 
216     SaveSubscribeInfos(deviceId, callback, subscribeInfos);
217 
218     if (subscribeInfos.empty()) {
219         FI_HILOGI("Profile events have been subscribed");
220         return RET_ERR;
221     }
222 
223     std::list<ProfileEvent> failedEvents;
224     return DistributedDeviceProfileClient::GetInstance().SubscribeProfileEvents(
225         subscribeInfos, callback, failedEvents);
226 }
227 
UnregisterCrossStateListener(const std::string & deviceId)228 int32_t FusionDeviceProfileAdapter::UnregisterCrossStateListener(const std::string &deviceId)
229 {
230     CALL_DEBUG_ENTER;
231     auto cbIter = callbacks_.find(deviceId);
232     if (cbIter == callbacks_.end()) {
233         FI_HILOGW("This device is not exists");
234         return RET_OK;
235     }
236     std::list<ProfileEvent> profileEvents;
237     profileEvents.emplace_back(ProfileEvent::EVENT_PROFILE_CHANGED);
238     std::list<ProfileEvent> failedEvents;
239     int32_t ret = DistributedDeviceProfileClient::GetInstance().UnsubscribeProfileEvents(profileEvents,
240         cbIter->second, failedEvents);
241     callbacks_.erase(cbIter);
242     return ret;
243 }
244 
SaveSubscribeInfos(const std::string & deviceId,const std::shared_ptr<ProfileEventCallback> & callback,std::list<SubscribeInfo> & subscribeInfos)245 void FusionDeviceProfileAdapter::SaveSubscribeInfos(const std::string &deviceId,
246     const std::shared_ptr<ProfileEventCallback> &callback, std::list<SubscribeInfo> &subscribeInfos)
247 {
248     CALL_DEBUG_ENTER;
249     std::shared_ptr<ProfileEventCallback> profileEventCb;
250     auto cbIter = callbacks_.find(deviceId);
251     if ((cbIter == callbacks_.end()) || (cbIter->second == nullptr)) {
252         if (callback == nullptr) {
253             subscribeInfos.clear();
254             FI_HILOGE("Find callback for device %{public}s failed, and the given callback is nullptr",
255                 GetAnonyString(deviceId).c_str());
256             return;
257         }
258         callbacks_.insert_or_assign(deviceId, callback);
259         profileEventCb = callback;
260     } else {
261         profileEventCb = cbIter->second;
262     }
263 
264     for (auto iter = subscribeInfos.begin(); iter != subscribeInfos.end();) {
265         if (profileEventCb->SupportProfileEvent(iter->profileEvent)) {
266             iter = subscribeInfos.erase(iter);
267         } else {
268             ++iter;
269         }
270     }
271 }
272 
RemoveFailedSubscriptions(const std::string & deviceId,const std::list<ProfileEvent> & failedEvents)273 void FusionDeviceProfileAdapter::RemoveFailedSubscriptions(const std::string &deviceId,
274     const std::list<ProfileEvent> &failedEvents)
275 {
276     CALL_DEBUG_ENTER;
277     std::shared_ptr<IProfileEventCallback> profileEventCb;
278     auto cbIter = callbacks_.find(deviceId);
279     if (cbIter == callbacks_.end()) {
280         FI_HILOGW("This device is not exists");
281         return;
282     }
283     if (cbIter->second == nullptr) {
284         callbacks_.erase(cbIter);
285         FI_HILOGW("This device is not exists");
286         return;
287     }
288 
289     cbIter->second->RemoveProfileEvents(failedEvents);
290     if (!cbIter->second->HasProfileEvent()) {
291         callbacks_.erase(deviceId);
292     }
293 }
294 
UpdateCrossSwitchState(size_t switchState)295 int32_t UpdateCrossSwitchState(size_t switchState)
296 {
297     CALL_DEBUG_ENTER;
298     return DelayedRefSingleton<FusionDeviceProfileAdapter>::GetInstance().UpdateCrossSwitchState(
299         static_cast<bool>(switchState));
300 }
301 
SyncCrossSwitchState(size_t switchState,CIStringVector * deviceIds)302 int32_t SyncCrossSwitchState(size_t switchState, CIStringVector* deviceIds)
303 {
304     CALL_DEBUG_ENTER;
305     CHKPR(deviceIds, RET_ERR);
306     CHKPR(deviceIds->get, RET_ERR);
307     CHKPR(deviceIds->getSize, RET_ERR);
308     std::vector<std::string> deviceId;
309 
310     for (size_t i = 0; i < deviceIds->getSize(deviceIds); ++i) {
311         const char* device_id = deviceIds->get(deviceIds, i);
312         CHKPR(device_id, RET_ERR);
313         deviceId.emplace_back(std::string(device_id));
314     }
315     return DelayedRefSingleton<FusionDeviceProfileAdapter>::GetInstance().SyncCrossSwitchState(
316         static_cast<bool>(switchState), deviceId);
317 }
318 
GetCrossSwitchState(const char * deviceId)319 int32_t GetCrossSwitchState(const char* deviceId)
320 {
321     CALL_DEBUG_ENTER;
322     CHKPR(deviceId, RET_ERR);
323     bool switchState =
324         DelayedRefSingleton<FusionDeviceProfileAdapter>::GetInstance().GetCrossSwitchState(std::string(deviceId));
325     return (static_cast<int32_t>(switchState));
326 }
327 
RegisterCrossStateListener(const char * deviceId,CICrossStateListener * listener)328 int32_t RegisterCrossStateListener(const char* deviceId, CICrossStateListener* listener)
329 {
330     CALL_DEBUG_ENTER;
331     CHKPR(deviceId, RET_ERR);
332     CHKPR(listener, RET_ERR);
333     auto profileCallback = std::make_shared<ProfileEventCallback>(listener);
334     return DelayedRefSingleton<FusionDeviceProfileAdapter>::GetInstance().RegisterCrossStateListener(
335         std::string(deviceId), profileCallback);
336 }
337 
UnregisterCrossStateListener(const char * deviceId)338 int32_t UnregisterCrossStateListener(const char* deviceId)
339 {
340     CALL_DEBUG_ENTER;
341     CHKPR(deviceId, RET_ERR);
342     return DelayedRefSingleton<FusionDeviceProfileAdapter>::GetInstance().UnregisterCrossStateListener(
343         std::string(deviceId));
344 }
345