Unify bundle data in client, mgr, and widget
[platform/core/uifw/voice-control.git] / client / vc_setting_tidl.c
1 /*
2 * Copyright (c) 2011-2015 Samsung Electronics Co., Ltd All Rights Reserved
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 "vc_command.h"
18 #include "vc_setting_tidl.h"
19 #include "vc_setting_proxy.h"
20 #include "vc_main.h"
21
22 #include <vconf.h>
23
24 typedef struct {
25         int pid;
26         bool connected;
27         bool connection_requesting;
28         bool register_notify_callback_invoked;
29
30         rpc_port_proxy_vc_setting_proxy_vc_setting_h rpc_h;
31         rpc_port_proxy_vc_setting_proxy_vc_setting_notify_cb_h notify_cb_h;
32
33         char* engine_appid;
34 } vc_setting_tidl_info_s;
35
36 static GList* g_tidl_infos = NULL;
37
38
39 static vc_setting_tidl_info_s* __get_tidl_info_s(int pid)
40 {
41         // TODO: Hmm.... is this necessary...??
42         GList* iter = NULL;
43         vc_setting_tidl_info_s* info = NULL;
44
45         if (g_list_length(g_tidl_infos) > 0) {
46                 /* Get a first item */
47                 iter = g_list_first(g_tidl_infos);
48
49                 while (NULL != iter) {
50                         info = iter->data;
51
52                         if (info->pid == pid) {
53                                 return info;
54                         }
55
56                         /* Next item */
57                         iter = g_list_next(iter);
58                 }
59         }
60
61         return NULL;
62 }
63
64 static char* __get_engine_appid(void)
65 {
66         char* engine_name = vconf_get_str(VC_ENGINE_DB_DEFAULT);
67         if (NULL == engine_name) {
68                 SLOG(LOG_WARN, TAG_VCC, "[WARNING] Fail to get engine name. Please use default engine name.");
69                 engine_name = strdup("org.tizen.vc-engine-default");
70         }
71
72         char* appid = strdup(engine_name);
73
74         SLOG(LOG_INFO, TAG_VCC, "[INFO] VC engine appid(%s)", appid);
75
76         return appid;
77 }
78
79 static void __on_connected(rpc_port_proxy_vc_setting_proxy_vc_setting_h h, void* user_data)
80 {
81         unsigned int pid = (uintptr_t)user_data;
82
83         vc_setting_tidl_info_s* info = __get_tidl_info_s(pid);
84         RETM_IF(NULL == info, "[ERROR] Fail to get tidl info");
85
86         info->connected = true;
87         info->connection_requesting = false;
88         info->register_notify_callback_invoked = false;
89
90         SLOG(LOG_INFO, TAG_VCC, "[INFO] Connected to server");
91 }
92
93 static void __on_disconnected(rpc_port_proxy_vc_setting_proxy_vc_setting_h h, void* user_data)
94 {
95         unsigned int pid = (uintptr_t)user_data;
96
97         vc_setting_tidl_info_s* info = __get_tidl_info_s(pid);
98         RETM_IF(NULL == info, "[ERROR] Fail to get tidl info");
99
100         info->connected = false;
101         info->connection_requesting = false;
102         info->register_notify_callback_invoked = false;
103
104         /* retry to connect */
105         SLOG(LOG_INFO, TAG_VCC, "[INFO] Disconnected to server");
106 }
107
108 static void __on_rejected(rpc_port_proxy_vc_setting_proxy_vc_setting_h h, void* user_data)
109 {
110         unsigned int pid = (uintptr_t)user_data;
111
112         vc_setting_tidl_info_s* info = __get_tidl_info_s(pid);
113         RETM_IF(NULL == info, "[ERROR] Fail to get tidl info");
114
115         info->connection_requesting = false;
116         info->register_notify_callback_invoked = false;
117
118         SLOG(LOG_INFO, TAG_VCC, "[INFO] Rejected from server(%d)", pid);
119 }
120
121
122 static rpc_port_proxy_vc_setting_proxy_vc_setting_h __create_rpc_port(int pid, const char* engine_app_id)
123 {
124         SLOG(LOG_INFO, TAG_VCC, "[INFO] vc setting __create_rpc_port");
125
126         rpc_port_proxy_vc_setting_proxy_vc_setting_callback_s rpc_callback = {
127                 .connected = __on_connected,
128                 .disconnected = __on_disconnected,
129                 .rejected = __on_rejected
130         };
131
132         rpc_port_proxy_vc_setting_proxy_vc_setting_h handle = NULL;
133         uintptr_t ptr_pid = pid;
134         if (0 != rpc_port_proxy_vc_setting_proxy_vc_setting_create(engine_app_id, &rpc_callback, (void*)ptr_pid, &handle)) {
135                 SLOG(LOG_ERROR, TAG_VCC, "[ERROR] Fail rpc_port_proxy_vc_setting_proxy_vc_setting_create");
136                 return NULL;
137         }
138         SLOG(LOG_DEBUG, TAG_VCC, "[DEBUG] Succeed rpc_port_proxy_vc_setting_proxy_vc_setting_create");
139
140         return handle;
141 }
142
143 static void __request_tidl_connect(vc_setting_tidl_info_s* info)
144 {
145         if (info->connection_requesting) {
146                 SLOG(LOG_INFO, TAG_VCC, "[TIDL] Already connection is requested. Skip to call rpc_port_proxy_vc_setting_proxy_vc_setting_connect().");
147                 return;
148         }
149
150         int ret = rpc_port_proxy_vc_setting_proxy_vc_setting_connect(info->rpc_h);
151         if (0 != ret) {
152                 SLOG(LOG_ERROR, TAG_VCC, "[ERROR] Fail to request connection to stub. ret(%d)", ret);
153                 return;
154         }
155
156         SLOG(LOG_INFO, TAG_VCC, "[INFO] Request connection to stub. ret(%d)", ret);
157         info->connection_requesting = true;
158 }
159
160 static void __notify_cb(void* user_data, int pid, bundle* msg)
161 {
162         // corresponding to listener_event_callback
163         char* method = NULL;
164
165         SLOG(LOG_DEBUG, TAG_VCC, "__notify_cb is invoked pid(%d)", pid);
166
167         bundle_get_str(msg, VC_BUNDLE_METHOD, &method);
168
169         if (0 == strncmp(VCD_METHOD_HELLO, method, strlen(VCD_METHOD_HELLO))) {
170                 SLOG(LOG_DEBUG, TAG_VCC, "[DEBUG] HELLO received");
171         } /* VCD_METHOD_HELLO */
172         else {
173                 SLOG(LOG_ERROR, TAG_VCC, "[ERROR] Invalid msg");
174         }
175 }
176
177 static int __create_notify_callback_handle(vc_setting_tidl_info_s* info)
178 {
179         if (NULL != info->notify_cb_h) {
180                 rpc_port_proxy_vc_setting_proxy_vc_setting_notify_cb_dispose(info->rpc_h, info->notify_cb_h);
181                 info->notify_cb_h = NULL;
182         }
183
184         if (RPC_PORT_ERROR_NONE != rpc_port_proxy_vc_setting_proxy_vc_setting_notify_cb_create(&info->notify_cb_h)) {
185                 return VC_ERROR_OUT_OF_MEMORY;
186         }
187
188         rpc_port_proxy_vc_setting_proxy_vc_setting_notify_cb_set_callback(info->notify_cb_h, __notify_cb, NULL);
189         rpc_port_proxy_vc_setting_proxy_vc_setting_notify_cb_set_once(info->notify_cb_h, false);
190
191         return VC_ERROR_NONE;
192 }
193
194 static int __invoke_register_notify_callback(int pid, vc_setting_tidl_info_s* info)
195 {
196         if (info->register_notify_callback_invoked) {
197                 SLOG(LOG_ERROR, TAG_VCC, "[INFO] Already register callback is invoked");
198                 return VC_ERROR_NONE;
199         }
200
201         int ret = __create_notify_callback_handle(info);
202         if (VC_ERROR_NONE != ret) {
203                 SLOG(LOG_ERROR, TAG_VCC, "[ERROR] Fail to create callback handle. ret(%d)", ret);
204                 return VC_ERROR_OPERATION_FAILED;
205         }
206
207         rpc_port_proxy_vc_setting_proxy_vc_setting_invoke_register_notify_cb(info->rpc_h, pid, info->notify_cb_h);
208         info->register_notify_callback_invoked = true;
209         return VC_ERROR_NONE;
210 }
211
212 int vc_setting_tidl_open_connection()
213 {
214         SLOG(LOG_INFO, TAG_VCC, "[TIDL] vc_setting_tidl_open_connection");
215
216         vc_setting_tidl_info_s* info = (vc_setting_tidl_info_s*)calloc(1, sizeof(vc_setting_tidl_info_s));
217         if (NULL == info) {
218                 SLOG(LOG_ERROR, TAG_VCC, "[TIDL ERROR] Fail to create tidl_info_s");
219                 return VC_ERROR_OUT_OF_MEMORY;
220         }
221
222         int pid = getpid();
223         char* engine_appid = __get_engine_appid();
224
225         info->rpc_h = __create_rpc_port(pid, engine_appid);
226         if (NULL == info->rpc_h) {
227                 SLOG(LOG_ERROR, TAG_VCC, "[TIDL ERROR] Fail to create proxy");
228                 free(info);
229                 return VC_ERROR_OPERATION_FAILED;
230         }
231
232         info->pid = pid;
233         g_tidl_infos = g_list_append(g_tidl_infos, info);
234
235         SLOG(LOG_ERROR, TAG_VCC, "[TIDL] pid(%d) rpc_h(%p), engine_appid(%s)", pid, info->rpc_h, info->engine_appid);
236         return VC_ERROR_NONE;
237
238 }
239
240 int vc_setting_tidl_close_connection()
241 {
242         SLOG(LOG_INFO, TAG_VCC, "[TIDL] vc_setting_tidl_close_connection");
243
244         int pid = getpid();
245         vc_setting_tidl_info_s* info = __get_tidl_info_s(pid);
246         RETVM_IF(NULL == info, VC_ERROR_INVALID_PARAMETER, "[ERROR] Fail to get tidl info");
247
248         if (0 != rpc_port_proxy_vc_setting_proxy_vc_setting_destroy(info->rpc_h)) {
249                 SLOG(LOG_ERROR, TAG_VCC, "[ERROR] Fail to disconnect");
250                 return VC_ERROR_OPERATION_FAILED;
251         }
252
253         info->rpc_h = NULL;
254         info->notify_cb_h = NULL;
255
256         g_tidl_infos = g_list_remove(g_tidl_infos, info);
257         free(info);
258
259         return VC_ERROR_NONE;
260 }
261
262 int vc_setting_tidl_request_hello()
263 {
264         SLOG(LOG_INFO, TAG_VCC, "[TIDL] vc_tidl_request_hello");
265
266         int pid = getpid();
267         vc_setting_tidl_info_s* info = __get_tidl_info_s(pid);
268         RETVM_IF(NULL == info, VC_ERROR_INVALID_PARAMETER, "[ERROR] Fail to get tidl info");
269
270         if (!info->connected) {
271                 SLOG(LOG_ERROR, TAG_VCC, "[ERROR] Not Connected. Call __request_tidl_connect()");
272                 __request_tidl_connect(info);
273                 return VC_ERROR_OPERATION_FAILED;
274         }
275
276         SLOG(LOG_DEBUG, TAG_VCC, ">>>>> VCC Hello");
277         if (VC_ERROR_NONE != __invoke_register_notify_callback(pid, info)) {
278                 SLOG(LOG_ERROR, TAG_VCC, "[ERROR] Fail to invoke register callback");
279                 return VC_ERROR_OPERATION_FAILED;
280         }
281
282         SLOG(LOG_DEBUG, TAG_VCC, "<<<<");
283         return VC_ERROR_NONE;
284
285 }
286
287 static int __covert_unhandled_error(int ret)
288 {
289         if (RPC_PORT_ERROR_IO_ERROR == ret || RPC_PORT_ERROR_OUT_OF_MEMORY == ret) {
290                 return VC_ERROR_OPERATION_FAILED;
291         }
292
293         return ret;
294 }
295
296 int vc_setting_tidl_request_set_language(int pid, const char* language)
297 {
298         SLOG(LOG_INFO, TAG_VCC, "[TIDL] vc_setting_tidl_request_set_language");
299
300         vc_setting_tidl_info_s* info = __get_tidl_info_s(pid);
301         RETVM_IF(NULL == info, VC_ERROR_INVALID_PARAMETER, "[ERROR] Fail to get tidl info");
302         RETVM_IF(false == info->connected, VC_ERROR_OPERATION_FAILED, "[ERROR] Not Connected");
303
304         int ret = rpc_port_proxy_vc_setting_proxy_vc_setting_invoke_set_language(info->rpc_h, pid, language);
305         if (RPC_PORT_ERROR_NONE != ret) {
306                 SLOG(LOG_ERROR, TAG_VCC, ">>>> Request vc setting set language : Fail to invoke message");
307                 return __covert_unhandled_error(ret);
308         }
309
310         SLOG(LOG_DEBUG, TAG_VCC, "@@ vc setting set language : pid(%d), language(%s)", pid, language);
311
312         return VC_ERROR_NONE;
313 }
314