4 #include <Elementary.h>
15 #include "simple-popup.h"
17 #ifndef EET_COMPRESSION_DEFAULT
18 #define EET_COMPRESSION_DEFAULT 1
21 #define HISTORY_ENTRY "history"
23 typedef struct _Call_Info_List {
28 typedef struct _History {
30 Eet_Data_Descriptor *edd;
31 Eet_Data_Descriptor *edd_list;
32 Call_Info_List *calls;
33 Elm_Genlist_Item_Class *itc;
35 Evas_Object *clear_popup;
36 Evas_Object *genlist_all, *genlist_missed;
37 Ecore_Poller *updater;
41 typedef struct _Call_Info {
44 long long creation_time; /* not in edd */
49 const OFono_Call *call; /* not in edd */
51 Elm_Object_Item *it_all; /*not in edd */
52 Elm_Object_Item *it_missed; /*not in edd */
53 const Contact_Info *contact; /* not in edd */
54 const char *contact_type; /* not in edd */
55 double contact_last; /* not in edd, last time it was searched */
56 #define CONTACT_LAST_THRESHOLD 1.0
59 static OFono_Callback_List_Call_Node *callback_node_call_removed = NULL;
60 static OFono_Callback_List_Call_Node *callback_node_call_changed = NULL;
62 static Eina_Bool _history_time_updater(void *data)
66 double now = ecore_loop_time_get();
67 const double interval_threshold = 30.0;
68 const long long update_threshold = time(NULL) - WEEK - DAY;
71 * NOTE ABOUT CONSTANTS:
73 * - interval_threshold: to avoid updating too often (window
74 * lost and gained focus, object hidden or shown), we limit
75 * updates to this minimum interval. The poller should run
78 * - update_threshold: since we format strings over a week as
79 * fixed string (often day-month-year, not relative to
80 * today), we can stop flagging list items as updated. We
81 * give it a day of slack so we can be sure to update every
82 * item (for held and conferences, you may have items that
83 * are close in time but slightly out of order as items are
84 * prepended as the calls are removed from ofono, then
85 * history is not strictly in 'time' order). We must
86 * stop iterating after update_threshold so users that never
87 * deleted history and have thousand items will not
88 * uselessly update all the thousand items.
91 if (!ctx->calls->list) {
96 if (now - ctx->last_update < interval_threshold)
98 ctx->last_update = now;
100 it = elm_genlist_first_item_get(ctx->genlist_all);
101 for (; it != NULL; it = elm_genlist_item_next_get(it)) {
102 const Call_Info *call_info = elm_object_item_data_get(it);
103 long long t = call_info->end_time;
104 if (EINA_UNLIKELY(t == 0)) {
105 t = call_info->start_time;
106 if (EINA_UNLIKELY(t == 0))
107 t = call_info->creation_time;
109 if (EINA_UNLIKELY(t < update_threshold))
111 elm_genlist_item_update(it);
114 it = elm_genlist_first_item_get(ctx->genlist_missed);
115 for (; it != NULL; it = elm_genlist_item_next_get(it)) {
116 const Call_Info *call_info = elm_object_item_data_get(it);
117 long long t = call_info->end_time;
118 if (EINA_UNLIKELY(t == 0)) {
119 t = call_info->start_time;
120 if (EINA_UNLIKELY(t == 0))
121 t = call_info->creation_time;
123 if (EINA_UNLIKELY(t < update_threshold))
125 elm_genlist_item_update(it);
131 static void _history_time_updater_stop(History *history)
133 Evas *e = evas_object_evas_get(history->self);
134 Eina_Bool win_focused = evas_focus_state_get(e);
135 Eina_Bool obj_visible = evas_object_visible_get(history->self);
137 DBG("poller %p, win_focused=%hhu, obj_visible=%hhu",
138 history->updater, win_focused, obj_visible);
139 if (!history->updater)
141 if (win_focused && obj_visible)
144 DBG("delete poller %p", history->updater);
145 ecore_poller_del(history->updater);
146 history->updater = NULL;
149 static void _history_time_updater_start(History *history)
151 Evas *e = evas_object_evas_get(history->self);
152 Eina_Bool win_focused = evas_focus_state_get(e);
153 Eina_Bool obj_visible = evas_object_visible_get(history->self);
155 DBG("poller %p, win_focused=%hhu, obj_visible=%hhu",
156 history->updater, win_focused, obj_visible);
157 if (history->updater)
159 if (!history->calls->list)
161 if ((!win_focused) || (!obj_visible))
165 /* ECORE_POLLER_CORE is 1/8th of second. */
166 history->updater = ecore_poller_add(ECORE_POLLER_CORE, 8 * 60,
167 _history_time_updater,
169 _history_time_updater(history);
172 static Call_Info *_history_call_info_search(const History *history,
173 const OFono_Call *call)
175 Call_Info *call_info;
177 long long t = ofono_call_full_start_time_get(call);
178 const char *line_id = ofono_call_line_id_get(call); /* stringshare */
180 EINA_LIST_FOREACH(history->calls->list, l, call_info) {
181 if (call_info->call == call)
183 else if (!call_info->call) {
184 if ((t > 0) && (call_info->start_time == t) &&
185 (line_id == call_info->line_id)) {
186 DBG("associated existing log %p %s (%lld) with "
190 call_info->start_time,
192 call_info->call = call;
201 static Eina_Bool _history_call_info_update(Call_Info *call_info)
203 OFono_Call_State state;
205 EINA_SAFETY_ON_NULL_RETURN_VAL(call_info->call, EINA_FALSE);
206 state = ofono_call_state_get(call_info->call);
208 if (state == OFONO_CALL_STATE_INCOMING ||
209 state == OFONO_CALL_STATE_WAITING) {
210 if (!call_info->incoming) {
211 call_info->incoming = EINA_TRUE;
214 } else if (state == OFONO_CALL_STATE_DIALING ||
215 state == OFONO_CALL_STATE_ALERTING) {
216 if (!call_info->incoming) {
217 call_info->incoming = EINA_FALSE;
220 } else if (state == OFONO_CALL_STATE_ACTIVE ||
221 state == OFONO_CALL_STATE_HELD) {
222 if (!call_info->completed) {
223 call_info->start_time = ofono_call_full_start_time_get
225 if (call_info->start_time == 0)
226 call_info->start_time = call_info->creation_time;
228 call_info->completed = EINA_TRUE;
236 static void _on_item_clicked(void *data, Evas_Object *obj __UNUSED__,
239 Elm_Object_Item *it = event_info;
240 const char *number = data;
242 INF("call %s", number);
244 elm_genlist_item_selected_set(it, EINA_FALSE);
247 static void _history_call_changed(void *data, OFono_Call *call)
249 History *history = data;
250 const char *line_id = ofono_call_line_id_get(call);
251 Call_Info *call_info;
252 OFono_Call_State state = ofono_call_state_get(call);
254 call_info = _history_call_info_search(history, call);
255 DBG("call=%p, id=%s, state=%d, completed=%d, incoming=%d, info=%p",
256 call, line_id, state,
257 call_info ? call_info->completed : EINA_FALSE,
258 call_info ? call_info->incoming : EINA_FALSE,
264 call_info = calloc(1, sizeof(Call_Info));
265 EINA_SAFETY_ON_NULL_RETURN(call_info);
267 call_info->call = call;
268 call_info->start_time = ofono_call_full_start_time_get(call);
269 call_info->creation_time = time(NULL);
270 if (call_info->start_time == 0)
271 call_info->start_time = call_info->creation_time;
272 call_info->line_id = eina_stringshare_add(line_id);
273 call_info->name = eina_stringshare_add(ofono_call_name_get(call));
274 history->calls->list =
275 eina_list_prepend(history->calls->list, call_info);
276 history->calls->dirty = EINA_TRUE;
279 if (_history_call_info_update(call_info))
280 history->calls->dirty = EINA_TRUE;
283 static void _history_call_log_save(History *history)
287 EINA_SAFETY_ON_NULL_RETURN(history->calls);
288 DBG("save history (%u calls, dirty: %d) to %s",
289 eina_list_count(history->calls->list), history->calls->dirty,
292 ecore_file_unlink(history->bkp);
293 ecore_file_mv(history->path, history->bkp);
294 efile = eet_open(history->path, EET_FILE_MODE_WRITE);
295 EINA_SAFETY_ON_NULL_RETURN(efile);
296 if (!(eet_data_write(efile,
297 history->edd_list, HISTORY_ENTRY,
298 history->calls, EET_COMPRESSION_DEFAULT)))
299 ERR("Could in the history log file");
304 static void _history_call_removed(void *data, OFono_Call *call)
307 History *history = data;
308 const char *line_id = ofono_call_line_id_get(call);
309 Call_Info *call_info;
313 call_info = _history_call_info_search(history, call);
314 DBG("call=%p, id=%s, info=%p", call, line_id, call_info);
315 EINA_SAFETY_ON_NULL_RETURN(call_info);
317 if (call_info->start_time == 0)
318 call_info->start_time = call_info->creation_time;
320 start = call_info->start_time;
323 call_info->end_time = time(NULL);
324 call_info->call = NULL;
326 if (call_info->completed)
327 INF("Call end: %s at %s", line_id, tm);
329 if (!call_info->incoming)
330 INF("Not answered: %s at %s", line_id, tm);
332 INF("Missed: %s at %s", line_id, tm);
333 if (call_info->it_missed)
334 elm_genlist_item_update(call_info->it_missed);
336 it = elm_genlist_item_prepend
337 (history->genlist_missed,
340 ELM_GENLIST_ITEM_NONE,
343 elm_genlist_item_show
344 (it, ELM_GENLIST_ITEM_SCROLLTO_IN);
345 call_info->it_missed = it;
346 call_info->history = history;
347 _history_time_updater_start(history);
352 history->calls->dirty = EINA_TRUE;
353 _history_call_log_save(history);
355 if (call_info->it_all)
356 elm_genlist_item_update(call_info->it_all);
358 it = elm_genlist_item_prepend(history->genlist_all,
361 ELM_GENLIST_ITEM_NONE,
364 elm_genlist_item_show(it, ELM_GENLIST_ITEM_SCROLLTO_IN);
365 call_info->it_all = it;
366 call_info->history = history;
367 _history_time_updater_start(history);
371 static void _on_contact_del(void *data, const Contact_Info *contact __UNUSED__)
373 Call_Info *call_info = data;
374 call_info->contact = NULL;
375 call_info->contact_type = NULL;
376 call_info->contact_last = 0.0;
379 static void _on_contact_changed(void *data, Contact_Info *contact)
381 Call_Info *call_info = data;
383 if (contact_info_number_check(contact, call_info->line_id))
386 contact_info_on_del_callback_del(contact, _on_contact_del, call_info);
387 contact_info_on_changed_callback_del(contact, _on_contact_changed,
390 call_info->contact = NULL;
391 call_info->contact_type = NULL;
392 call_info->contact_last = 0.0;
395 if (call_info->it_all)
396 elm_genlist_item_update(call_info->it_all);
397 if (call_info->it_missed)
398 elm_genlist_item_update(call_info->it_missed);
401 static void _call_info_free(Call_Info *call_info)
403 if (call_info->contact) {
404 Contact_Info *contact = (Contact_Info *)call_info->contact;
405 contact_info_on_del_callback_del(contact, _on_contact_del,
407 contact_info_on_changed_callback_del(contact,
412 eina_stringshare_del(call_info->line_id);
413 eina_stringshare_del(call_info->name);
417 static void _on_del(void *data, Evas *e __UNUSED__,
418 Evas_Object *obj __UNUSED__, void *event __UNUSED__)
420 History *history = data;
421 Call_Info *call_info;
423 if (history->updater)
424 ecore_poller_del(history->updater);
426 if (history->calls->dirty)
427 _history_call_log_save(history);
429 ofono_call_removed_cb_del(callback_node_call_removed);
430 ofono_call_changed_cb_del(callback_node_call_changed);
431 eet_data_descriptor_free(history->edd);
432 eet_data_descriptor_free(history->edd_list);
433 EINA_LIST_FREE(history->calls->list, call_info)
434 _call_info_free(call_info);
435 free(history->calls);
436 elm_genlist_item_class_free(history->itc);
440 ecore_file_shutdown();
444 static void _on_hide(void *data, Evas *e __UNUSED__,
445 Evas_Object *obj __UNUSED__, void *event __UNUSED__)
447 History *history = data;
448 DBG("history became hidden");
449 _history_time_updater_stop(history);
452 static void _on_show(void *data, Evas *e __UNUSED__,
453 Evas_Object *obj __UNUSED__, void *event __UNUSED__)
455 History *history = data;
456 DBG("history became visible");
457 _history_time_updater_start(history);
460 static void _on_win_focus_out(void *data, Evas *e __UNUSED__,
461 void *event_info __UNUSED__)
463 History *history = data;
464 DBG("window is unfocused");
465 _history_time_updater_stop(history);
468 static void _on_win_focus_in(void *data, Evas *e __UNUSED__,
469 void *event_info __UNUSED__)
471 History *history = data;
472 DBG("window is focused");
473 _history_time_updater_start(history);
476 static void _history_call_info_descriptor_init(Eet_Data_Descriptor **edd,
477 Eet_Data_Descriptor **edd_list)
479 Eet_Data_Descriptor_Class eddc;
481 EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Call_Info);
482 *edd = eet_data_descriptor_stream_new(&eddc);
484 EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Call_Info_List);
485 *edd_list = eet_data_descriptor_stream_new(&eddc);
487 EET_DATA_DESCRIPTOR_ADD_BASIC(*edd, Call_Info,
488 "completed", completed, EET_T_UCHAR);
489 EET_DATA_DESCRIPTOR_ADD_BASIC(*edd, Call_Info,
490 "incoming", incoming, EET_T_UCHAR);
492 EET_DATA_DESCRIPTOR_ADD_BASIC(*edd, Call_Info,
493 "start_time", start_time, EET_T_LONG_LONG);
494 EET_DATA_DESCRIPTOR_ADD_BASIC(*edd, Call_Info,
495 "end_time", end_time, EET_T_LONG_LONG);
496 EET_DATA_DESCRIPTOR_ADD_BASIC(*edd, Call_Info,
497 "line_id", line_id, EET_T_STRING);
498 EET_DATA_DESCRIPTOR_ADD_BASIC(*edd, Call_Info,
499 "name", name, EET_T_STRING);
501 EET_DATA_DESCRIPTOR_ADD_LIST(*edd_list, Call_Info_List, "list", list,
505 static void _history_call_log_read(History *history)
507 Call_Info *call_info;
510 Call_Info_List *calls = NULL;
513 efile = eet_open(history->path, EET_FILE_MODE_READ);
516 calls = eet_data_read(efile, history->edd_list, HISTORY_ENTRY);
521 efile = eet_open(history->bkp, EET_FILE_MODE_READ);
523 calls = eet_data_read(efile, history->edd_list,
530 calls = calloc(1, sizeof(Call_Info_List));
532 history->calls = calls;
533 EINA_SAFETY_ON_NULL_RETURN(history->calls);
535 EINA_LIST_FOREACH(history->calls->list, l, call_info) {
536 it = elm_genlist_item_append(history->genlist_all,
539 ELM_GENLIST_ITEM_NONE,
542 call_info->it_all = it;
543 call_info->history = history;
545 if (call_info->completed)
548 it = elm_genlist_item_append(history->genlist_missed,
549 history->itc, call_info, NULL,
550 ELM_GENLIST_ITEM_NONE,
553 call_info->it_missed = it;
554 call_info->history = history;
557 it = elm_genlist_first_item_get(history->genlist_all);
559 elm_genlist_item_show(it, ELM_GENLIST_ITEM_SCROLLTO_TOP);
561 it = elm_genlist_first_item_get(history->genlist_missed);
563 elm_genlist_item_show(it, ELM_GENLIST_ITEM_SCROLLTO_TOP);
566 static void _history_call_info_del(Call_Info *call_info)
568 History *ctx = call_info->history;
570 EINA_SAFETY_ON_NULL_RETURN(ctx);
572 call_info->call = NULL;
573 if (call_info->it_all)
574 elm_object_item_del(call_info->it_all);
575 if (call_info->it_missed)
576 elm_object_item_del(call_info->it_missed);
578 ctx->calls->list = eina_list_remove(ctx->calls->list, call_info);
579 ctx->calls->dirty = EINA_TRUE;
580 _history_call_log_save(ctx);
582 if ((!ctx->calls->list) && (ctx->updater)) {
583 ecore_poller_del(ctx->updater);
587 _call_info_free(call_info);
590 static void _history_clear_do(void *data, Evas_Object *obj __UNUSED__,
591 void *event_info __UNUSED__)
594 Call_Info *call_info;
596 DBG("ctx=%p, deleting %u entries",
597 ctx, eina_list_count(ctx->calls->list));
599 evas_object_del(ctx->clear_popup);
600 ctx->clear_popup = NULL;
602 elm_genlist_clear(ctx->genlist_all);
603 elm_genlist_clear(ctx->genlist_missed);
605 EINA_LIST_FREE(ctx->calls->list, call_info)
606 _call_info_free(call_info);
608 ctx->calls->dirty = EINA_TRUE;
609 _history_call_log_save(ctx);
612 ecore_poller_del(ctx->updater);
616 elm_object_signal_emit(ctx->self, "toggle,off,edit", "gui");
619 static void _history_clear_cancel(void *data, Evas_Object *obj __UNUSED__,
620 void *event_info __UNUSED__)
626 evas_object_del(ctx->clear_popup);
627 ctx->clear_popup = NULL;
630 static void _history_clear(History *ctx)
634 EINA_SAFETY_ON_TRUE_RETURN(ctx->clear_popup != NULL);
636 ctx->clear_popup = p = gui_simple_popup("Clear History",
637 "Do you want to clear all history entries?");
639 simple_popup_buttons_set(p,
642 _history_clear_cancel,
649 static char *_item_label_get(void *data, Evas_Object *obj __UNUSED__,
652 Call_Info *call_info = data;
654 if (strncmp(part, "text.call", strlen("text.call")))
657 part += strlen("text.call.");
659 if (!call_info->contact) {
660 double now = ecore_loop_time_get();
661 double diff = now - call_info->contact_last;
662 if (diff > CONTACT_LAST_THRESHOLD) {
663 Contact_Info *contact = gui_contact_search(
664 call_info->line_id, &(call_info->contact_type));
666 call_info->contact_last = now;
667 call_info->contact = contact;
669 contact_info_on_del_callback_add(
670 contact, _on_contact_del, call_info);
671 contact_info_on_changed_callback_add(
672 contact, _on_contact_changed,
678 if (!strcmp(part, "name")) {
679 if (!call_info->contact)
680 return strdup(call_info->line_id);
681 return strdup(contact_info_full_name_get(call_info->contact));
684 if (!strcmp(part, "time")) {
685 if ((call_info->completed) && (call_info->end_time))
686 return date_format(call_info->end_time);
687 return date_format(call_info->start_time);
690 if (!strcmp(part, "type")) {
691 if (!call_info->contact_type)
692 return strdup("Unknown");
693 return strdup(call_info->contact_type);
696 ERR("Unexpected text part: %s", part);
701 static Eina_Bool _item_state_get(void *data, Evas_Object *obj __UNUSED__,
704 Call_Info *call_info = data;
706 if (!strcmp(part, "missed"))
707 return !call_info->completed;
708 else if (!strcmp(part, "completed"))
709 return call_info->completed;
710 else if (!strcmp(part, "outgoing"))
711 return !call_info->incoming;
712 else if (!strcmp(part, "incoming"))
713 return call_info->incoming;
715 ERR("Unexpected state part: %s", part);
719 static void _on_clicked(void *data, Evas_Object *obj __UNUSED__,
720 const char *emission, const char *source __UNUSED__)
724 EINA_SAFETY_ON_NULL_RETURN(emission);
725 emission += strlen("clicked,");
727 DBG("ctx=%p, signal: %s", ctx, emission);
729 if (!strcmp(emission, "all"))
730 elm_object_signal_emit(obj, "show,all", "gui");
731 else if (!strcmp(emission, "missed"))
732 elm_object_signal_emit(obj, "show,missed", "gui");
733 else if (!strcmp(emission, "clear"))
735 else if (!strcmp(emission, "edit")) {
736 elm_object_signal_emit(obj, "toggle,on,edit", "gui");
737 elm_genlist_decorate_mode_set(ctx->genlist_all, EINA_TRUE);
738 elm_genlist_decorate_mode_set(ctx->genlist_missed, EINA_TRUE);
739 } else if (!strcmp(emission, "edit,done")) {
740 elm_object_signal_emit(obj, "toggle,off,edit", "gui");
741 elm_genlist_decorate_mode_set(ctx->genlist_all, EINA_FALSE);
742 elm_genlist_decorate_mode_set(ctx->genlist_missed, EINA_FALSE);
746 static void _on_more_clicked(void *data __UNUSED__, Evas_Object *obj __UNUSED__,
747 const char *emission __UNUSED__,
748 const char *source __UNUSED__)
753 static void _on_del_clicked(void *data, Evas_Object *obj __UNUSED__,
754 void *event_info __UNUSED__)
756 Call_Info *call_info = data;
757 DBG("call_info=%p, items all=%p missed=%p",
758 call_info, call_info->it_all, call_info->it_missed);
759 _history_call_info_del(call_info);
762 static Evas_Object *_item_content_get(void *data, Evas_Object *obj,
765 Evas_Object *btn = NULL;
767 if (strcmp(part, "call.swallow.more") == 0) {
768 btn = layout_add(obj, "history/img");
769 EINA_SAFETY_ON_NULL_RETURN_VAL(btn, NULL);
770 elm_object_signal_callback_add(btn, "clicked,more", "gui",
771 _on_more_clicked, NULL);
772 evas_object_propagate_events_set(btn, EINA_FALSE);
773 } else if (strcmp(part, "call.swallow.delete") == 0) {
774 btn = elm_button_add(obj);
775 EINA_SAFETY_ON_NULL_RETURN_VAL(btn, NULL);
776 elm_object_style_set(btn, "history-delete");
777 elm_object_text_set(btn, "delete");
778 evas_object_smart_callback_add(btn, "clicked", _on_del_clicked,
780 evas_object_propagate_events_set(btn, EINA_FALSE);
782 ERR("unknown content part '%s'", part);
787 static void _on_list_slide_enter(void *data __UNUSED__,
791 Elm_Object_Item *it = elm_genlist_decorated_item_get(obj);
792 DBG("cancel decorated item=%p", it);
794 elm_genlist_item_decorate_mode_set(it, "slide", EINA_FALSE);
797 EINA_SAFETY_ON_NULL_RETURN(it);
799 elm_genlist_item_decorate_mode_set(it, "slide", EINA_TRUE);
802 static void _on_list_slide_cancel(void *data __UNUSED__,
804 void *event_info __UNUSED__)
806 Elm_Object_Item *it = elm_genlist_decorated_item_get(obj);
809 elm_genlist_item_decorate_mode_set(it, "slide", EINA_FALSE);
812 Evas_Object *history_add(Evas_Object *parent)
817 const char *config_path;
818 char *path, base_dir[PATH_MAX];
819 Elm_Genlist_Item_Class *itc;
820 Evas_Object *obj, *genlist_all, *genlist_missed;
824 history = calloc(1, sizeof(History));
825 EINA_SAFETY_ON_NULL_RETURN_VAL(history, NULL);
827 history->self = obj = layout_add(parent, "history_bg");
828 EINA_SAFETY_ON_NULL_GOTO(obj, err_layout);
830 genlist_all = elm_genlist_add(obj);
831 EINA_SAFETY_ON_NULL_GOTO(genlist_all, err_object_new);
832 elm_object_style_set(genlist_all, "history");
833 elm_genlist_homogeneous_set(genlist_all, EINA_TRUE);
835 evas_object_smart_callback_add(genlist_all, "drag,start,right",
836 _on_list_slide_enter, history);
837 evas_object_smart_callback_add(genlist_all, "drag,start,left",
838 _on_list_slide_cancel, history);
839 evas_object_smart_callback_add(genlist_all, "drag,start,down",
840 _on_list_slide_cancel, history);
841 evas_object_smart_callback_add(genlist_all, "drag,start,up",
842 _on_list_slide_cancel, history);
844 genlist_missed = elm_genlist_add(obj);
845 EINA_SAFETY_ON_NULL_GOTO(genlist_missed, err_object_new);
846 elm_object_style_set(genlist_missed, "history");
847 elm_genlist_homogeneous_set(genlist_missed, EINA_TRUE);
849 evas_object_smart_callback_add(genlist_missed, "drag,start,right",
850 _on_list_slide_enter, history);
851 evas_object_smart_callback_add(genlist_missed, "drag,start,left",
852 _on_list_slide_cancel, history);
853 evas_object_smart_callback_add(genlist_missed, "drag,start,down",
854 _on_list_slide_cancel, history);
855 evas_object_smart_callback_add(genlist_missed, "drag,start,up",
856 _on_list_slide_cancel, history);
858 itc = elm_genlist_item_class_new();
859 EINA_SAFETY_ON_NULL_GOTO(itc, err_object_new);
860 itc->item_style = "history";
861 itc->func.text_get = _item_label_get;
862 itc->func.content_get = _item_content_get;
863 itc->func.state_get = _item_state_get;
864 itc->func.del = NULL;
865 itc->decorate_all_item_style = "history-delete";
866 itc->decorate_item_style = "history-delete";
867 history->genlist_all = genlist_all;
868 history->genlist_missed = genlist_missed;
871 elm_object_part_content_set(obj, "elm.swallow.all", genlist_all);
872 elm_object_part_content_set(obj, "elm.swallow.missed", genlist_missed);
873 elm_object_signal_emit(obj, "show,all", "gui");
874 elm_object_signal_callback_add(obj, "clicked,*", "gui",
875 _on_clicked, history);
877 config_path = efreet_config_home_get();
878 snprintf(base_dir, sizeof(base_dir), "%s/%s", config_path,
880 ecore_file_mkpath(base_dir);
881 r = asprintf(&path, "%s/%s/history.eet", config_path, PACKAGE_NAME);
886 history->path = path;
887 r = asprintf(&path, "%s/%s/history.eet.bkp", config_path,
895 _history_call_info_descriptor_init(&history->edd, &history->edd_list);
896 _history_call_log_read(history);
897 EINA_SAFETY_ON_NULL_GOTO(history->calls, err_log_read);
898 evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _on_del,
900 evas_object_event_callback_add(obj, EVAS_CALLBACK_HIDE, _on_hide,
902 evas_object_event_callback_add(obj, EVAS_CALLBACK_SHOW, _on_show,
905 e = evas_object_evas_get(obj);
906 evas_event_callback_add(e, EVAS_CALLBACK_CANVAS_FOCUS_OUT,
907 _on_win_focus_out, history);
908 evas_event_callback_add(e, EVAS_CALLBACK_CANVAS_FOCUS_IN,
909 _on_win_focus_in, history);
911 callback_node_call_changed =
912 ofono_call_changed_cb_add(_history_call_changed, history);
913 callback_node_call_removed =
914 ofono_call_removed_cb_add(_history_call_removed, history);
920 eet_data_descriptor_free(history->edd);
921 eet_data_descriptor_free(history->edd_list);
925 elm_genlist_item_class_free(itc);
930 ecore_file_shutdown();