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