Adding license and copyright info
[profile/ivi/lemolo.git] / dialer / callscreen.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 "ofono.h"
9 #include "util.h"
10 #include "simple-popup.h"
11
12 typedef struct _Callscreen
13 {
14         Evas_Object *self;
15         Evas_Object *gui_activecall; /* for gui.h */
16         struct {
17                 Evas_Object *sc;
18                 Evas_Object *bx;
19                 Eina_List *calls;
20                 double start;
21         } multiparty;
22         struct {
23                 OFono_Call *first;
24                 OFono_Call *second;
25                 OFono_Call *current; /* first or second */
26                 OFono_Call *waiting;
27                 OFono_Call *incoming; /* should be first && current */
28                 Eina_List *list;
29         } calls;
30         Ecore_Timer *elapsed_updater;
31         struct {
32                 Eina_Strbuf *todo;
33                 OFono_Pending *pending;
34         } tones;
35         struct {
36                 const void *call;
37                 const char *number;
38                 Evas_Object *popup;
39         } disconnected;
40 } Callscreen;
41
42 static void _on_active_call_clicked(void *data __UNUSED__,
43                                         Evas_Object *o __UNUSED__,
44                                         const char *emission __UNUSED__,
45                                         const char *source __UNUSED__)
46 {
47         gui_call_enter();
48 }
49
50 static OFono_Callback_List_Modem_Node *callback_node_modem_changed = NULL;
51
52 static OFono_Callback_List_Call_Node *callback_node_call_added = NULL;
53 static OFono_Callback_List_Call_Node *callback_node_call_removed = NULL;
54 static OFono_Callback_List_Call_Node *callback_node_call_changed = NULL;
55
56 static OFono_Callback_List_Call_Disconnected_Node
57 *callback_node_call_disconnected = NULL;
58
59 static char *_call_name_or_id(const OFono_Call *call)
60 {
61         const char *s = ofono_call_line_id_get(call);
62         Contact_Info *info;
63
64         if (!s)
65                 return NULL;
66
67         info = gui_contact_search(s, NULL);
68         if (info)
69                 return strdup(contact_info_full_name_get(info));
70
71         return phone_format(s);
72 }
73
74 static Evas_Object *_call_photo_get(const OFono_Call *call, Evas_Object *parent)
75 {
76         const char *s = ofono_call_line_id_get(call);
77         Contact_Info *info;
78
79         if (!s)
80                 return NULL;
81
82         info = gui_contact_search(s, NULL);
83         if (info)
84                 return picture_icon_get(parent, contact_info_picture_get(info));
85         return NULL;
86 }
87
88 static char *_call_name_get(const Callscreen *ctx __UNUSED__,
89                                 const OFono_Call *call)
90 {
91         if (!ofono_call_multiparty_get(call))
92                 return _call_name_or_id(call);
93
94         return strdup("Conference");
95 }
96
97 static const char *_call_type_get(const OFono_Call *call)
98 {
99         const char *type;
100         const char *s = ofono_call_line_id_get(call);
101         Contact_Info *info;
102
103         if (!s)
104                 return NULL;
105
106         info = gui_contact_search(s, &type);
107         if (info)
108                 return type;
109
110         return NULL;
111 }
112
113 static void _on_mp_hangup(void *data, Evas_Object *o __UNUSED__,
114                                 const char *emission __UNUSED__,
115                                 const char *source __UNUSED__)
116 {
117         OFono_Call *call = data;
118         DBG("User ask hangup of multiparty call=%p", call);
119         ofono_call_hangup(call, NULL, NULL);
120 }
121
122 static void _on_mp_pvt_reply(void *data, OFono_Error err)
123 {
124         Callscreen *ctx = data;
125
126         DBG("PrivateChat: err=%d", err);
127
128         if (err == OFONO_ERROR_NONE)
129                 elm_object_signal_emit(ctx->self, "multiparty,private", "call");
130 }
131
132 static void _on_mp_pvt(void *data, Evas_Object *o,
133                                 const char *emission __UNUSED__,
134                                 const char *source __UNUSED__)
135 {
136         Callscreen *ctx = evas_object_data_get(o, "callscreen.ctx");
137         OFono_Call *call = data;
138         DBG("User ask private chat of multiparty call=%p", call);
139         ofono_private_chat(call, _on_mp_pvt_reply, ctx);
140 }
141
142 static void _on_raise(void *data __UNUSED__, Evas_Object *o,
143                                 const char *emission __UNUSED__,
144                                 const char *source __UNUSED__)
145 {
146         evas_object_raise(o);
147 }
148
149 static void _multiparty_update(Callscreen *ctx)
150 {
151         Eina_List *new = NULL, *old = NULL;
152         const Eina_List *n1, *n2;
153         OFono_Call *c;
154         Evas_Object *it;
155
156         EINA_LIST_FOREACH(ctx->calls.list, n1, c) {
157                 if (ofono_call_multiparty_get(c))
158                         new = eina_list_append(new, c);
159         }
160
161         old = ctx->multiparty.calls;
162         if (eina_list_count(new) != eina_list_count(old))
163                 goto repopulate;
164
165         for (n1 = new, n2 = old; n1 && n2; n1 = n1->next, n2 = n2->next) {
166                 if (n1->data != n2->data)
167                         break;
168         }
169
170         if (n1)
171                 goto repopulate;
172
173         eina_list_free(new);
174         return;
175
176 repopulate:
177         if ((new) && (!ctx->multiparty.calls))
178                 ctx->multiparty.start = ecore_loop_time_get();
179
180         eina_list_free(ctx->multiparty.calls);
181         ctx->multiparty.calls = new;
182
183         elm_box_clear(ctx->multiparty.bx);
184
185         if (!new) {
186                 ctx->multiparty.start = -1.0;
187                 elm_object_signal_emit(ctx->self, "hide,multiparty-details",
188                                         "call");
189                 return;
190         }
191
192         EINA_LIST_FOREACH(new, n1, c) {
193                 char *name, *number;
194                 const char *type;
195
196                 name = _call_name_or_id(c);
197                 type = _call_type_get(c);
198                 number = phone_format(ofono_call_line_id_get(c));
199
200                 it = layout_add(ctx->multiparty.bx, "multiparty-details");
201                 evas_object_size_hint_align_set(it,
202                                                 EVAS_HINT_FILL, EVAS_HINT_FILL);
203                 evas_object_show(it);
204
205                 elm_object_part_text_set(it, "elm.text.name", name);
206                 elm_object_part_text_set(it, "elm.text.number", number);
207                 elm_object_part_text_set(it, "elm.text.type", type);
208
209                 if (strcmp(name, number) == 0)
210                         elm_object_signal_emit(it, "hide,name", "call");
211                 else
212                         elm_object_signal_emit(it, "show,name", "call");
213
214                 elm_object_signal_callback_add(it, "clicked,hangup", "call",
215                                                 _on_mp_hangup, c);
216                 elm_object_signal_callback_add(it, "clicked,private", "call",
217                                                 _on_mp_pvt, c);
218                 elm_object_signal_callback_add(it, "raise", "call",
219                                                 _on_raise, NULL);
220
221                 evas_object_data_set(it, "callscreen.ctx", ctx);
222                 elm_box_pack_end(ctx->multiparty.bx, it);
223
224                 free(name);
225                 free(number);
226         }
227         elm_object_signal_emit(ctx->self, "show,multiparty-details", "call");
228 }
229
230 static void _multiparty_private_available_update(Callscreen *ctx)
231 {
232         Eina_List *lst = elm_box_children_get(ctx->multiparty.bx);
233         const char *sig = ctx->calls.second ? "hide,private" : "show,private";
234         Evas_Object *it;
235
236         EINA_LIST_FREE(lst, it)
237                 elm_object_signal_emit(it, sig, "call");
238 }
239
240 static void _call_text_set(Callscreen *ctx, unsigned int id,
241                                 const char *part, const char *str)
242 {
243         char buf[128];
244         snprintf(buf, sizeof(buf), "elm.text.%u.%s", id, part);
245         elm_object_part_text_set(ctx->self, buf, str ? str : "");
246 }
247
248 static const char *_call_state_str(OFono_Call_State state)
249 {
250         switch (state) {
251         case OFONO_CALL_STATE_DISCONNECTED:
252                 return "Disconnected";
253         case OFONO_CALL_STATE_ACTIVE:
254                 return "Active";
255         case OFONO_CALL_STATE_HELD:
256                 return "On Hold";
257         case OFONO_CALL_STATE_DIALING:
258                 return "Dialing...";
259         case OFONO_CALL_STATE_ALERTING:
260                 return "Alerting...";
261         case OFONO_CALL_STATE_INCOMING:
262                 return "Incoming...";
263         case OFONO_CALL_STATE_WAITING:
264                 return "Waiting...";
265         default:
266                 ERR("unknown state: %d", state);
267                 return NULL;
268         }
269 }
270
271 static const char *_call_state_id(OFono_Call_State state)
272 {
273         switch (state) {
274         case OFONO_CALL_STATE_DISCONNECTED:
275                 return "disconnected";
276         case OFONO_CALL_STATE_ACTIVE:
277                 return "active";
278         case OFONO_CALL_STATE_HELD:
279                 return "held";
280         case OFONO_CALL_STATE_DIALING:
281                 return "dialing";
282         case OFONO_CALL_STATE_ALERTING:
283                 return "alerting";
284         case OFONO_CALL_STATE_INCOMING:
285                 return "incoming";
286         case OFONO_CALL_STATE_WAITING:
287                 return "waiting";
288         default:
289                 ERR("unknown state: %d", state);
290                 return NULL;
291         }
292 }
293
294 static void _call_photo_set(Callscreen *ctx, unsigned int id,
295                                 Evas_Object *photo)
296 {
297         char buf[128];
298
299         if (!photo) {
300                 photo = elm_icon_add(ctx->self);
301                 elm_icon_standard_set(photo, "no-picture");
302         }
303
304         snprintf(buf, sizeof(buf), "elm.swallow.img.%u", id);
305         elm_object_part_content_set(ctx->self, buf, photo);
306 }
307
308 static void _call_show(Callscreen *ctx, unsigned int id, const OFono_Call *c)
309 {
310         char *contact = _call_name_get(ctx, c);
311         const char *type = _call_type_get(c);
312         const char *status = _call_state_str(ofono_call_state_get(c));
313         Evas_Object *photo;
314
315         if (ofono_call_multiparty_get(c)) {
316                 photo = elm_icon_add(ctx->self);
317                 elm_icon_standard_set(photo, "multiparty");
318         } else
319                 photo = _call_photo_get(c, ctx->self);
320
321         _call_text_set(ctx, id, "name", contact);
322         _call_text_set(ctx, id, "phone.type", type);
323         _call_text_set(ctx, id, "status", status);
324         _call_text_set(ctx, id, "elapsed", "");
325         _call_photo_set(ctx, id, photo);
326         free(contact);
327 }
328
329 static void _call_elapsed_update(Callscreen *ctx, unsigned int id,
330                                         const OFono_Call *c)
331 {
332         Edje_Message_Float msgf = {0};
333         Evas_Object *ed;
334         OFono_Call_State state = ofono_call_state_get(c);
335         double start, now, elapsed;
336         char part[128], buf[128] = "";
337
338         if ((state != OFONO_CALL_STATE_ACTIVE) &&
339                 (state != OFONO_CALL_STATE_HELD))
340                 goto end;
341
342         if (ofono_call_multiparty_get(c))
343                 start = ctx->multiparty.start;
344         else
345                 start = ofono_call_start_time_get(c);
346
347         if (start < 0) {
348                 ERR("Unknown start time for call");
349                 goto end;
350         }
351
352         now = ecore_loop_time_get();
353         elapsed =  now - start;
354         if (elapsed < 0) {
355                 ERR("Time rewinded? %f - %f = %f", now, start, elapsed);
356                 goto end;
357         }
358
359         msgf.val = elapsed;
360         if (elapsed > 3600)
361                 snprintf(buf, sizeof(buf), "%02d:%02d:%02d",
362                                 (int)elapsed / 3600,
363                                 (int)elapsed % 3600 / 60,
364                                 (int)elapsed % 60);
365         else
366                 snprintf(buf, sizeof(buf), "%02d:%02d",
367                                 (int)elapsed / 60,
368                                 (int)elapsed % 60);
369
370 end:
371         ed = elm_layout_edje_get(ctx->self);
372         edje_object_message_send(ed, EDJE_MESSAGE_FLOAT, 10 + id, &msgf);
373
374         snprintf(part, sizeof(part), "elm.text.%u.elapsed", id);
375         elm_object_part_text_set(ctx->self, part, buf);
376 }
377
378 static void _activecall_elapsed_update(Callscreen *ctx)
379 {
380         Edje_Message_Float msgf = {0};
381         Evas_Object *ed;
382         OFono_Call_State state = ofono_call_state_get(ctx->calls.current);
383         double start, now, elapsed;
384         char buf[128] = "";
385
386         if ((state != OFONO_CALL_STATE_ACTIVE) &&
387                 (state != OFONO_CALL_STATE_HELD))
388                 goto end;
389
390         if (ofono_call_multiparty_get(ctx->calls.current))
391                 start = ctx->multiparty.start;
392         else
393                 start = ofono_call_start_time_get(ctx->calls.current);
394
395         if (start < 0) {
396                 ERR("Unknown start time for call");
397                 goto end;
398         }
399
400         now = ecore_loop_time_get();
401         elapsed =  now - start;
402         if (elapsed < 0) {
403                 ERR("Time rewinded? %f - %f = %f", now, start, elapsed);
404                 goto end;
405         }
406
407         msgf.val = elapsed;
408         if (elapsed > 3600)
409                 snprintf(buf, sizeof(buf), "%02d:%02d:%02d",
410                                 (int)elapsed / 3600,
411                                 (int)elapsed % 3600 / 60,
412                                 (int)elapsed % 60);
413         else
414                 snprintf(buf, sizeof(buf), "%02d:%02d",
415                                 (int)elapsed / 60,
416                                 (int)elapsed % 60);
417
418 end:
419         ed = elm_layout_edje_get(ctx->gui_activecall);
420         edje_object_message_send(ed, EDJE_MESSAGE_FLOAT, 1, &msgf);
421
422         elm_object_part_text_set(ctx->gui_activecall, "elm.text.elapsed", buf);
423 }
424
425 static void _call_update(Callscreen *ctx, unsigned int id, const OFono_Call *c)
426 {
427         Evas_Object *o = ctx->self;
428         OFono_Call_State state = ofono_call_state_get(c);
429         const char *status_label = _call_state_str(state);
430         const char *status_id = _call_state_id(state);
431         char buf[128];
432
433         _call_text_set(ctx, id, "status", status_label);
434
435         snprintf(buf, sizeof(buf), "state,%u,%s", id, status_id);
436         elm_object_signal_emit(o, buf, "call");
437
438         snprintf(buf, sizeof(buf), "%s,%u,multiparty",
439                         ofono_call_multiparty_get(c) ? "show" : "hide", id);
440         elm_object_signal_emit(o, buf, "call");
441
442         if ((state == OFONO_CALL_STATE_ACTIVE) ||
443                 (state == OFONO_CALL_STATE_HELD)) {
444                 _call_elapsed_update(ctx, id, c);
445                 snprintf(buf, sizeof(buf), "show,%u,elapsed", id);
446                 elm_object_signal_emit(o, buf, "call");
447         } else {
448                 Edje_Message_Float msgf;
449
450                 _call_text_set(ctx, id, "elapsed", "");
451                 snprintf(buf, sizeof(buf), "hide,%u,elapsed", id);
452                 elm_object_signal_emit(o, buf, "call");
453
454                 msgf.val = 0.0;
455                 edje_object_message_send(elm_layout_edje_get(o),
456                                 EDJE_MESSAGE_FLOAT, 10 + id, &msgf);
457         }
458 }
459
460 static void _call_clear(Callscreen *ctx, unsigned int id)
461 {
462         Evas_Object *o = ctx->self;
463         Edje_Message_Float msgf;
464         char buf[128];
465
466         _call_text_set(ctx, id, "name", "");
467         _call_text_set(ctx, id, "phone.type", "");
468         _call_text_set(ctx, id, "status", "");
469         _call_text_set(ctx, id, "elapsed", "");
470
471         snprintf(buf, sizeof(buf), "state,%u,disconnected", id);
472         elm_object_signal_emit(o, buf, "call");
473
474         snprintf(buf, sizeof(buf), "hide,%u,multiparty", id);
475         elm_object_signal_emit(o, buf, "call");
476
477         snprintf(buf, sizeof(buf), "hide,%u,elapsed", id);
478         elm_object_signal_emit(o, buf, "call");
479
480         msgf.val = 0.0;
481         edje_object_message_send(elm_layout_edje_get(o),
482                                         EDJE_MESSAGE_FLOAT, 10 + id, &msgf);
483 }
484
485 static void _activecall_update(Callscreen *ctx)
486 {
487         OFono_Call_State state = ofono_call_state_get(ctx->calls.current);
488         char *contact = _call_name_get(ctx, ctx->calls.current);
489         const char *type = _call_type_get(ctx->calls.current);
490         const char *status_label = _call_state_str(state);
491         const char *status_id = _call_state_id(state);
492         Evas_Object *o = ctx->gui_activecall;
493         char buf[128];
494
495         elm_object_part_text_set(o, "elm.text.name", contact);
496         elm_object_part_text_set(o, "elm.text.phone.type", type);
497         elm_object_part_text_set(o, "elm.text.status", status_label);
498
499         snprintf(buf, sizeof(buf), "state,%s", status_id);
500         elm_object_signal_emit(o, buf, "call");
501
502         _activecall_elapsed_update(ctx);
503
504         free(contact);
505 }
506
507 static void _call_waiting_set(Callscreen *ctx, OFono_Call *c)
508 {
509         Evas_Object *o = ctx->self;
510
511         if (!c) {
512                 elm_object_part_text_set(o, "elm.text.waiting", "");
513                 elm_object_signal_emit(o, "hide,waiting", "call");
514         } else {
515                 char *name = _call_name_get(ctx, c);
516                 Evas_Object *photo = _call_photo_get(c, o);
517                 if (!photo) {
518                         photo = elm_icon_add(o);
519                         elm_icon_standard_set(photo, "no-picture");
520                 }
521                 elm_object_part_content_set(o, "elm.swallow.waiting.photo",
522                                                 photo);
523                 elm_object_part_text_set(o, "elm.text.waiting", name);
524                 elm_object_signal_emit(o, "show,waiting", "call");
525                 free(name);
526         }
527
528         ctx->calls.waiting = c;
529 }
530
531 static void _call_incoming_set(Callscreen *ctx, OFono_Call *c)
532 {
533         Evas_Object *o = ctx->self;
534
535         if (!c)
536                 elm_object_signal_emit(o, "hide,answer", "call");
537         else
538                 elm_object_signal_emit(o, "show,answer", "call");
539
540         ctx->calls.incoming = c;
541 }
542
543 static void _call_current_actions_update(Callscreen *ctx)
544 {
545         Evas_Object *o = ctx->self;
546         OFono_Call_State s;
547
548         if (ctx->calls.current)
549                 s = ofono_call_state_get(ctx->calls.current);
550         else
551                 s = OFONO_CALL_STATE_DISCONNECTED;
552
553         if ((s == OFONO_CALL_STATE_ACTIVE) || (s == OFONO_CALL_STATE_HELD))
554                 elm_object_signal_emit(o, "enable,actions", "call");
555         else
556                 elm_object_signal_emit(o, "disable,actions", "call");
557 }
558
559 static void _call_current_set(Callscreen *ctx, OFono_Call *c)
560 {
561         Evas_Object *o = ctx->self;
562         Eina_Bool need_activecall_update = EINA_FALSE;
563
564         DBG("was=%p, now=%p, first=%p, second=%p",
565                 ctx->calls.current, c, ctx->calls.first, ctx->calls.second);
566
567         if (!c) {
568                 elm_object_signal_emit(o, "active,disconnected", "call");
569                 if (ctx->gui_activecall) {
570                         gui_activecall_set(NULL);
571                         evas_object_del(ctx->gui_activecall);
572                         ctx->gui_activecall = NULL;
573                 }
574         } else {
575                 if (!ctx->gui_activecall) {
576                         ctx->gui_activecall = layout_add(o, "activecall");
577                         elm_object_signal_callback_add(
578                                 ctx->gui_activecall, "clicked", "call",
579                                 _on_active_call_clicked, ctx);
580                         gui_activecall_set(ctx->gui_activecall);
581                         need_activecall_update = EINA_TRUE;
582                 } else if (ctx->calls.current != c)
583                         need_activecall_update = EINA_TRUE;
584         }
585
586         ctx->calls.current = c;
587
588         _call_current_actions_update(ctx);
589
590         if (need_activecall_update)
591                 _activecall_update(ctx);
592 }
593
594 static void _call_first_set(Callscreen *ctx, OFono_Call *c)
595 {
596         DBG("was=%p, now=%p", ctx->calls.first, c);
597
598         if (!c)
599                 _call_clear(ctx, 1);
600         else {
601                 _call_show(ctx, 1, c);
602                 _call_update(ctx, 1, c);
603         }
604
605         ctx->calls.first = c;
606 }
607
608 static void _call_second_set(Callscreen *ctx, OFono_Call *c)
609 {
610         DBG("was=%p, now=%p", ctx->calls.second, c);
611
612         if (!c) {
613                 _call_clear(ctx, 2);
614                 elm_object_signal_emit(ctx->self, "calls,1", "call");
615         } else {
616                 _call_show(ctx, 2, c);
617                 _call_update(ctx, 2, c);
618                 elm_object_signal_emit(ctx->self, "calls,2", "call");
619         }
620
621         ctx->calls.second = c;
622 }
623
624 static void _call_auto_place(Callscreen *ctx, OFono_Call *c)
625 {
626         OFono_Call_State state = ofono_call_state_get(c);
627         Eina_Bool is_multiparty = ofono_call_multiparty_get(c);
628
629         DBG("ctx=%p, %p, %p, call=%p, state=%d, multiparty=%d",
630                 ctx, ctx->calls.first, ctx->calls.second, c,
631                 state, is_multiparty);
632
633         if (!ctx->calls.first) {
634                 DBG("first call %p", c);
635                 _call_first_set(ctx, c);
636                 _call_current_set(ctx, c);
637                 return;
638         }
639
640         if (is_multiparty) {
641                 if (ofono_call_multiparty_get(ctx->calls.first)) {
642                         DBG("call %p is already part of first multiparty", c);
643                         return;
644                 } else if (ctx->calls.second &&
645                                 ofono_call_multiparty_get(ctx->calls.second)) {
646                         DBG("call %p is already part of second multiparty", c);
647                         return;
648                 }
649         }
650
651         DBG("second call %p", c);
652         _call_second_set(ctx, c);
653         if (state == OFONO_CALL_STATE_ACTIVE)
654                 _call_current_set(ctx, c);
655 }
656
657 static OFono_Call *_multiparty_find_other(const Callscreen *ctx,
658                                                 const OFono_Call *c)
659 {
660         OFono_Call *itr;
661         const Eina_List *n;
662         EINA_LIST_FOREACH(ctx->calls.list, n, itr) {
663                 if (itr == c)
664                         continue;
665                 if (!ofono_call_multiparty_get(itr))
666                         continue;
667                 if (ofono_call_state_get(itr) == OFONO_CALL_STATE_DISCONNECTED)
668                         continue;
669                 DBG("%p is another multiparty peer of %p", itr, c);
670                 return itr;
671         }
672         DBG("no other multiparty peers of %p", c);
673         return NULL;
674 }
675
676 static void _call_auto_unplace(Callscreen *ctx, OFono_Call *c)
677 {
678         Eina_Bool is_multiparty = ofono_call_multiparty_get(c);
679         OFono_Call *replacement = NULL;
680
681         DBG("ctx=%p, %p, %p, current=%p, call=%p, multiparty=%d",
682                 ctx, ctx->calls.first, ctx->calls.second, ctx->calls.current,
683                 c, is_multiparty);
684
685         if (is_multiparty) {
686                 replacement = _multiparty_find_other(ctx, c);
687                 DBG("replacement=%p", replacement);
688         }
689
690         if (ctx->calls.first == c) {
691                 if (replacement) {
692                         _call_first_set(ctx, replacement);
693                         if (ctx->calls.current == c)
694                                 _call_current_set(ctx, replacement);
695                         return;
696                 }
697
698                 if (!ctx->calls.second) {
699                         DBG("no calls left");
700                         _call_first_set(ctx, NULL);
701                         _call_current_set(ctx, NULL);
702                 } else {
703                         DBG("move second to first");
704                         _call_first_set(ctx, ctx->calls.second);
705                         _call_second_set(ctx, NULL);
706                         _call_current_set(ctx, ctx->calls.first);
707                 }
708         } else if (ctx->calls.second == c) {
709                 if (replacement) {
710                         _call_second_set(ctx, replacement);
711                         if (ctx->calls.current == c)
712                                 _call_current_set(ctx, replacement);
713                         return;
714                 }
715
716                 DBG("remove second");
717                 _call_second_set(ctx, NULL);
718                 _call_current_set(ctx, ctx->calls.first);
719         }
720 }
721
722 static void _call_disconnected_done(Callscreen *ctx,
723                                         const char *reason __UNUSED__)
724 {
725         _multiparty_update(ctx);
726
727         if (!ctx->calls.list)
728                 gui_call_exit();
729         ctx->disconnected.call = NULL;
730 }
731
732 static void _popup_close(void *data, Evas_Object *o __UNUSED__,
733                                 void *event __UNUSED__)
734 {
735         Callscreen *ctx = data;
736
737         evas_object_del(ctx->disconnected.popup);
738         ctx->disconnected.popup = NULL;
739
740         eina_stringshare_replace(&ctx->disconnected.number, NULL);
741
742         _call_disconnected_done(ctx, "network");
743 }
744
745 static void _popup_redial(void *data, Evas_Object *o __UNUSED__,
746                                 void *event __UNUSED__)
747 {
748         Callscreen *ctx = data;
749
750         gui_dial(ctx->disconnected.number);
751         _popup_close(ctx, NULL, NULL);
752 }
753
754 static void _call_disconnected_show(Callscreen *ctx, OFono_Call *c,
755                                         const char *reason)
756 {
757         Evas_Object *p;
758         const char *number, *title;
759         char msg[1024];
760
761         DBG("ctx=%p, %p, %p, current=%p, waiting=%p, previous=%s, "
762                 "disconnected=%p (%s)",
763                 ctx, ctx->calls.first, ctx->calls.second, ctx->calls.current,
764                 ctx->calls.waiting, ctx->disconnected.number, c, reason);
765
766         if (ctx->calls.waiting == c) {
767                 _call_waiting_set(ctx, NULL);
768                 goto done; /* do not ask to redial to waiting number */
769         }
770
771         _call_auto_unplace(ctx, c);
772
773         ctx->disconnected.call = c;
774
775         elm_object_signal_emit(ctx->self, "active,disconnected", "call");
776
777         if ((strcmp(reason, "local") == 0) || (strcmp(reason, "remote") == 0))
778                 goto done;
779
780         number = ofono_call_line_id_get(c);
781         if ((!number) || (number[0] == '\0'))
782                 goto done;
783
784         if (ctx->disconnected.number)
785                 goto done;
786
787         if (strcmp(reason, "network") == 0)
788                 title = "Network Disconnected!";
789         else
790                 title = "Disconnected!";
791
792         snprintf(msg, sizeof(msg), "Try to redial %s", number);
793
794         eina_stringshare_replace(&ctx->disconnected.number, number);
795
796         ctx->disconnected.popup = p = gui_simple_popup(title, msg);
797         simple_popup_buttons_set(p,
798                                         "Dismiss",
799                                         "dialer",
800                                         _popup_close,
801                                         "Redial",
802                                         "dialer",
803                                         _popup_redial,
804                                         ctx);
805
806         /* TODO: sound to notify user */
807
808         return;
809
810 done:
811         _call_disconnected_done(ctx, reason);
812 }
813
814 static void _tones_send_reply(void *data, OFono_Error err)
815 {
816         Callscreen *ctx = data;
817
818         if (err)
819                 ERR("Failed to send tones: %d", err);
820
821         ctx->tones.pending = NULL;
822         if (eina_strbuf_length_get(ctx->tones.todo) > 0) {
823                 const char *tones = eina_strbuf_string_get(ctx->tones.todo);
824
825                 DBG("Send pending tones: %s", tones);
826                 ctx->tones.pending = ofono_tones_send(
827                         tones, _tones_send_reply, ctx);
828                 eina_strbuf_reset(ctx->tones.todo);
829         }
830 }
831
832 static void _on_pressed(void *data, Evas_Object *obj __UNUSED__,
833                         const char *emission, const char *source __UNUSED__)
834 {
835         Callscreen *ctx = data;
836         DBG("ctx=%p, %p, %p, current=%p, waiting=%p, signal: %s",
837                 ctx, ctx->calls.first, ctx->calls.second, ctx->calls.current,
838                 ctx->calls.waiting, emission);
839
840         EINA_SAFETY_ON_FALSE_RETURN(eina_str_has_prefix(emission, "pressed,"));
841         emission += strlen("pressed,");
842
843 }
844
845 static void _on_released(void *data, Evas_Object *obj __UNUSED__,
846                                 const char *emission,
847                                 const char *source __UNUSED__)
848 {
849         Callscreen *ctx = data;
850         DBG("ctx=%p, %p, %p, current=%p, waiting=%p, signal: %s",
851                 ctx, ctx->calls.first, ctx->calls.second, ctx->calls.current,
852                 ctx->calls.waiting, emission);
853
854         EINA_SAFETY_ON_FALSE_RETURN(eina_str_has_prefix(emission, "released,"));
855         emission += strlen("released,");
856
857 }
858
859 static void _on_clicked(void *data, Evas_Object *obj __UNUSED__,
860                         const char *emission, const char *source __UNUSED__)
861 {
862         Callscreen *ctx = data;
863         const char *dtmf = NULL;
864
865         DBG("ctx=%p, %p, %p, current=%p, waiting=%p, signal: %s",
866                 ctx, ctx->calls.first, ctx->calls.second, ctx->calls.current,
867                 ctx->calls.waiting, emission);
868
869         EINA_SAFETY_ON_FALSE_RETURN(eina_str_has_prefix(emission, "clicked,"));
870         emission += strlen("clicked,");
871
872         if ((emission[0] >= '0') && (emission[0] <= '9') && (emission[1] == 0))
873                 dtmf = emission;
874         else if (strcmp(emission, "star") == 0)
875                 dtmf = "*";
876         else if (strcmp(emission, "hash") == 0)
877                 dtmf = "#";
878
879         if (dtmf) {
880                 if (!ctx->tones.pending)
881                         ctx->tones.pending = ofono_tones_send(
882                                 dtmf, _tones_send_reply, ctx);
883                 else
884                         eina_strbuf_append_char(ctx->tones.todo, dtmf[0]);
885                 return;
886         }
887
888         if (strcmp(emission, "hangup") == 0) {
889                 OFono_Call *c = ctx->calls.current;
890                 if ((c) && (ofono_call_state_get(c) == OFONO_CALL_STATE_ACTIVE))
891                         ofono_release_and_swap(NULL, NULL);
892                 else if (c)
893                         ofono_call_hangup(c, NULL, NULL);
894         } else if (strcmp(emission, "answer") == 0) {
895                 if (ctx->calls.current)
896                         ofono_call_answer(ctx->calls.current, NULL, NULL);
897         } else if (strcmp(emission, "mute") == 0) {
898                 Eina_Bool val = !ofono_mute_get();
899                 ofono_mute_set(val, NULL, NULL);
900         } else if (strcmp(emission, "speaker") == 0) {
901                 ERR("TODO - implement platform loudspeaker code");
902         } else if (strcmp(emission, "contacts") == 0) {
903                 gui_contacts_show();
904         } else if (strcmp(emission, "add-call") == 0) {
905                 gui_call_exit();
906         } else if (strcmp(emission, "merge") == 0) {
907                 ofono_multiparty_create(NULL, NULL);
908         } else if (strcmp(emission, "swap") == 0) {
909                 if (ctx->calls.current) {
910                         OFono_Call_State state;
911                         state = ofono_call_state_get(ctx->calls.current);
912                         if (state == OFONO_CALL_STATE_HELD ||
913                                 state == OFONO_CALL_STATE_ACTIVE)
914                                 ofono_swap_calls(NULL, NULL);
915                 }
916         } else if (strcmp(emission, "waiting-hangup") == 0) {
917                 if (ctx->calls.waiting)
918                         ofono_call_hangup(ctx->calls.waiting, NULL, NULL);
919         } else if (strcmp(emission, "hangup-answer") == 0) {
920                 if (ctx->calls.waiting)
921                         ofono_release_and_answer(NULL, NULL);
922         } else if (strcmp(emission, "hold-answer") == 0) {
923                 if (ctx->calls.waiting)
924                         ofono_hold_and_answer(NULL, NULL);
925         }
926 }
927
928 static void _on_key_down(void *data, Evas *e __UNUSED__,
929                                 Evas_Object *o __UNUSED__,
930                                 void *event_info)
931 {
932         Callscreen *ctx = data;
933         Evas_Event_Key_Down *ev = event_info;
934         DBG("ctx=%p, key=%s (%s, %s)", ctx, ev->keyname, ev->key, ev->string);
935
936         if ((strcmp(ev->key, "minus") == 0) ||
937                 (strcmp(ev->key, "KP_Subtract") == 0) ||
938                 (strcmp(ev->key, "XF86AudioLowerVolume") == 0)) {
939                 unsigned char last, cur;
940
941                 last = cur = ofono_volume_speaker_get();
942                 if (cur < 10)
943                         cur = 0;
944                 else
945                         cur -= 10;
946
947                 if (last != cur)
948                         ofono_volume_speaker_set(cur, NULL, NULL);
949         } else if ((strcmp(ev->key, "plus") == 0) ||
950                         (strcmp(ev->key, "KP_Add") == 0) ||
951                         (strcmp(ev->key, "XF86AudioRaiseVolume") == 0)) {
952                 unsigned char last, cur;
953
954                 last = cur = ofono_volume_speaker_get();
955                 if (cur > 90)
956                         cur = 100;
957                 else
958                         cur += 10;
959
960                 if (last != cur)
961                         ofono_volume_speaker_set(cur, NULL, NULL);
962         }
963 }
964
965 static void _ofono_changed(void *data)
966 {
967         Callscreen *ctx = data;
968         Edje_Message_Float msgf;
969         Evas_Object *ed;
970         const char *sig;
971
972         sig = ofono_mute_get() ? "toggle,on,mute" : "toggle,off,mute";
973         elm_object_signal_emit(ctx->self, sig, "call");
974
975         ed = elm_layout_edje_get(ctx->self);
976
977         msgf.val = (ofono_volume_speaker_get() / 100.0);
978         edje_object_message_send(ed, EDJE_MESSAGE_FLOAT, 1, &msgf);
979
980         msgf.val = (ofono_volume_microphone_get() / 100.0);
981         edje_object_message_send(ed, EDJE_MESSAGE_FLOAT, 2, &msgf);
982 }
983
984 static void _call_added(void *data, OFono_Call *c)
985 {
986         Callscreen *ctx = data;
987         OFono_Call_State state = ofono_call_state_get(c);
988
989         DBG("ctx=%p, %p, %p, current=%p, waiting=%p, added=%p(%d)",
990                 ctx, ctx->calls.first, ctx->calls.second, ctx->calls.current,
991                 ctx->calls.waiting, c, state);
992
993         ctx->calls.list = eina_list_append(ctx->calls.list, c);
994
995         if (state == OFONO_CALL_STATE_WAITING)
996                 _call_waiting_set(ctx, c);
997         else {
998                 _call_auto_place(ctx, c);
999                 if (state == OFONO_CALL_STATE_INCOMING)
1000                         _call_incoming_set(ctx, c);
1001         }
1002
1003         gui_call_enter();
1004 }
1005
1006 static void _call_removed(void *data, OFono_Call *c)
1007 {
1008         Callscreen *ctx = data;
1009         DBG("ctx=%p, %p, %p, current=%p, waiting=%p, removed=%p",
1010                 ctx, ctx->calls.first, ctx->calls.second, ctx->calls.current,
1011                 ctx->calls.waiting, c);
1012
1013         ctx->calls.list = eina_list_remove(ctx->calls.list, c);
1014         _call_disconnected_show(ctx, c, "local");
1015 }
1016
1017 static Eina_Bool _on_elapsed_updater(void *data)
1018 {
1019         Callscreen *ctx = data;
1020         double next, now;
1021
1022         if ((!ctx->calls.first) && (!ctx->calls.second)) {
1023                 ctx->elapsed_updater = NULL;
1024                 return EINA_FALSE;
1025         }
1026
1027         if (ctx->calls.first)
1028                 _call_elapsed_update(ctx, 1, ctx->calls.first);
1029         if (ctx->calls.second)
1030                 _call_elapsed_update(ctx, 2, ctx->calls.second);
1031
1032         if (ctx->gui_activecall)
1033                 _activecall_elapsed_update(ctx);
1034
1035         now = ecore_loop_time_get();
1036         next = 1.0 - (now - (int)now);
1037         ctx->elapsed_updater = ecore_timer_add(next, _on_elapsed_updater, ctx);
1038         return EINA_FALSE;
1039 }
1040
1041 static Eina_Bool _call_multiparty_changed(const Callscreen *ctx,
1042                                                 const OFono_Call *c)
1043 {
1044         Eina_Bool current = ofono_call_multiparty_get(c);
1045         Eina_Bool previous = !!eina_list_data_find(ctx->multiparty.calls, c);
1046         return current ^ previous;
1047 }
1048
1049 static inline int _call_priority_cmp(OFono_Call_State a, OFono_Call_State b)
1050 {
1051         static const int state_priority[] = {
1052                 [OFONO_CALL_STATE_DISCONNECTED] = 0,
1053                 [OFONO_CALL_STATE_ACTIVE] = 6,
1054                 [OFONO_CALL_STATE_HELD] = 3,
1055                 [OFONO_CALL_STATE_DIALING] = 5,
1056                 [OFONO_CALL_STATE_ALERTING] = 4,
1057                 [OFONO_CALL_STATE_INCOMING] = 2,
1058                 [OFONO_CALL_STATE_WAITING] = 1
1059         };
1060         return state_priority[a] - state_priority[b];
1061 }
1062
1063 static Eina_Bool _call_priority_higher_than_current(const Callscreen *ctx,
1064                                                         const OFono_Call *c)
1065 {
1066         OFono_Call_State cur_state, new_state;
1067
1068         new_state = ofono_call_state_get(c);
1069         if ((new_state == OFONO_CALL_STATE_DISCONNECTED) ||
1070                 (new_state == OFONO_CALL_STATE_WAITING))
1071                 return EINA_FALSE;
1072
1073         if (!ctx->calls.current)
1074                 return EINA_TRUE;
1075
1076         cur_state = ofono_call_state_get(ctx->calls.current);
1077         return _call_priority_cmp(new_state, cur_state) > 0;
1078 }
1079
1080 static OFono_Call *_call_priority_find_higher(const Callscreen *ctx,
1081                                                 OFono_Call *c)
1082 {
1083         OFono_Call_State first, second, query, higher_state;
1084         OFono_Call *higher = NULL;
1085
1086         if (!ctx->calls.first)
1087                 return NULL;
1088
1089         query = ofono_call_state_get(c);
1090         first = ofono_call_state_get(ctx->calls.first);
1091         if (ctx->calls.second)
1092                 second = ofono_call_state_get(ctx->calls.second);
1093         else
1094                 second = OFONO_CALL_STATE_DISCONNECTED;
1095
1096         if (_call_priority_cmp(first, query) > 0) {
1097                 higher = ctx->calls.first;
1098                 higher_state = first;
1099         } else {
1100                 higher = c;
1101                 higher_state = query;
1102         }
1103
1104         if (_call_priority_cmp(second, higher_state) > 0) {
1105                 higher = ctx->calls.second;
1106                 higher_state = second;
1107         }
1108
1109         if (higher != c)
1110                 return higher;
1111
1112         return NULL;
1113 }
1114
1115 static void _call_changed_waiting_update(Callscreen *ctx, OFono_Call *c)
1116 {
1117         OFono_Call_State state = ofono_call_state_get(c);
1118
1119         if (state == OFONO_CALL_STATE_DISCONNECTED) {
1120                 DBG("waiting was disconnected");
1121                 _call_waiting_set(ctx, NULL);
1122         } else if (state != OFONO_CALL_STATE_WAITING) {
1123                 _call_waiting_set(ctx, NULL);
1124                 DBG("waiting was answered");
1125                 _call_auto_place(ctx, c);
1126         }
1127 }
1128
1129 static void _call_changed_current_update(Callscreen *ctx, OFono_Call *c)
1130 {
1131         if (ctx->calls.current != c) {
1132                 if (_call_priority_higher_than_current(ctx, c)) {
1133                         DBG("changed call %p is higher than previous %p",
1134                                 c, ctx->calls.current);
1135                         _call_current_set(ctx, c);
1136                 } else {
1137                         DBG("changed call %p is lower than previous %p",
1138                                 c, ctx->calls.current);
1139                 }
1140         } else if (ctx->calls.current == c) {
1141                 OFono_Call *other = _call_priority_find_higher(ctx, c);
1142                 if (other) {
1143                         DBG("other call %p is higher than changed %p",
1144                                 other, c);
1145                         _call_current_set(ctx, other);
1146                 } else {
1147                         DBG("changed call %p is still the current", c);
1148                         _call_current_actions_update(ctx);
1149                 }
1150         }
1151 }
1152
1153 static void _call_changed_multiparty_update(Callscreen *ctx, OFono_Call *c)
1154 {
1155         if (!_call_multiparty_changed(ctx, c)) {
1156                 DBG("multiparty unchanged");
1157                 return;
1158         }
1159
1160         _multiparty_update(ctx);
1161
1162         _call_show(ctx, 1, ctx->calls.first);
1163         _call_update(ctx, 1, ctx->calls.first);
1164         _activecall_update(ctx);
1165
1166         if (ofono_call_state_get(c) == OFONO_CALL_STATE_DISCONNECTED) {
1167                 DBG("multiparty peer was disconnected");
1168                 return;
1169         }
1170
1171         if (ofono_call_multiparty_get(c)) {
1172                 if (ctx->calls.first &&
1173                         (!ofono_call_multiparty_get(ctx->calls.first)))
1174                         DBG("multiparty added to second display");
1175                 else {
1176                         DBG("multiparty merged to first display, "
1177                                 "remove second display");
1178                         _call_second_set(ctx, NULL);
1179                 }
1180         } else if (ctx->calls.first != c) {
1181                 DBG("multiparty split, add peer as second display");
1182                 _call_second_set(ctx, c);
1183         } else {
1184                 OFono_Call *other = _multiparty_find_other(ctx, c);
1185                 DBG("multiparty split, add another %p peer as second display",
1186                         other);
1187                 _call_second_set(ctx, other);
1188         }
1189 }
1190
1191 static void _call_changed_swap_merge_update(Callscreen *ctx)
1192 {
1193         Evas_Object *o = ctx->self;
1194
1195         if (!ctx->calls.first) {
1196                 DBG("no calls, disable swap, pause and merge");
1197                 elm_object_signal_emit(o, "disable,swap", "call");
1198                 elm_object_signal_emit(o, "disable,pause", "call");
1199                 elm_object_signal_emit(o, "disable,merge", "call");
1200                 return;
1201         }
1202
1203         if (ctx->calls.second) {
1204                 DBG("two calls, enable swap and merge, disable pause");
1205                 elm_object_signal_emit(o, "enable,swap", "call");
1206                 elm_object_signal_emit(o, "disable,pause", "call");
1207                 elm_object_signal_emit(o, "enable,merge", "call");
1208         } else {
1209                 const char *sig_swap, *sig_pause;
1210                 if (ofono_call_state_get(ctx->calls.first) ==
1211                         OFONO_CALL_STATE_HELD) {
1212                         sig_swap = "enable,swap";
1213                         sig_pause = "disable,pause";
1214                 } else {
1215                         sig_swap = "disable,swap";
1216                         sig_pause = "enable,pause";
1217                 }
1218                 DBG("one call, disable merge and %s %s", sig_swap, sig_pause);
1219                 elm_object_signal_emit(o, sig_swap, "call");
1220                 elm_object_signal_emit(o, sig_pause, "call");
1221                 elm_object_signal_emit(o, "disable,merge", "call");
1222         }
1223 }
1224
1225 static void _call_changed(void *data, OFono_Call *c)
1226 {
1227         Callscreen *ctx = data;
1228         OFono_Call_State state = ofono_call_state_get(c);
1229
1230         DBG("BEGIN: ctx=%p, %p, %p, current=%p, waiting=%p, changed=%p (%d)",
1231                 ctx, ctx->calls.first, ctx->calls.second, ctx->calls.current,
1232                 ctx->calls.waiting, c, state);
1233
1234         if (ctx->calls.waiting == c)
1235                 _call_changed_waiting_update(ctx, c);
1236         else if (ctx->calls.incoming == c) {
1237                 if (state != OFONO_CALL_STATE_INCOMING)
1238                         _call_incoming_set(ctx, NULL);
1239         }
1240
1241         _call_changed_current_update(ctx, c);
1242         _call_changed_multiparty_update(ctx, c);
1243
1244         if (ctx->calls.first == c)
1245                 _call_update(ctx, 1, c);
1246         else if (ctx->calls.second == c)
1247                 _call_update(ctx, 2, c);
1248
1249         if (ctx->multiparty.calls)
1250                 _multiparty_private_available_update(ctx);
1251
1252         if (ctx->calls.current) {
1253                 if (!ctx->elapsed_updater)
1254                         _on_elapsed_updater(ctx);
1255         } else if (ctx->elapsed_updater) {
1256                 ecore_timer_del(ctx->elapsed_updater);
1257                 ctx->elapsed_updater = NULL;
1258         }
1259
1260         _call_changed_swap_merge_update(ctx);
1261
1262         DBG("END: ctx=%p, %p, %p, current=%p, waiting=%p, changed=%p (%d)",
1263                 ctx, ctx->calls.first, ctx->calls.second, ctx->calls.current,
1264                 ctx->calls.waiting, c, state);
1265 }
1266
1267 static void _call_disconnected(void *data, OFono_Call *c, const char *reason)
1268 {
1269         Callscreen *ctx = data;
1270         DBG("ctx=%p, %p, %p, current=%p, waiting=%p, disconnected=%p (%s)",
1271                 ctx, ctx->calls.first, ctx->calls.second, ctx->calls.current,
1272                 ctx->calls.waiting, c, reason);
1273
1274         EINA_SAFETY_ON_NULL_RETURN(reason);
1275         _call_disconnected_show(ctx, c, reason);
1276 }
1277
1278 static void _on_del(void *data, Evas *e __UNUSED__,
1279                         Evas_Object *obj __UNUSED__, void *event __UNUSED__)
1280 {
1281         Callscreen *ctx = data;
1282
1283         ofono_call_added_cb_del(callback_node_call_added);
1284         ofono_call_removed_cb_del(callback_node_call_removed);
1285         ofono_call_changed_cb_del(callback_node_call_changed);
1286         ofono_call_disconnected_cb_del(callback_node_call_disconnected);
1287         ofono_modem_changed_cb_del(callback_node_modem_changed);
1288
1289         eina_strbuf_free(ctx->tones.todo);
1290         if (ctx->tones.pending)
1291                 ofono_pending_cancel(ctx->tones.pending);
1292
1293         if (ctx->elapsed_updater)
1294                 ecore_timer_del(ctx->elapsed_updater);
1295
1296         eina_stringshare_del(ctx->disconnected.number);
1297
1298         eina_list_free(ctx->multiparty.calls);
1299
1300         eina_list_free(ctx->calls.list);
1301         free(ctx);
1302 }
1303
1304 Evas_Object *callscreen_add(Evas_Object *parent)
1305 {
1306         Callscreen *ctx;
1307         Evas_Object *obj = layout_add(parent, "call");
1308         EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL);
1309
1310         ctx = calloc(1, sizeof(Callscreen));
1311         ctx->self = obj;
1312         ctx->tones.todo = eina_strbuf_new();
1313
1314         evas_object_data_set(obj, "callscreen.ctx", ctx);
1315
1316         evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
1317                                         _on_del, ctx);
1318         elm_object_signal_callback_add(obj, "pressed,*", "call",
1319                                         _on_pressed, ctx);
1320         elm_object_signal_callback_add(obj, "released,*", "call",
1321                                         _on_released, ctx);
1322         elm_object_signal_callback_add(obj, "clicked,*", "call",
1323                                         _on_clicked, ctx);
1324
1325         elm_object_focus_allow_set(obj, EINA_TRUE);
1326         evas_object_event_callback_add(obj, EVAS_CALLBACK_KEY_DOWN,
1327                                         _on_key_down, ctx);
1328
1329         _call_clear(ctx, 1);
1330         _call_clear(ctx, 2);
1331         elm_object_signal_emit(obj, "calls,1", "call");
1332
1333         ctx->multiparty.sc = elm_scroller_add(obj);
1334         elm_scroller_policy_set(ctx->multiparty.sc, ELM_SCROLLER_POLICY_AUTO,
1335                                 ELM_SCROLLER_POLICY_OFF);
1336         elm_scroller_bounce_set(ctx->multiparty.sc, EINA_FALSE, EINA_TRUE);
1337         elm_object_style_set(ctx->multiparty.sc, "multiparty-details");
1338
1339         ctx->multiparty.bx = elm_box_add(obj);
1340         evas_object_size_hint_weight_set(ctx->multiparty.bx,
1341                                                 EVAS_HINT_EXPAND, 0.0);
1342         evas_object_size_hint_align_set(ctx->multiparty.bx,
1343                                         EVAS_HINT_FILL, 0.0);
1344         evas_object_show(ctx->multiparty.bx);
1345         elm_object_content_set(ctx->multiparty.sc, ctx->multiparty.bx);
1346
1347         elm_object_part_content_set(obj, "elm.swallow.multiparty-details",
1348                                         ctx->multiparty.sc);
1349
1350         callback_node_call_added = ofono_call_added_cb_add(_call_added, ctx);
1351
1352         callback_node_call_removed =
1353                 ofono_call_removed_cb_add(_call_removed, ctx);
1354
1355         callback_node_call_changed =
1356                 ofono_call_changed_cb_add(_call_changed, ctx);
1357
1358         callback_node_call_disconnected =
1359                 ofono_call_disconnected_cb_add(_call_disconnected, ctx);
1360
1361         callback_node_modem_changed =
1362                 ofono_modem_changed_cb_add(_ofono_changed, ctx);
1363
1364         return obj;
1365 }