d6288cd517f96373963f5fd73e0801bdcc72e139
[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
10 typedef struct _Callscreen
11 {
12         Evas_Object *self;
13         OFono_Call *in_use;
14         Eina_List *calls;
15         struct {
16                 const char *number;
17                 Evas_Object *popup;
18         } disconnected;
19 } Callscreen;
20
21 static void _call_in_use_update(Callscreen *ctx)
22 {
23         const Eina_List *n;
24         OFono_Call *c, *found = NULL;
25         OFono_Call_State found_state = OFONO_CALL_STATE_DISCONNECTED;
26         static const int state_priority[] = {
27                 [OFONO_CALL_STATE_DISCONNECTED] = 0,
28                 [OFONO_CALL_STATE_ACTIVE] = 6,
29                 [OFONO_CALL_STATE_HELD] = 1,
30                 [OFONO_CALL_STATE_DIALING] = 5,
31                 [OFONO_CALL_STATE_ALERTING] = 4,
32                 [OFONO_CALL_STATE_INCOMING] = 3,
33                 [OFONO_CALL_STATE_WAITING] = 2
34         };
35
36         if (ctx->in_use)
37                 return;
38
39         EINA_LIST_FOREACH(ctx->calls, n, c) {
40                 OFono_Call_State state = ofono_call_state_get(c);
41
42                 DBG("compare %p (%d) to %p (%d)", found, found_state,
43                         c, state);
44                 if (state_priority[state] > state_priority[found_state]) {
45                         found_state = state;
46                         found = c;
47                 }
48         }
49
50         if (!found) {
51                 DBG("No calls usable");
52                 return;
53         }
54
55         DBG("found=%p, state=%d", found, found_state);
56         ctx->in_use = found;
57         gui_call_enter();
58 }
59
60 static void _call_disconnected_done(Callscreen *ctx)
61 {
62         if (!ctx->calls)
63                 gui_call_exit();
64         else
65                 _call_in_use_update(ctx);
66 }
67
68 static void _popup_close(void *data, Evas_Object *o __UNUSED__, void *event __UNUSED__)
69 {
70         Callscreen *ctx = data;
71
72         evas_object_del(ctx->disconnected.popup);
73         ctx->disconnected.popup = NULL;
74
75         eina_stringshare_replace(&ctx->disconnected.number, NULL);
76
77         _call_disconnected_done(ctx);
78 }
79
80 static void _popup_redial(void *data, Evas_Object *o __UNUSED__, void *event __UNUSED__)
81 {
82         Callscreen *ctx = data;
83
84         ofono_dial(ctx->disconnected.number, NULL, NULL, NULL);
85         _popup_close(ctx, NULL, NULL);
86 }
87
88 static void _call_disconnected_show(Callscreen *ctx, OFono_Call *c,
89                                         const char *reason)
90 {
91         Evas_Object *p, *bt;
92         const char *number, *title;
93         char msg[1024];
94
95         DBG("ctx=%p, call=%p, previous=%s, disconnected=%p (%s)",
96                 ctx, ctx->in_use, ctx->disconnected.number, c, reason);
97
98         if ((ctx->in_use) && (ctx->in_use != c))
99                 return;
100         ctx->in_use = NULL;
101
102         if ((strcmp(reason, "local") == 0) || (strcmp(reason, "remote") == 0)) {
103                 _call_disconnected_done(ctx);
104                 return;
105         }
106
107         number = ofono_call_line_id_get(c);
108         if ((!number) || (number[0] == '\0')) {
109                 _call_disconnected_done(ctx);
110                 return;
111         }
112
113         if (ctx->disconnected.number)
114                 return;
115
116         if (strcmp(reason, "network") == 0)
117                 title = "Network Disconnected!";
118         else
119                 title = "Disconnected!";
120
121         snprintf(msg, sizeof(msg), "Try to redial %s", number);
122
123         eina_stringshare_replace(&ctx->disconnected.number, number);
124
125         ctx->disconnected.popup = p = elm_popup_add(ctx->self);
126         evas_object_size_hint_weight_set(p, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
127         elm_object_part_text_set(p, "title,text", title);
128         elm_object_text_set(p, msg);
129
130         bt = elm_button_add(p);
131         elm_object_text_set(bt, "Close");
132         elm_object_part_content_set(p, "button1", bt);
133         evas_object_smart_callback_add(bt, "clicked", _popup_close, ctx);
134
135         bt = elm_button_add(p);
136         elm_object_text_set(bt, "Redial");
137         elm_object_part_content_set(p, "button2", bt);
138         evas_object_smart_callback_add(bt, "clicked", _popup_redial, ctx);
139
140         evas_object_show(p);
141 }
142
143 static void _on_pressed(void *data, Evas_Object *obj __UNUSED__,
144                         const char *emission, const char *source __UNUSED__)
145 {
146         Callscreen *ctx = data;
147         DBG("ctx=%p, call=%p, signal: %s", ctx, ctx->in_use, emission);
148
149         EINA_SAFETY_ON_FALSE_RETURN(eina_str_has_prefix(emission, "pressed,"));
150         emission += strlen("pressed,");
151
152 }
153
154 static void _on_released(void *data, Evas_Object *obj __UNUSED__,
155                                 const char *emission,
156                                 const char *source __UNUSED__)
157 {
158         Callscreen *ctx = data;
159         DBG("ctx=%p, call=%p, signal: %s", ctx, ctx->in_use, emission);
160
161         EINA_SAFETY_ON_FALSE_RETURN(eina_str_has_prefix(emission, "released,"));
162         emission += strlen("released,");
163
164 }
165
166 static void _on_clicked(void *data, Evas_Object *obj __UNUSED__,
167                         const char *emission, const char *source __UNUSED__)
168 {
169         Callscreen *ctx = data;
170         DBG("ctx=%p, call=%p, signal: %s", ctx, ctx->in_use, emission);
171
172         EINA_SAFETY_ON_FALSE_RETURN(eina_str_has_prefix(emission, "clicked,"));
173         emission += strlen("clicked,");
174
175         if (strcmp(emission, "hangup") == 0) {
176                 if (ctx->in_use)
177                         ofono_call_hangup(ctx->in_use, NULL, NULL);
178         } else if (strcmp(emission, "answer") == 0) {
179                 if (ctx->in_use)
180                         ofono_call_answer(ctx->in_use, NULL, NULL);
181         }
182 }
183
184 static void _call_added(void *data, OFono_Call *c)
185 {
186         Callscreen *ctx = data;
187         DBG("ctx=%p, call=%p, added=%p", ctx, ctx->in_use, c);
188         ctx->calls = eina_list_append(ctx->calls, c);
189         if ((!ctx->in_use) && (ofono_call_state_valid_check(c))) {
190                 ctx->in_use = c;
191                 gui_call_enter();
192         }
193 }
194
195 static void _call_removed(void *data, OFono_Call *c)
196 {
197         Callscreen *ctx = data;
198         DBG("ctx=%p, call=%p, removed=%p", ctx, ctx->in_use, c);
199         ctx->calls = eina_list_remove(ctx->calls, c);
200         _call_disconnected_show(ctx, c, "local");
201 }
202
203 static void _call_changed(void *data, OFono_Call *c)
204 {
205         Callscreen *ctx = data;
206         OFono_Call_State state;
207         const char *contact, *status, *sig = "hide,answer";
208
209         DBG("ctx=%p, call=%p, changed=%p", ctx, ctx->in_use, c);
210
211         _call_in_use_update(ctx);
212         if (ctx->in_use != c)
213                 return;
214
215         contact = ofono_call_name_get(c);
216         if ((!contact) || (contact[0] == '\0'))
217                 contact = ofono_call_line_id_get(c);
218
219         state = ofono_call_state_get(c);
220         switch (state) {
221         case OFONO_CALL_STATE_DISCONNECTED:
222                 status = "Disconnected";
223                 break;
224         case OFONO_CALL_STATE_ACTIVE:
225                 status = "Active";
226                 break;
227         case OFONO_CALL_STATE_HELD:
228                 status = "Held";
229                 break;
230         case OFONO_CALL_STATE_DIALING:
231                 status = "Dialing...";
232                 break;
233         case OFONO_CALL_STATE_ALERTING:
234                 status = "Alerting...";
235                 break;
236         case OFONO_CALL_STATE_INCOMING:
237                 status = "Incoming...";
238                 sig = "show,answer";
239                 break;
240         case OFONO_CALL_STATE_WAITING:
241                 status = "Waiting...";
242                 break;
243         default:
244                 status = "?";
245         }
246
247         elm_object_part_text_set(ctx->self, "elm.text.name", contact);
248         elm_object_part_text_set(ctx->self, "elm.text.status", status);
249         elm_object_signal_emit(ctx->self, sig, "call");
250
251         if (state == OFONO_CALL_STATE_DISCONNECTED)
252                 _call_disconnected_show(ctx, c, "local");
253 }
254
255 static void _call_disconnected(void *data, OFono_Call *c, const char *reason)
256 {
257         Callscreen *ctx = data;
258         DBG("ctx=%p, call=%p, disconnected=%p (%s)",
259                 ctx, ctx->in_use, c, reason);
260
261         EINA_SAFETY_ON_NULL_RETURN(reason);
262         _call_disconnected_show(ctx, c, reason);
263 }
264
265 static void _on_del(void *data, Evas *e __UNUSED__,
266                         Evas_Object *obj __UNUSED__, void *event __UNUSED__)
267 {
268         Callscreen *ctx = data;
269
270         ofono_call_added_cb_set(NULL, NULL);
271         ofono_call_removed_cb_set(NULL, NULL);
272         ofono_call_changed_cb_set(NULL, NULL);
273         ofono_call_disconnected_cb_set(NULL, NULL);
274
275         eina_stringshare_del(ctx->disconnected.number);
276
277         eina_list_free(ctx->calls);
278         free(ctx);
279 }
280
281 Evas_Object *callscreen_add(Evas_Object *parent) {
282         Callscreen *ctx;
283         Evas_Object *obj = gui_layout_add(parent, "call");
284         EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL);
285
286         ctx = calloc(1, sizeof(Callscreen));
287         ctx->self = obj;
288
289         evas_object_data_set(obj, "callscreen.ctx", ctx);
290
291         evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
292                                         _on_del, ctx);
293         elm_object_signal_callback_add(obj, "pressed,*", "call",
294                                         _on_pressed, ctx);
295         elm_object_signal_callback_add(obj, "released,*", "call",
296                                         _on_released, ctx);
297         elm_object_signal_callback_add(obj, "clicked,*", "call",
298                                         _on_clicked, ctx);
299
300         elm_object_part_text_set(obj, "elm.text.name", "");
301         elm_object_part_text_set(obj, "elm.text.status", "");
302
303         ofono_call_added_cb_set(_call_added, ctx);
304         ofono_call_removed_cb_set(_call_removed, ctx);
305         ofono_call_changed_cb_set(_call_changed, ctx);
306         ofono_call_disconnected_cb_set(_call_disconnected, ctx);
307
308         return obj;
309 }