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;
34 Evas_Object *clear_popup;
35 Evas_Object *genlist_all, *genlist_missed;
36 Ecore_Poller *updater;
40 typedef struct _Call_Info {
43 long long creation_time; /* not in edd */
48 const OFono_Call *call; /* not in edd */
50 Elm_Object_Item *it_all; /*not in edd */
51 Elm_Object_Item *it_missed; /*not in edd */
54 static OFono_Callback_List_Call_Node *callback_node_call_removed = NULL;
55 static OFono_Callback_List_Call_Node *callback_node_call_changed = NULL;
57 static Eina_Bool _history_time_updater(void *data)
61 double now = ecore_loop_time_get();
62 const double interval_threshold = 30.0;
63 const long long update_threshold = time(NULL) - WEEK - DAY;
66 * NOTE ABOUT CONSTANTS:
68 * - interval_threshold: to avoid updating too often (window
69 * lost and gained focus, object hidden or shown), we limit
70 * updates to this minimum interval. The poller should run
73 * - update_threshold: since we format strings over a week as
74 * fixed string (often day-month-year, not relative to
75 * today), we can stop flagging list items as updated. We
76 * give it a day of slack so we can be sure to update every
77 * item (for held and conferences, you may have items that
78 * are close in time but slightly out of order as items are
79 * prepended as the calls are removed from ofono, then
80 * history is not strictly in 'time' order). We must
81 * stop iterating after update_threshold so users that never
82 * deleted history and have thousand items will not
83 * uselessly update all the thousand items.
86 if (!ctx->calls->list) {
91 if (now - ctx->last_update < interval_threshold)
93 ctx->last_update = now;
95 it = elm_genlist_first_item_get(ctx->genlist_all);
96 for (; it != NULL; it = elm_genlist_item_next_get(it)) {
97 const Call_Info *call_info = elm_object_item_data_get(it);
98 long long t = call_info->end_time;
99 if (EINA_UNLIKELY(t == 0)) {
100 t = call_info->start_time;
101 if (EINA_UNLIKELY(t == 0))
102 t = call_info->creation_time;
104 if (EINA_UNLIKELY(t < update_threshold))
106 elm_genlist_item_update(it);
109 it = elm_genlist_first_item_get(ctx->genlist_missed);
110 for (; it != NULL; it = elm_genlist_item_next_get(it)) {
111 const Call_Info *call_info = elm_object_item_data_get(it);
112 long long t = call_info->end_time;
113 if (EINA_UNLIKELY(t == 0)) {
114 t = call_info->start_time;
115 if (EINA_UNLIKELY(t == 0))
116 t = call_info->creation_time;
118 if (EINA_UNLIKELY(t < update_threshold))
120 elm_genlist_item_update(it);
126 static void _history_time_updater_stop(History *history)
128 Evas *e = evas_object_evas_get(history->self);
129 Eina_Bool win_focused = evas_focus_state_get(e);
130 Eina_Bool obj_visible = evas_object_visible_get(history->self);
132 DBG("poller %p, win_focused=%hhu, obj_visible=%hhu",
133 history->updater, win_focused, obj_visible);
134 if (!history->updater)
136 if (win_focused && obj_visible)
139 DBG("delete poller %p", history->updater);
140 ecore_poller_del(history->updater);
141 history->updater = NULL;
144 static void _history_time_updater_start(History *history)
146 Evas *e = evas_object_evas_get(history->self);
147 Eina_Bool win_focused = evas_focus_state_get(e);
148 Eina_Bool obj_visible = evas_object_visible_get(history->self);
150 DBG("poller %p, win_focused=%hhu, obj_visible=%hhu",
151 history->updater, win_focused, obj_visible);
152 if (history->updater)
154 if (!history->calls->list)
156 if ((!win_focused) || (!obj_visible))
160 /* ECORE_POLLER_CORE is 1/8th of second. */
161 history->updater = ecore_poller_add(ECORE_POLLER_CORE, 8 * 60,
162 _history_time_updater,
164 _history_time_updater(history);
167 static Call_Info *_history_call_info_search(const History *history,
168 const OFono_Call *call)
170 Call_Info *call_info;
172 long long t = ofono_call_full_start_time_get(call);
173 const char *line_id = ofono_call_line_id_get(call); /* stringshare */
175 EINA_LIST_FOREACH(history->calls->list, l, call_info) {
176 if (call_info->call == call)
178 else if (!call_info->call) {
179 if ((t > 0) && (call_info->start_time == t) &&
180 (line_id == call_info->line_id)) {
181 DBG("associated existing log %p %s (%lld) with "
185 call_info->start_time,
187 call_info->call = call;
196 static Eina_Bool _history_call_info_update(Call_Info *call_info)
198 OFono_Call_State state;
200 EINA_SAFETY_ON_NULL_RETURN_VAL(call_info->call, EINA_FALSE);
201 state = ofono_call_state_get(call_info->call);
203 if (state == OFONO_CALL_STATE_INCOMING ||
204 state == OFONO_CALL_STATE_WAITING) {
205 if (!call_info->incoming) {
206 call_info->incoming = EINA_TRUE;
209 } else if (state == OFONO_CALL_STATE_DIALING ||
210 state == OFONO_CALL_STATE_ALERTING) {
211 if (!call_info->incoming) {
212 call_info->incoming = EINA_FALSE;
215 } else if (state == OFONO_CALL_STATE_ACTIVE ||
216 state == OFONO_CALL_STATE_HELD) {
217 if (!call_info->completed) {
218 call_info->start_time = ofono_call_full_start_time_get
220 if (call_info->start_time == 0)
221 call_info->start_time = call_info->creation_time;
223 call_info->completed = EINA_TRUE;
231 static void _dial_reply(void *data, OFono_Error err,
232 OFono_Call *call __UNUSED__)
234 const char *number = data;
236 if (err != OFONO_ERROR_NONE) {
238 snprintf(buf, sizeof(buf), "Could not call: %s", number);
239 gui_simple_popup("Error", buf);
243 static void _on_item_clicked(void *data, Evas_Object *obj __UNUSED__,
246 Elm_Object_Item *it = event_info;
247 const char *number = data;
249 INF("call %s", number);
250 ofono_dial(number, NULL, _dial_reply, number);
251 elm_genlist_item_selected_set(it, EINA_FALSE);
254 static void _history_call_changed(void *data, OFono_Call *call)
256 History *history = data;
257 const char *line_id = ofono_call_line_id_get(call);
258 Call_Info *call_info;
259 OFono_Call_State state = ofono_call_state_get(call);
261 call_info = _history_call_info_search(history, call);
262 DBG("call=%p, id=%s, state=%d, completed=%d, incoming=%d, info=%p",
263 call, line_id, state,
264 call_info ? call_info->completed : EINA_FALSE,
265 call_info ? call_info->incoming : EINA_FALSE,
271 call_info = calloc(1, sizeof(Call_Info));
272 EINA_SAFETY_ON_NULL_RETURN(call_info);
274 call_info->call = call;
275 call_info->start_time = ofono_call_full_start_time_get(call);
276 call_info->creation_time = time(NULL);
277 if (call_info->start_time == 0)
278 call_info->start_time = call_info->creation_time;
279 call_info->line_id = eina_stringshare_add(line_id);
280 call_info->name = eina_stringshare_add(ofono_call_name_get(call));
281 history->calls->list =
282 eina_list_prepend(history->calls->list, call_info);
283 history->calls->dirty = EINA_TRUE;
286 if (_history_call_info_update(call_info))
287 history->calls->dirty = EINA_TRUE;
290 static void _history_call_log_save(History *history)
294 EINA_SAFETY_ON_NULL_RETURN(history->calls);
295 DBG("save history (%u calls, dirty: %d) to %s",
296 eina_list_count(history->calls->list), history->calls->dirty,
299 ecore_file_unlink(history->bkp);
300 ecore_file_mv(history->path, history->bkp);
301 efile = eet_open(history->path, EET_FILE_MODE_WRITE);
302 EINA_SAFETY_ON_NULL_RETURN(efile);
303 if (!(eet_data_write(efile,
304 history->edd_list, HISTORY_ENTRY,
305 history->calls, EET_COMPRESSION_DEFAULT)))
306 ERR("Could in the history log file");
311 static void _history_call_removed(void *data, OFono_Call *call)
314 History *history = data;
315 const char *line_id = ofono_call_line_id_get(call);
316 Call_Info *call_info;
320 call_info = _history_call_info_search(history, call);
321 DBG("call=%p, id=%s, info=%p", call, line_id, call_info);
322 EINA_SAFETY_ON_NULL_RETURN(call_info);
324 if (call_info->start_time == 0)
325 call_info->start_time = call_info->creation_time;
327 start = call_info->start_time;
330 call_info->end_time = time(NULL);
331 call_info->call = NULL;
333 if (call_info->completed)
334 INF("Call end: %s at %s", line_id, tm);
336 if (!call_info->incoming)
337 INF("Not answered: %s at %s", line_id, tm);
339 INF("Missed: %s at %s", line_id, tm);
340 if (call_info->it_missed)
341 elm_genlist_item_update(call_info->it_missed);
343 it = elm_genlist_item_prepend
344 (history->genlist_missed,
347 ELM_GENLIST_ITEM_NONE,
350 elm_genlist_item_show
351 (it, ELM_GENLIST_ITEM_SCROLLTO_IN);
352 call_info->it_missed = it;
353 call_info->history = history;
354 _history_time_updater_start(history);
359 history->calls->dirty = EINA_TRUE;
360 _history_call_log_save(history);
362 if (call_info->it_all)
363 elm_genlist_item_update(call_info->it_all);
365 it = elm_genlist_item_prepend(history->genlist_all,
368 ELM_GENLIST_ITEM_NONE,
371 elm_genlist_item_show(it, ELM_GENLIST_ITEM_SCROLLTO_IN);
372 call_info->it_all = it;
373 call_info->history = history;
374 _history_time_updater_start(history);
378 static void _call_info_free(Call_Info *call_info)
380 eina_stringshare_del(call_info->line_id);
381 eina_stringshare_del(call_info->name);
385 static void _on_del(void *data, Evas *e __UNUSED__,
386 Evas_Object *obj __UNUSED__, void *event __UNUSED__)
388 History *history = data;
389 Call_Info *call_info;
391 if (history->updater)
392 ecore_poller_del(history->updater);
394 if (history->calls->dirty)
395 _history_call_log_save(history);
397 ofono_call_removed_cb_del(callback_node_call_removed);
398 ofono_call_changed_cb_del(callback_node_call_changed);
399 eet_data_descriptor_free(history->edd);
400 eet_data_descriptor_free(history->edd_list);
401 EINA_LIST_FREE(history->calls->list, call_info)
402 _call_info_free(call_info);
403 free(history->calls);
404 elm_genlist_item_class_free(history->itc);
408 ecore_file_shutdown();
412 static void _on_hide(void *data, Evas *e __UNUSED__,
413 Evas_Object *obj __UNUSED__, void *event __UNUSED__)
415 History *history = data;
416 DBG("history became hidden");
417 _history_time_updater_stop(history);
420 static void _on_show(void *data, Evas *e __UNUSED__,
421 Evas_Object *obj __UNUSED__, void *event __UNUSED__)
423 History *history = data;
424 DBG("history became visible");
425 _history_time_updater_start(history);
428 static void _on_win_focus_out(void *data, Evas *e __UNUSED__,
429 void *event_info __UNUSED__)
431 History *history = data;
432 DBG("window is unfocused");
433 _history_time_updater_stop(history);
436 static void _on_win_focus_in(void *data, Evas *e __UNUSED__,
437 void *event_info __UNUSED__)
439 History *history = data;
440 DBG("window is focused");
441 _history_time_updater_start(history);
444 static void _history_call_info_descriptor_init(Eet_Data_Descriptor **edd,
445 Eet_Data_Descriptor **edd_list)
447 Eet_Data_Descriptor_Class eddc;
449 EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Call_Info);
450 *edd = eet_data_descriptor_stream_new(&eddc);
452 EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Call_Info_List);
453 *edd_list = eet_data_descriptor_stream_new(&eddc);
455 EET_DATA_DESCRIPTOR_ADD_BASIC(*edd, Call_Info,
456 "completed", completed, EET_T_UCHAR);
457 EET_DATA_DESCRIPTOR_ADD_BASIC(*edd, Call_Info,
458 "incoming", incoming, EET_T_UCHAR);
460 EET_DATA_DESCRIPTOR_ADD_BASIC(*edd, Call_Info,
461 "start_time", start_time, EET_T_LONG_LONG);
462 EET_DATA_DESCRIPTOR_ADD_BASIC(*edd, Call_Info,
463 "end_time", end_time, EET_T_LONG_LONG);
464 EET_DATA_DESCRIPTOR_ADD_BASIC(*edd, Call_Info,
465 "line_id", line_id, EET_T_STRING);
466 EET_DATA_DESCRIPTOR_ADD_BASIC(*edd, Call_Info,
467 "name", name, EET_T_STRING);
469 EET_DATA_DESCRIPTOR_ADD_LIST(*edd_list, Call_Info_List, "list", list,
473 static void _history_call_log_read(History *history)
475 Call_Info *call_info;
478 Call_Info_List *calls = NULL;
481 efile = eet_open(history->path, EET_FILE_MODE_READ);
484 calls = eet_data_read(efile, history->edd_list, HISTORY_ENTRY);
489 efile = eet_open(history->bkp, EET_FILE_MODE_READ);
491 calls = eet_data_read(efile, history->edd_list,
498 calls = calloc(1, sizeof(Call_Info_List));
500 history->calls = calls;
501 EINA_SAFETY_ON_NULL_RETURN(history->calls);
503 EINA_LIST_FOREACH(history->calls->list, l, call_info) {
504 it = elm_genlist_item_append(history->genlist_all,
507 ELM_GENLIST_ITEM_NONE,
510 call_info->it_all = it;
511 call_info->history = history;
513 if (call_info->completed)
516 it = elm_genlist_item_append(history->genlist_missed,
517 history->itc, call_info, NULL,
518 ELM_GENLIST_ITEM_NONE,
521 call_info->it_missed = it;
522 call_info->history = history;
525 it = elm_genlist_first_item_get(history->genlist_all);
527 elm_genlist_item_show(it, ELM_GENLIST_ITEM_SCROLLTO_TOP);
529 it = elm_genlist_first_item_get(history->genlist_missed);
531 elm_genlist_item_show(it, ELM_GENLIST_ITEM_SCROLLTO_TOP);
534 static void _history_call_info_del(Call_Info *call_info)
536 History *ctx = call_info->history;
538 EINA_SAFETY_ON_NULL_RETURN(ctx);
540 call_info->call = NULL;
541 if (call_info->it_all)
542 elm_object_item_del(call_info->it_all);
543 if (call_info->it_missed)
544 elm_object_item_del(call_info->it_missed);
546 ctx->calls->list = eina_list_remove(ctx->calls->list, call_info);
547 ctx->calls->dirty = EINA_TRUE;
548 _history_call_log_save(ctx);
550 if ((!ctx->calls->list) && (ctx->updater)) {
551 ecore_poller_del(ctx->updater);
555 _call_info_free(call_info);
558 static void _history_clear_do(void *data, Evas_Object *obj __UNUSED__,
559 void *event_info __UNUSED__)
562 Call_Info *call_info;
564 DBG("ctx=%p, deleting %u entries",
565 ctx, eina_list_count(ctx->calls->list));
567 evas_object_del(ctx->clear_popup);
568 ctx->clear_popup = NULL;
570 elm_genlist_clear(ctx->genlist_all);
571 elm_genlist_clear(ctx->genlist_missed);
573 EINA_LIST_FREE(ctx->calls->list, call_info)
574 _call_info_free(call_info);
576 ctx->calls->dirty = EINA_TRUE;
577 _history_call_log_save(ctx);
580 ecore_poller_del(ctx->updater);
584 elm_object_signal_emit(ctx->self, "toggle,off,edit", "gui");
587 static void _history_clear_cancel(void *data, Evas_Object *obj __UNUSED__,
588 void *event_info __UNUSED__)
594 evas_object_del(ctx->clear_popup);
595 ctx->clear_popup = NULL;
598 static void _history_clear(History *ctx)
602 EINA_SAFETY_ON_TRUE_RETURN(ctx->clear_popup != NULL);
604 ctx->clear_popup = p = elm_popup_add(ctx->self);
605 evas_object_size_hint_weight_set(p, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
606 elm_object_part_text_set(p, "title,text", "Clear History");
607 elm_object_text_set(p, "Do you want to clear all history entries?");
609 bt = elm_button_add(p);
610 elm_object_text_set(bt, "No");
611 elm_object_part_content_set(p, "button1", bt);
612 evas_object_smart_callback_add(bt, "clicked",
613 _history_clear_cancel, ctx);
615 bt = elm_button_add(p);
616 elm_object_text_set(bt, "Yes, Clear");
617 elm_object_part_content_set(p, "button2", bt);
618 evas_object_smart_callback_add(bt, "clicked", _history_clear_do, ctx);
623 static char *_item_label_get(void *data, Evas_Object *obj __UNUSED__,
626 Call_Info *call_info = data;
628 if (strncmp(part, "text.call", strlen("text.call")))
631 part += strlen("text.call.");
633 if (!strcmp(part, "name")) {
634 if (!call_info->name || call_info->name[0] == '\0')
635 return phone_format(call_info->line_id);
636 return strdup(call_info->name);
639 if (!strcmp(part, "time")) {
640 if ((call_info->completed) && (call_info->end_time))
641 return date_format(call_info->end_time);
642 return date_format(call_info->start_time);
645 /* TODO: Fetch phone type from contacts information*/
646 if (!strcmp(part, "type"))
647 return strdup("TODO:TELEPHONE TYPE");
649 ERR("Unexpected text part: %s", part);
654 static Eina_Bool _item_state_get(void *data, Evas_Object *obj __UNUSED__,
657 Call_Info *call_info = data;
659 if (!strcmp(part, "missed"))
660 return !call_info->completed;
661 else if (!strcmp(part, "completed"))
662 return call_info->completed;
663 else if (!strcmp(part, "outgoing"))
664 return !call_info->incoming;
665 else if (!strcmp(part, "incoming"))
666 return call_info->incoming;
668 ERR("Unexpected state part: %s", part);
672 static void _on_clicked(void *data, Evas_Object *obj __UNUSED__,
673 const char *emission, const char *source __UNUSED__)
677 EINA_SAFETY_ON_NULL_RETURN(emission);
678 emission += strlen("clicked,");
680 DBG("ctx=%p, signal: %s", ctx, emission);
682 if (!strcmp(emission, "all"))
683 elm_object_signal_emit(obj, "show,all", "gui");
684 else if (!strcmp(emission, "missed"))
685 elm_object_signal_emit(obj, "show,missed", "gui");
686 else if (!strcmp(emission, "clear"))
688 else if (!strcmp(emission, "edit")) {
689 elm_object_signal_emit(obj, "toggle,on,edit", "gui");
690 elm_genlist_decorate_mode_set(ctx->genlist_all, EINA_TRUE);
691 elm_genlist_decorate_mode_set(ctx->genlist_missed, EINA_TRUE);
692 } else if (!strcmp(emission, "edit,done")) {
693 elm_object_signal_emit(obj, "toggle,off,edit", "gui");
694 elm_genlist_decorate_mode_set(ctx->genlist_all, EINA_FALSE);
695 elm_genlist_decorate_mode_set(ctx->genlist_missed, EINA_FALSE);
699 static void _on_more_clicked(void *data __UNUSED__, Evas_Object *obj __UNUSED__,
700 const char *emission __UNUSED__,
701 const char *source __UNUSED__)
706 static void _on_del_clicked(void *data, Evas_Object *obj __UNUSED__,
707 void *event_info __UNUSED__)
709 Call_Info *call_info = data;
710 DBG("call_info=%p, items all=%p missed=%p",
711 call_info, call_info->it_all, call_info->it_missed);
712 _history_call_info_del(call_info);
715 static Evas_Object *_item_content_get(void *data, Evas_Object *obj,
718 Evas_Object *btn = NULL;
720 if (strcmp(part, "call.swallow.more") == 0) {
721 btn = gui_layout_add(obj, "history/img");
722 EINA_SAFETY_ON_NULL_RETURN_VAL(btn, NULL);
723 elm_object_signal_callback_add(btn, "clicked,more", "gui",
724 _on_more_clicked, NULL);
725 evas_object_propagate_events_set(btn, EINA_FALSE);
726 } else if (strcmp(part, "call.swallow.delete") == 0) {
727 btn = elm_button_add(obj);
728 EINA_SAFETY_ON_NULL_RETURN_VAL(btn, NULL);
729 elm_object_style_set(btn, "history-delete");
730 elm_object_text_set(btn, "delete");
731 evas_object_smart_callback_add(btn, "clicked", _on_del_clicked,
733 evas_object_propagate_events_set(btn, EINA_FALSE);
735 ERR("unknown content part '%s'", part);
740 static void _on_list_slide_enter(void *data __UNUSED__,
744 Elm_Object_Item *it = elm_genlist_decorated_item_get(obj);
745 DBG("cancel decorated item=%p", it);
747 elm_genlist_item_decorate_mode_set(it, "slide", EINA_FALSE);
750 EINA_SAFETY_ON_NULL_RETURN(it);
752 elm_genlist_item_decorate_mode_set(it, "slide", EINA_TRUE);
755 static void _on_list_slide_cancel(void *data __UNUSED__,
757 void *event_info __UNUSED__)
759 Elm_Object_Item *it = elm_genlist_decorated_item_get(obj);
762 elm_genlist_item_decorate_mode_set(it, "slide", EINA_FALSE);
765 Evas_Object *history_add(Evas_Object *parent)
770 const char *config_path;
771 char *path, base_dir[PATH_MAX];
772 Elm_Genlist_Item_Class *itc;
773 Evas_Object *obj, *genlist_all, *genlist_missed;
777 history = calloc(1, sizeof(History));
778 EINA_SAFETY_ON_NULL_RETURN_VAL(history, NULL);
780 history->self = obj = gui_layout_add(parent, "history_bg");
781 EINA_SAFETY_ON_NULL_GOTO(obj, err_layout);
783 genlist_all = elm_genlist_add(obj);
784 EINA_SAFETY_ON_NULL_GOTO(genlist_all, err_object_new);
785 elm_object_style_set(genlist_all, "history");
788 evas_object_smart_callback_add(genlist_all, "drag,start,right",
789 _on_list_slide_enter, history);
790 evas_object_smart_callback_add(genlist_all, "drag,start,left",
791 _on_list_slide_cancel, history);
792 evas_object_smart_callback_add(genlist_all, "drag,start,down",
793 _on_list_slide_cancel, history);
794 evas_object_smart_callback_add(genlist_all, "drag,start,up",
795 _on_list_slide_cancel, history);
797 genlist_missed = elm_genlist_add(obj);
798 EINA_SAFETY_ON_NULL_GOTO(genlist_missed, err_object_new);
799 elm_object_style_set(genlist_missed, "history");
801 evas_object_smart_callback_add(genlist_missed, "drag,start,right",
802 _on_list_slide_enter, history);
803 evas_object_smart_callback_add(genlist_missed, "drag,start,left",
804 _on_list_slide_cancel, history);
805 evas_object_smart_callback_add(genlist_missed, "drag,start,down",
806 _on_list_slide_cancel, history);
807 evas_object_smart_callback_add(genlist_missed, "drag,start,up",
808 _on_list_slide_cancel, history);
810 itc = elm_genlist_item_class_new();
811 EINA_SAFETY_ON_NULL_GOTO(itc, err_object_new);
812 itc->item_style = "history";
813 itc->func.text_get = _item_label_get;
814 itc->func.content_get = _item_content_get;
815 itc->func.state_get = _item_state_get;
816 itc->func.del = NULL;
817 itc->decorate_all_item_style = "history-delete";
818 itc->decorate_item_style = "history-delete";
819 history->genlist_all = genlist_all;
820 history->genlist_missed = genlist_missed;
823 elm_object_part_content_set(obj, "elm.swallow.all", genlist_all);
824 elm_object_part_content_set(obj, "elm.swallow.missed", genlist_missed);
825 elm_object_signal_emit(obj, "show,all", "gui");
826 elm_object_signal_callback_add(obj, "clicked,*", "gui",
827 _on_clicked, history);
829 config_path = efreet_config_home_get();
830 snprintf(base_dir, sizeof(base_dir), "%s/%s", config_path,
832 ecore_file_mkpath(base_dir);
833 r = asprintf(&path, "%s/%s/history.eet", config_path, PACKAGE_NAME);
838 history->path = path;
839 r = asprintf(&path, "%s/%s/history.eet.bkp", config_path,
847 _history_call_info_descriptor_init(&history->edd, &history->edd_list);
848 _history_call_log_read(history);
849 EINA_SAFETY_ON_NULL_GOTO(history->calls, err_log_read);
850 evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _on_del,
852 evas_object_event_callback_add(obj, EVAS_CALLBACK_HIDE, _on_hide,
854 evas_object_event_callback_add(obj, EVAS_CALLBACK_SHOW, _on_show,
857 e = evas_object_evas_get(obj);
858 evas_event_callback_add(e, EVAS_CALLBACK_CANVAS_FOCUS_OUT,
859 _on_win_focus_out, history);
860 evas_event_callback_add(e, EVAS_CALLBACK_CANVAS_FOCUS_IN,
861 _on_win_focus_in, history);
863 callback_node_call_changed =
864 ofono_call_changed_cb_add(_history_call_changed, history);
865 callback_node_call_removed =
866 ofono_call_removed_cb_add(_history_call_removed, history);
872 eet_data_descriptor_free(history->edd);
873 eet_data_descriptor_free(history->edd_list);
877 elm_genlist_item_class_free(itc);
882 ecore_file_shutdown();