rc: add nasty tizen work around.
[profile/ivi/lemolo.git] / dialer / gui.c
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4 #include <Elementary.h>
5
6 #include "log.h"
7 #include "gui.h"
8 #include "keypad.h"
9 #include "history.h"
10 #include "callscreen.h"
11 #include "ussd.h"
12 #include "util.h"
13
14 #ifdef HAVE_TIZEN
15 #include <appcore-efl.h>
16 #include <ui-gadget.h>
17 #include <Ecore_X.h>
18 #endif
19
20 static Evas_Object *win = NULL;
21 static Evas_Object *main_layout = NULL;
22 static Evas_Object *keypad = NULL;
23 static Evas_Object *contacts = NULL;
24 static Evas_Object *history = NULL;
25 static Evas_Object *cs = NULL;
26 static Evas_Object *flip = NULL;
27 static char def_theme[PATH_MAX] = "";
28
29 static OFono_Callback_List_Modem_Node *callback_node_modem_changed = NULL;
30 static OFono_Callback_List_USSD_Notify_Node *callback_node_ussd_notify = NULL;
31
32 /* XXX elm_flip should just do the right thing, but it does not */
33 static Eina_Bool in_call = EINA_FALSE;
34 static Eina_Bool in_flip_anim = EINA_FALSE;
35
36 Contact_Info *gui_contact_search(const char *number, const char **type)
37 {
38         return contact_search(contacts, number, type);
39 }
40
41 Evas_Object *gui_layout_add(Evas_Object *parent, const char *style)
42 {
43         Evas_Object *layout = elm_layout_add(parent);
44         if (!elm_layout_theme_set(layout, "layout", "dialer", style)) {
45                 CRITICAL("No theme for 'elm/layout/dialer/%s' at %s",
46                                 style, def_theme);
47                 evas_object_del(layout);
48                 return NULL;
49         }
50         return layout;
51 }
52
53 static void _gui_show(Evas_Object *o)
54 {
55         if (o == keypad)
56                 elm_object_signal_emit(main_layout, "show,keypad", "gui");
57         else if (o == contacts)
58                 elm_object_signal_emit(main_layout, "show,contacts", "gui");
59         else if (o == history)
60                 elm_object_signal_emit(main_layout, "show,history", "gui");
61         elm_object_focus_set(o, EINA_TRUE);
62 }
63
64 typedef struct _Simple_Popup
65 {
66         Evas_Object *popup;
67         Evas_Object *box;
68         Evas_Object *message;
69         Evas_Object *entry;
70         Ecore_Timer *recalc_timer; /* HACK */
71 } Simple_Popup;
72
73 static void _popup_close(void *data, Evas_Object *bt __UNUSED__, void *event __UNUSED__)
74 {
75         Evas_Object *popup = data;
76         evas_object_del(popup);
77 }
78
79 void gui_simple_popup_title_set(Evas_Object *p, const char *title)
80 {
81         if (title) {
82                 elm_object_part_text_set(p, "elm.text.title", title);
83                 elm_object_signal_emit(p, "show,title", "gui");
84         } else {
85                 elm_object_part_text_set(p, "elm.text.title", "");
86                 elm_object_signal_emit(p, "hide,title", "gui");
87         }
88 }
89
90 /* HACK: force recalc from an idler to fix elm_entry problem */
91 static Eina_Bool _gui_simple_popup_entries_reeval(void *data)
92 {
93         Simple_Popup *ctx = data;
94         if (ctx->message)
95                 elm_entry_calc_force(ctx->message);
96         if (ctx->entry)
97                 elm_entry_calc_force(ctx->entry);
98         ctx->recalc_timer = NULL;
99         return EINA_FALSE;
100 }
101
102 static void _gui_simple_popup_timer_cancel_if_needed(Simple_Popup *ctx)
103 {
104         if (!ctx->recalc_timer)
105                 return;
106         if (ctx->message || ctx->entry)
107                 return;
108         ecore_timer_del(ctx->recalc_timer);
109         ctx->recalc_timer = NULL;
110 }
111
112 static void _gui_simple_popup_message_del(void *data, Evas *e __UNUSED__,
113                                                 Evas_Object *en __UNUSED__,
114                                                 void *einfo __UNUSED__)
115 {
116         Simple_Popup *ctx = data;
117         ctx->message = NULL;
118         _gui_simple_popup_timer_cancel_if_needed(ctx);
119 }
120
121 static void _gui_simple_popup_entry_del(void *data, Evas *e __UNUSED__,
122                                         Evas_Object *en __UNUSED__,
123                                         void *einfo __UNUSED__)
124 {
125         Simple_Popup *ctx = data;
126         ctx->entry = NULL;
127         _gui_simple_popup_timer_cancel_if_needed(ctx);
128 }
129
130 static void _gui_simple_popup_reeval_content(Simple_Popup *ctx)
131 {
132         if ((!ctx->message) && (!ctx->entry)) {
133                 elm_object_part_content_unset(ctx->popup,
134                                                 "elm.swallow.content");
135                 elm_object_signal_emit(ctx->popup, "hide,content", "gui");
136                 evas_object_hide(ctx->box);
137                 return;
138         }
139
140         elm_box_unpack_all(ctx->box);
141         if (ctx->message) {
142                 elm_box_pack_end(ctx->box, ctx->message);
143                 evas_object_show(ctx->message);
144         }
145         if (ctx->entry) {
146                 elm_box_pack_end(ctx->box, ctx->entry);
147                 evas_object_show(ctx->entry);
148         }
149
150         elm_object_part_content_set(ctx->popup, "elm.swallow.content",
151                                         ctx->box);
152         elm_object_signal_emit(ctx->popup, "show,content", "gui");
153
154         /* HACK: elm_entry is not evaluating properly and the text is
155          * not centered as it should be. Then we must force a
156          * calculation from an timer.
157          */
158         if (ctx->recalc_timer)
159                 ecore_timer_del(ctx->recalc_timer);
160         ctx->recalc_timer = ecore_timer_add(
161                 0.02, _gui_simple_popup_entries_reeval, ctx);
162 }
163
164 void gui_simple_popup_message_set(Evas_Object *p, const char *msg)
165 {
166         Simple_Popup *ctx = evas_object_data_get(p, "simple_popup");
167         Evas_Object *en;
168
169         EINA_SAFETY_ON_NULL_RETURN(ctx);
170
171         if (!msg) {
172                 if (ctx->message)
173                         evas_object_del(ctx->message);
174                 _gui_simple_popup_reeval_content(ctx);
175                 return;
176         }
177
178         if (ctx->message)
179                 en = ctx->message;
180         else {
181                 en = ctx->message = elm_entry_add(p);
182                 elm_object_style_set(en, "dialer-popup");
183                 elm_entry_editable_set(en, EINA_FALSE);
184                 elm_entry_scrollable_set(en, EINA_TRUE);
185                 elm_entry_scrollbar_policy_set(en, ELM_SCROLLER_POLICY_OFF,
186                                                 ELM_SCROLLER_POLICY_AUTO);
187
188                 evas_object_event_callback_add(en, EVAS_CALLBACK_DEL,
189                                         _gui_simple_popup_message_del,
190                                         ctx);
191                 evas_object_size_hint_weight_set(en, EVAS_HINT_EXPAND,
192                                                         EVAS_HINT_EXPAND);
193                 evas_object_size_hint_align_set(en, EVAS_HINT_FILL,
194                                                 EVAS_HINT_FILL);
195         }
196
197         elm_object_text_set(en, msg);
198         _gui_simple_popup_reeval_content(ctx);
199 }
200
201 void gui_simple_popup_entry_enable(Evas_Object *p)
202 {
203         Simple_Popup *ctx = evas_object_data_get(p, "simple_popup");
204         Evas_Object *en;
205
206         EINA_SAFETY_ON_NULL_RETURN(ctx);
207
208         if (ctx->entry)
209                 return;
210         en = ctx->entry = elm_entry_add(p);
211         elm_object_style_set(en, "dialer-popup-editable");
212         elm_entry_editable_set(en, EINA_TRUE);
213         elm_entry_scrollable_set(en, EINA_TRUE);
214         elm_entry_scrollbar_policy_set(en, ELM_SCROLLER_POLICY_OFF,
215                                         ELM_SCROLLER_POLICY_AUTO);
216
217         evas_object_size_hint_weight_set(en, EVAS_HINT_EXPAND,
218                                                 EVAS_HINT_EXPAND);
219         evas_object_size_hint_align_set(en, EVAS_HINT_FILL,
220                                         EVAS_HINT_FILL);
221
222         evas_object_event_callback_add(en, EVAS_CALLBACK_DEL,
223                                         _gui_simple_popup_entry_del,
224                                         ctx);
225         _gui_simple_popup_reeval_content(ctx);
226 }
227
228 void gui_simple_popup_entry_disable(Evas_Object *p)
229 {
230         Simple_Popup *ctx = evas_object_data_get(p, "simple_popup");
231         EINA_SAFETY_ON_NULL_RETURN(ctx);
232         if (!ctx->entry)
233                 return;
234         evas_object_del(ctx->entry);
235         _gui_simple_popup_reeval_content(ctx);
236 }
237
238 const char *gui_simple_popup_entry_get(const Evas_Object *p)
239 {
240         Simple_Popup *ctx = evas_object_data_get(p, "simple_popup");
241         EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, NULL);
242         EINA_SAFETY_ON_NULL_RETURN_VAL(ctx->entry, NULL);
243         return elm_object_text_get(ctx->entry);
244 }
245
246 void gui_simple_popup_button_dismiss_set(Evas_Object *p)
247 {
248         gui_simple_popup_buttons_set(p,
249                                         "Dismiss",
250                                         "dialer",
251                                         _popup_close,
252                                         NULL, NULL, NULL,
253                                         p);
254 }
255
256 void gui_simple_popup_buttons_set(Evas_Object *p,
257                                         const char *b1_label,
258                                         const char *b1_class,
259                                         Evas_Smart_Cb b1_cb,
260                                         const char *b2_label,
261                                         const char *b2_class,
262                                         Evas_Smart_Cb b2_cb,
263                                         const void *data)
264 {
265         Evas_Object *bt;
266         unsigned int count = 0;
267
268         if (b1_label) {
269                 bt = elm_button_add(p);
270                 elm_object_style_set(bt, b1_class ? b1_class : "dialer");
271                 elm_object_text_set(bt, b1_label);
272                 elm_object_part_content_set(p, "elm.swallow.button1", bt);
273                 evas_object_smart_callback_add(bt, "clicked", b1_cb, data);
274                 count++;
275         }
276
277         if (b2_label) {
278                 const char *part;
279                 bt = elm_button_add(p);
280                 elm_object_style_set(bt, b2_class ? b2_class : "dialer");
281                 elm_object_text_set(bt, b2_label);
282
283                 if (count == 1)
284                         part = "elm.swallow.button2";
285                 else
286                         part = "elm.swallow.button1";
287
288                 elm_object_part_content_set(p, part, bt);
289                 evas_object_smart_callback_add(bt, "clicked", b2_cb, data);
290                 count++;
291         }
292
293         if (count == 2)
294                 elm_object_signal_emit(p, "buttons,2", "gui");
295         else if (count == 1) {
296                 elm_object_signal_emit(p, "buttons,1", "gui");
297                 elm_object_part_content_set(p, "elm.swallow.button2", NULL);
298         } else {
299                 elm_object_signal_emit(p, "buttons,0", "gui");
300                 elm_object_part_content_set(p, "elm.swallow.button1", NULL);
301                 elm_object_part_content_set(p, "elm.swallow.button2", NULL);
302         }
303 }
304
305 static void _gui_simple_popup_del(void *data, Evas *e __UNUSED__,
306                                         Evas_Object *o __UNUSED__,
307                                         void *event_info __UNUSED__)
308 {
309         Simple_Popup *ctx = data;
310         free(ctx);
311 }
312
313 Evas_Object *gui_simple_popup(const char *title, const char *message)
314 {
315         Evas_Object *p = gui_layout_add(win, "popup");
316         Simple_Popup *ctx;
317
318         EINA_SAFETY_ON_NULL_RETURN_VAL(p, NULL);
319
320         ctx = calloc(1, sizeof(Simple_Popup));
321         EINA_SAFETY_ON_NULL_GOTO(ctx, failed_calloc);
322
323         evas_object_data_set(p, "simple_popup", ctx);
324         ctx->popup = p;
325         evas_object_event_callback_add(p, EVAS_CALLBACK_DEL,
326                                         _gui_simple_popup_del, ctx);
327
328         evas_object_size_hint_weight_set(p, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
329         elm_win_resize_object_add(win, p);
330
331         ctx->box = elm_box_add(p);
332
333         gui_simple_popup_title_set(p, title);
334         gui_simple_popup_message_set(p, message);
335         gui_simple_popup_button_dismiss_set(p);
336
337         evas_object_show(p);
338
339         return p;
340
341 failed_calloc:
342         evas_object_del(p);
343         return NULL;
344 }
345
346 void gui_activate(void)
347 {
348         elm_win_raise(win);
349         elm_win_activate(win);
350         evas_object_show(win);
351 }
352
353 void gui_number_set(const char *number, Eina_Bool auto_dial)
354 {
355         _gui_show(keypad);
356         keypad_number_set(keypad, number, auto_dial);
357 }
358
359 void gui_activecall_set(Evas_Object *o)
360 {
361         if (o) {
362                 elm_object_part_content_set(main_layout,
363                                                 "elm.swallow.activecall", o);
364                 elm_object_signal_emit(main_layout, "show,activecall", "gui");
365         } else {
366                 o = elm_object_part_content_unset(
367                         main_layout, "elm.swallow.activecall");
368                 elm_object_signal_emit(main_layout, "hide,activecall", "gui");
369                 evas_object_hide(o);
370         }
371 }
372
373 void gui_contacts_show(void)
374 {
375         _gui_show(contacts);
376         gui_call_exit();
377 }
378
379 void gui_call_enter(void)
380 {
381         gui_activate();
382         if (in_call)
383                 return;
384         in_call = EINA_TRUE;
385         if (in_flip_anim)
386                 return;
387         in_flip_anim = EINA_TRUE;
388         elm_flip_go(flip, ELM_FLIP_ROTATE_Y_CENTER_AXIS);
389         elm_object_focus_set(cs, EINA_TRUE);
390 }
391
392 void gui_call_exit(void)
393 {
394         if (!in_call)
395                 return;
396         in_call = EINA_FALSE;
397         if (in_flip_anim)
398                 return;
399         in_flip_anim = EINA_TRUE;
400         elm_flip_go(flip, ELM_FLIP_ROTATE_Y_CENTER_AXIS);
401         elm_object_focus_set(cs, EINA_FALSE);
402 }
403
404 static void _gui_call_sync(void *data __UNUSED__, Evas_Object *o __UNUSED__,
405                                 void *event_info __UNUSED__)
406 {
407         Eina_Bool showing_call = !elm_flip_front_visible_get(flip);
408
409         if (showing_call ^ in_call) {
410                 DBG("Flip back to sync");
411                 elm_flip_go(flip, ELM_FLIP_ROTATE_Y_CENTER_AXIS);
412                 elm_object_focus_set(cs, in_call);
413         }
414         in_flip_anim = EINA_FALSE;
415 }
416
417 static void _gui_voicemail(void)
418 {
419         const char *number = ofono_voicemail_number_get();
420         EINA_SAFETY_ON_NULL_RETURN(number);
421         EINA_SAFETY_ON_FALSE_RETURN(*number != '\0');
422
423         dial(number);
424 }
425
426 static void _on_clicked(void *data __UNUSED__, Evas_Object *o __UNUSED__,
427                         const char *emission, const char *source __UNUSED__)
428 {
429         DBG("signal: %s", emission);
430
431         EINA_SAFETY_ON_FALSE_RETURN(eina_str_has_prefix(emission, "clicked,"));
432         emission += strlen("clicked,");
433
434         if (strcmp(emission, "keypad") == 0)
435                 _gui_show(keypad);
436         else if (strcmp(emission, "contacts") == 0)
437                 _gui_show(contacts);
438         else if (strcmp(emission, "history") == 0)
439                 _gui_show(history);
440         else if (strcmp(emission, "voicemail") == 0)
441                 _gui_voicemail();
442 }
443
444 static void _ofono_changed(void *data __UNUSED__)
445 {
446         const char *number;
447         Eina_Bool waiting;
448         unsigned char count;
449         char buf[32];
450
451         if ((ofono_modem_api_get() & OFONO_API_MSG_WAITING) == 0) {
452                 elm_object_signal_emit(main_layout, "disable,voicemail", "gui");
453                 elm_object_signal_emit(main_layout,
454                                         "toggle,off,voicemail", "gui");
455                 elm_object_part_text_set(main_layout, "elm.text.voicemail", "");
456                 return;
457         }
458
459         number = ofono_voicemail_number_get();
460         waiting = ofono_voicemail_waiting_get();
461         count = ofono_voicemail_count_get();
462
463         if (number)
464                 elm_object_signal_emit(main_layout, "enable,voicemail", "gui");
465         else
466                 elm_object_signal_emit(main_layout, "disable,voicemail", "gui");
467
468         if (waiting) {
469                 if (count == 0)
470                         snprintf(buf, sizeof(buf), "*");
471                 else if (count < 255)
472                         snprintf(buf, sizeof(buf), "%d", count);
473                 else
474                         snprintf(buf, sizeof(buf), "255+");
475
476                 elm_object_signal_emit(main_layout,
477                                         "toggle,on,voicemail", "gui");
478         } else {
479                 buf[0] = '\0';
480                 elm_object_signal_emit(main_layout,
481                                         "toggle,off,voicemail", "gui");
482         }
483
484         elm_object_part_text_set(main_layout, "elm.text.voicemail", buf);
485 }
486
487 static void _ofono_ussd_notify(void *data __UNUSED__, Eina_Bool needs_reply,
488                                 const char *message)
489 {
490         DBG("needs_reply=%d, message=%s", needs_reply, message);
491         ussd_start(message);
492 }
493
494 Eina_Bool gui_init(const char *theme)
495 {
496         Evas_Object *lay, *obj;
497         Evas_Coord w, h;
498
499         /* dialer should never, ever quit */
500         elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_NONE);
501
502         elm_app_compile_bin_dir_set(PACKAGE_BIN_DIR);
503         elm_app_compile_data_dir_set(PACKAGE_DATA_DIR);
504         elm_app_info_set(gui_init, "ofono-efl", "themes/default.edj");
505
506         snprintf(def_theme, sizeof(def_theme), "%s/themes/default.edj",
507                         elm_app_data_dir_get());
508
509         elm_theme_extension_add(NULL, def_theme);
510         if (!theme)
511                 elm_theme_overlay_add(NULL, def_theme);
512         else {
513                 char tmp[PATH_MAX];
514                 if (theme[0] != '/') {
515                         if (eina_str_has_suffix(theme, ".edj")) {
516                                 snprintf(tmp, sizeof(tmp), "%s/themes/%s",
517                                                 elm_app_data_dir_get(), theme);
518                         } else {
519                                 snprintf(tmp, sizeof(tmp), "%s/themes/%s.edj",
520                                                 elm_app_data_dir_get(), theme);
521                         }
522                         theme = tmp;
523                 }
524                 elm_theme_overlay_add(NULL, theme);
525         }
526
527         win = elm_win_util_standard_add("ofono-dialer", "oFono Dialer");
528         EINA_SAFETY_ON_NULL_RETURN_VAL(win, EINA_FALSE);
529         elm_win_autodel_set(win, EINA_FALSE);
530
531 #ifdef HAVE_TIZEN
532         appcore_set_i18n("ofono-efl", "en-US");
533         UG_INIT_EFL(win, UG_OPT_INDICATOR_PORTRAIT_ONLY);
534 #endif
535
536         flip = elm_flip_add(win);
537         evas_object_size_hint_weight_set(flip,
538                                 EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
539         evas_object_size_hint_align_set(flip, EVAS_HINT_FILL, EVAS_HINT_FILL);
540         elm_win_resize_object_add(win, flip);
541         evas_object_smart_callback_add(flip, "animate,done",
542                                         _gui_call_sync, NULL);
543         evas_object_show(flip);
544
545         main_layout = lay = gui_layout_add(win, "main");
546         EINA_SAFETY_ON_NULL_RETURN_VAL(lay, EINA_FALSE);
547         evas_object_size_hint_weight_set(lay,
548                                 EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
549         evas_object_size_hint_align_set(lay, EVAS_HINT_FILL, EVAS_HINT_FILL);
550         elm_object_part_content_set(flip, "front", lay);
551         evas_object_show(lay);
552
553         elm_object_signal_callback_add(lay, "clicked,*", "gui",
554                                         _on_clicked, NULL);
555
556         keypad = obj = keypad_add(win);
557         EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EINA_FALSE);
558         elm_object_part_content_set(lay, "elm.swallow.keypad", obj);
559
560         contacts = obj = contacts_add(win);
561         EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EINA_FALSE);
562         elm_object_part_content_set(lay, "elm.swallow.contacts", obj);
563
564         history = obj = history_add(win);
565         EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EINA_FALSE);
566         elm_object_part_content_set(lay, "elm.swallow.history", obj);
567
568         _gui_show(keypad);
569
570         cs = obj = callscreen_add(win);
571         EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EINA_FALSE);
572         evas_object_size_hint_weight_set(obj,
573                                 EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
574         evas_object_size_hint_align_set(obj, EVAS_HINT_FILL, EVAS_HINT_FILL);
575         elm_object_part_content_set(flip, "back", obj);
576         evas_object_show(obj);
577
578         callback_node_modem_changed =
579                 ofono_modem_changed_cb_add(_ofono_changed, NULL);
580         callback_node_ussd_notify =
581                 ofono_ussd_notify_cb_add(_ofono_ussd_notify, NULL);
582
583         /* TODO: make it match better with Tizen: icon and other properties */
584         obj = elm_layout_edje_get(lay);
585         edje_object_size_min_get(obj, &w, &h);
586         if ((w == 0) || (h == 0))
587                 edje_object_size_min_restricted_calc(obj, &w, &h, w, h);
588         if ((w == 0) || (h == 0))
589                 edje_object_parts_extends_calc(obj, NULL, NULL, &w, &h);
590         evas_object_resize(win, w, h);
591
592         /* do not show it yet, RC will check if it should be visible or not */
593         return EINA_TRUE;
594 }
595
596 void gui_shutdown(void)
597 {
598 }