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