Fix TC-2372 Dialer crashes when BT phone is offline
[profile/ivi/lemolo.git] / tizen / answer_daemon.c
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4 #include <Ecore.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <Eina.h>
8 #include <Evas.h>
9 #include <Elementary.h>
10 #include <Eldbus.h>
11
12 #ifdef HAVE_TIZEN
13 #include <vconf.h>
14 #include <vconf-keys.h>
15 #include <power.h>
16 #include <aul.h>
17 #endif
18 #include "i18n.h"
19
20 #define APP_NAME "org.tizen.answer"
21 #define BUS_NAME "org.tizen.dialer"
22 #define PATH "/"
23 #define RC_IFACE "org.tizen.dialer.Control"
24 #define FREEDESKTOP_IFACE "org.freedesktop.DBus"
25
26 static int _log_domain = -1;
27 #define ERR(...)      EINA_LOG_DOM_ERR(_log_domain, __VA_ARGS__)
28 #define INF(...)      EINA_LOG_DOM_INFO(_log_domain, __VA_ARGS__)
29 #define DBG(...)      EINA_LOG_DOM_DBG(_log_domain, __VA_ARGS__)
30
31 static Eldbus_Connection *bus_conn = NULL;
32
33 typedef struct _Call {
34         const char *line_id, *img, *type, *name;
35 } Call;
36
37 typedef struct _Call_Screen {
38         Evas_Object *win, *layout;
39         Call *call;
40         Eina_Bool screen_visible;
41         Eldbus_Signal_Handler *sig_call_add;
42         Eldbus_Signal_Handler *sig_call_removed;
43         Eldbus_Signal_Handler *sig_name_changed;
44 } Call_Screen;
45
46 static void _set_notification_type(Evas_Object *win, Eina_Bool high)
47 {
48         (void)win;
49         (void)high;
50 }
51
52 static Eina_Bool _phone_locked(void)
53 {
54 #ifdef HAVE_TIZEN
55         int lock;
56         if (vconf_get_int(VCONFKEY_IDLE_LOCK_STATE, &lock) == -1)
57                 return EINA_FALSE;
58
59         if (lock == VCONFKEY_IDLE_LOCK)
60                 return EINA_TRUE;
61
62         return EINA_FALSE;
63 #else
64         return EINA_TRUE; /* always have it to show */
65 #endif
66 }
67
68 static Call *_call_create(Eldbus_Message *msg)
69 {
70         Call *call;
71         const char *img, *name, *id, *type;
72
73         EINA_SAFETY_ON_NULL_RETURN_VAL(msg, NULL);
74
75         if (!eldbus_message_arguments_get(msg, "ssss", &img, &id, &name, &type)) {
76                 ERR("Could not get call create arguments");
77                 return;
78         }
79
80         call = calloc(1, sizeof(Call));
81         EINA_SAFETY_ON_NULL_RETURN_VAL(call, NULL);
82         call->img = eina_stringshare_add(img);
83         call->line_id = eina_stringshare_add(id);
84         call->type = eina_stringshare_add(type);
85         call->name = eina_stringshare_add(name);
86         DBG("c=%p line_id=%s, name=%s, type=%s, img=%s",
87                 call, call->line_id, call->name, call->type, call->img);
88         return call;
89 }
90
91 static void _call_destroy(Call *c)
92 {
93         DBG("c=%p line_id=%s, name=%s, type=%s, img=%s",
94                 c, c->line_id, c->name, c->type, c->img);
95         eina_stringshare_del(c->img);
96         eina_stringshare_del(c->line_id);
97         eina_stringshare_del(c->type);
98         eina_stringshare_del(c->name);
99         free(c);
100 }
101
102 static void _call_screen_show(Call_Screen *cs)
103 {
104         Call *c = cs->call;
105         Evas_Object *icon = NULL;
106
107         INF("Show line_id=%s, name=%s, type=%s",
108                 c->line_id, c->name, c->type);
109
110         _set_notification_type(cs->win, EINA_TRUE);
111         cs->screen_visible = EINA_TRUE;
112         elm_win_raise(cs->win);
113         elm_win_activate(cs->win);
114
115         if (strcmp("", c->name) == 0)
116                 elm_object_part_text_set(cs->layout, "elm.text.name",
117                                                 c->line_id);
118         else
119                 elm_object_part_text_set(cs->layout, "elm.text.name",
120                                                 c->name);
121         icon = elm_icon_add(cs->layout);
122
123         if (strcmp("", c->img) != 0) {
124                 elm_image_file_set(icon, c->img, NULL);
125         } else
126                 elm_icon_standard_set(icon, "no-picture");
127
128         elm_object_part_text_set(cs->layout, "elm.text.state", _("Incoming..."));
129         elm_object_part_text_set(cs->layout, "elm.text.phone.type", c->type);
130         elm_object_part_content_set(cs->layout, "elm.swallow.photo", icon);
131         elm_object_signal_emit(cs->layout, "show,activecall", "gui");
132         evas_object_show(cs->win);
133 #ifdef HAVE_TIZEN
134         //screen can't be off
135         power_lock_state(POWER_STATE_NORMAL, 0);
136 #endif
137 }
138
139 static void _sig_call_added(void *data, Eldbus_Message *msg)
140 {
141         Call_Screen *cs = data;
142         Eina_Bool locked = _phone_locked();
143
144         DBG("previous=%p, visible=%d, locked=%d", cs->call, cs->screen_visible,
145                 locked);
146
147         if (cs->call)
148                 _call_destroy(cs->call);
149         cs->call = _call_create(msg);
150
151         if (!locked)
152                 return;
153
154         _call_screen_show(cs);
155 }
156
157 static void _call_screen_hide(Call_Screen *cs)
158 {
159         INF("hide call");
160         cs->screen_visible = EINA_FALSE;
161         _set_notification_type(cs->win, EINA_FALSE);
162         elm_object_signal_emit(cs->layout, "hide,activecall", "gui");
163         evas_object_hide(cs->win);
164 #ifdef HAVE_TIZEN
165         //screen can go off again
166         power_unlock_state(POWER_STATE_NORMAL);
167 #endif
168 }
169
170 static void _sig_call_removed(void *data, Eldbus_Message *msg __UNUSED__)
171 {
172         Call_Screen *cs = data;
173
174         DBG("previous=%p, visible=%d", cs->call, cs->screen_visible);
175
176         if (cs->call) {
177                 _call_destroy(cs->call);
178                 cs->call = NULL;
179         }
180
181         if (!cs->screen_visible)
182                 return;
183
184         _call_screen_hide(cs);
185 }
186
187 static void _signal_handlers_add(Call_Screen *cs)
188 {
189         cs->sig_call_add = eldbus_signal_handler_add(bus_conn, BUS_NAME,
190                                                         PATH, RC_IFACE,
191                                                         "AddedCall",
192                                                         _sig_call_added,
193                                                         cs);
194         cs->sig_call_removed = eldbus_signal_handler_add(bus_conn,
195                                                                 BUS_NAME, PATH,
196                                                                 RC_IFACE,
197                                                                 "RemovedCall",
198                                                                 _sig_call_removed,
199                                                                 cs);
200 }
201
202 static void _signal_handlers_del(Call_Screen *cs)
203 {
204         if (cs->sig_call_add) {
205                 eldbus_signal_handler_del(cs->sig_call_add);
206                 cs->sig_call_add = NULL;
207         }
208
209         if (cs->sig_call_removed) {
210                 eldbus_signal_handler_del(cs->sig_call_removed);
211                 cs->sig_call_removed = NULL;
212         }
213 }
214
215 static void _daemon_method_call_reply(void *data __UNUSED__, Eldbus_Message *msg,
216                                                 Eldbus_Pending *pending __UNUSED__)
217 {
218         const char *err_name, *err_message;
219
220         if (eldbus_message_error_get(msg, &err_name, &err_message)) {
221                 ERR("Error calling remote method: %s: %s", err_name, err_message);
222                 return;
223         }
224 }
225
226 static void _daemon_method_call_make_with_reply(const char *method,
227                                                 Eldbus_Message_Cb cb,
228                                                 void *data)
229 {
230         Eldbus_Message *msg;
231
232         msg = eldbus_message_method_call_new(BUS_NAME, PATH, RC_IFACE, method);
233         INF("msg=%p name=%s, path=%s, %s.%s()",
234                 msg, BUS_NAME, PATH, RC_IFACE, method);
235         EINA_SAFETY_ON_NULL_RETURN(msg);
236
237         eldbus_connection_send(bus_conn, msg,  cb, data, -1);
238 }
239
240 static void _daemon_method_call_make(const char *method)
241 {
242         _daemon_method_call_make_with_reply(method, _daemon_method_call_reply,
243                                                 NULL);
244 }
245
246 static void _daemon_available_call_reply(void *data, Eldbus_Message *msg,
247                                                 Eldbus_Pending *pending __UNUSED__)
248 {
249         Call_Screen *cs;
250         const char *err_name, *err_message;
251
252         EINA_SAFETY_ON_NULL_RETURN(data);
253
254         cs = data;
255
256         if (eldbus_message_error_get(msg, &err_name, &err_message)) {
257                 ERR("Available call reply error %s: %s",        err_name, err_message);
258                 return;
259         }
260
261         if (cs->call)
262                 _call_destroy(cs->call);
263
264         cs->call = _call_create(msg);
265         _call_screen_show(cs);
266 }
267
268 static void _service_start_reply(void *data, Eldbus_Message *msg,
269                                                 Eldbus_Pending *pending __UNUSED__)
270 {
271         Call_Screen *cs;
272         const char *err_name, *err_message;
273
274         EINA_SAFETY_ON_NULL_RETURN(data);
275
276         cs = data;
277
278         if (eldbus_message_error_get(msg, &err_name, &err_message)) {
279                 ERR("Ofono reply error %s: %s", err_name, err_message);
280                 return;
281         }
282
283         _signal_handlers_add(cs);
284         _daemon_method_call_make_with_reply("GetAvailableCall",
285                                                 _daemon_available_call_reply,
286                                                 cs);
287 }
288
289 static void _has_owner_cb(void *data, Eldbus_Message *msg,
290                                                 Eldbus_Pending *pending __UNUSED__)
291 {
292         Eina_Bool online;
293         Call_Screen *cs;
294         const char *err_name, *err_message;
295
296         EINA_SAFETY_ON_NULL_RETURN(data);
297
298         if (eldbus_message_error_get(msg, &err_name, &err_message)) {
299                 ERR("Error %s: %s",     err_name, err_message);
300                 return;
301         }
302
303         cs = data;
304
305         if (!eldbus_message_arguments_get(msg, "b", &online)) {
306                 ERR("Could not get arguments");
307                 return;
308         }
309
310         if (!online) {
311                 INF("no dialer, start it");
312                 Eldbus_Message *send_msg = eldbus_message_method_call_new(
313                         BUS_NAME, PATH, FREEDESKTOP_IFACE,
314                         "StartServiceByName");
315
316                 if (!send_msg)
317                         return;
318
319                 if (!eldbus_message_arguments_append(send_msg, "si", BUS_NAME, 0))
320                         return;
321
322                 eldbus_connection_send(bus_conn, send_msg, _service_start_reply, (void *) cs, -1);
323                 return;
324         }
325
326         _signal_handlers_add(cs);
327         _daemon_method_call_make_with_reply("GetAvailableCall",
328                                                 _daemon_available_call_reply,
329                                                 cs);
330 }
331
332 static void _name_owner_changed(void *data, Eldbus_Message *msg)
333 {
334         Call_Screen *cs = data;
335         const char *name, *from, *to;
336
337         if (!eldbus_message_arguments_get(msg, "sss", &name, &from, &to)) {
338                 ERR("Could not get NameOwnerChanged arguments");
339                 return;
340         }
341
342         if (strcmp(name, BUS_NAME) != 0)
343                 return;
344
345         if ((to == NULL) || (*to == '\0')) {
346                 INF("missed dialer");
347                 _signal_handlers_del(cs);
348                 return;
349         }
350
351         INF("got new dialer at %s", to);
352         _signal_handlers_add(cs);
353         _daemon_method_call_make_with_reply("GetAvailableCall",
354                                                 _daemon_available_call_reply,
355                                                 cs);
356 }
357
358 static Eina_Bool _dbus_init(Call_Screen *cs)
359 {
360         Eldbus_Message *msg;
361         char *bus_name = BUS_NAME;
362
363         INF("Running on Session bus");
364         bus_conn = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SESSION);
365
366         if (!bus_conn) {
367                 ERR("Could not fetch the DBus session");
368                 return EINA_FALSE;
369         }
370
371         cs->sig_name_changed = eldbus_signal_handler_add(
372                 bus_conn, ELDBUS_FDO_BUS, ELDBUS_FDO_PATH, ELDBUS_FDO_INTERFACE,
373                 "NameOwnerChanged", _name_owner_changed, cs);
374
375         msg = eldbus_message_method_call_new(ELDBUS_FDO_BUS, ELDBUS_FDO_PATH,
376                                                 ELDBUS_FDO_INTERFACE,
377                                                 "NameHasOwner");
378
379         EINA_SAFETY_ON_NULL_RETURN_VAL(msg, EINA_FALSE);
380
381         if (!eldbus_message_arguments_append(msg,"s", bus_name))
382                 goto err_msg;
383
384         eldbus_connection_send(bus_conn, msg, _has_owner_cb, cs, -1);
385
386         return EINA_TRUE;
387 err_msg:
388         eldbus_message_unref(msg);
389         return EINA_FALSE;
390 }
391
392 Evas_Object *gui_layout_add(Evas_Object *parent, const char *style)
393 {
394         Evas_Object *layout = elm_layout_add(parent);
395         if (!elm_layout_theme_set(layout, "layout", "dialer", style)) {
396                 evas_object_del(layout);
397                 return NULL;
398         }
399         return layout;
400 }
401
402 #ifdef HAVE_TIZEN
403 static int _running_apps_iter(const aul_app_info *info, void *data __UNUSED__)
404 {
405         if (strcmp(info->pkg_name, "org.tizen.draglock") == 0)
406                  aul_terminate_pid(info->pid);
407         return 0;
408 }
409 #endif
410
411 static void _phone_unlock_screen(void)
412 {
413         INF("unlock screen");
414 #ifdef HAVE_TIZEN
415         aul_app_get_running_app_info(_running_apps_iter, NULL);
416 #endif
417 }
418
419 static void _slider_pos_changed_cb(void *data, Evas_Object *obj,
420                                         void *event_inf __UNUSED__)
421 {
422         Call_Screen *cs = data;
423         const char *label = elm_actionslider_selected_label_get(obj);
424
425         if (!label)
426                 return;
427
428         if (strcmp(label, "Answer") == 0) {
429                 _daemon_method_call_make("AnswerCall");
430                 elm_actionslider_indicator_pos_set(obj,
431                                                         ELM_ACTIONSLIDER_CENTER);
432                 _phone_unlock_screen();
433                 _call_screen_hide(cs);
434         } else if (strcmp(label, "Hangup") == 0) {
435                 _daemon_method_call_make("HangupCall");
436                 elm_actionslider_indicator_pos_set(obj,
437                                                         ELM_ACTIONSLIDER_CENTER);
438         }
439 }
440
441 static Eina_Bool _gui_init(Call_Screen *cs)
442 {
443         Evas_Object *win, *obj, *lay, *slider;
444         Evas_Coord h, w;
445         char def_theme[PATH_MAX];
446         /* should never, ever quit */
447
448         elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_NONE);
449         elm_app_compile_bin_dir_set(PACKAGE_BIN_DIR);
450         elm_app_compile_data_dir_set(PACKAGE_DATA_DIR);
451         elm_app_info_set(_gui_init, "answer-ofono-efl", "themes/default.edj");
452
453         snprintf(def_theme, sizeof(def_theme), "%s/themes/default.edj",
454                         elm_app_data_dir_get());
455
456         elm_theme_extension_add(NULL, def_theme);
457         elm_theme_overlay_add(NULL, def_theme);
458
459         win = elm_win_util_standard_add("answer screen", "oFono Answer");
460         EINA_SAFETY_ON_NULL_RETURN_VAL(win, EINA_FALSE);
461         elm_win_autodel_set(win, EINA_FALSE);
462         elm_object_part_text_set(win, "elm.text.name", _("Unknown"));
463         elm_object_part_text_set(win, "elm.text.state", _("Incoming..."));
464
465         lay = gui_layout_add(win, "answer");
466         EINA_SAFETY_ON_NULL_RETURN_VAL(lay, EINA_FALSE);
467         evas_object_show(lay);
468
469         slider = elm_actionslider_add(win);
470         EINA_SAFETY_ON_NULL_GOTO(slider, err_obj);
471         elm_object_style_set(slider, "answer");
472         elm_actionslider_indicator_pos_set(slider, ELM_ACTIONSLIDER_CENTER);
473         elm_actionslider_magnet_pos_set(slider, ELM_ACTIONSLIDER_CENTER);
474         elm_object_part_text_set(slider, "left", _("Hangup"));
475         elm_object_part_text_set(slider, "right", _("Answer"));
476         evas_object_smart_callback_add(slider, "selected",
477                                         _slider_pos_changed_cb, cs);
478         evas_object_show(slider);
479         elm_object_part_content_set(lay, "elm.swallow.slider", slider);
480
481         obj = elm_layout_edje_get(lay);
482         edje_object_size_min_get(obj, &w, &h);
483         if ((w == 0) || (h == 0))
484                 edje_object_size_min_restricted_calc(obj, &w, &h, w, h);
485         if ((w == 0) || (h == 0))
486                 edje_object_parts_extends_calc(obj, NULL, NULL, &w, &h);
487         evas_object_resize(lay, w, h);
488         evas_object_resize(win, w, h);
489         cs->win = win;
490         cs->layout = lay;
491
492         return EINA_TRUE;
493
494 err_obj:
495         evas_object_del(win);
496         return EINA_FALSE;
497 }
498
499 EAPI int elm_main(int argc __UNUSED__, char **argv __UNUSED__)
500 {
501         Call_Screen *cs;
502
503         if (!elm_need_eldbus()) {
504                 ERR("Could not start E_dbus");
505                 return -1;
506         }
507
508         _log_domain = eina_log_domain_register("answer_daemon", NULL);
509         cs = calloc(1, sizeof(Call_Screen));
510         EINA_SAFETY_ON_NULL_RETURN_VAL(cs, -1);
511
512         EINA_SAFETY_ON_FALSE_GOTO(_dbus_init(cs), err_dbus);
513         EINA_SAFETY_ON_FALSE_GOTO(_gui_init(cs), err_dbus);
514
515         elm_run();
516
517         _signal_handlers_del(cs);
518
519         if (cs->sig_name_changed)
520                 eldbus_signal_handler_del(cs->sig_name_changed);
521
522         evas_object_del(cs->win);
523         if (cs->call)
524                 _call_destroy(cs->call);
525
526         elm_shutdown();
527
528         free(cs);
529
530         return EXIT_SUCCESS;
531
532 err_dbus:
533         elm_shutdown();
534
535         free(cs);
536         return EXIT_FAILURE;
537 }
538 ELM_MAIN()