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(jsonData.c_str());
180 if (!cJSON_IsObject(parser.Get())) {
181 FI_HILOGE("parser json is not object");
182 return false;
183 }
184 cJSON* state = cJSON_GetObjectItemCaseSensitive(parser.Get(), characteristicsName_.c_str());
185 if (!cJSON_IsNumber(state)) {
186 FI_HILOGE("State is not number type");
187 return false;
188 }
189 return (static_cast<bool>(state->valueint));
190 }
191
RegisterCrossStateListener(const std::string & deviceId,const std::shared_ptr<ProfileEventCallback> & callback)192 int32_t FusionDeviceProfileAdapter::RegisterCrossStateListener(const std::string &deviceId,
193 const std::shared_ptr<ProfileEventCallback> &callback)
194 {
195 CALL_DEBUG_ENTER;
196 CHKPR(callback, RET_ERR);
197 std::list<std::string> serviceIds;
198 serviceIds.emplace_back(SERVICE_ID);
199
200 ExtraInfo extraInfo;
201 extraInfo["deviceId"] = deviceId;
202 extraInfo["serviceIds"] = serviceIds;
203
204 SubscribeInfo changeEventInfo;
205 changeEventInfo.profileEvent = ProfileEvent::EVENT_PROFILE_CHANGED;
206 changeEventInfo.extraInfo = std::move(extraInfo);
207
208 std::list<SubscribeInfo> subscribeInfos;
209 subscribeInfos.emplace_back(changeEventInfo);
210
211 SubscribeInfo syncEventInfo;
212 syncEventInfo.profileEvent = ProfileEvent::EVENT_SYNC_COMPLETED;
213 subscribeInfos.emplace_back(syncEventInfo);
214
215 SaveSubscribeInfos(deviceId, callback, subscribeInfos);
216
217 if (subscribeInfos.empty()) {
218 FI_HILOGI("Profile events have been subscribed");
219 return RET_ERR;
220 }
221
222 std::list<ProfileEvent> failedEvents;
223 return DistributedDeviceProfileClient::GetInstance().SubscribeProfileEvents(
224 subscribeInfos, callback, failedEvents);
225 }
226
UnregisterCrossStateListener(const std::string & deviceId)227 int32_t FusionDeviceProfileAdapter::UnregisterCrossStateListener(const std::string &deviceId)
228 {
229 CALL_DEBUG_ENTER;
230 auto cbIter = callbacks_.find(deviceId);
231 if (cbIter == callbacks_.end()) {
232 FI_HILOGW("This device is not exists");
233 return RET_OK;
234 }
235 std::list<ProfileEvent> profileEvents;
236 profileEvents.emplace_back(ProfileEvent::EVENT_PROFILE_CHANGED);
237 std::list<ProfileEvent> failedEvents;
238 int32_t ret = DistributedDeviceProfileClient::GetInstance().UnsubscribeProfileEvents(profileEvents,
239 cbIter->second, failedEvents);
240 callbacks_.erase(cbIter);
241 return ret;
242 }
243
SaveSubscribeInfos(const std::string & deviceId,const std::shared_ptr<ProfileEventCallback> & callback,std::list<SubscribeInfo> & subscribeInfos)244 void FusionDeviceProfileAdapter::SaveSubscribeInfos(const std::string &deviceId,
245 const std::shared_ptr<ProfileEventCallback> &callback, std::list<SubscribeInfo> &subscribeInfos)
246 {
247 CALL_DEBUG_ENTER;
248 std::shared_ptr<ProfileEventCallback> profileEventCb;
249 auto cbIter = callbacks_.find(deviceId);
250 if ((cbIter == callbacks_.end()) || (cbIter->second == nullptr)) {
251 if (callback == nullptr) {
252 subscribeInfos.clear();
253 FI_HILOGE("Find callback for device %{public}s failed, and the given callback is nullptr",
254 GetAnonyString(deviceId).c_str());
255 return;
256 }
257 callbacks_.insert_or_assign(deviceId, callback);
258 profileEventCb = callback;
259 } else {
260 profileEventCb = cbIter->second;
261 }
262
263 for (auto iter = subscribeInfos.begin(); iter != subscribeInfos.end();) {
264 if (profileEventCb->SupportProfileEvent(iter->profileEvent)) {
265 iter = subscribeInfos.erase(iter);
266 } else {
267 ++iter;
268 }
269 }
270 }
271
RemoveFailedSubscriptions(const std::string & deviceId,const std::list<ProfileEvent> & failedEvents)272 void FusionDeviceProfileAdapter::RemoveFailedSubscriptions(const std::string &deviceId,
273 const std::list<ProfileEvent> &failedEvents)
274 {
275 CALL_DEBUG_ENTER;
276 std::shared_ptr<IProfileEventCallback> profileEventCb;
277 auto cbIter = callbacks_.find(deviceId);
278 if (cbIter == callbacks_.end()) {
279 FI_HILOGW("This device is not exists");
280 return;
281 }
282 if (cbIter->second == nullptr) {
283 callbacks_.erase(cbIter);
284 FI_HILOGW("This device is not exists");
285 return;
286 }
287
288 cbIter->second->RemoveProfileEvents(failedEvents);
289 if (!cbIter->second->HasProfileEvent()) {
290 callbacks_.erase(deviceId);
291 }
292 }
293
UpdateCrossSwitchState(size_t switchState)294 int32_t UpdateCrossSwitchState(size_t switchState)
295 {
296 CALL_DEBUG_ENTER;
297 return DelayedRefSingleton<FusionDeviceProfileAdapter>::GetInstance().UpdateCrossSwitchState(
298 static_cast<bool>(switchState));
299 }
300
SyncCrossSwitchState(size_t switchState,CIStringVector * deviceIds)301 int32_t SyncCrossSwitchState(size_t switchState, CIStringVector* deviceIds)
302 {
303 CALL_DEBUG_ENTER;
304 CHKPR(deviceIds, RET_ERR);
305 CHKPR(deviceIds->get, RET_ERR);
306 CHKPR(deviceIds->getSize, RET_ERR);
307 std::vector<std::string> deviceId;
308
309 for (size_t i = 0; i < deviceIds->getSize(deviceIds); ++i) {
310 const char* device_id = deviceIds->get(deviceIds, i);
311 CHKPR(device_id, RET_ERR);
312 deviceId.emplace_back(std::string(device_id));
313 }
314 return DelayedRefSingleton<FusionDeviceProfileAdapter>::GetInstance().SyncCrossSwitchState(
315 static_cast<bool>(switchState), deviceId);
316 }
317
GetCrossSwitchState(const char * deviceId)318 int32_t GetCrossSwitchState(const char* deviceId)
319 {
320 CALL_DEBUG_ENTER;
321 CHKPR(deviceId, RET_ERR);
322 bool switchState =
323 DelayedRefSingleton<FusionDeviceProfileAdapter>::GetInstance().GetCrossSwitchState(std::string(deviceId));
324 return (static_cast<int32_t>(switchState));
325 }
326
RegisterCrossStateListener(const char * deviceId,CICrossStateListener * listener)327 int32_t RegisterCrossStateListener(const char* deviceId, CICrossStateListener* listener)
328 {
329 CALL_DEBUG_ENTER;
330 CHKPR(deviceId, RET_ERR);
331 CHKPR(listener, RET_ERR);
332 auto profileCallback = std::make_shared<ProfileEventCallback>(listener);
333 return DelayedRefSingleton<FusionDeviceProfileAdapter>::GetInstance().RegisterCrossStateListener(
334 std::string(deviceId), profileCallback);
335 }
336
UnregisterCrossStateListener(const char * deviceId)337 int32_t UnregisterCrossStateListener(const char* deviceId)
338 {
339 CALL_DEBUG_ENTER;
340 CHKPR(deviceId, RET_ERR);
341 return DelayedRefSingleton<FusionDeviceProfileAdapter>::GetInstance().UnregisterCrossStateListener(
342 std::string(deviceId));
343 }
344