From 46bb9ebca7586fe833e2b2eccec03321a3c596cb Mon Sep 17 00:00:00 2001 From: Gustavo Sverzut Barbieri Date: Wed, 11 Jul 2012 18:53:29 -0300 Subject: [PATCH] support waiting and held calls. --- data/themes/includes/call.edc | 364 +++++++++++++++++++++++++++++++++++++++++- dialer/callscreen.c | 211 +++++++++++++++++++----- 2 files changed, 534 insertions(+), 41 deletions(-) diff --git a/data/themes/includes/call.edc b/data/themes/includes/call.edc index 45b7272..bab262e 100644 --- a/data/themes/includes/call.edc +++ b/data/themes/includes/call.edc @@ -8,6 +8,8 @@ group { * TEXT: elm.text.name * TEXT: elm.text.status * TEXT: elm.text.elapsed + * TEXT: elm.text.waiting + * TEXT: elm.text.held * * Signals: * Emit (source is "call"): @@ -17,6 +19,10 @@ group { * Listen (source is "call"): * show,answer: show "answer" action * hide,answer: hide "answer" action + * show,waiting: show call waiting popup (decline, hold+answer...) + * hide,waiting: hide call waiting popup + * show,held: show call held entry + * hide,held: hide call held entry * show,elapsed: have elapsed (elm.text.elapsed) and should be visible * hide,elapsed: don't have elapsed and it should be hidden * state,: state changed to @@ -31,7 +37,8 @@ group { * 3 - FLOAT: elapsed time in seconds (> 0.0) * * Where is: numbers 0 to 9, star, hash, mute, keypad, speaker, - * merge, swap, contacts, answer, hangup. + * merge, swap, contacts, answer, hangup, waiting-hangup, hold-answer, + * hangup-answer. * * Where is: disconnected, active, held, dialing, alerting, * incoming, waiting. @@ -209,6 +216,112 @@ group { } \ } + part { + name: "clipper.held"; + type: RECT; + clip_to: "clipper.keypad-hidden"; + description { + state: "default" 0.0; + color: 255 255 255 0; + color_class: "disabled"; + visible: 0; + } + description { + state: "visible" 0.0; + inherit: "default" 0.0; + color: 255 255 255 255; + visible: 1; + } + } + part { + name: "elm.text.held"; + type: TEXT; + mouse_events: 0; + scale: 1; + api: "held" "held party call name"; + clip_to: "clipper.held"; + description { + state: "default" 0.0; + color: 255 255 255 255; + color_class: "action"; + min: 628 170; + rel1 { + to_y: "elm.text.status"; + to_x: "elm.text.name"; + relative: 0.0 1.0; + offset: 0 30; + } + rel2 { + to_y: "elm.text.status"; + to_x: "elm.text.name"; + relative: 1.0 1.0; + offset: -1 199; + } + text { + text: "Someone on hold"; + font: "Verdana"; + size: 99; + size_range: 16 99; + fit: 1 1; + align: 0.0 0.5; + ellipsis: 0.0; + } + } + } + part { + name: "label.held"; + type: TEXT; + mouse_events: 0; + scale: 1; + clip_to: "clipper.held"; + description { + state: "default" 0.0; + color: 255 255 255 255; + color_class: "light"; + fixed: 1 1; + align: 0.0 0.0; + rel1 { + to: "elm.text.held"; + relative: 0.0 1.0; + offset: -1.0 -20; + } + rel2 { + to: "elm.text.held"; + relative: 0.0 1.0; + offset: -1.0 -1; + } + text { + text: "on hold"; + font: "Verdana"; + size: 43; + min: 1 1; + align: 0.0 0.0; + } + } + } + + SEPARATOR("held1", "clipper.held", 0.0, -8, "elm.text.held"); + + programs { + program { + signal: "show,held"; + source: "call"; + action: STATE_SET "visible" 0.0; + transition: DECELERATE 0.3; + target: "clipper.held"; + api: "held_show" "make held entry visible"; + } + program { + signal: "hide,held"; + source: "call"; + action: STATE_SET "default" 0.0; + transition: ACCELERATE 0.3; + target: "clipper.held"; + api: "held_hide" "make held entry hidden"; + } + } + + SEPARATOR("actions", "clipper.actions", 0.0, -8, "bg.actions"); part { @@ -278,7 +391,7 @@ group { program { signal: "state,held"; source: "call"; - after: "hide,actions"; + after: "show,actions"; } program { signal: "state,dialing"; @@ -662,6 +775,7 @@ group { part { name: "clipper.keypad-hidden"; type: RECT; + clip_to: "clipper.waiting-hidden"; description { state: "default" 0.0; color: 255 255 255 255; @@ -677,6 +791,7 @@ group { part { name: "clipper.keypad-visible"; type: RECT; + clip_to: "clipper.waiting-hidden"; description { state: "default" 0.0; color: 255 255 255 0; @@ -1128,6 +1243,7 @@ group { action: STATE_SET "visible" 0.0; target: "area.answer"; target: "clipper.answer"; + api: "answer_show" "make answer button visible"; } program { signal: "hide,answer"; @@ -1135,6 +1251,7 @@ group { action: STATE_SET "default" 0.0; target: "area.answer"; target: "clipper.answer"; + api: "answer_hide" "make answer button hidden"; } } @@ -1142,6 +1259,7 @@ group { name: "button.hangup"; type: RECT; mouse_events: 1; + clip_to: "clipper.waiting-hidden"; description { state: "default" 0.0; color: 255 255 255 255; @@ -1165,6 +1283,7 @@ group { name: "label.hangup"; type: TEXT; mouse_events: 0; + clip_to: "clipper.waiting-hidden"; description { state: "default" 0.0; color: 255 255 255 255; @@ -1220,6 +1339,247 @@ group { api: "hangup_clicked" "hangup was clicked"; } } + + /* waiting popup */ + part { + name: "clipper.waiting-hidden"; + type: RECT; + description { + state: "default" 0.0; + color: 255 255 255 255; + visible: 1; + } + description { + state: "alternate" 0.0; + inherit: "default" 0.0; + color: 255 255 255 0; + visible: 0; + } + } + part { + name: "clipper.waiting-visible"; + type: RECT; + description { + state: "default" 0.0; + color: 255 255 255 0; + visible: 0; + } + description { + state: "alternate" 0.0; + inherit: "default" 0.0; + color: 255 255 255 255; + visible: 1; + } + } + part { + name: "area.waiting"; + type: RECT; + mouse_events: 0; + clip_to: "clipper.waiting-visible"; + description { + state: "default" 0.0; + color: 255 255 255 255; + color_class: "bg"; + visible: 0; + fixed: 1 1; + min: 0 712; + max: 99999 712; + align: 0.5 1.0; + rel1 { + relative: 0.0 -1.0; + offset: 0 0; + } + rel2 { + relative: 1.0 1.0; + offset: -1 712; + } + } + description { + state: "alternate" 0.0; + inherit: "default" 0.0; + visible: 1; + rel1 { + relative: 0.0 -1.0; + offset: 0 -712; + } + rel2 { + relative: 1.0 1.0; + offset: -1 -1; + } + } + } + +#define BUTTON(id, label, colcls, y1, y2) \ + SEPARATOR(id, "clipper.waiting-visible", 0.0, -8, "button."##id); \ + part { \ + name: "button."##id; \ + type: RECT; \ + mouse_events: 1; \ + clip_to: "clipper.waiting-visible"; \ + description { \ + state: "default" 0.0; \ + color: 255 255 255 0; \ + color_class: colcls; \ + rel1 { \ + to: "area.waiting"; \ + relative: 0.0 0.0; \ + offset: 0 y1; \ + } \ + rel2 { \ + to: "area.waiting"; \ + relative: 1.0 0.0; \ + offset: -1 y2; \ + } \ + } \ + description { \ + state: "pressed" 0.0; \ + inherit: "default" 0.0; \ + color: 255 255 255 255; \ + } \ + } \ + part { \ + name: "label."##id; \ + type: TEXT; \ + mouse_events: 0; \ + clip_to: "clipper.waiting-visible"; \ + description { \ + state: "default" 0.0; \ + color: 255 255 255 255; \ + color_class: colcls; \ + rel1 { \ + to: "button."##id; \ + offset: 46 0; \ + } \ + rel2 { \ + to: "button."##id; \ + offset: -47 -1; \ + } \ + text { \ + text: label; \ + font: "Verdana"; \ + size: 58; \ + align: 0.5 0.5; \ + } \ + } \ + description { \ + state: "pressed" 0.0; \ + inherit: "default" 0.0; \ + color_class: "bg"; \ + } \ + } \ + programs { \ + program { \ + signal: "mouse,up,1"; \ + source: "button."##id; \ + action: SIGNAL_EMIT "released,"##id "call"; \ + api: id"_released" id" was released"; \ + after: "show_up_"##id; \ + } \ + program { \ + name: "show_up_"##id; \ + action: STATE_SET "default" 0.0; \ + transition: DECELERATE 0.1; \ + target: "button."##id; \ + target: "label."##id; \ + } \ + program { \ + signal: "mouse,down,1"; \ + source: "button."##id; \ + after: "show_down_"##id; \ + action: SIGNAL_EMIT "pressed,"##id "call"; \ + api: id"_pressed" id" was pressed"; \ + } \ + program { \ + name: "show_down_"##id; \ + action: STATE_SET "pressed" 0.0; \ + transition: ACCELERATE 0.3; \ + target: "button."##id; \ + target: "label."##id; \ + } \ + program { \ + signal: "mouse,clicked,1"; \ + source: "button."##id; \ + action: SIGNAL_EMIT "clicked,"##id "call"; \ + api: id"_clicked" id" was clicked"; \ + } \ + } + + BUTTON("waiting-hangup", "Decline", "action", 186, 355); + BUTTON("hold-answer", "Hold + Answer", "action", 364, 533); + BUTTON("hangup-answer", "Hangup + Answer", "caution", 542, 711); +#undef BUTTON + + SEPARATOR("waiting", "clipper.waiting-visible", 0.0, 0, "area.waiting"); + part { + name: "elm.text.waiting"; + type: TEXT; + mouse_events: 0; + scale: 1; + clip_to: "clipper.waiting-visible"; + api: "waiting" "waiting call name"; + description { + state: "default" 0.0; + color: 255 255 255 255; + color_class: "disabled"; + rel1 { + to: "area.waiting"; + offset: 46 8; + } + rel2 { + to: "area.waiting"; + relative: 1.0 0.0; + offset: -47.0 177; + } + text { + text: "Someone"; + font: "Verdana"; + size: 99; + size_range: 16 99; + fit: 1 1; + align: 0.0 0.5; + ellipsis: 0.0; + } + } + } + + programs { + program { + name: "hide-waiting-phase1"; + signal: "hide,waiting"; + source: "call"; + action: STATE_SET "default" 0.0; + transition: ACCELERATE 0.3; + target: "clipper.waiting-visible"; + target: "area.waiting"; + after: "hide-waiting-phase2"; + api: "waiting_hide" "make waiting popup hidden"; + } + program { + name: "hide-waiting-phase2"; + action: STATE_SET "default" 0.0; + transition: ACCELERATE 0.3; + target: "clipper.waiting-hidden"; + } + + program { + name: "show-waiting-phase1"; + signal: "show,waiting"; + source: "call"; + action: STATE_SET "alternate" 0.0; + transition: ACCELERATE 0.3; + target: "clipper.waiting-hidden"; + after: "show-waiting-phase2"; + api: "waiting_show" "make waiting popup visible"; + } + program { + name: "show-waiting-phase2"; + action: STATE_SET "alternate" 0.0; + transition: ACCELERATE 0.3; + target: "area.waiting"; + target: "clipper.waiting-visible"; + } + } + #undef SEPARATOR } diff --git a/dialer/callscreen.c b/dialer/callscreen.c index 9acf8aa..a128d4d 100644 --- a/dialer/callscreen.c +++ b/dialer/callscreen.c @@ -12,6 +12,8 @@ typedef struct _Callscreen Evas_Object *self; struct { OFono_Call *active; + OFono_Call *waiting; + OFono_Call *held; Eina_List *list; } calls; OFono_Call_State last_state; @@ -21,15 +23,16 @@ typedef struct _Callscreen OFono_Pending *pending; } tones; struct { + const void *call; const char *number; Evas_Object *popup; } disconnected; } Callscreen; -static void _call_active_update(Callscreen *ctx) +static void _calls_update(Callscreen *ctx) { const Eina_List *n; - OFono_Call *c, *found = NULL; + OFono_Call *c, *found = NULL, *waiting = NULL, *held = NULL; OFono_Call_State found_state = OFONO_CALL_STATE_DISCONNECTED; static const int state_priority[] = { [OFONO_CALL_STATE_DISCONNECTED] = 0, @@ -41,7 +44,25 @@ static void _call_active_update(Callscreen *ctx) [OFONO_CALL_STATE_WAITING] = 2 }; - if (ctx->calls.active) + if (ctx->calls.active) { + OFono_Call_State s = ofono_call_state_get(ctx->calls.active); + if (s != OFONO_CALL_STATE_ACTIVE) { + ctx->calls.active = NULL; + ctx->last_state = 0; + } + } + if (ctx->calls.waiting) { + OFono_Call_State s = ofono_call_state_get(ctx->calls.waiting); + if (s != OFONO_CALL_STATE_WAITING) + ctx->calls.waiting = NULL; + } + if (ctx->calls.held) { + OFono_Call_State s = ofono_call_state_get(ctx->calls.held); + if (s != OFONO_CALL_STATE_HELD) + ctx->calls.held = NULL; + } + + if (ctx->calls.active && ctx->calls.waiting && ctx->calls.held) return; EINA_LIST_FOREACH(ctx->calls.list, n, c) { @@ -53,24 +74,54 @@ static void _call_active_update(Callscreen *ctx) found_state = state; found = c; } + if ((!waiting) && (state == OFONO_CALL_STATE_WAITING)) + waiting = c; + if ((!held) && (state == OFONO_CALL_STATE_HELD)) + held = c; } - if (!found) { - DBG("No calls usable"); + DBG("found=%p, state=%d, waiting=%p, held=%p", + found, found_state, waiting, held); + if (!found) return; + + if (!ctx->calls.active) { + ctx->calls.active = found; + ctx->last_state = 0; } + if (!ctx->calls.waiting) + ctx->calls.waiting = waiting; + if (!ctx->calls.held) + ctx->calls.held = held; - DBG("found=%p, state=%d", found, found_state); - ctx->calls.active = found; gui_call_enter(); } -static void _call_disconnected_done(Callscreen *ctx) +static void _call_disconnected_done(Callscreen *ctx, const char *reason) { if (!ctx->calls.list) gui_call_exit(); - else - _call_active_update(ctx); + else { + _calls_update(ctx); + if (strcmp(reason, "local") == 0) { + /* If there is a held call and active is + * hangup we're left with held but no active, + * which is strange. + * + * Just make the held active by calling + * SwapCalls. + */ + if (ctx->calls.active == ctx->disconnected.call && + ctx->calls.held != ctx->disconnected.call) { + INF("User disconnected and left held call. " + "Automatically activate it."); + + /* TODO: sound to notify user */ + ofono_swap_calls(NULL, NULL); + } + } + } + ctx->disconnected.call = NULL; } static void _popup_close(void *data, Evas_Object *o __UNUSED__, void *event __UNUSED__) @@ -82,7 +133,7 @@ static void _popup_close(void *data, Evas_Object *o __UNUSED__, void *event __UN eina_stringshare_replace(&ctx->disconnected.number, NULL); - _call_disconnected_done(ctx); + _call_disconnected_done(ctx, "network"); } static void _popup_redial(void *data, Evas_Object *o __UNUSED__, void *event __UNUSED__) @@ -100,21 +151,38 @@ static void _call_disconnected_show(Callscreen *ctx, OFono_Call *c, const char *number, *title; char msg[1024]; - DBG("ctx=%p, call=%p, previous=%s, disconnected=%p (%s)", - ctx, ctx->calls.active, ctx->disconnected.number, c, reason); + DBG("ctx=%p, active=%p, held=%p, waiting=%p, previous=%s, " + "disconnected=%p (%s)", + ctx, ctx->calls.active, ctx->calls.held, ctx->calls.waiting, + ctx->disconnected.number, c, reason); + + if (ctx->calls.waiting == c) { + ctx->calls.waiting = NULL; + elm_object_part_text_set(ctx->self, "elm.text.waiting", ""); + elm_object_signal_emit(ctx->self, "hide,waiting", "call"); + return; + } + if (ctx->calls.held == c) { + ctx->calls.held = NULL; + elm_object_part_text_set(ctx->self, "elm.text.held", ""); + elm_object_signal_emit(ctx->self, "hide,held", "call"); + return; + } if ((ctx->calls.active) && (ctx->calls.active != c)) return; ctx->calls.active = NULL; + ctx->last_state = 0; + ctx->disconnected.call = c; if ((strcmp(reason, "local") == 0) || (strcmp(reason, "remote") == 0)) { - _call_disconnected_done(ctx); + _call_disconnected_done(ctx, reason); return; } number = ofono_call_line_id_get(c); if ((!number) || (number[0] == '\0')) { - _call_disconnected_done(ctx); + _call_disconnected_done(ctx, reason); return; } @@ -145,6 +213,8 @@ static void _call_disconnected_show(Callscreen *ctx, OFono_Call *c, elm_object_part_content_set(p, "button2", bt); evas_object_smart_callback_add(bt, "clicked", _popup_redial, ctx); + /* TODO: sound to notify user */ + evas_object_show(p); } @@ -170,7 +240,9 @@ static void _on_pressed(void *data, Evas_Object *obj __UNUSED__, const char *emission, const char *source __UNUSED__) { Callscreen *ctx = data; - DBG("ctx=%p, call=%p, signal: %s", ctx, ctx->calls.active, emission); + DBG("ctx=%p, active=%p, held=%p, waiting=%p, signal: %s", + ctx, ctx->calls.active, ctx->calls.held, ctx->calls.waiting, + emission); EINA_SAFETY_ON_FALSE_RETURN(eina_str_has_prefix(emission, "pressed,")); emission += strlen("pressed,"); @@ -182,7 +254,9 @@ static void _on_released(void *data, Evas_Object *obj __UNUSED__, const char *source __UNUSED__) { Callscreen *ctx = data; - DBG("ctx=%p, call=%p, signal: %s", ctx, ctx->calls.active, emission); + DBG("ctx=%p, active=%p, held=%p, waiting=%p, signal: %s", + ctx, ctx->calls.active, ctx->calls.held, ctx->calls.waiting, + emission); EINA_SAFETY_ON_FALSE_RETURN(eina_str_has_prefix(emission, "released,")); emission += strlen("released,"); @@ -194,7 +268,9 @@ static void _on_clicked(void *data, Evas_Object *obj __UNUSED__, { Callscreen *ctx = data; const char *dtmf = NULL; - DBG("ctx=%p, call=%p, signal: %s", ctx, ctx->calls.active, emission); + DBG("ctx=%p, active=%p, held=%p, waiting=%p, signal: %s", + ctx, ctx->calls.active, ctx->calls.held, ctx->calls.waiting, + emission); EINA_SAFETY_ON_FALSE_RETURN(eina_str_has_prefix(emission, "clicked,")); emission += strlen("clicked,"); @@ -228,6 +304,18 @@ static void _on_clicked(void *data, Evas_Object *obj __UNUSED__, ERR("TODO - implement platform loudspeaker code"); } else if (strcmp(emission, "contacts") == 0) { ERR("TODO - implement access to contacts"); + } else if (strcmp(emission, "swap") == 0) { + if (ctx->calls.held) + ofono_swap_calls(NULL, NULL); + } else if (strcmp(emission, "waiting-hangup") == 0) { + if (ctx->calls.waiting) + ofono_call_hangup(ctx->calls.waiting, NULL, NULL); + } else if (strcmp(emission, "hangup-answer") == 0) { + if (ctx->calls.waiting) + ofono_release_and_answer(NULL, NULL); + } else if (strcmp(emission, "hold-answer") == 0) { + if (ctx->calls.waiting) + ofono_hold_and_answer(NULL, NULL); } } @@ -294,14 +382,12 @@ static void _ofono_changed(void *data) static void _call_added(void *data, OFono_Call *c) { Callscreen *ctx = data; - DBG("ctx=%p, call=%p, added=%p", ctx, ctx->calls.active, c); - - if (!ofono_call_state_valid_check(c)) - return; + DBG("ctx=%p, active=%p, held=%p, waiting=%p, added=%p", + ctx, ctx->calls.active, ctx->calls.held, ctx->calls.waiting, c); ctx->calls.list = eina_list_append(ctx->calls.list, c); if (!ctx->calls.active) { - ctx->calls.active = c; + _calls_update(ctx); gui_call_enter(); } } @@ -309,7 +395,8 @@ static void _call_added(void *data, OFono_Call *c) static void _call_removed(void *data, OFono_Call *c) { Callscreen *ctx = data; - DBG("ctx=%p, call=%p, removed=%p", ctx, ctx->calls.active, c); + DBG("ctx=%p, active=%p, held=%p, waiting=%p, removed=%p", + ctx, ctx->calls.active, ctx->calls.held, ctx->calls.waiting, c); ctx->calls.list = eina_list_remove(ctx->calls.list, c); _call_disconnected_show(ctx, c, "local"); } @@ -322,19 +409,20 @@ static Eina_Bool _on_elapsed_updater(void *data) Evas_Object *ed; char buf[128]; + if (!ctx->calls.active) + goto stop; + start = ofono_call_start_time_get(ctx->calls.active); if (start < 0) { ERR("Unknown start time for call"); - ctx->elapsed_updater = NULL; - return EINA_FALSE; + goto stop; } elapsed = ecore_loop_time_get() - start; if (elapsed < 0) { ERR("Time rewinded? %f - %f = %f", ecore_loop_time_get(), start, elapsed); - ctx->elapsed_updater = NULL; - return EINA_FALSE; + goto stop; } ed = elm_layout_edje_get(ctx->self); @@ -355,19 +443,50 @@ static Eina_Bool _on_elapsed_updater(void *data) next = 1.0 - (elapsed - (int)elapsed); ctx->elapsed_updater = ecore_timer_add(next, _on_elapsed_updater, ctx); return EINA_FALSE; + +stop: + elm_object_part_text_set(ctx->self, "elm.text.elapsed", ""); + elm_object_signal_emit(ctx->self, "hide,elapsed", "call"); + ctx->elapsed_updater = NULL; + return EINA_FALSE; } static void _call_changed(void *data, OFono_Call *c) { Callscreen *ctx = data; OFono_Call_State state; + Eina_Bool was_waiting, was_held; const char *contact, *status, *sig = "hide,answer"; - DBG("ctx=%p, call=%p, changed=%p", ctx, ctx->calls.active, c); + DBG("ctx=%p, active=%p, held=%p, waiting=%p, changed=%p", + ctx, ctx->calls.active, ctx->calls.held, ctx->calls.waiting, c); + + was_waiting = !!ctx->calls.waiting; + was_held = !!ctx->calls.held; + + _calls_update(ctx); + + if ((ctx->calls.waiting) && (!was_waiting)) { + char buf[256]; + contact = ofono_call_name_get(ctx->calls.waiting); + if ((!contact) || (contact[0] == '\0')) + contact = ofono_call_line_id_get(ctx->calls.waiting); + snprintf(buf, sizeof(buf), "%s is waiting...", contact); + elm_object_part_text_set(ctx->self, "elm.text.waiting", buf); + elm_object_signal_emit(ctx->self, "show,waiting", "call"); + } else if ((!ctx->calls.waiting) && (was_waiting)) { + elm_object_part_text_set(ctx->self, "elm.text.waiting", ""); + elm_object_signal_emit(ctx->self, "hide,waiting", "call"); + } + + if ((ctx->calls.held) && (!was_held)) + elm_object_signal_emit(ctx->self, "show,held", "call"); + else if ((!ctx->calls.held) && (was_held)) { + elm_object_part_text_set(ctx->self, "elm.text.held", ""); + elm_object_signal_emit(ctx->self, "hide,held", "call"); + } - _call_active_update(ctx); - if (ctx->calls.active != c) - return; + c = ctx->calls.active; contact = ofono_call_name_get(c); if ((!contact) || (contact[0] == '\0')) @@ -446,17 +565,30 @@ static void _call_changed(void *data, OFono_Call *c) sig = "hide,elapsed"; elm_object_part_text_set(ctx->self, "elm.text.elapsed", ""); - } else if (!have_updater && want_updater) { - ctx->elapsed_updater = ecore_timer_add(0.01, - _on_elapsed_updater, ctx); - sig = "show,elapsed"; + } else if (want_updater) { + if (!have_updater) + sig = "show,elapsed"; + else { + ecore_timer_del(ctx->elapsed_updater); + ctx->elapsed_updater = NULL; + } + _on_elapsed_updater(ctx); } if (sig) elm_object_signal_emit(ctx->self, sig, "call"); } + if (ctx->calls.held) { + contact = ofono_call_name_get(ctx->calls.held); + if ((!contact) || (contact[0] == '\0')) + contact = ofono_call_line_id_get(ctx->calls.held); + elm_object_part_text_set(ctx->self, "elm.text.held", contact); + } + elm_object_signal_emit(ctx->self, "disable,merge", "call"); - elm_object_signal_emit(ctx->self, "disable,swap", "call"); + + sig = ctx->calls.held ? "enable,swap" : "disable,swap"; + elm_object_signal_emit(ctx->self, sig, "call"); if (state == OFONO_CALL_STATE_DISCONNECTED) _call_disconnected_show(ctx, c, "local"); @@ -467,8 +599,9 @@ static void _call_changed(void *data, OFono_Call *c) static void _call_disconnected(void *data, OFono_Call *c, const char *reason) { Callscreen *ctx = data; - DBG("ctx=%p, call=%p, disconnected=%p (%s)", - ctx, ctx->calls.active, c, reason); + DBG("ctx=%p, active=%p, held=%p, waiting=%p, disconnected=%p (%s)", + ctx, ctx->calls.active, ctx->calls.held, ctx->calls.waiting, + c, reason); EINA_SAFETY_ON_NULL_RETURN(reason); _call_disconnected_show(ctx, c, reason); -- 2.7.4