Add update of GenlistItem fields when text and description are changed
[profile/mobile/apps/native/accessibility-setting.git] / src / setting-accessibility-universal-switch-dbus.cpp
1 /*
2  * Copyright 2018 Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *  http://www.apache.org/licenses/LICENSE-2.0
9
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "setting-accessibility-universal-switch-dbus.h"
18
19 #include "AccessibilitySettingLog.hpp"
20 #include "setting-accessibility.h"
21
22 #define BUS "org.tizen.UniversalSwitch"
23 #define PATH "/org/tizen/UniversalSwitch"
24 #define IFACE "org.tizen.UniversalSwitch"
25 #define ELDBUS_TIMEOUT 400.0
26
27 static void __bus_name_acquired(void *data, const char *bus, const char *old_id, const char *new_id);
28
29 static Eina_Bool __eldbus_init(UniversalSwitchDbusConfig *config)
30 {
31         UniversalSwitchEldbus *eldbus = &config->eldbus;
32         eldbus->dobj = NULL;
33         eldbus->proxy = NULL;
34         eldbus->capture_switch_request = NULL;
35
36         eldbus->is_init = eldbus_init();
37         if (!eldbus->is_init) {
38                 ERROR("DBus initialization failed");
39                 return EINA_FALSE;
40         }
41
42         if (!(eldbus->conn = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SESSION))) {
43                 ERROR("Connection to session bus failed");
44                 return EINA_FALSE;
45         }
46
47         eldbus_name_owner_changed_callback_add(eldbus->conn, BUS, __bus_name_acquired, config, EINA_TRUE);
48
49         return EINA_TRUE;
50 }
51
52 static void __eldbus_shutdown(UniversalSwitchDbusConfig *config)
53 {
54         UniversalSwitchEldbus *eldbus = &config->eldbus;
55
56         if (!eldbus->is_init)
57                 return;
58
59         if (eldbus->conn)
60                 eldbus_name_owner_changed_callback_del(eldbus->conn, BUS, __bus_name_acquired, config);
61
62         if (eldbus->capture_switch_request)
63                 eldbus_pending_cancel(eldbus->capture_switch_request);
64         eldbus->capture_switch_request = NULL;
65
66         if (eldbus->proxy)
67                 eldbus_proxy_unref(eldbus->proxy);
68         eldbus->proxy = NULL;
69
70         if (eldbus->dobj)
71                 eldbus_object_unref(eldbus->dobj);
72         eldbus->dobj = NULL;
73
74         if (eldbus->conn)
75                 eldbus_connection_unref(eldbus->conn);
76         eldbus->conn = NULL;
77
78         eldbus_shutdown();
79 }
80
81 static void __eldbus_getInfoArray(std::vector<UniversalSwitchInfoType *> &infoTypes, Eldbus_Message *reply)
82 {
83         Eldbus_Message_Iter *array;
84         Eldbus_Message_Iter *struct_sss;
85         if (!eldbus_message_arguments_get(reply, "a(sss)", &array)) {
86                 ERROR("Error on eldbus_message_arguments_get()");
87                 return;
88         }
89         while (eldbus_message_iter_get_and_next(array, 'r', &struct_sss)) {
90                 char *id = NULL;
91                 char *name = NULL;
92                 char *description = NULL;
93                 if (!eldbus_message_iter_arguments_get(struct_sss, "sss", &id, &name, &description)) {
94                         ERROR("Error on eldbus_message_arguments_get()");
95                         return;
96                 }
97                 auto info = new UniversalSwitchInfoType;
98
99                 info->id = id;
100                 info->name = name;
101                 info->description = description;
102                 infoTypes.push_back(info);
103         }
104 }
105
106 static std::vector<UniversalSwitchInfoType *> __eldbus_getAllSwitchesByProviderId(
107         UniversalSwitchEldbus *eldbus,
108         const std::string &provider_id)
109 {
110         Eldbus_Message *req = NULL;
111         Eldbus_Message *reply = NULL;
112         Eldbus_Message_Iter *iter = NULL;
113         const char *errname = NULL;
114         const char *errmsg = NULL;
115
116         if (!(req = eldbus_proxy_method_call_new(eldbus->proxy, "getAllSwitchesByProviderId"))) {
117                 ERROR("Failed to create method call on " IFACE ".getAllSwitchesByProviderId");
118                 return {};
119         }
120         iter = eldbus_message_iter_get(req);
121         eldbus_message_iter_arguments_append(iter, "s", provider_id.c_str());
122
123         std::vector<UniversalSwitchInfoType *> switches;
124         reply = eldbus_proxy_send_and_block(eldbus->proxy, req, ELDBUS_TIMEOUT);
125         if (!reply || eldbus_message_error_get(reply, &errname, &errmsg))
126                 ERROR("Unable to call method " IFACE ".getAllSwitchesByProviderId: %s %s", errname, errmsg);
127         else
128                 __eldbus_getInfoArray(switches, reply);
129
130         if (reply)
131                 eldbus_message_unref(reply);
132
133         return switches;
134 }
135
136 static std::vector<UniversalSwitchSwitchProvider *> __eldbus_getAllSwitchProviders(UniversalSwitchEldbus *eldbus)
137 {
138         Eldbus_Message *req = NULL;
139         Eldbus_Message *reply = NULL;
140         const char *errname = NULL;
141         const char *errmsg = NULL;
142
143         if (!(req = eldbus_proxy_method_call_new(eldbus->proxy, "getAllSwitchProviders"))) {
144                 ERROR("Failed to create method call on " IFACE ".getAllSwitchProviders");
145                 return {};
146         }
147
148         std::vector<UniversalSwitchSwitchProvider *> switch_providers;
149         reply = eldbus_proxy_send_and_block(eldbus->proxy, req, ELDBUS_TIMEOUT);
150         if (!reply || eldbus_message_error_get(reply, &errname, &errmsg)) {
151                 ERROR("Unable to call method " IFACE ".getAllSwitchProviders: %s %s", errname, errmsg);
152
153         } else {
154                 std::vector<UniversalSwitchInfoType *> switch_providers_info;
155                 if (true) {
156                         __eldbus_getInfoArray(switch_providers_info, reply);
157
158                         for (auto &it : switch_providers_info) {
159                                 auto switch_provider = new UniversalSwitchSwitchProvider;
160                                 switch_provider->info = it;
161                                 switch_provider->switches = __eldbus_getAllSwitchesByProviderId(eldbus, it->id);
162                                 switch_providers.push_back(switch_provider);
163                         }
164                 } else
165                         ERROR("Switch Providers could not be initialized!");
166         }
167
168         if (reply)
169                 eldbus_message_unref(reply);
170
171         return switch_providers;
172 }
173
174 static std::vector<UniversalSwitchInfoType *> __eldbus_getBindableActivityTypes(UniversalSwitchEldbus *eldbus)
175 {
176         Eldbus_Message *req = NULL;
177         Eldbus_Message *reply = NULL;
178         const char *errname = NULL;
179         const char *errmsg = NULL;
180
181         if (!(req = eldbus_proxy_method_call_new(eldbus->proxy, "getBindableActivityTypes"))) {
182                 ERROR("Failed to create method call on " IFACE ".getBindableActivityTypes");
183                 return {};
184         }
185
186         std::vector<UniversalSwitchInfoType *> activity_types;
187         reply = eldbus_proxy_send_and_block(eldbus->proxy, req, ELDBUS_TIMEOUT);
188         if (!reply || eldbus_message_error_get(reply, &errname, &errmsg)) {
189                 ERROR("Unable to call method " IFACE ".getBindableActivityTypes: %s %s", errname, errmsg);
190         } else {
191                 __eldbus_getInfoArray(activity_types, reply);
192         }
193
194         if (reply)
195                 eldbus_message_unref(reply);
196
197         return activity_types;
198 }
199
200 static void __eldbus_getAllSwitchConfigurationItemsArray(
201         std::vector<UniversalSwitchConfigurationItem *> &infoTypes,
202         Eldbus_Message *reply)
203 {
204
205         Eldbus_Message_Iter *array;
206         Eldbus_Message_Iter *struct_sssi;
207
208         if (!eldbus_message_arguments_get(reply, "a(sssi)", &array)) {
209                 ERROR("Error on eldbus_message_arguments_get()");
210                 return;
211         }
212         while (eldbus_message_iter_get_and_next(array, 'r', &struct_sssi)) {
213                 char *switchId;
214                 char *userName;
215                 char *activityType;
216                 int changeType;
217
218                 if (!eldbus_message_iter_arguments_get(struct_sssi, "sssi", &switchId, &userName, &activityType, &changeType)) {
219                         ERROR("Error on eldbus_message_arguments_get()\n");
220                         return;
221                 }
222                 char *pointer_to_end_of_switch_provider_str = strstr(switchId, "_");
223                 if (!pointer_to_end_of_switch_provider_str) {
224                         ERROR("Wrong switch ID format");
225                         return;
226                 }
227                 size_t provider_id_size = pointer_to_end_of_switch_provider_str - switchId;
228                 auto item = new UniversalSwitchConfigurationItem;
229                 item->provider_id = std::string{switchId, provider_id_size};
230                 item->switch_id = switchId;
231                 item->user_name = userName;
232                 item->activity_type = activityType;
233                 infoTypes.push_back(item);
234         }
235 }
236
237 static std::vector<UniversalSwitchConfigurationItem *> __eldbus_getAllSwitchConfigurationItems(UniversalSwitchEldbus *eldbus)
238 {
239         Eldbus_Message *req = NULL;
240         Eldbus_Message *reply = NULL;
241         const char *errname = NULL;
242         const char *errmsg = NULL;
243
244         if (!(req = eldbus_proxy_method_call_new(eldbus->proxy, "getAllSwitchConfigurationItems"))) {
245                 ERROR("Failed to create method call on " IFACE ".getAllSwitchConfigurationItems");
246                 return {};
247         }
248
249         std::vector<UniversalSwitchConfigurationItem *> configurationItems;
250         reply = eldbus_proxy_send_and_block(eldbus->proxy, req, ELDBUS_TIMEOUT);
251         if (!reply || eldbus_message_error_get(reply, &errname, &errmsg)) {
252                 ERROR("Unable to call method " IFACE ".getAllSwitchConfigurationItems: %s %s", errname, errmsg);
253         } else {
254                 __eldbus_getAllSwitchConfigurationItemsArray(configurationItems, reply);
255         }
256
257         if (reply)
258                 eldbus_message_unref(reply);
259
260         return configurationItems;
261 }
262
263 static void __relese_configuration_items(UniversalSwitchDbusConfig *config)
264 {
265         for (auto &it : config->configuration_items) {
266                 delete it;
267         }
268
269         config->configuration_items = {};
270 }
271
272 static void __relese_info_type(UniversalSwitchInfoType *info)
273 {
274         if (!info)
275                 return;
276
277         delete info;
278 }
279
280 static void __relese_info_type_array(std::vector<UniversalSwitchInfoType *> &infoArray)
281 {
282         for (auto &it : infoArray)
283                 delete it;
284
285         infoArray = {};
286 }
287
288 static void __relese_activity_types(UniversalSwitchDbusConfig *config)
289 {
290         if (config->activity_types.empty())
291                 return;
292
293         __relese_info_type_array(config->activity_types);
294         config->activity_types = {};
295 }
296
297 static void __relese_switch_providers(UniversalSwitchDbusConfig *config)
298 {
299         if (config->switch_providers.empty())
300                 return;
301
302         for (auto &it : config->switch_providers) {
303                 __relese_info_type(it->info);
304                 __relese_info_type_array(it->switches);
305                 delete it;
306         }
307
308         config->switch_providers = {};
309 }
310
311 static void __update_configuration_items(UniversalSwitchDbusConfig *config)
312 {
313         __relese_configuration_items(config);
314         config->configuration_items = __eldbus_getAllSwitchConfigurationItems(&config->eldbus);
315 }
316
317 static void __bus_name_acquired(void *data, const char *bus, const char *old_id, const char *new_id)
318 {
319         DEBUG("dbus name acquired, bus=%s, old_id=%s, new_id=%s", bus, old_id, new_id);
320
321         if (!new_id || strlen(new_id) == 0)
322                 return;
323
324         auto config = static_cast<UniversalSwitchDbusConfig *>(data);
325         UniversalSwitchEldbus *eldbus = &config->eldbus;
326
327         if (!eldbus->dobj && !(eldbus->dobj = eldbus_object_get(eldbus->conn, BUS, PATH))) {
328                 ERROR("Failed to create eldbus object for " PATH);
329                 return;
330         }
331
332         if (!eldbus->proxy && !(eldbus->proxy = eldbus_proxy_get(eldbus->dobj, IFACE))) {
333                 ERROR("Failed to create proxy object for " IFACE);
334                 return;
335         }
336
337         config->activity_types = __eldbus_getBindableActivityTypes(&config->eldbus);
338         config->switch_providers = __eldbus_getAllSwitchProviders(&config->eldbus);
339         __update_configuration_items(config);
340
341         if (eldbus->init_done_callback) {
342                 eldbus->init_done_callback(eldbus->init_done_callback_data);
343                 eldbus->init_done_callback = NULL;
344                 eldbus->init_done_callback_data = NULL;
345         }
346 }
347
348 Eina_Bool setting_accessibility_universal_switch_dbus_config_init(
349         UniversalSwitchDbusConfig *config,
350         init_done_cb callback,
351         void *callback_data)
352 {
353
354         config->eldbus.init_done_callback = callback;
355         config->eldbus.init_done_callback_data = callback_data;
356         Eina_Bool v = __eldbus_init(config);
357
358         return v;
359 }
360
361 int setting_accessibility_universal_switch_dbus_config_get_switch_count(UniversalSwitchDbusConfig *config)
362 {
363         return config->configuration_items.size();
364 }
365
366 void setting_accessibility_universal_switch_dbus_config_addSwitchConfigurationItem(
367         UniversalSwitchDbusConfig *config,
368         const std::string &switch_id,
369         const std::string &user_name,
370         const std::string &activity_type)
371 {
372         DEBUG("Running " IFACE ".addSwitchConfigurationItem(%s, %s ,%s)", switch_id.c_str(), user_name.c_str(), activity_type.c_str());
373         eldbus_proxy_call(
374                 config->eldbus.proxy, "addSwitchConfigurationItem", NULL, NULL, ELDBUS_TIMEOUT, "sss", switch_id.c_str(), user_name.c_str(), activity_type.c_str());
375         __update_configuration_items(config);
376 }
377 void setting_accessibility_universal_switch_dbus_config_updateSwitchConfigurationItem(
378         UniversalSwitchDbusConfig *config,
379         const std::string &switch_id,
380         const std::string &user_name,
381         const std::string &activity_type)
382 {
383         DEBUG("Running " IFACE ".updateSwitchConfigurationItem(%s, %s ,%s)", switch_id.c_str(), user_name.c_str(), activity_type.c_str());
384         eldbus_proxy_call(
385                 config->eldbus.proxy, "updateSwitchConfigurationItem", NULL, NULL, ELDBUS_TIMEOUT, "sss", switch_id.c_str(), user_name.c_str(), activity_type.c_str());
386         __update_configuration_items(config);
387 }
388
389 void setting_accessibility_universal_switch_dbus_config_removeSwitchConfigurationItem(
390         UniversalSwitchDbusConfig *config,
391         const std::string &switch_id)
392 {
393         DEBUG("Running " IFACE ".removeSwitchConfigurationItem(%s)", switch_id.c_str());
394         eldbus_proxy_call(config->eldbus.proxy, "removeSwitchConfigurationItem", NULL, NULL, ELDBUS_TIMEOUT, "s", switch_id.c_str());
395         __update_configuration_items(config);
396 }
397
398 void setting_accessibility_universal_switch_dbus_config_shutdown(UniversalSwitchDbusConfig *config)
399 {
400         __relese_configuration_items(config);
401         __relese_activity_types(config);
402         __relese_switch_providers(config);
403         __eldbus_shutdown(config);
404 }
405
406 std::string setting_accessibility_universal_switch_dbus_config_get_activity_name(
407         UniversalSwitchDbusConfig *config,
408         const std::string &activity_id)
409 {
410         for (auto &it : config->activity_types)
411                 if (it->id == activity_id)
412                         return it->name;
413
414         return {};
415 }
416 std::vector<UniversalSwitchInfoType *> setting_accessibility_universal_switch_dbus_config_get_switches(
417         UniversalSwitchDbusConfig *config,
418         const std::string &provider_id)
419 {
420         for (auto &it : config->switch_providers)
421                 if (it->info->id == provider_id)
422                         return it->switches;
423         return {};
424 }
425
426 static void __eldbus_on_capture_switch(void *data EINA_UNUSED, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED)
427 {
428         auto eldbus = static_cast<UniversalSwitchEldbus *>(data);
429         const char *errname, *errmsg;
430         const char *switch_id = NULL;
431
432         if (eldbus_message_error_get(msg, &errname, &errmsg)) {
433                 DEBUG("Error: %s %s", errname, errmsg);
434         } else {
435                 if (!eldbus_message_arguments_get(msg, "s", &switch_id))
436                         ERROR("Could not get switch_id");
437         }
438
439         DEBUG("DBus got captureSwitch %s", switch_id);
440
441         if (eldbus->capture_switch_callback) {
442                 eldbus->capture_switch_callback(eldbus->capture_switch_data, switch_id);
443                 eldbus->capture_switch_callback = NULL;
444         }
445         eldbus->capture_switch_request = NULL;
446 }
447
448 void setting_accessibility_universal_switch_dbus_config_captureSwitch(
449         UniversalSwitchDbusConfig *config,
450         const std::string &provider_id,
451         double timeout,
452         capture_switch_cb callback,
453         void *callback_data)
454 {
455         UniversalSwitchEldbus *eldbus = &config->eldbus;
456         DEBUG("DBus call captureSwitch for %s", provider_id.c_str());
457         eldbus->capture_switch_request = eldbus_proxy_call(
458                 eldbus->proxy, "captureSwitch", __eldbus_on_capture_switch, eldbus, timeout, "s", provider_id.c_str());
459         if (eldbus->capture_switch_request) {
460                 eldbus->capture_switch_callback = callback;
461                 eldbus->capture_switch_data = callback_data;
462         } else {
463                 ERROR("Dbus call to captureSwitch failed");
464         }
465 }
466
467 void setting_accessibility_universal_switch_dbus_config_cancelCaptureSwitch(UniversalSwitchDbusConfig *config)
468 {
469         UniversalSwitchEldbus *eldbus = &config->eldbus;
470
471         DEBUG("Running " IFACE ".cancelCaptureSwitch");
472         eldbus_proxy_call(config->eldbus.proxy, "cancelCaptureSwitch", NULL, NULL, ELDBUS_TIMEOUT, "");
473
474         DEBUG("DBus call captureSwitch canceled");
475         eldbus->capture_switch_callback = NULL;
476         if (eldbus->capture_switch_request) {
477                 eldbus_pending_cancel(eldbus->capture_switch_request);
478                 eldbus->capture_switch_request = NULL;
479         }
480 }