sync with master branch
[apps/core/preloaded/quickpanel.git] / daemon / notifications / noti.c
1 /*
2  * Copyright 2012  Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *  http://floralicense.org/license/
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <appsvc.h>
18
19 #include <time.h>
20 #include <vconf.h>
21 #include <appcore-common.h>
22 #include <app_service.h>
23 #include <runtime_info.h>
24 #include <Ecore_X.h>
25
26 #include <unicode/uloc.h>
27 #include <unicode/udat.h>
28 #include <unicode/udatpg.h>
29 #include <unicode/ustring.h>
30 #include <notification.h>
31
32 #include "quickpanel-ui.h"
33 #include "quickpanel_def.h"
34 #include "common.h"
35 #include "noti_node.h"
36 #include "noti_gridbox.h"
37 #include "noti_box.h"
38 #include "noti_listbox.h"
39 #include "noti_list_item.h"
40 #include "noti_section.h"
41 #include "noti.h"
42 #include "list_util.h"
43
44 #ifndef VCONFKEY_QUICKPANEL_STARTED
45 #define VCONFKEY_QUICKPANEL_STARTED "memory/private/"PACKAGE_NAME"/started"
46 #endif /* VCONFKEY_QUICKPANEL_STARTED */
47
48 #define QP_NOTI_DAY_DEC (24 * 60 * 60)
49
50 #define QP_NOTI_ONGOING_DBUS_PATH       "/dbus/signal"
51 #define QP_NOTI_ONGOING_DBUS_INTERFACE  "notification.ongoing"
52
53 static noti_node *g_noti_node;
54 static Evas_Object *g_noti_section;
55 static Evas_Object *g_noti_listbox;
56 static Evas_Object *g_noti_gridbox;
57 static Eina_List *g_animated_image_list;
58
59 static int quickpanel_noti_init(void *data);
60 static int quickpanel_noti_fini(void *data);
61 static int quickpanel_noti_suspend(void *data);
62 static int quickpanel_noti_resume(void *data);
63 static void quickpanel_noti_lang_changed(void *data);
64 static void quickpanel_noti_refresh(void *data);
65
66 QP_Module noti = {
67         .name = "noti",
68         .init = quickpanel_noti_init,
69         .fini = quickpanel_noti_fini,
70         .suspend = quickpanel_noti_suspend,
71         .resume = quickpanel_noti_resume,
72         .lang_changed = quickpanel_noti_lang_changed,
73         .hib_enter = NULL,
74         .hib_leave = NULL,
75         .refresh = quickpanel_noti_refresh,
76         .get_height = NULL,
77 };
78
79 static notification_h _quickpanel_noti_update_item_progress(const char *pkgname,
80                                                             int priv_id,
81                                                             double progress)
82 {
83         char *noti_pkgname = NULL;
84         int noti_priv_id = 0;
85
86         noti_node_item *node = noti_node_get(g_noti_node, priv_id);
87
88         if (node != NULL && node->noti != NULL) {
89                 notification_get_pkgname(node->noti, &noti_pkgname);
90                 notification_get_id(node->noti, NULL, &noti_priv_id);
91                 if (!strcmp(noti_pkgname, pkgname)
92                     && priv_id == noti_priv_id) {
93
94                         if (notification_set_progress(node->noti, progress) != NOTIFICATION_ERROR_NONE) {
95                                 ERR("fail to set progress");
96                         }
97                         return node->noti;
98                 }
99         }
100
101         return NULL;
102 }
103
104 static notification_h _quickpanel_noti_update_item_size(const char *pkgname,
105                                                         int priv_id,
106                                                         double size)
107 {
108         char *noti_pkgname = NULL;
109         int noti_priv_id = 0;
110
111         noti_node_item *node = noti_node_get(g_noti_node, priv_id);
112
113         if (node != NULL && node->noti != NULL) {
114                 notification_get_pkgname(node->noti, &noti_pkgname);
115                 notification_get_id(node->noti, NULL, &noti_priv_id);
116                 if (!strcmp(noti_pkgname, pkgname)
117                     && priv_id == noti_priv_id) {
118                         notification_set_size(node->noti, size);
119                         return node->noti;
120                 }
121         }
122
123         return NULL;
124 }
125
126 static notification_h _quickpanel_noti_update_item_content(const char *pkgname,
127                                                         int priv_id,
128                                                         char *content)
129 {
130         char *noti_pkgname = NULL;
131         int noti_priv_id = 0;
132
133         noti_node_item *node = noti_node_get(g_noti_node, priv_id);
134
135         if (node != NULL && node->noti != NULL) {
136                 notification_get_pkgname(node->noti, &noti_pkgname);
137                 notification_get_id(node->noti, NULL, &noti_priv_id);
138                 if (!strcmp(noti_pkgname, pkgname)
139                     && priv_id == noti_priv_id) {
140                         notification_set_text(node->noti,
141                                 NOTIFICATION_TEXT_TYPE_CONTENT,
142                                 content, NULL,
143                                 NOTIFICATION_VARIABLE_TYPE_NONE);
144                         return node->noti;
145                 }
146         }
147
148         return NULL;
149 }
150
151 static void _quickpanel_noti_update_progressbar(void *data,
152                                                 notification_h update_noti)
153 {
154         struct appdata *ad = NULL;
155         Elm_Object_Item *found = NULL;
156         noti_node_item *node = NULL;
157
158         retif(!data, , "data is NULL");
159         ad = data;
160
161         retif(!ad->list, , "ad->list is NULL");
162
163         int priv_id = 0;
164
165         if (notification_get_id(update_noti, NULL, &priv_id) == NOTIFICATION_ERROR_NONE) {
166                 node = noti_node_get(g_noti_node, priv_id);
167
168                 if (node != NULL) {
169                         found = node->view;
170                 }
171         }
172
173         retif(node == NULL, , "fail to find node of priv_id:%d", priv_id);
174         retif(node->view == NULL, , "fail to find %p", node->view);
175
176         listbox_update_item(g_noti_listbox, node->view);
177 }
178
179 static void _quickpanel_noti_item_progress_update_cb(void *data,
180                                                 DBusMessage *msg)
181 {
182         DBusError err;
183         char *pkgname = 0;
184         int priv_id = 0;
185         double progress = 0;
186         notification_h noti = NULL;
187
188         retif(data == NULL || msg == NULL, , "Invalid parameter!");
189
190         dbus_error_init(&err);
191         dbus_message_get_args(msg, &err,
192                         DBUS_TYPE_STRING, &pkgname,
193                         DBUS_TYPE_INT32, &priv_id,
194                         DBUS_TYPE_DOUBLE, &progress,
195                         DBUS_TYPE_INVALID);
196
197         if (dbus_error_is_set(&err)) {
198                 ERR("dbus err: %s", err.message);
199                 dbus_error_free(&err);
200                 return;
201         }
202
203         if (pkgname == NULL) {
204                 ERR("pkgname is null");
205                 return;
206         }
207
208         /* check item on the list */
209         noti = _quickpanel_noti_update_item_progress(pkgname,
210                                                 priv_id, progress);
211         retif(noti == NULL, , "Can not found noti data.");
212
213         DBG("pkgname[%s], priv_id[%d], progress[%lf]",
214                                 pkgname, priv_id, progress);
215         if (!quickpanel_is_suspended())
216                 _quickpanel_noti_update_progressbar(data, noti);
217 }
218
219 static void _quickpanel_noti_item_size_update_cb(void *data, DBusMessage * msg)
220 {
221         DBusError err;
222         char *pkgname = 0;
223         int priv_id = 0;
224         double size = 0;
225         notification_h noti = NULL;
226
227         retif(data == NULL || msg == NULL, , "Invalid parameter!");
228
229         dbus_error_init(&err);
230         dbus_message_get_args(msg, &err,
231                         DBUS_TYPE_STRING, &pkgname,
232                         DBUS_TYPE_INT32, &priv_id,
233                         DBUS_TYPE_DOUBLE, &size, DBUS_TYPE_INVALID);
234         if (dbus_error_is_set(&err)) {
235                 ERR("dbus err: %s", err.message);
236                 dbus_error_free(&err);
237                 return;
238         }
239
240         if (pkgname == NULL) {
241                 ERR("pkgname is null");
242                 return;
243         }
244
245         /* check item on the list */
246         noti = _quickpanel_noti_update_item_size(pkgname, priv_id, size);
247         retif(noti == NULL, , "Can not found noti data.");
248
249         DBG("pkgname[%s], priv_id[%d], progress[%lf]",
250                                 pkgname, priv_id, size);
251
252         if (!quickpanel_is_suspended())
253                 _quickpanel_noti_update_progressbar(data, noti);
254 }
255
256 static void _quickpanel_noti_item_content_update_cb(void *data,
257                                                 DBusMessage *msg)
258 {
259         DBusError err;
260         char *pkgname = NULL;
261         int priv_id = 0;
262         char *content = NULL;
263         notification_h noti = NULL;
264
265         retif(data == NULL || msg == NULL, , "Invalid parameter!");
266
267         dbus_error_init(&err);
268         dbus_message_get_args(msg, &err,
269                         DBUS_TYPE_STRING, &pkgname,
270                         DBUS_TYPE_INT32, &priv_id,
271                         DBUS_TYPE_STRING, &content, DBUS_TYPE_INVALID);
272
273         if (pkgname == NULL) {
274                 ERR("pkgname  is null");
275                 return;
276         }
277         if (content == NULL) {
278                 ERR("content is null");
279                 return;
280         }
281
282         if (dbus_error_is_set(&err)) {
283                 ERR("dbus err: %s", err.message);
284                 dbus_error_free(&err);
285                 return;
286         }
287
288         DBG("pkgname[%s], priv_id[%d], content[%s]",
289                                 pkgname, priv_id, content);
290
291         /* check item on the list */
292         noti = _quickpanel_noti_update_item_content(pkgname, priv_id, content);
293         retif(noti == NULL, , "Can not found noti data.");
294
295         if (!quickpanel_is_suspended())
296                 _quickpanel_noti_update_progressbar(data, noti);
297 }
298
299 char *quickpanel_noti_get_time(time_t t, char *buf, int buf_len)
300 {
301         UErrorCode status = U_ZERO_ERROR;
302         UDateTimePatternGenerator *generator;
303         UDateFormat *formatter;
304         UChar skeleton[40] = { 0 };
305         UChar pattern[40] = { 0 };
306         UChar formatted[40] = { 0 };
307         int32_t patternCapacity, formattedCapacity;
308         int32_t skeletonLength, patternLength, formattedLength;
309         UDate date;
310         const char *locale;
311         const char customSkeleton[] = UDAT_YEAR_NUM_MONTH_DAY;
312         char bf1[32] = { 0, };
313         bool is_24hour_enabled = FALSE;
314
315         struct tm loc_time;
316         time_t today, yesterday;
317         int ret = 0;
318
319         today = time(NULL);
320         localtime_r(&today, &loc_time);
321
322         loc_time.tm_sec = 0;
323         loc_time.tm_min = 0;
324         loc_time.tm_hour = 0;
325         today = mktime(&loc_time);
326
327         yesterday = today - QP_NOTI_DAY_DEC;
328
329         localtime_r(&t, &loc_time);
330
331         if (t >= yesterday && t < today) {
332                 ret = snprintf(buf, buf_len, _S("IDS_COM_BODY_YESTERDAY"));
333         } else if (t < yesterday) {
334                 /* set UDate  from time_t */
335                 date = (UDate) t * 1000;
336
337                 /* get default locale  */
338                 /* for thread saftey  */
339                 uloc_setDefault(__secure_getenv("LC_TIME"), &status);
340                 locale = uloc_getDefault();
341
342                 /* open datetime pattern generator */
343                 generator = udatpg_open(locale, &status);
344                 if (generator == NULL)
345                         return NULL;
346
347                 /* calculate pattern string capacity */
348                 patternCapacity =
349                     (int32_t) (sizeof(pattern) / sizeof((pattern)[0]));
350
351                 /* ascii to unicode for input skeleton */
352                 u_uastrcpy(skeleton, customSkeleton);
353
354                 /* get skeleton length */
355                 skeletonLength = strlen(customSkeleton);
356
357                 /* get best pattern using skeleton */
358                 patternLength =
359                     udatpg_getBestPattern(generator, skeleton, skeletonLength,
360                                           pattern, patternCapacity, &status);
361
362                 /* open datetime formatter using best pattern */
363                 formatter =
364                     udat_open(UDAT_IGNORE, UDAT_DEFAULT, locale, NULL, -1,
365                               pattern, patternLength, &status);
366                 if (formatter == NULL) {
367                         udatpg_close(generator);
368                         return NULL;
369                 }
370
371                 /* calculate formatted string capacity */
372                 formattedCapacity =
373                     (int32_t) (sizeof(formatted) / sizeof((formatted)[0]));
374
375                 /* formatting date using formatter by best pattern */
376                 formattedLength =
377                     udat_format(formatter, date, formatted, formattedCapacity,
378                                 NULL, &status);
379
380                 /* unicode to ascii to display */
381                 u_austrcpy(bf1, formatted);
382
383                 /* close datetime pattern generator */
384                 udatpg_close(generator);
385
386                 /* close datetime formatter */
387                 udat_close(formatter);
388
389                 ret = snprintf(buf, buf_len, "%s", bf1);
390         } else {
391                 ret = runtime_info_get_value_bool(
392                                         RUNTIME_INFO_KEY_24HOUR_CLOCK_FORMAT_ENABLED, &is_24hour_enabled);
393                 if (ret == RUNTIME_INFO_ERROR_NONE && is_24hour_enabled == TRUE) {
394                         ret = strftime(buf, buf_len, "%H:%M", &loc_time);
395                 } else {
396                         strftime(bf1, sizeof(bf1), "%l:%M", &loc_time);
397
398                         if (loc_time.tm_hour >= 0 && loc_time.tm_hour < 12)
399                                 ret = snprintf(buf, buf_len, "%s%s", bf1, "AM");
400                         else
401                                 ret = snprintf(buf, buf_len, "%s%s", bf1, "PM");
402                 }
403
404         }
405
406         return ret <= 0 ? NULL : buf;
407 }
408
409 static void _quickpanel_noti_ani_image_control(Eina_Bool on)
410 {
411         const Eina_List *l = NULL;
412         const Eina_List *ln = NULL;
413         Evas_Object *entry_obj = NULL;
414
415         retif(g_animated_image_list == NULL, ,"");
416
417         EINA_LIST_FOREACH_SAFE(g_animated_image_list, l, ln, entry_obj) {
418                 if (entry_obj == NULL) continue;
419
420                 if (on == EINA_TRUE) {
421                         if (elm_image_animated_play_get(entry_obj) == EINA_FALSE) {
422                                 elm_image_animated_play_set(entry_obj, EINA_TRUE);
423                         }
424                 } else {
425                         if (elm_image_animated_play_get(entry_obj) == EINA_TRUE) {
426                                 elm_image_animated_play_set(entry_obj, EINA_FALSE);
427                         }
428                 }
429         }
430 }
431
432 static void _quickpanel_noti_ani_image_deleted_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
433 {
434         retif(obj == NULL, , "obj is NULL");
435         retif(g_animated_image_list == NULL, , "list is empty");
436
437         g_animated_image_list = eina_list_remove(g_animated_image_list, obj);
438 }
439
440 static void _quickpanel_do_noti_delete(notification_h noti) {
441         char *pkgname = NULL;
442         char *caller_pkgname = NULL;
443         int flags = 0, priv_id = 0, flag_delete = 0;
444         notification_type_e type = NOTIFICATION_TYPE_NONE;
445
446         quickpanel_play_feedback();
447
448         retif(noti == NULL, , "Invalid parameter!");
449
450         notification_get_pkgname(noti, &caller_pkgname);
451         notification_get_application(noti, &pkgname);
452         if (pkgname == NULL)
453                 pkgname = caller_pkgname;
454
455         notification_get_id(noti, NULL, &priv_id);
456         notification_get_property(noti, &flags);
457         notification_get_type(noti, &type);
458
459         if (flags & NOTIFICATION_PROP_PERMANENT_DISPLAY)
460                 flag_delete = 0;
461         else
462                 flag_delete = 1;
463
464         if (flag_delete == 1 && type == NOTIFICATION_TYPE_NOTI) {
465                 notification_delete_by_priv_id(caller_pkgname, NOTIFICATION_TYPE_NOTI,
466                                 priv_id);
467         }
468 }
469
470 static void _quickpanel_do_noti_press(notification_h noti, int pressed_area) {
471         int ret = -1;
472         char *pkgname = NULL;
473         char *caller_pkgname = NULL;
474         bundle *args = NULL;
475         bundle *group_args = NULL;
476         bundle *responding_service_handle = NULL;
477         bundle *single_service_handle = NULL;
478         bundle *multi_service_handle = NULL;
479         int flags = 0, group_id = 0, priv_id = 0, count = 0, flag_launch = 0,
480                         flag_delete = 0;
481         notification_type_e type = NOTIFICATION_TYPE_NONE;
482
483         quickpanel_play_feedback();
484
485         retif(noti == NULL, , "Invalid parameter!");
486
487         notification_get_pkgname(noti, &caller_pkgname);
488         notification_get_application(noti, &pkgname);
489         if (pkgname == NULL)
490                 pkgname = caller_pkgname;
491
492         notification_get_id(noti, &group_id, &priv_id);
493         notification_get_property(noti, &flags);
494         notification_get_type(noti, &type);
495
496         if (flags & NOTIFICATION_PROP_DISABLE_APP_LAUNCH)
497                 flag_launch = 0;
498         else
499                 flag_launch = 1;
500
501         if (flags & NOTIFICATION_PROP_DISABLE_AUTO_DELETE)
502                 flag_delete = 0;
503         else
504                 flag_delete = 1;
505
506         notification_get_execute_option(noti,
507                         NOTIFICATION_EXECUTE_TYPE_RESPONDING,
508                                 NULL, &responding_service_handle);
509         notification_get_execute_option(noti,
510                                 NOTIFICATION_EXECUTE_TYPE_SINGLE_LAUNCH,
511                                 NULL, &single_service_handle);
512         notification_get_execute_option(noti,
513                                 NOTIFICATION_EXECUTE_TYPE_MULTI_LAUNCH,
514                                 NULL, &multi_service_handle);
515
516         if (pressed_area == NOTI_PRESS_BUTTON_1 && responding_service_handle != NULL) {
517                 DBG("");
518                 quickpanel_close_quickpanel(true);
519                 ret = quickpanel_launch_app(NULL, responding_service_handle);
520                 quickpanel_launch_app_inform_result(pkgname, ret);
521         } else if (flag_launch == 1) {
522                 /* Hide quickpanel */
523                 quickpanel_close_quickpanel(true);
524
525                 char *text_count = NULL;
526                 notification_get_text(noti, NOTIFICATION_TEXT_TYPE_EVENT_COUNT, &text_count);
527
528                 if (text_count != NULL) {
529                         count = atoi(text_count);
530                 } else {
531                         count = 1;
532                 }
533
534                 if (single_service_handle != NULL && multi_service_handle == NULL) {
535                         DBG("");
536                         ret = quickpanel_launch_app(NULL, single_service_handle);
537                         quickpanel_launch_app_inform_result(pkgname, ret);
538                 }
539                 if (single_service_handle == NULL && multi_service_handle != NULL) {
540                         DBG("");
541                         ret = quickpanel_launch_app(NULL, multi_service_handle);
542                         quickpanel_launch_app_inform_result(pkgname, ret);
543                 }
544                 if (single_service_handle != NULL && multi_service_handle != NULL) {
545                         DBG("");
546                         if (count <= 1) {
547                                 ret = quickpanel_launch_app(NULL, single_service_handle);
548                                 quickpanel_launch_app_inform_result(pkgname, ret);
549                         } else {
550                                 ret = quickpanel_launch_app(NULL, multi_service_handle);
551                                 quickpanel_launch_app_inform_result(pkgname, ret);
552                         }
553                 }
554                 if (single_service_handle == NULL && multi_service_handle == NULL) {
555                         DBG("");
556                         notification_get_args(noti, &args, &group_args);
557
558                         if (count > 1 && group_args != NULL) {
559                                 ret = quickpanel_launch_app(pkgname, group_args);
560                                 quickpanel_launch_app_inform_result(pkgname, ret);
561                         } else {
562                                 ret = quickpanel_launch_app(pkgname, args);
563                                 quickpanel_launch_app_inform_result(pkgname, ret);
564                         }
565                 }
566         }
567
568         if (flag_delete == 1 && type == NOTIFICATION_TYPE_NOTI) {
569                 notification_delete_by_priv_id(caller_pkgname,
570                                 NOTIFICATION_TYPE_NOTI,
571                                 priv_id);
572         }
573 }
574
575 static void quickpanel_notibox_delete_cb(void *data, Evas_Object * obj) {
576         DBG("");
577         noti_node_item *item = data;
578         retif(item == NULL, , "Invalid parameter!");
579
580         notification_h noti = item->noti;
581         retif(noti == NULL, , "Invalid parameter!");
582
583         _quickpanel_do_noti_delete(noti);
584
585 }
586
587 static void quickpanel_notibox_button_1_cb(void *data, Evas_Object * obj) {
588         DBG("");
589         noti_node_item *item = data;
590         retif(item == NULL, , "Invalid parameter!");
591
592         notification_h noti = item->noti;
593         retif(noti == NULL, , "Invalid parameter!");
594
595         _quickpanel_do_noti_press(noti, NOTI_PRESS_BUTTON_1);
596 }
597
598 static void quickpanel_notibox_select_cb(void *data, Evas_Object * obj) {
599         DBG("");
600         noti_node_item *item = data;
601         retif(item == NULL, , "Invalid parameter!");
602
603         notification_h noti = item->noti;
604         retif(noti == NULL, , "Invalid parameter!");
605
606         _quickpanel_do_noti_press(noti, NOTI_PRESS_BG);
607 }
608
609 static void quickpanel_noti_listitem_select_cb(void *data, Evas_Object * obj) {
610         DBG("");
611         noti_node_item *item = data;
612         retif(item == NULL, , "Invalid parameter!");
613
614         notification_h noti = item->noti;
615         retif(noti == NULL, , "Invalid parameter!");
616
617         _quickpanel_do_noti_press(noti, NOTI_PRESS_BG);
618 }
619
620 static inline void __ongoing_comp_n_copy(notification_h old, notification_h new)
621 {
622         int priv_id = 0;
623         int new_priv_id = 0;
624         char *pkgname = NULL;
625         char *new_pkgname = NULL;
626
627         if (!old)
628                 return;
629
630         if (!new)
631                 return;
632
633         notification_get_id(old, NULL, &priv_id);
634         notification_get_id(new, NULL, &new_priv_id);
635
636         notification_get_pkgname(old, &pkgname);
637         notification_get_pkgname(new, &new_pkgname);
638
639         if (!pkgname || !new_pkgname)
640                 return;
641
642         if (!strcmp(pkgname, new_pkgname) && priv_id == new_priv_id) {
643                 double percentage = 0.0;
644                 double size = 0.0;
645                 time_t insert_time = 0;
646                 time_t new_insert_time = 0;
647
648                 notification_get_progress(old, &percentage);
649                 notification_get_size(old, &size);
650                 if (notification_set_progress(new, percentage) != NOTIFICATION_ERROR_NONE) {
651                         ERR("fail to set progress");
652                 }
653                 if (notification_set_size(new, size) != NOTIFICATION_ERROR_NONE) {
654                         ERR("fail to set size");
655                 }
656                 notification_get_insert_time(old, &insert_time);
657                 notification_get_insert_time(new, &new_insert_time);
658
659                 if (insert_time == new_insert_time) {
660                         char *content = NULL;
661                         notification_get_text(old,
662                                 NOTIFICATION_TEXT_TYPE_CONTENT, &content);
663                         notification_set_text(new,
664                                 NOTIFICATION_TEXT_TYPE_CONTENT, content,
665                                 NULL, NOTIFICATION_VARIABLE_TYPE_NONE);
666                 }
667         }
668 }
669
670 static void _quickpanel_noti_clear_ongoinglist()
671 {
672         if (g_noti_listbox != NULL) {
673                 listbox_remove_all_item(g_noti_listbox, EINA_FALSE);
674         }
675 }
676
677 static void _quickpanel_noti_clear_notilist(void)
678 {
679         if (g_noti_gridbox != NULL) {
680                 gridbox_remove_all_item(g_noti_gridbox, EINA_FALSE);
681         }
682 }
683
684 static void _quickpanel_noti_clear_list_all(void)
685 {
686         _quickpanel_noti_clear_ongoinglist();
687         _quickpanel_noti_clear_notilist();
688 }
689
690 static void _quickpanel_noti_section_add(void)
691 {
692         struct appdata *ad = quickpanel_get_app_data();
693         retif(ad == NULL, , "Invalid parameter!");
694         retif(ad->list == NULL, , "Invalid parameter!");
695
696         if (g_noti_section == NULL) {
697                 g_noti_section = noti_section_create(ad->list);
698                 if (g_noti_section != NULL) {
699                         quickpanel_list_util_sort_insert(ad->list, g_noti_section);
700                         DBG("noti section[%p]", g_noti_section);
701                 }
702         }
703 }
704
705 static void _quickpanel_noti_section_remove(void)
706 {
707         struct appdata *ad = quickpanel_get_app_data();
708         retif(ad == NULL, , "Invalid parameter!");
709         retif(ad->list == NULL, , "Invalid parameter!");
710
711         if (g_noti_section != NULL) {
712                 quickpanel_list_util_item_unpack_by_type(ad->list, QP_ITEM_TYPE_NOTI_GROUP);
713                 noti_section_remove(g_noti_section);
714                 g_noti_section = NULL;
715         }
716 }
717
718 void _quickpanel_noti_box_deleted_cb(void *data, Evas_Object *obj) {
719         int priv_id = -1;
720
721         retif(data == NULL, , "Invalid parameter!");
722         DBG("deleting:%p", data);
723
724         noti_node_item *item = data;
725         notification_h noti = item->noti;
726
727         if (noti != NULL) {
728                 notification_get_id(noti, NULL, &priv_id);
729                 noti_node_remove(g_noti_node, priv_id);
730         }
731 }
732
733 void _quickpanel_list_box_deleted_cb(void *data, Evas_Object *obj) {
734         int priv_id = -1;
735
736         retif(data == NULL, , "Invalid parameter!");
737         DBG("deleting:%p", data);
738
739         noti_node_item *item = data;
740         notification_h noti = item->noti;
741
742         if (noti != NULL) {
743                 notification_get_id(noti, NULL, &priv_id);
744                 noti_node_remove(g_noti_node, priv_id);
745         }
746 }
747
748 static void _quickpanel_noti_ongoing_add(Evas_Object *list, void *data, int is_prepend)
749 {
750         Evas_Object *noti_list_item = NULL;
751         notification_ly_type_e layout = NOTIFICATION_LY_ONGOING_EVENT;
752
753         retif(list == NULL, , "Invalid parameter!");
754         notification_h noti = data;
755
756         if (noti != NULL) {
757                 notification_get_layout(noti, &layout);
758                 noti_list_item = noti_list_item_create(g_noti_listbox, layout);
759
760                 if (noti_list_item != NULL) {
761                         noti_node_item *item = noti_node_add(g_noti_node, (void*)data, (void*)noti_list_item);
762                         if (item != NULL) {
763                                 noti_list_item_node_set(noti_list_item, item);
764                                 noti_list_item_set_item_selected_cb(noti_list_item, quickpanel_noti_listitem_select_cb);
765                                 listbox_add_item(g_noti_listbox, noti_list_item, is_prepend);
766                         }
767                 } else
768                         ERR("fail to insert item to list : %p", data);
769         }
770
771         DBG("noti[%p] data[%p] added listbox[%p]",
772                         data, noti_list_item, g_noti_listbox);
773 }
774
775 static void _quickpanel_noti_noti_add(Evas_Object *list, void *data, int is_prepend)
776 {
777         notification_h noti = data;
778         notification_ly_type_e layout = NOTIFICATION_LY_NOTI_EVENT_SINGLE;
779         Evas_Object *noti_box = NULL;
780
781         retif(list == NULL, , "Invalid parameter!");
782
783         if (g_noti_section == NULL) {
784                 _quickpanel_noti_section_add();
785         }
786
787         if (noti != NULL) {
788                 notification_get_layout(noti, &layout);
789                 Evas_Object *noti_box = noti_box_create(g_noti_gridbox, layout);
790
791                 if (noti_box != NULL) {
792                         noti_node_item *item = noti_node_add(g_noti_node, (void*)data, (void*)noti_box);
793                         if (item != NULL) {
794                                 noti_box_node_set(noti_box, item);
795                                 noti_box_set_item_selected_cb(noti_box, quickpanel_notibox_select_cb);
796                                 noti_box_set_item_button_1_cb(noti_box, quickpanel_notibox_button_1_cb);
797                                 noti_box_set_item_deleted_cb(noti_box, quickpanel_notibox_delete_cb);
798                                 gridbox_add_item(g_noti_gridbox, noti_box, is_prepend);
799                         }
800                 } else
801                         ERR("fail to insert item to list : %p", data);
802         }
803
804         int noti_count =
805                         noti_node_get_item_count(g_noti_node, NOTIFICATION_TYPE_NOTI);
806
807         if (g_noti_section != NULL) {
808                 noti_section_update(g_noti_section, noti_count);
809         }
810
811         DBG("noti[%p] view[%p] added gridbox[%p]",
812                         data, noti_box, g_noti_gridbox);
813 }
814
815 void _quickpanel_noti_update_notilist(struct appdata *ad)
816 {
817         Evas_Object *list = NULL;
818         notification_h noti = NULL;
819         notification_h noti_save = NULL;
820         notification_list_h get_list = NULL;
821         int applist = NOTIFICATION_DISPLAY_APP_ALL;
822
823         DBG("");
824
825         retif(ad == NULL, , "Invalid parameter!");
826
827         list = ad->list;
828         retif(list == NULL, , "Failed to get noti genlist.");
829
830         _quickpanel_noti_clear_list_all();
831
832         notification_get_list(NOTIFICATION_TYPE_ONGOING, -1, &get_list);
833         while (get_list != NULL) {
834                 noti = notification_list_get_data(get_list);
835                 notification_get_display_applist(noti, &applist);
836
837                 if (applist &
838                     NOTIFICATION_DISPLAY_APP_NOTIFICATION_TRAY) {
839                         notification_clone(noti, &noti_save);
840                         _quickpanel_noti_ongoing_add(list, noti_save, LISTBOX_APPEND);
841                 }
842                 get_list = notification_list_get_next(get_list);
843         }
844         notification_free_list(get_list);
845
846         notification_get_list(NOTIFICATION_TYPE_NOTI , -1, &get_list);
847         while (get_list != NULL) {
848                 noti = notification_list_get_data(get_list);
849                 notification_get_display_applist(noti, &applist);
850
851                 if (applist &
852                     NOTIFICATION_DISPLAY_APP_NOTIFICATION_TRAY) {
853                         notification_clone(noti, &noti_save);
854                         _quickpanel_noti_noti_add(list, noti_save, GRIDBOX_APPEND);
855                 }
856                 get_list = notification_list_get_next(get_list);
857         }
858         notification_free_list(get_list);
859
860         if (g_noti_gridbox != NULL) {
861                 elm_box_recalculate(g_noti_gridbox);
862         }
863 }
864
865 static void _quickpanel_noti_delete_volatil_data(void)
866 {
867         notification_list_h noti_list = NULL;
868         notification_list_h noti_list_head = NULL;
869         notification_h noti = NULL;
870         int property = 0;
871
872         notification_get_grouping_list(NOTIFICATION_TYPE_NONE, -1, &noti_list);
873
874         noti_list_head = noti_list;
875
876         while (noti_list != NULL) {
877                 noti = notification_list_get_data(noti_list);
878                 notification_get_property(noti, &property);
879
880                 if (property & NOTIFICATION_PROP_VOLATILE_DISPLAY) {
881                         notification_set_property(noti,
882                                 property |
883                                 NOTIFICATION_PROP_DISABLE_UPDATE_ON_DELETE);
884                         notification_delete(noti);
885                 }
886
887                 noti_list = notification_list_get_next(noti_list);
888         }
889
890         notification_free_list(noti_list_head);
891
892         notification_update(NULL);
893 }
894
895 static void _quickpanel_noti_detailed_changed_cb(void *data, notification_type_e type, notification_op *op_list, int num_op)
896 {
897         int i = 0;
898         int op_type = 0;
899         int priv_id = 0;
900         struct appdata *ad = NULL;
901         notification_h new_noti = NULL;
902         notification_type_e noti_type = NOTIFICATION_TYPE_NONE;
903         int noti_applist = NOTIFICATION_DISPLAY_APP_ALL;
904         notification_ly_type_e noti_layout = NOTIFICATION_LY_NONE;
905
906         retif(data == NULL, , "Invalid parameter!");
907         ad = data;
908
909         DBG("test detailed quickpanel:%d", num_op);
910
911         for (i = 0; i < num_op; i++) {
912                 notification_op_get_data(op_list + i, NOTIFICATION_OP_DATA_TYPE, &op_type);
913                 DBG("op_type:%d", op_type);
914                 notification_op_get_data(op_list + i, NOTIFICATION_OP_DATA_PRIV_ID, &priv_id);
915                 DBG("op_priv_id:%d", priv_id);
916
917                 if (op_type == NOTIFICATION_OP_INSERT) {
918                         new_noti = notification_load(NULL, priv_id);
919                         if (new_noti == NULL) continue;
920
921                         notification_get_type(new_noti, &noti_type);
922                         notification_get_display_applist(new_noti, &noti_applist);
923                         notification_get_layout(new_noti, &noti_layout);
924
925                         DBG("layout:%d", noti_layout);
926
927                         if (noti_applist & NOTIFICATION_DISPLAY_APP_NOTIFICATION_TRAY) {
928                                 noti_node_item *node = noti_node_get(g_noti_node, priv_id);
929                                 if (node != NULL) {
930                                         if (noti_type == NOTIFICATION_TYPE_NOTI) {
931                                                 DBG("cb after inserted:%d", priv_id);
932                                         }
933                                 } else {
934                                         if (noti_type == NOTIFICATION_TYPE_NOTI) {
935                                                 _quickpanel_noti_noti_add(ad->list, new_noti, GRIDBOX_PREPEND);
936                                         } else if (noti_type == NOTIFICATION_TYPE_ONGOING) {
937                                                 _quickpanel_noti_ongoing_add(ad->list, new_noti, LISTBOX_PREPEND);
938                                         }
939                                 }
940                                 DBG("%d noti added", priv_id);
941                         } else {
942                                 notification_free(new_noti);
943                         }
944                 }
945                 if (op_type == NOTIFICATION_OP_DELETE) {
946                         noti_node_item *node = noti_node_get(g_noti_node, priv_id);
947
948                         if (node != NULL && node->noti != NULL) {
949                                 notification_h noti = node->noti;
950                                 notification_get_type(noti, &noti_type);
951
952                                 if (noti_type == NOTIFICATION_TYPE_NOTI) {
953                                         gridbox_remove_item(g_noti_gridbox, node->view, 0);
954                                 } else if (noti_type == NOTIFICATION_TYPE_ONGOING) {
955                                         listbox_remove_item(g_noti_listbox, node->view, 0);
956                                 }
957                                 noti_node_remove(g_noti_node, priv_id);
958                         }
959                         DBG("%d noti deleted", priv_id);
960                 }
961                 if (op_type == NOTIFICATION_OP_UPDATE) {
962                         noti_node_item *node = noti_node_get(g_noti_node, priv_id);
963                         notification_h old_noti = NULL;
964
965                         new_noti = notification_load(NULL, priv_id);
966                         retif(new_noti == NULL, , "fail to load updated noti");
967
968                         if (node != NULL && node->view != NULL && node->noti != NULL) {
969                                 notification_get_type(new_noti, &noti_type);
970
971                                 if (noti_type == NOTIFICATION_TYPE_NOTI) {
972                                         gridbox_remove_item(g_noti_gridbox, node->view, 0);
973                                         _quickpanel_noti_noti_add(ad->list, new_noti, GRIDBOX_PREPEND);
974 /*
975                                         gridbox_remove_and_add_item(g_noti_gridbox, node->view,
976                                                         _quickpanel_noti_noti_add
977                                                         ,ad->list, new_noti, GRIDBOX_PREPEND);
978 */
979                                 } else if (noti_type == NOTIFICATION_TYPE_ONGOING) {
980                                         old_noti = node->noti;
981                                         node->noti = new_noti;
982
983                                         listbox_update_item(g_noti_listbox, node->view);
984                                 }
985
986                                 if (old_noti != NULL) {
987                                         notification_free(old_noti);
988                                 }
989                         } else {
990                                 notification_get_display_applist(new_noti, &noti_applist);
991
992                                 if (noti_applist & NOTIFICATION_DISPLAY_APP_NOTIFICATION_TRAY) {
993
994                                         if (noti_type == NOTIFICATION_TYPE_NOTI) {
995                                                 _quickpanel_noti_noti_add(ad->list, new_noti, GRIDBOX_PREPEND);
996                                         } else if (noti_type == NOTIFICATION_TYPE_ONGOING) {
997                                                 _quickpanel_noti_ongoing_add(ad->list, new_noti, GRIDBOX_PREPEND);
998                                         }
999                                 }
1000                         }
1001
1002                         DBG("%d noti updated", priv_id);
1003                 }
1004         }
1005
1006         int noti_count = 0;
1007
1008         if ((noti_count = noti_node_get_item_count(g_noti_node, NOTIFICATION_TYPE_NOTI))
1009                         <= 0) {
1010                 DBG("");
1011                 _quickpanel_noti_clear_notilist();
1012                 _quickpanel_noti_section_remove();
1013         } else {
1014                 if (g_noti_section != NULL) {
1015                         DBG("");
1016                         noti_section_update(g_noti_section, noti_count);
1017                 }
1018         }
1019 }
1020
1021 static void _quickpanel_noti_update_desktop_cb(keynode_t *node, void *data)
1022 {
1023         char *event = NULL;
1024         char type[10] = {0,};
1025         char package[1024] = {0,};
1026
1027         event = vconf_get_str(vconf_keynode_get_name(node));
1028         retif(NULL == event, , "invalid event");
1029
1030         DBG("%s", event);
1031
1032         if (sscanf(event, "%10[^:]:%1023s", type, package) != 2) {
1033                 DBG("Failed to parse the event format : [%s], [%s]", type, package);
1034         }
1035
1036         if (strncasecmp(type, "delete", strlen(type)) == 0) {
1037                 notification_delete_all_by_type(package, NOTIFICATION_TYPE_NONE);
1038         }
1039
1040         if (event != NULL)
1041                 free(event);
1042 }
1043
1044 static void _quickpanel_noti_update_sim_status_cb(keynode_t *node, void *data)
1045 {
1046         struct appdata *ad = data;
1047
1048         if (ad != NULL && ad->list != NULL) {
1049                 _quickpanel_noti_update_notilist(ad);
1050         }
1051 }
1052
1053 static int _quickpanel_noti_register_event_handler(struct appdata *ad)
1054 {
1055         int ret = 0;
1056         retif(ad == NULL, QP_FAIL, "Invalid parameter!");
1057
1058         /* Add dbus signal */
1059         e_dbus_init();
1060         ad->dbus_connection = e_dbus_bus_get(DBUS_BUS_SYSTEM);
1061         if (ad->dbus_connection == NULL) {
1062                 ERR("noti register : failed to get dbus bus");
1063                 return -1;
1064         }
1065
1066         ad->dbus_handler_size =
1067                 e_dbus_signal_handler_add(ad->dbus_connection, NULL,
1068                         QP_NOTI_ONGOING_DBUS_PATH,
1069                         QP_NOTI_ONGOING_DBUS_INTERFACE, "update_progress",
1070                         _quickpanel_noti_item_progress_update_cb,
1071                         ad);
1072         if (ad->dbus_handler_size == NULL)
1073                 ERR("fail to add size signal");
1074
1075         ad->dbus_handler_progress =
1076                 e_dbus_signal_handler_add(ad->dbus_connection, NULL,
1077                         QP_NOTI_ONGOING_DBUS_PATH,
1078                         QP_NOTI_ONGOING_DBUS_INTERFACE, "update_size",
1079                         _quickpanel_noti_item_size_update_cb,
1080                         ad);
1081         if (ad->dbus_handler_progress == NULL)
1082                 ERR("fail to add progress signal");
1083
1084         ad->dbus_handler_content =
1085                 e_dbus_signal_handler_add(ad->dbus_connection, NULL,
1086                         QP_NOTI_ONGOING_DBUS_PATH,
1087                         QP_NOTI_ONGOING_DBUS_INTERFACE, "update_content",
1088                         _quickpanel_noti_item_content_update_cb,
1089                         ad);
1090         if (ad->dbus_handler_content == NULL)
1091                 ERR("fail to add content signal");
1092
1093         /* Notify vconf key */
1094         ret = vconf_notify_key_changed(VCONFKEY_TELEPHONY_SIM_SLOT,
1095                                        _quickpanel_noti_update_sim_status_cb,
1096                                        (void *)ad);
1097         if (ret != 0)
1098                 ERR("Failed to register SIM_SLOT change callback!");
1099
1100         /* Notify vconf key */
1101         ret = vconf_notify_key_changed(VCONFKEY_MENUSCREEN_DESKTOP,
1102                                        _quickpanel_noti_update_desktop_cb,
1103                                        (void *)ad);
1104         if (ret != 0)
1105                 ERR("Failed to register DESKTOP change callback!");
1106
1107         /* Register notification changed cb */
1108         notification_register_detailed_changed_cb(_quickpanel_noti_detailed_changed_cb, ad);
1109
1110         return ret;
1111 }
1112
1113 static int _quickpanel_noti_unregister_event_handler(struct appdata *ad)
1114 {
1115         int ret = 0;
1116
1117         /* Unregister notification changed cb */
1118         notification_unregister_detailed_changed_cb(_quickpanel_noti_detailed_changed_cb, (void *)ad);
1119
1120         /* Ignore vconf key */
1121         ret = vconf_ignore_key_changed(VCONFKEY_MENUSCREEN_DESKTOP,
1122                         _quickpanel_noti_update_desktop_cb);
1123         if (ret != 0)
1124                 ERR("Failed to ignore DESKTOP change callback!");
1125
1126         ret = vconf_ignore_key_changed(VCONFKEY_TELEPHONY_SIM_SLOT,
1127                                 _quickpanel_noti_update_sim_status_cb);
1128         if (ret != 0)
1129                 ERR("Failed to ignore SIM_SLOT change callback!");
1130
1131         /* Delete dbus signal */
1132         if (ad->dbus_handler_size != NULL) {
1133                 e_dbus_signal_handler_del(ad->dbus_connection,
1134                                 ad->dbus_handler_size);
1135                 ad->dbus_handler_size = NULL;
1136         }
1137         if (ad->dbus_handler_progress != NULL) {
1138                 e_dbus_signal_handler_del(ad->dbus_connection,
1139                                 ad->dbus_handler_progress);
1140                 ad->dbus_handler_progress = NULL;
1141         }
1142         if (ad->dbus_handler_content != NULL) {
1143                 e_dbus_signal_handler_del(ad->dbus_connection,
1144                                 ad->dbus_handler_content);
1145                 ad->dbus_handler_content = NULL;
1146         }
1147
1148         if (ad->dbus_connection != NULL) {
1149                 e_dbus_connection_close(ad->dbus_connection);
1150                 ad->dbus_connection = NULL;
1151         }
1152
1153         return QP_OK;
1154 }
1155
1156 static int _quickpanel_noti_check_first_start(void)
1157 {
1158         int status = 0;
1159         int ret = 0;
1160
1161         ret = vconf_get_bool(VCONFKEY_QUICKPANEL_STARTED, &status);
1162         if (ret) {
1163                 INFO("fail to get %s", VCONFKEY_QUICKPANEL_STARTED);
1164                 /* reboot */
1165                 ret = vconf_set_bool(VCONFKEY_QUICKPANEL_STARTED, 1);
1166                 INFO("set : %s, result : %d", VCONFKEY_QUICKPANEL_STARTED, ret);
1167         }
1168
1169         if (status)
1170                 return 0;
1171
1172         return 1;
1173 }
1174
1175 static void _quickpanel_noti_init(void *data)
1176 {
1177         struct appdata *ad = NULL;
1178
1179         retif(data == NULL, , "Invalid parameter!");
1180         ad = data;
1181
1182         retif(ad->list == NULL, , "Invalid parameter!");
1183
1184         DBG("wr");
1185
1186         if (g_noti_listbox == NULL) {
1187                 g_noti_listbox = listbox_create(ad->list, quickpanel_get_app_data());
1188                 listbox_set_item_deleted_cb(g_noti_listbox, _quickpanel_list_box_deleted_cb);
1189                 quickpanel_list_util_sort_insert(ad->list, g_noti_listbox);
1190         }
1191
1192         if (g_noti_gridbox == NULL) {
1193                 g_noti_gridbox = gridbox_create(ad->list, quickpanel_get_app_data());
1194                 gridbox_set_item_deleted_cb(g_noti_gridbox, _quickpanel_noti_box_deleted_cb);
1195                 quickpanel_list_util_sort_insert(ad->list, g_noti_gridbox);
1196         }
1197
1198         /* Update notification list */
1199         _quickpanel_noti_update_notilist(ad);
1200 }
1201
1202 static void _quickpanel_noti_fini(void *data)
1203 {
1204         struct appdata *ad = NULL;
1205
1206         retif(data == NULL, , "Invalid parameter!");
1207         ad = data;
1208
1209         retif(ad->list == NULL, , "Invalid parameter!");
1210
1211         DBG("dr");
1212
1213         if (g_noti_listbox != NULL) {
1214                 quickpanel_list_util_item_unpack_by_object(ad->list
1215                                 , g_noti_listbox);
1216                 listbox_remove(g_noti_listbox);
1217                 g_noti_listbox = NULL;
1218         }
1219
1220         if (g_noti_gridbox != NULL) {
1221                 quickpanel_list_util_item_unpack_by_object(ad->list
1222                                 , g_noti_gridbox);
1223                 gridbox_remove(g_noti_gridbox);
1224                 g_noti_gridbox = NULL;
1225         }
1226 }
1227
1228 static int quickpanel_noti_init(void *data)
1229 {
1230         struct appdata *ad = data;
1231         int is_first = 0;
1232
1233         retif(ad == NULL, QP_FAIL, "Invalid parameter!");
1234
1235         noti_node_create(&g_noti_node);
1236
1237         is_first = _quickpanel_noti_check_first_start();
1238         if (is_first) {
1239                 /* Remove ongoing and volatile noti data */
1240                 notifiation_clear(NOTIFICATION_TYPE_ONGOING);
1241                 _quickpanel_noti_delete_volatil_data();
1242         }
1243
1244         _quickpanel_noti_init(ad);
1245
1246         _quickpanel_noti_register_event_handler(ad);
1247
1248         return QP_OK;
1249 }
1250
1251 static int quickpanel_noti_fini(void *data)
1252 {
1253         struct appdata *ad = data;
1254         retif(ad == NULL, QP_FAIL, "Invalid parameter!");
1255
1256         /* Unregister event handler */
1257         _quickpanel_noti_unregister_event_handler(data);
1258
1259         if (g_noti_node != NULL) {
1260                 noti_node_destroy(&g_noti_node);
1261         }
1262
1263         _quickpanel_noti_clear_list_all();
1264
1265         _quickpanel_noti_fini(ad);
1266
1267         return QP_OK;
1268 }
1269
1270 static int quickpanel_noti_suspend(void *data)
1271 {
1272         struct appdata *ad = data;
1273         retif(ad == NULL, QP_FAIL, "Invalid parameter!");
1274
1275         if (ad->list) {
1276                 _quickpanel_noti_ani_image_control(EINA_FALSE);
1277         }
1278
1279         return QP_OK;
1280 }
1281
1282 static int quickpanel_noti_resume(void *data)
1283 {
1284         struct appdata *ad = data;
1285         retif(ad == NULL, QP_FAIL, "Invalid parameter!");
1286
1287         if (ad->list) {
1288                 listbox_update(g_noti_listbox);
1289
1290                 _quickpanel_noti_ani_image_control(EINA_TRUE);
1291         }
1292
1293         return QP_OK;
1294 }
1295
1296 static void quickpanel_noti_refresh(void *data) {
1297         struct appdata *ad = NULL;
1298
1299         retif(data == NULL, , "Invalid parameter!");
1300         ad = data;
1301
1302         if (g_noti_gridbox != NULL) {
1303                 gridbox_rotation(g_noti_gridbox, ad->angle);
1304         }
1305 }
1306
1307 void quickpanel_noti_lang_changed(void *data)
1308 {
1309         struct appdata *ad = data;
1310
1311         retif(ad == NULL, , "Invalid parameter!");
1312
1313         _quickpanel_noti_update_notilist(ad);
1314 }