4 #include <Elementary.h>
16 #ifndef EET_COMPRESSION_DEFAULT
17 #define EET_COMPRESSION_DEFAULT 1
20 #define HISTORY_ENTRY "history"
22 typedef struct _Call_Info_List {
27 typedef struct _History {
29 Eet_Data_Descriptor *edd;
30 Eet_Data_Descriptor *edd_list;
31 Call_Info_List *calls;
32 Elm_Genlist_Item_Class *itc;
33 Evas_Object *genlist_all, *genlist_missed;
34 Ecore_Poller *updater;
37 typedef struct _Call_Info {
40 long long creation_time; /* not in edd */
45 const OFono_Call *call; /* not in edd */
48 static OFono_Callback_List_Call_Node *callback_node_call_removed = NULL;
49 static OFono_Callback_List_Call_Node *callback_node_call_changed = NULL;
51 static Eina_Bool _history_time_updater(void *data)
56 it = elm_genlist_first_item_get(ctx->genlist_all);
57 for (; it != NULL; it = elm_genlist_item_next_get(it))
58 elm_genlist_item_update(it);
60 it = elm_genlist_first_item_get(ctx->genlist_missed);
61 for (; it != NULL; it = elm_genlist_item_next_get(it))
62 elm_genlist_item_update(it);
67 static Call_Info *_history_call_info_search(const History *history,
68 const OFono_Call *call)
73 EINA_LIST_FOREACH(history->calls->list, l, call_info)
74 if (call_info->call == call)
80 static Eina_Bool _history_call_info_update(Call_Info *call_info)
82 OFono_Call_State state;
84 EINA_SAFETY_ON_NULL_RETURN_VAL(call_info->call, EINA_FALSE);
85 state = ofono_call_state_get(call_info->call);
87 if (state == OFONO_CALL_STATE_INCOMING ||
88 state == OFONO_CALL_STATE_WAITING) {
89 if (!call_info->incoming) {
90 call_info->incoming = EINA_TRUE;
93 } else if (state == OFONO_CALL_STATE_DIALING ||
94 state == OFONO_CALL_STATE_ALERTING) {
95 if (!call_info->incoming) {
96 call_info->incoming = EINA_FALSE;
99 } else if (state == OFONO_CALL_STATE_ACTIVE ||
100 state == OFONO_CALL_STATE_HELD) {
101 if (!call_info->completed) {
102 call_info->start_time = ofono_call_full_start_time_get
104 if (call_info->start_time == 0)
105 call_info->start_time = call_info->creation_time;
107 call_info->completed = EINA_TRUE;
115 static void _on_item_clicked(void *data, Evas_Object *obj __UNUSED__,
118 Elm_Object_Item *it = event_info;
119 const char *number = data;
120 gui_number_set(number, EINA_TRUE);
121 elm_genlist_item_selected_set(it, EINA_FALSE);
124 static void _history_call_changed(void *data, OFono_Call *call)
126 History *history = data;
127 const char *line_id = ofono_call_line_id_get(call);
128 Call_Info *call_info;
129 OFono_Call_State state = ofono_call_state_get(call);
131 call_info = _history_call_info_search(history, call);
132 DBG("call=%p, id=%s, state=%d, completed=%d, incoming=%d, info=%p",
133 call, line_id, state,
134 call_info ? call_info->completed : EINA_FALSE,
135 call_info ? call_info->incoming : EINA_FALSE,
141 call_info = calloc(1, sizeof(Call_Info));
142 EINA_SAFETY_ON_NULL_RETURN(call_info);
144 call_info->call = call;
145 call_info->start_time = ofono_call_full_start_time_get(call);
146 call_info->creation_time = time(NULL);
147 call_info->line_id = eina_stringshare_add(line_id);
148 call_info->name = eina_stringshare_add(ofono_call_name_get(call));
149 history->calls->list =
150 eina_list_prepend(history->calls->list, call_info);
151 history->calls->dirty = EINA_TRUE;
154 if (_history_call_info_update(call_info))
155 history->calls->dirty = EINA_TRUE;
158 static void _history_call_log_save(History *history)
162 EINA_SAFETY_ON_NULL_RETURN(history->calls);
163 DBG("save history (%u calls, dirty: %d) to %s",
164 eina_list_count(history->calls->list), history->calls->dirty,
167 ecore_file_unlink(history->bkp);
168 ecore_file_mv(history->path, history->bkp);
169 efile = eet_open(history->path, EET_FILE_MODE_WRITE);
170 EINA_SAFETY_ON_NULL_RETURN(efile);
171 if (!(eet_data_write(efile,
172 history->edd_list, HISTORY_ENTRY,
173 history->calls, EET_COMPRESSION_DEFAULT)))
174 ERR("Could in the history log file");
179 static void _history_call_removed(void *data, OFono_Call *call)
182 History *history = data;
183 const char *line_id = ofono_call_line_id_get(call);
184 Call_Info *call_info;
188 call_info = _history_call_info_search(history, call);
189 DBG("call=%p, id=%s, info=%p", call, line_id, call_info);
190 EINA_SAFETY_ON_NULL_RETURN(call_info);
192 if (call_info->start_time == 0)
193 call_info->start_time = call_info->creation_time;
195 start = call_info->start_time;
198 if (call_info->completed)
199 INF("Call end: %s at %s", line_id, tm);
201 if (!call_info->incoming)
202 INF("Not answered: %s at %s", line_id, tm);
204 INF("Missed: %s at %s", line_id, tm);
205 it = elm_genlist_item_prepend(history->genlist_missed,
208 ELM_GENLIST_ITEM_NONE,
211 elm_genlist_item_show(it, ELM_GENLIST_ITEM_SCROLLTO_IN);
215 call_info->end_time = time(NULL);
216 call_info->call = NULL;
217 history->calls->dirty = EINA_TRUE;
218 _history_call_log_save(history);
220 it = elm_genlist_item_prepend(history->genlist_all, history->itc,
221 call_info, NULL, ELM_GENLIST_ITEM_NONE,
222 _on_item_clicked, call_info->line_id);
223 elm_genlist_item_show(it, ELM_GENLIST_ITEM_SCROLLTO_IN);
226 static void _call_info_free(Call_Info *call_info)
228 eina_stringshare_del(call_info->line_id);
229 eina_stringshare_del(call_info->name);
233 static void _on_del(void *data, Evas *e __UNUSED__,
234 Evas_Object *obj __UNUSED__, void *event __UNUSED__)
236 History *history = data;
237 Call_Info *call_info;
239 ecore_poller_del(history->updater);
241 if (history->calls->dirty)
242 _history_call_log_save(history);
244 ofono_call_removed_cb_del(callback_node_call_removed);
245 ofono_call_changed_cb_del(callback_node_call_changed);
246 eet_data_descriptor_free(history->edd);
247 eet_data_descriptor_free(history->edd_list);
248 EINA_LIST_FREE(history->calls->list, call_info)
249 _call_info_free(call_info);
250 free(history->calls);
251 elm_genlist_item_class_free(history->itc);
255 ecore_file_shutdown();
259 static void _history_call_info_descriptor_init(Eet_Data_Descriptor **edd,
260 Eet_Data_Descriptor **edd_list)
262 Eet_Data_Descriptor_Class eddc;
264 EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Call_Info);
265 *edd = eet_data_descriptor_stream_new(&eddc);
267 EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Call_Info_List);
268 *edd_list = eet_data_descriptor_stream_new(&eddc);
270 EET_DATA_DESCRIPTOR_ADD_BASIC(*edd, Call_Info,
271 "completed", completed, EET_T_UCHAR);
272 EET_DATA_DESCRIPTOR_ADD_BASIC(*edd, Call_Info,
273 "incoming", incoming, EET_T_UCHAR);
275 EET_DATA_DESCRIPTOR_ADD_BASIC(*edd, Call_Info,
276 "start_time", start_time, EET_T_LONG_LONG);
277 EET_DATA_DESCRIPTOR_ADD_BASIC(*edd, Call_Info,
278 "end_time", end_time, EET_T_LONG_LONG);
279 EET_DATA_DESCRIPTOR_ADD_BASIC(*edd, Call_Info,
280 "line_id", line_id, EET_T_STRING);
281 EET_DATA_DESCRIPTOR_ADD_BASIC(*edd, Call_Info,
282 "name", name, EET_T_STRING);
284 EET_DATA_DESCRIPTOR_ADD_LIST(*edd_list, Call_Info_List, "list", list,
288 static void _history_call_log_read(History *history)
290 Call_Info *call_info;
293 Call_Info_List *calls = NULL;
296 efile = eet_open(history->path, EET_FILE_MODE_READ);
299 calls = eet_data_read(efile, history->edd_list, HISTORY_ENTRY);
304 efile = eet_open(history->bkp, EET_FILE_MODE_READ);
306 calls = eet_data_read(efile, history->edd_list,
313 calls = calloc(1, sizeof(Call_Info_List));
315 history->calls = calls;
316 EINA_SAFETY_ON_NULL_RETURN(history->calls);
318 EINA_LIST_FOREACH(history->calls->list, l, call_info) {
319 elm_genlist_item_append(history->genlist_all, history->itc,
320 call_info, NULL, ELM_GENLIST_ITEM_NONE,
321 _on_item_clicked, call_info->line_id);
322 if (!call_info->completed)
323 elm_genlist_item_append(history->genlist_missed,
324 history->itc, call_info, NULL,
325 ELM_GENLIST_ITEM_NONE,
330 it = elm_genlist_first_item_get(history->genlist_all);
332 elm_genlist_item_show(it, ELM_GENLIST_ITEM_SCROLLTO_TOP);
334 it = elm_genlist_first_item_get(history->genlist_missed);
336 elm_genlist_item_show(it, ELM_GENLIST_ITEM_SCROLLTO_TOP);
339 static char *_item_label_get(void *data, Evas_Object *obj __UNUSED__,
342 Call_Info *call_info = data;
344 if (strncmp(part, "text.call", strlen("text.call")))
347 part += strlen("text.call.");
349 if (!strcmp(part, "name")) {
350 if (!call_info->name || call_info->name[0] == '\0')
351 return phone_format(call_info->line_id);
352 return strdup(call_info->name);
355 if (!strcmp(part, "time")) {
356 if ((call_info->completed) && (call_info->end_time))
357 return date_format(call_info->end_time);
358 return date_format(call_info->start_time);
361 /* TODO: Fetch phone type from contacts information*/
362 if (!strcmp(part, "type"))
363 return strdup("TODO:TELEPHONE TYPE");
365 ERR("Unexpected text part: %s", part);
370 static Eina_Bool _item_state_get(void *data, Evas_Object *obj __UNUSED__,
373 Call_Info *call_info = data;
375 if (!strcmp(part, "missed"))
376 return !call_info->completed;
377 else if (!strcmp(part, "completed"))
378 return call_info->completed;
379 else if (!strcmp(part, "outgoing"))
380 return !call_info->incoming;
381 else if (!strcmp(part, "incoming"))
382 return call_info->incoming;
384 ERR("Unexpected state part: %s", part);
388 static void _on_clicked(void *data __UNUSED__, Evas_Object *obj __UNUSED__,
389 const char *emission, const char *source __UNUSED__)
391 EINA_SAFETY_ON_NULL_RETURN(emission);
392 emission += strlen("clicked,");
394 if (!strcmp(emission, "all"))
395 elm_object_signal_emit(obj, "show,all", "gui");
397 elm_object_signal_emit(obj, "show,missed", "gui");
400 static void _on_more_clicked(void *data __UNUSED__, Evas_Object *obj __UNUSED__,
401 const char *emission __UNUSED__,
402 const char *source __UNUSED__)
407 static Evas_Object *_item_content_get(void *data __UNUSED__, Evas_Object *obj,
408 const char *part __UNUSED__)
412 btn = gui_layout_add(obj, "history/img");
413 EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL);
414 elm_object_signal_callback_add(btn, "clicked,more", "gui",
415 _on_more_clicked, NULL);
416 evas_object_propagate_events_set(btn, EINA_FALSE);
421 Evas_Object *history_add(Evas_Object *parent)
425 const char *config_path;
426 char *path, base_dir[PATH_MAX];
427 Elm_Genlist_Item_Class *itc;
428 Evas_Object *obj, *genlist_all, *genlist_missed;
432 history = calloc(1, sizeof(History));
433 EINA_SAFETY_ON_NULL_RETURN_VAL(history, NULL);
435 obj = gui_layout_add(parent, "history_bg");
436 EINA_SAFETY_ON_NULL_GOTO(obj, err_layout);
438 genlist_all = elm_genlist_add(obj);
439 EINA_SAFETY_ON_NULL_GOTO(genlist_all, err_object_new);
440 elm_object_style_set(genlist_all, "history");
442 genlist_missed = elm_genlist_add(obj);
443 EINA_SAFETY_ON_NULL_GOTO(genlist_missed, err_object_new);
444 elm_object_style_set(genlist_missed, "history");
446 itc = elm_genlist_item_class_new();
447 EINA_SAFETY_ON_NULL_GOTO(itc, err_object_new);
448 itc->item_style = "history";
449 itc->func.text_get = _item_label_get;
450 itc->func.content_get = _item_content_get;
451 itc->func.state_get = _item_state_get;
452 itc->func.del = NULL;
453 history->genlist_all = genlist_all;
454 history->genlist_missed = genlist_missed;
457 elm_object_part_content_set(obj, "elm.swallow.all", genlist_all);
458 elm_object_part_content_set(obj, "elm.swallow.missed", genlist_missed);
459 elm_object_signal_emit(obj, "show,all", "gui");
460 elm_object_signal_callback_add(obj, "clicked,*", "gui",
463 config_path = efreet_config_home_get();
464 snprintf(base_dir, sizeof(base_dir), "%s/%s", config_path,
466 ecore_file_mkpath(base_dir);
467 r = asprintf(&path, "%s/%s/history.eet", config_path, PACKAGE_NAME);
472 history->path = path;
473 r = asprintf(&path, "%s/%s/history.eet.bkp", config_path,
481 _history_call_info_descriptor_init(&history->edd, &history->edd_list);
482 _history_call_log_read(history);
483 EINA_SAFETY_ON_NULL_GOTO(history->calls, err_log_read);
484 evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _on_del,
486 callback_node_call_changed =
487 ofono_call_changed_cb_add(_history_call_changed, history);
488 callback_node_call_removed =
489 ofono_call_removed_cb_add(_history_call_removed, history);
491 /* ECORE_POLLER_CORE is 1/8th of second. */
492 history->updater = ecore_poller_add(ECORE_POLLER_CORE, 8 * 60,
493 _history_time_updater,
499 eet_data_descriptor_free(history->edd);
500 eet_data_descriptor_free(history->edd_list);
504 elm_genlist_item_class_free(itc);
509 ecore_file_shutdown();