4 #include <Elementary.h>
10 #include "simple-popup.h"
12 typedef struct _Callscreen
15 Evas_Object *gui_activecall; /* for gui.h */
25 OFono_Call *current; /* first or second */
27 OFono_Call *incoming; /* should be first && current */
30 Ecore_Timer *elapsed_updater;
33 OFono_Pending *pending;
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__)
50 static OFono_Callback_List_Modem_Node *callback_node_modem_changed = NULL;
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;
56 static OFono_Callback_List_Call_Disconnected_Node
57 *callback_node_call_disconnected = NULL;
59 static char *_call_name_or_id(const OFono_Call *call)
61 const char *s = ofono_call_line_id_get(call);
67 info = gui_contact_search(s, NULL);
69 return strdup(contact_info_full_name_get(info));
71 return phone_format(s);
74 static Evas_Object *_call_photo_get(const OFono_Call *call, Evas_Object *parent)
76 const char *s = ofono_call_line_id_get(call);
82 info = gui_contact_search(s, NULL);
84 return picture_icon_get(parent, contact_info_picture_get(info));
88 static char *_call_name_get(const Callscreen *ctx __UNUSED__,
89 const OFono_Call *call)
91 if (!ofono_call_multiparty_get(call))
92 return _call_name_or_id(call);
94 return strdup("Conference");
97 static const char *_call_type_get(const OFono_Call *call)
100 const char *s = ofono_call_line_id_get(call);
106 info = gui_contact_search(s, &type);
113 static void _on_mp_hangup(void *data, Evas_Object *o __UNUSED__,
114 const char *emission __UNUSED__,
115 const char *source __UNUSED__)
117 OFono_Call *call = data;
118 DBG("User ask hangup of multiparty call=%p", call);
119 ofono_call_hangup(call, NULL, NULL);
122 static void _on_mp_pvt_reply(void *data, OFono_Error err)
124 Callscreen *ctx = data;
126 DBG("PrivateChat: err=%d", err);
128 if (err == OFONO_ERROR_NONE)
129 elm_object_signal_emit(ctx->self, "multiparty,private", "call");
132 static void _on_mp_pvt(void *data, Evas_Object *o,
133 const char *emission __UNUSED__,
134 const char *source __UNUSED__)
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);
142 static void _on_raise(void *data __UNUSED__, Evas_Object *o,
143 const char *emission __UNUSED__,
144 const char *source __UNUSED__)
146 evas_object_raise(o);
149 static void _multiparty_update(Callscreen *ctx)
151 Eina_List *new = NULL, *old = NULL;
152 const Eina_List *n1, *n2;
156 EINA_LIST_FOREACH(ctx->calls.list, n1, c) {
157 if (ofono_call_multiparty_get(c))
158 new = eina_list_append(new, c);
161 old = ctx->multiparty.calls;
162 if (eina_list_count(new) != eina_list_count(old))
165 for (n1 = new, n2 = old; n1 && n2; n1 = n1->next, n2 = n2->next) {
166 if (n1->data != n2->data)
177 if ((new) && (!ctx->multiparty.calls))
178 ctx->multiparty.start = ecore_loop_time_get();
180 eina_list_free(ctx->multiparty.calls);
181 ctx->multiparty.calls = new;
183 elm_box_clear(ctx->multiparty.bx);
186 ctx->multiparty.start = -1.0;
187 elm_object_signal_emit(ctx->self, "hide,multiparty-details",
192 EINA_LIST_FOREACH(new, n1, c) {
196 name = _call_name_or_id(c);
197 type = _call_type_get(c);
198 number = phone_format(ofono_call_line_id_get(c));
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);
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);
209 if (strcmp(name, number) == 0)
210 elm_object_signal_emit(it, "hide,name", "call");
212 elm_object_signal_emit(it, "show,name", "call");
214 elm_object_signal_callback_add(it, "clicked,hangup", "call",
216 elm_object_signal_callback_add(it, "clicked,private", "call",
218 elm_object_signal_callback_add(it, "raise", "call",
221 evas_object_data_set(it, "callscreen.ctx", ctx);
222 elm_box_pack_end(ctx->multiparty.bx, it);
227 elm_object_signal_emit(ctx->self, "show,multiparty-details", "call");
230 static void _multiparty_private_available_update(Callscreen *ctx)
232 Eina_List *lst = elm_box_children_get(ctx->multiparty.bx);
233 const char *sig = ctx->calls.second ? "hide,private" : "show,private";
236 EINA_LIST_FREE(lst, it)
237 elm_object_signal_emit(it, sig, "call");
240 static void _call_text_set(Callscreen *ctx, unsigned int id,
241 const char *part, const char *str)
244 snprintf(buf, sizeof(buf), "elm.text.%u.%s", id, part);
245 elm_object_part_text_set(ctx->self, buf, str ? str : "");
248 static const char *_call_state_str(OFono_Call_State state)
251 case OFONO_CALL_STATE_DISCONNECTED:
252 return "Disconnected";
253 case OFONO_CALL_STATE_ACTIVE:
255 case OFONO_CALL_STATE_HELD:
257 case OFONO_CALL_STATE_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:
266 ERR("unknown state: %d", state);
271 static const char *_call_state_id(OFono_Call_State state)
274 case OFONO_CALL_STATE_DISCONNECTED:
275 return "disconnected";
276 case OFONO_CALL_STATE_ACTIVE:
278 case OFONO_CALL_STATE_HELD:
280 case OFONO_CALL_STATE_DIALING:
282 case OFONO_CALL_STATE_ALERTING:
284 case OFONO_CALL_STATE_INCOMING:
286 case OFONO_CALL_STATE_WAITING:
289 ERR("unknown state: %d", state);
294 static void _call_photo_set(Callscreen *ctx, unsigned int id,
300 photo = elm_icon_add(ctx->self);
301 elm_icon_standard_set(photo, "no-picture");
304 snprintf(buf, sizeof(buf), "elm.swallow.img.%u", id);
305 elm_object_part_content_set(ctx->self, buf, photo);
308 static void _call_show(Callscreen *ctx, unsigned int id, const OFono_Call *c)
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));
315 if (ofono_call_multiparty_get(c)) {
316 photo = elm_icon_add(ctx->self);
317 elm_icon_standard_set(photo, "multiparty");
319 photo = _call_photo_get(c, ctx->self);
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);
329 static void _call_elapsed_update(Callscreen *ctx, unsigned int id,
332 Edje_Message_Float msgf = {0};
334 OFono_Call_State state = ofono_call_state_get(c);
335 double start, now, elapsed;
336 char part[128], buf[128] = "";
338 if ((state != OFONO_CALL_STATE_ACTIVE) &&
339 (state != OFONO_CALL_STATE_HELD))
342 if (ofono_call_multiparty_get(c))
343 start = ctx->multiparty.start;
345 start = ofono_call_start_time_get(c);
348 ERR("Unknown start time for call");
352 now = ecore_loop_time_get();
353 elapsed = now - start;
355 ERR("Time rewinded? %f - %f = %f", now, start, elapsed);
361 snprintf(buf, sizeof(buf), "%02d:%02d:%02d",
363 (int)elapsed % 3600 / 60,
366 snprintf(buf, sizeof(buf), "%02d:%02d",
371 ed = elm_layout_edje_get(ctx->self);
372 edje_object_message_send(ed, EDJE_MESSAGE_FLOAT, 10 + id, &msgf);
374 snprintf(part, sizeof(part), "elm.text.%u.elapsed", id);
375 elm_object_part_text_set(ctx->self, part, buf);
378 static void _activecall_elapsed_update(Callscreen *ctx)
380 Edje_Message_Float msgf = {0};
382 OFono_Call_State state = ofono_call_state_get(ctx->calls.current);
383 double start, now, elapsed;
386 if ((state != OFONO_CALL_STATE_ACTIVE) &&
387 (state != OFONO_CALL_STATE_HELD))
390 if (ofono_call_multiparty_get(ctx->calls.current))
391 start = ctx->multiparty.start;
393 start = ofono_call_start_time_get(ctx->calls.current);
396 ERR("Unknown start time for call");
400 now = ecore_loop_time_get();
401 elapsed = now - start;
403 ERR("Time rewinded? %f - %f = %f", now, start, elapsed);
409 snprintf(buf, sizeof(buf), "%02d:%02d:%02d",
411 (int)elapsed % 3600 / 60,
414 snprintf(buf, sizeof(buf), "%02d:%02d",
419 ed = elm_layout_edje_get(ctx->gui_activecall);
420 edje_object_message_send(ed, EDJE_MESSAGE_FLOAT, 1, &msgf);
422 elm_object_part_text_set(ctx->gui_activecall, "elm.text.elapsed", buf);
425 static void _call_update(Callscreen *ctx, unsigned int id, const OFono_Call *c)
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);
433 _call_text_set(ctx, id, "status", status_label);
435 snprintf(buf, sizeof(buf), "state,%u,%s", id, status_id);
436 elm_object_signal_emit(o, buf, "call");
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");
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");
448 Edje_Message_Float msgf;
450 _call_text_set(ctx, id, "elapsed", "");
451 snprintf(buf, sizeof(buf), "hide,%u,elapsed", id);
452 elm_object_signal_emit(o, buf, "call");
455 edje_object_message_send(elm_layout_edje_get(o),
456 EDJE_MESSAGE_FLOAT, 10 + id, &msgf);
460 static void _call_clear(Callscreen *ctx, unsigned int id)
462 Evas_Object *o = ctx->self;
463 Edje_Message_Float msgf;
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", "");
471 snprintf(buf, sizeof(buf), "state,%u,disconnected", id);
472 elm_object_signal_emit(o, buf, "call");
474 snprintf(buf, sizeof(buf), "hide,%u,multiparty", id);
475 elm_object_signal_emit(o, buf, "call");
477 snprintf(buf, sizeof(buf), "hide,%u,elapsed", id);
478 elm_object_signal_emit(o, buf, "call");
481 edje_object_message_send(elm_layout_edje_get(o),
482 EDJE_MESSAGE_FLOAT, 10 + id, &msgf);
485 static void _activecall_update(Callscreen *ctx)
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;
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);
499 snprintf(buf, sizeof(buf), "state,%s", status_id);
500 elm_object_signal_emit(o, buf, "call");
502 _activecall_elapsed_update(ctx);
507 static void _call_waiting_set(Callscreen *ctx, OFono_Call *c)
509 Evas_Object *o = ctx->self;
512 elm_object_part_text_set(o, "elm.text.waiting", "");
513 elm_object_signal_emit(o, "hide,waiting", "call");
515 char *name = _call_name_get(ctx, c);
516 Evas_Object *photo = _call_photo_get(c, o);
518 photo = elm_icon_add(o);
519 elm_icon_standard_set(photo, "no-picture");
521 elm_object_part_content_set(o, "elm.swallow.waiting.photo",
523 elm_object_part_text_set(o, "elm.text.waiting", name);
524 elm_object_signal_emit(o, "show,waiting", "call");
528 ctx->calls.waiting = c;
531 static void _call_incoming_set(Callscreen *ctx, OFono_Call *c)
533 Evas_Object *o = ctx->self;
536 elm_object_signal_emit(o, "hide,answer", "call");
538 elm_object_signal_emit(o, "show,answer", "call");
540 ctx->calls.incoming = c;
543 static void _call_current_actions_update(Callscreen *ctx)
545 Evas_Object *o = ctx->self;
548 if (ctx->calls.current)
549 s = ofono_call_state_get(ctx->calls.current);
551 s = OFONO_CALL_STATE_DISCONNECTED;
553 if ((s == OFONO_CALL_STATE_ACTIVE) || (s == OFONO_CALL_STATE_HELD))
554 elm_object_signal_emit(o, "enable,actions", "call");
556 elm_object_signal_emit(o, "disable,actions", "call");
559 static void _call_current_set(Callscreen *ctx, OFono_Call *c)
561 Evas_Object *o = ctx->self;
562 Eina_Bool need_activecall_update = EINA_FALSE;
564 DBG("was=%p, now=%p, first=%p, second=%p",
565 ctx->calls.current, c, ctx->calls.first, ctx->calls.second);
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;
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;
586 ctx->calls.current = c;
588 _call_current_actions_update(ctx);
590 if (need_activecall_update)
591 _activecall_update(ctx);
594 static void _call_first_set(Callscreen *ctx, OFono_Call *c)
596 DBG("was=%p, now=%p", ctx->calls.first, c);
601 _call_show(ctx, 1, c);
602 _call_update(ctx, 1, c);
605 ctx->calls.first = c;
608 static void _call_second_set(Callscreen *ctx, OFono_Call *c)
610 DBG("was=%p, now=%p", ctx->calls.second, c);
614 elm_object_signal_emit(ctx->self, "calls,1", "call");
616 _call_show(ctx, 2, c);
617 _call_update(ctx, 2, c);
618 elm_object_signal_emit(ctx->self, "calls,2", "call");
621 ctx->calls.second = c;
624 static void _call_auto_place(Callscreen *ctx, OFono_Call *c)
626 OFono_Call_State state = ofono_call_state_get(c);
627 Eina_Bool is_multiparty = ofono_call_multiparty_get(c);
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);
633 if (!ctx->calls.first) {
634 DBG("first call %p", c);
635 _call_first_set(ctx, c);
636 _call_current_set(ctx, c);
641 if (ofono_call_multiparty_get(ctx->calls.first)) {
642 DBG("call %p is already part of first multiparty", c);
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);
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);
657 static OFono_Call *_multiparty_find_other(const Callscreen *ctx,
662 EINA_LIST_FOREACH(ctx->calls.list, n, itr) {
665 if (!ofono_call_multiparty_get(itr))
667 if (ofono_call_state_get(itr) == OFONO_CALL_STATE_DISCONNECTED)
669 DBG("%p is another multiparty peer of %p", itr, c);
672 DBG("no other multiparty peers of %p", c);
676 static void _call_auto_unplace(Callscreen *ctx, OFono_Call *c)
678 Eina_Bool is_multiparty = ofono_call_multiparty_get(c);
679 OFono_Call *replacement = NULL;
681 DBG("ctx=%p, %p, %p, current=%p, call=%p, multiparty=%d",
682 ctx, ctx->calls.first, ctx->calls.second, ctx->calls.current,
686 replacement = _multiparty_find_other(ctx, c);
687 DBG("replacement=%p", replacement);
690 if (ctx->calls.first == c) {
692 _call_first_set(ctx, replacement);
693 if (ctx->calls.current == c)
694 _call_current_set(ctx, replacement);
698 if (!ctx->calls.second) {
699 DBG("no calls left");
700 _call_first_set(ctx, NULL);
701 _call_current_set(ctx, NULL);
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);
708 } else if (ctx->calls.second == c) {
710 _call_second_set(ctx, replacement);
711 if (ctx->calls.current == c)
712 _call_current_set(ctx, replacement);
716 DBG("remove second");
717 _call_second_set(ctx, NULL);
718 _call_current_set(ctx, ctx->calls.first);
722 static void _call_disconnected_done(Callscreen *ctx,
723 const char *reason __UNUSED__)
725 _multiparty_update(ctx);
727 if (!ctx->calls.list)
729 ctx->disconnected.call = NULL;
732 static void _popup_close(void *data, Evas_Object *o __UNUSED__,
733 void *event __UNUSED__)
735 Callscreen *ctx = data;
737 evas_object_del(ctx->disconnected.popup);
738 ctx->disconnected.popup = NULL;
740 eina_stringshare_replace(&ctx->disconnected.number, NULL);
742 _call_disconnected_done(ctx, "network");
745 static void _popup_redial(void *data, Evas_Object *o __UNUSED__,
746 void *event __UNUSED__)
748 Callscreen *ctx = data;
750 gui_dial(ctx->disconnected.number);
751 _popup_close(ctx, NULL, NULL);
754 static void _call_disconnected_show(Callscreen *ctx, OFono_Call *c,
758 const char *number, *title;
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);
766 if (ctx->calls.waiting == c) {
767 _call_waiting_set(ctx, NULL);
768 goto done; /* do not ask to redial to waiting number */
771 _call_auto_unplace(ctx, c);
773 ctx->disconnected.call = c;
775 elm_object_signal_emit(ctx->self, "active,disconnected", "call");
777 if ((strcmp(reason, "local") == 0) || (strcmp(reason, "remote") == 0))
780 number = ofono_call_line_id_get(c);
781 if ((!number) || (number[0] == '\0'))
784 if (ctx->disconnected.number)
787 if (strcmp(reason, "network") == 0)
788 title = "Network Disconnected!";
790 title = "Disconnected!";
792 snprintf(msg, sizeof(msg), "Try to redial %s", number);
794 eina_stringshare_replace(&ctx->disconnected.number, number);
796 ctx->disconnected.popup = p = gui_simple_popup(title, msg);
797 simple_popup_buttons_set(p,
806 /* TODO: sound to notify user */
811 _call_disconnected_done(ctx, reason);
814 static void _tones_send_reply(void *data, OFono_Error err)
816 Callscreen *ctx = data;
819 ERR("Failed to send tones: %d", err);
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);
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);
832 static void _on_pressed(void *data, Evas_Object *obj __UNUSED__,
833 const char *emission, const char *source __UNUSED__)
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);
840 EINA_SAFETY_ON_FALSE_RETURN(eina_str_has_prefix(emission, "pressed,"));
841 emission += strlen("pressed,");
845 static void _on_released(void *data, Evas_Object *obj __UNUSED__,
846 const char *emission,
847 const char *source __UNUSED__)
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);
854 EINA_SAFETY_ON_FALSE_RETURN(eina_str_has_prefix(emission, "released,"));
855 emission += strlen("released,");
859 static void _on_clicked(void *data, Evas_Object *obj __UNUSED__,
860 const char *emission, const char *source __UNUSED__)
862 Callscreen *ctx = data;
863 const char *dtmf = NULL;
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);
869 EINA_SAFETY_ON_FALSE_RETURN(eina_str_has_prefix(emission, "clicked,"));
870 emission += strlen("clicked,");
872 if ((emission[0] >= '0') && (emission[0] <= '9') && (emission[1] == 0))
874 else if (strcmp(emission, "star") == 0)
876 else if (strcmp(emission, "hash") == 0)
880 if (!ctx->tones.pending)
881 ctx->tones.pending = ofono_tones_send(
882 dtmf, _tones_send_reply, ctx);
884 eina_strbuf_append_char(ctx->tones.todo, dtmf[0]);
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);
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) {
904 } else if (strcmp(emission, "add-call") == 0) {
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);
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);
928 static void _on_key_down(void *data, Evas *e __UNUSED__,
929 Evas_Object *o __UNUSED__,
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);
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;
941 last = cur = ofono_volume_speaker_get();
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;
954 last = cur = ofono_volume_speaker_get();
961 ofono_volume_speaker_set(cur, NULL, NULL);
965 static void _ofono_changed(void *data)
967 Callscreen *ctx = data;
968 Edje_Message_Float msgf;
972 sig = ofono_mute_get() ? "toggle,on,mute" : "toggle,off,mute";
973 elm_object_signal_emit(ctx->self, sig, "call");
975 ed = elm_layout_edje_get(ctx->self);
977 msgf.val = (ofono_volume_speaker_get() / 100.0);
978 edje_object_message_send(ed, EDJE_MESSAGE_FLOAT, 1, &msgf);
980 msgf.val = (ofono_volume_microphone_get() / 100.0);
981 edje_object_message_send(ed, EDJE_MESSAGE_FLOAT, 2, &msgf);
984 static void _call_added(void *data, OFono_Call *c)
986 Callscreen *ctx = data;
987 OFono_Call_State state = ofono_call_state_get(c);
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);
993 ctx->calls.list = eina_list_append(ctx->calls.list, c);
995 if (state == OFONO_CALL_STATE_WAITING)
996 _call_waiting_set(ctx, c);
998 _call_auto_place(ctx, c);
999 if (state == OFONO_CALL_STATE_INCOMING)
1000 _call_incoming_set(ctx, c);
1006 static void _call_removed(void *data, OFono_Call *c)
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);
1013 ctx->calls.list = eina_list_remove(ctx->calls.list, c);
1014 _call_disconnected_show(ctx, c, "local");
1017 static Eina_Bool _on_elapsed_updater(void *data)
1019 Callscreen *ctx = data;
1022 if ((!ctx->calls.first) && (!ctx->calls.second)) {
1023 ctx->elapsed_updater = NULL;
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);
1032 if (ctx->gui_activecall)
1033 _activecall_elapsed_update(ctx);
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);
1041 static Eina_Bool _call_multiparty_changed(const Callscreen *ctx,
1042 const OFono_Call *c)
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;
1049 static inline int _call_priority_cmp(OFono_Call_State a, OFono_Call_State b)
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
1060 return state_priority[a] - state_priority[b];
1063 static Eina_Bool _call_priority_higher_than_current(const Callscreen *ctx,
1064 const OFono_Call *c)
1066 OFono_Call_State cur_state, new_state;
1068 new_state = ofono_call_state_get(c);
1069 if ((new_state == OFONO_CALL_STATE_DISCONNECTED) ||
1070 (new_state == OFONO_CALL_STATE_WAITING))
1073 if (!ctx->calls.current)
1076 cur_state = ofono_call_state_get(ctx->calls.current);
1077 return _call_priority_cmp(new_state, cur_state) > 0;
1080 static OFono_Call *_call_priority_find_higher(const Callscreen *ctx,
1083 OFono_Call_State first, second, query, higher_state;
1084 OFono_Call *higher = NULL;
1086 if (!ctx->calls.first)
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);
1094 second = OFONO_CALL_STATE_DISCONNECTED;
1096 if (_call_priority_cmp(first, query) > 0) {
1097 higher = ctx->calls.first;
1098 higher_state = first;
1101 higher_state = query;
1104 if (_call_priority_cmp(second, higher_state) > 0) {
1105 higher = ctx->calls.second;
1106 higher_state = second;
1115 static void _call_changed_waiting_update(Callscreen *ctx, OFono_Call *c)
1117 OFono_Call_State state = ofono_call_state_get(c);
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);
1129 static void _call_changed_current_update(Callscreen *ctx, OFono_Call *c)
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);
1137 DBG("changed call %p is lower than previous %p",
1138 c, ctx->calls.current);
1140 } else if (ctx->calls.current == c) {
1141 OFono_Call *other = _call_priority_find_higher(ctx, c);
1143 DBG("other call %p is higher than changed %p",
1145 _call_current_set(ctx, other);
1147 DBG("changed call %p is still the current", c);
1148 _call_current_actions_update(ctx);
1153 static void _call_changed_multiparty_update(Callscreen *ctx, OFono_Call *c)
1155 if (!_call_multiparty_changed(ctx, c)) {
1156 DBG("multiparty unchanged");
1160 _multiparty_update(ctx);
1162 _call_show(ctx, 1, ctx->calls.first);
1163 _call_update(ctx, 1, ctx->calls.first);
1164 _activecall_update(ctx);
1166 if (ofono_call_state_get(c) == OFONO_CALL_STATE_DISCONNECTED) {
1167 DBG("multiparty peer was disconnected");
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");
1176 DBG("multiparty merged to first display, "
1177 "remove second display");
1178 _call_second_set(ctx, NULL);
1180 } else if (ctx->calls.first != c) {
1181 DBG("multiparty split, add peer as second display");
1182 _call_second_set(ctx, c);
1184 OFono_Call *other = _multiparty_find_other(ctx, c);
1185 DBG("multiparty split, add another %p peer as second display",
1187 _call_second_set(ctx, other);
1191 static void _call_changed_swap_merge_update(Callscreen *ctx)
1193 Evas_Object *o = ctx->self;
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");
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");
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";
1215 sig_swap = "disable,swap";
1216 sig_pause = "enable,pause";
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");
1225 static void _call_changed(void *data, OFono_Call *c)
1227 Callscreen *ctx = data;
1228 OFono_Call_State state = ofono_call_state_get(c);
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);
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);
1241 _call_changed_current_update(ctx, c);
1242 _call_changed_multiparty_update(ctx, c);
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);
1249 if (ctx->multiparty.calls)
1250 _multiparty_private_available_update(ctx);
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;
1260 _call_changed_swap_merge_update(ctx);
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);
1267 static void _call_disconnected(void *data, OFono_Call *c, const char *reason)
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);
1274 EINA_SAFETY_ON_NULL_RETURN(reason);
1275 _call_disconnected_show(ctx, c, reason);
1278 static void _on_del(void *data, Evas *e __UNUSED__,
1279 Evas_Object *obj __UNUSED__, void *event __UNUSED__)
1281 Callscreen *ctx = data;
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);
1289 eina_strbuf_free(ctx->tones.todo);
1290 if (ctx->tones.pending)
1291 ofono_pending_cancel(ctx->tones.pending);
1293 if (ctx->elapsed_updater)
1294 ecore_timer_del(ctx->elapsed_updater);
1296 eina_stringshare_del(ctx->disconnected.number);
1298 eina_list_free(ctx->multiparty.calls);
1300 eina_list_free(ctx->calls.list);
1304 Evas_Object *callscreen_add(Evas_Object *parent)
1307 Evas_Object *obj = layout_add(parent, "call");
1308 EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL);
1310 ctx = calloc(1, sizeof(Callscreen));
1312 ctx->tones.todo = eina_strbuf_new();
1314 evas_object_data_set(obj, "callscreen.ctx", ctx);
1316 evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
1318 elm_object_signal_callback_add(obj, "pressed,*", "call",
1320 elm_object_signal_callback_add(obj, "released,*", "call",
1322 elm_object_signal_callback_add(obj, "clicked,*", "call",
1325 elm_object_focus_allow_set(obj, EINA_TRUE);
1326 evas_object_event_callback_add(obj, EVAS_CALLBACK_KEY_DOWN,
1329 _call_clear(ctx, 1);
1330 _call_clear(ctx, 2);
1331 elm_object_signal_emit(obj, "calls,1", "call");
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");
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);
1347 elm_object_part_content_set(obj, "elm.swallow.multiparty-details",
1348 ctx->multiparty.sc);
1350 callback_node_call_added = ofono_call_added_cb_add(_call_added, ctx);
1352 callback_node_call_removed =
1353 ofono_call_removed_cb_add(_call_removed, ctx);
1355 callback_node_call_changed =
1356 ofono_call_changed_cb_add(_call_changed, ctx);
1358 callback_node_call_disconnected =
1359 ofono_call_disconnected_cb_add(_call_disconnected, ctx);
1361 callback_node_modem_changed =
1362 ofono_modem_changed_cb_add(_ofono_changed, ctx);