modules/information/ext_storage: fix sigsegv
[apps/core/preloaded/indicator-win.git] / src / ticker.c
1 /*
2  * Copyright (c) 2009-2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.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://www.apache.org/licenses/LICENSE-2.0
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
18 #include <Elementary.h>
19 //#include <Ecore_X.h>
20 #include <vconf.h>
21 #include <app_control.h>
22 #include <notification_internal.h>
23 #include <feedback.h>
24 #include <system_settings.h>
25 #include <player.h>
26 #include <sound_manager.h>
27 #include <metadata_extractor.h>
28 #include <notification.h>
29 #include <notification_text_domain.h>
30 #include <app_manager.h>
31
32 #include "common.h"
33 #include "main.h"
34 #include "noti_win.h"
35 #include "util.h"
36 #include "log.h"
37 #include "indicator.h"
38 #include "ticker.h"
39
40 #define _SPACE ' '
41 #define TICKERNOTI_DURATION     3
42 #define QP_TICKER_DETAIL_DURATION 6
43 #define QP_PLAY_DURATION_LIMIT 15
44 #define TICKER_MSG_LEN                          1024
45 #define TICKER_PHONE_NUMBER_MAX_LEN 40
46
47 #define DEFAULT_ICON ICONDIR            "/quickpanel_icon_default.png"
48
49 #define FORMAT_1LINE "<font_size=29><color=#F4F4F4FF>%s</color></font_size>"
50 #define FORMAT_2LINE "<font_size=26><color=#BABABAFF>%s</color></font_size><br/><font_size=29><color=#F4F4F4FF>%s</color></font_size>"
51
52 #define PRIVATE_DATA_KEY_APPDATA "pdka"
53 #define PRIVATE_DATA_KEY_DETAIL "pdkd"
54 #define PRIVATE_DATA_KEY_TICKERNOTI_EXECUTED "pdkte"
55 #define PRIVATE_DATA_KEY_ANI_ICON_TYPE "pdkait"
56 #define PRIVATE_DATA_KEY_ICON "pdki"
57 #define PRIVATE_DATA_KEY_BOX "pdkb"
58 #define PRIVATE_DATA_KEY_TICKER_INFO "pdkti"
59 #define PRIVATE_DATA_KEY_NOTI "pdkn"
60
61 #define PATH_DOWNLOAD "reserved://quickpanel/ani/downloading"
62 #define PATH_UPLOAD "reserved://quickpanel/ani/uploading"
63 #define PATH_INSTALL "reserved://quickpanel/ani/install"
64
65 static void _create_tickernoti(notification_h noti, struct appdata *ad, ticker_info_s *ticker_info);
66 static void _destroy_tickernoti(ticker_info_s *ticker_info);
67
68 static inline int _is_text_exist(const char *text)
69 {
70         if (text != NULL) {
71                 if (strlen(text) > 0) {
72                         if (strcmp(text, "") != 0) {
73                                 return 1;
74                         }
75                 }
76         }
77
78         return 0;
79 }
80
81 static int _is_security_lockscreen_launched(void)
82 {
83         int ret = 0;
84         int is_lock_launched = 0;
85
86         if ((ret = vconf_get_int(VCONFKEY_IDLE_LOCK_STATE, &is_lock_launched)) == 0) {
87                 if (is_lock_launched == VCONFKEY_IDLE_LOCK && (ret = vconf_get_int(VCONFKEY_SETAPPL_SCREEN_LOCK_TYPE_INT, &is_lock_launched)) == 0) {
88                 /*      if (is_lock_launched != SETTING_SCREEN_LOCK_TYPE_NONE && is_lock_launched != SETTING_SCREEN_LOCK_TYPE_SWIPE) {
89                                 return 1;
90                         }*/
91                 }
92         }
93
94         return 0;
95 }
96
97 static int _check_is_noti_from_email(char *pkgname)
98 {
99         retv_if(!pkgname, 0);
100
101         if (strcmp(pkgname, TIZEN_EMAIL_PACKAGE) == 0 || strcmp(pkgname, "/usr/bin/eas-engine") == 0) {
102                 return 1;
103         } else {
104                 return 0;
105         }
106 }
107
108 static int _check_is_noti_from_message(char *pkgname)
109 {
110         retv_if(!pkgname, 0);
111
112         if (strcmp(pkgname, TIZEN_MESSAGE_PACKAGE) == 0 || strcmp(pkgname, "/usr/bin/msg-server") == 0) {
113                 return 1;
114         } else {
115                 return 0;
116         }
117 }
118
119 static int _check_is_noti_from_im(char *pkgname)
120 {
121         retv_if(!pkgname, 0);
122
123         if (strcmp(pkgname, "xnq5eh9vop.ChatON") == 0) {
124                 return 1;
125         } else {
126                 return 0;
127         }
128 }
129
130 static notification_h _get_instant_latest_message_from_list(ticker_info_s *ticker_info)
131 {
132         int count = 0;
133         notification_h noti = NULL;
134
135         count = eina_list_count(ticker_info->ticker_list);
136         if (count > 1) {
137                 noti = eina_list_nth(ticker_info->ticker_list, count-1);
138         }
139         eina_list_free(ticker_info->ticker_list);
140         ticker_info->ticker_list = NULL;
141
142         return noti;
143 }
144
145 static int _ticker_check_ticker_off(notification_h noti)
146 {
147         char *pkgname = NULL;
148
149         notification_get_pkgname(noti, &pkgname);
150
151         if (pkgname == NULL) return 1;  /* Ticker is not displaying. */
152
153         return 0;
154 }
155
156 static int _ticker_check_displaying_contents_off(notification_h noti)
157 {
158         char *pkgname = NULL;
159         int ret = 0;
160         int boolval = 0;
161
162         notification_get_pkgname(noti, &pkgname);
163
164         if (pkgname == NULL) return 0;  /* Ticker is not displaying. */
165
166         /* FIXME : we have to confirm architecture for communiating with message or email */
167         if (_check_is_noti_from_message(pkgname) == 1) {
168                 ret = vconf_get_bool(VCONFKEY_TICKER_NOTI_DISPLAY_CONTENT_MESSASGES, &boolval);
169                 if (ret == 0 && boolval == 0) return 1;
170
171         } else if (_check_is_noti_from_email(pkgname) == 1) {
172                 ret = vconf_get_bool(VCONFKEY_TICKER_NOTI_DISPLAY_CONTENT_EMAIL, &boolval);
173                 if (ret == 0 && boolval == 0) return 1;
174
175         } else if (_check_is_noti_from_im(pkgname) == 1) {
176                 ret = vconf_get_bool(VCONFKEY_TICKER_NOTI_DISPLAY_CONTENT_IM, &boolval);
177                 if (ret == 0 && boolval == 0) return 1;
178
179         }
180
181         return 0;
182 }
183
184 static inline void __ticker_only_noti_del(notification_h noti)
185 {
186         int applist = NOTIFICATION_DISPLAY_APP_ALL;
187
188         ret_if(!noti);
189
190         notification_get_display_applist(noti, &applist);
191         if ((applist & NOTIFICATION_DISPLAY_APP_TICKER) || (applist & NOTIFICATION_DISPLAY_APP_INDICATOR)) {
192                 char *pkgname = NULL;
193                 int priv_id = 0;
194
195                 notification_get_pkgname(noti, &pkgname);
196                 notification_get_id(noti, NULL, &priv_id);
197                 notification_delete_by_priv_id(pkgname, NOTIFICATION_TYPE_NONE, priv_id);
198         }
199 }
200
201 static Eina_Bool _timeout_cb(void *data)
202 {
203         ticker_info_s *ticker_info = NULL;
204         int h_page = 0;
205         int v_page = 0;
206         int h_last_page = 0;
207         int v_last_page = 0;
208
209         retv_if(!data, EINA_FALSE);
210
211         _D("message is timeout");
212
213         ticker_info = data;
214
215         /* If count is 1, self*/
216         if (ticker_info->ticker_list && eina_list_count(ticker_info->ticker_list) > 1) {
217                 if (ticker_info->timer) {
218                         ecore_timer_del(ticker_info->timer);
219                         ticker_info->timer = NULL;
220                 }
221                 _destroy_tickernoti(ticker_info);
222
223                 return ECORE_CALLBACK_CANCEL;
224         }
225
226         elm_scroller_last_page_get(ticker_info->scroller, &h_last_page, &v_last_page);
227         elm_scroller_current_page_get(ticker_info->scroller, &h_page, &v_page);
228
229         if (v_last_page > v_page) {
230                 elm_scroller_page_bring_in(ticker_info->scroller, h_page, v_page + 1);
231
232                 return ECORE_CALLBACK_RENEW;
233         }
234
235         if (ticker_info->timer) {
236                 ecore_timer_del(ticker_info->timer);
237                 ticker_info->timer = NULL;
238         }
239         _destroy_tickernoti(ticker_info);
240
241         return ECORE_CALLBACK_CANCEL;
242 }
243
244 static indicator_animated_icon_type _animated_type_get(const char *path)
245 {
246         retv_if(path == NULL, INDICATOR_ANIMATED_ICON_NONE);
247
248         if (strncasecmp(path, PATH_DOWNLOAD, MIN(strlen(PATH_DOWNLOAD), strlen(path))) == 0) {
249                 return INDICATOR_ANIMATED_ICON_DOWNLOAD;
250         } else if (strncasecmp(path, PATH_UPLOAD, MIN(strlen(PATH_UPLOAD), strlen(path))) == 0) {
251                 return INDICATOR_ANIMATED_ICON_UPLOAD;
252         } else if (strncasecmp(path, PATH_INSTALL, MIN(strlen(PATH_INSTALL), strlen(path))) == 0) {
253                 return INDICATOR_ANIMATED_ICON_INSTALL;
254         }
255
256         return INDICATOR_ANIMATED_ICON_NONE;
257 }
258
259 #define DEFAULT_EDJ EDJDIR"/ticker_default.edj"
260 /* FIXME : evas_object_del(icon), we have to unset PRIVATE_DATA_KEY_ANI_ICON_TYPE) */
261 static Evas_Object *_animated_icon_get(Evas_Object *parent, const char *path)
262 {
263         indicator_animated_icon_type type = INDICATOR_ANIMATED_ICON_NONE;
264
265         const char *layout_icon = NULL;
266         Evas_Object *layout = NULL;
267
268         retv_if(!parent, NULL);
269         retv_if(!path, NULL);
270
271         type = _animated_type_get(path);
272
273         if (type == INDICATOR_ANIMATED_ICON_DOWNLOAD) {
274                 layout_icon = "quickpanel/animated_icon_download";
275         } else if (type == INDICATOR_ANIMATED_ICON_UPLOAD) {
276                 layout_icon = "quickpanel/animated_icon_upload";
277         } else if (type == INDICATOR_ANIMATED_ICON_INSTALL) {
278                 layout_icon = "quickpanel/animated_icon_install";
279         } else {
280                 return NULL;
281         }
282
283         layout = elm_layout_add(parent);
284         if (layout != NULL) {
285                 elm_layout_file_set(layout, DEFAULT_EDJ, layout_icon);
286                 evas_object_size_hint_weight_set(layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
287                 evas_object_size_hint_align_set(layout, EVAS_HINT_FILL, EVAS_HINT_FILL);
288                 evas_object_data_set(layout, PRIVATE_DATA_KEY_ANI_ICON_TYPE, (void *)type);
289                 evas_object_show(layout);
290         }
291
292         return layout;
293 }
294
295 static char *_get_pkginfo_icon(const char *pkgid)
296 {
297         int ret;
298         char *icon_path = NULL;
299         app_info_h app_info;
300
301         retif(pkgid == NULL, NULL, "invalid parameter");
302
303         ret = app_info_create(pkgid, &app_info);
304         if (ret != APP_MANAGER_ERROR_NONE) {
305                 _E("app_info_create for %s failed %d", pkgid, ret);
306                 return NULL;
307         }
308
309         ret = app_info_get_icon(app_info, &icon_path);
310         if (ret != APP_MANAGER_ERROR_NONE) {
311                 app_info_destroy(app_info);
312                 _E("app_info_get_icon failed %d", ret);
313                 return NULL;
314         }
315
316         app_info_destroy(app_info);
317
318         return icon_path;
319 }
320
321 static Evas_Object *_ticker_create_icon(Evas_Object *parent, notification_h noti)
322 {
323         char *pkgname = NULL;
324         char *icon_path = NULL;
325         char *icon_default = NULL;
326         Evas_Object *icon = NULL;
327
328         retif(noti == NULL || parent == NULL, NULL, "Invalid parameter!");
329
330         notification_get_pkgname(noti, &pkgname);
331         if (NOTIFICATION_ERROR_NONE != notification_get_image(noti, NOTIFICATION_IMAGE_TYPE_ICON, &icon_path)) {
332                 _E("Cannot get image path");
333                 return NULL;
334         }
335         if (icon_path) {
336                 icon = _animated_icon_get(parent, icon_path);
337                 if (icon == NULL) {
338                         icon = elm_image_add(parent);
339                         if (icon_path == NULL
340                                         || (elm_image_file_set(icon, icon_path, NULL) == EINA_FALSE)) {
341                                 icon_default = _get_pkginfo_icon(pkgname);
342                                 if (icon_default != NULL) {
343                                         elm_image_file_set(icon, icon_default, NULL);
344                                         elm_image_resizable_set(icon, EINA_TRUE, EINA_TRUE);
345                                         free(icon_default);
346                                 } else {
347                                         elm_image_file_set(icon, DEFAULT_ICON, NULL);
348                                         elm_image_resizable_set(icon, EINA_TRUE, EINA_TRUE);
349                                 }
350                         }
351                 }
352         }
353
354         return icon;
355 }
356
357 static inline char *_get_text(notification_h noti, notification_text_type_e text_type)
358 {
359         char *text = NULL;
360
361         notification_get_text(noti, text_type, &text);
362         if (text) {
363                 return elm_entry_utf8_to_markup(text);
364         }
365
366         return NULL;
367 }
368
369 static inline void _strbuf_add(Eina_Strbuf *str_buf, char *text, const char *delimiter)
370 {
371         if (text != NULL) {
372                 if (strlen(text) > 0) {
373                         if (delimiter != NULL) {
374                                 eina_strbuf_append(str_buf, delimiter);
375                         }
376                         eina_strbuf_append(str_buf, text);
377                 }
378         }
379 }
380
381 static int _is_phone_number(const char *address)
382 {
383         int digit_count = 0;
384         retif(address == NULL, 0, "address is NULL");
385
386         int addr_len = 0;
387         addr_len = strlen(address);
388
389         if (addr_len == 0) {
390                 return 0;
391         }
392
393         /*  length check phone address should be longer than 2 and shorter than 40 */
394         if (addr_len > 2 && addr_len <= TICKER_PHONE_NUMBER_MAX_LEN) {
395                 const char *pszOneChar = address;
396
397                 while (*pszOneChar) {
398                         if (isdigit(*pszOneChar)) {
399                                 digit_count++;
400                         }
401
402                         ++pszOneChar;
403                 }
404
405                 pszOneChar = address;
406
407                 if (*pszOneChar == '+') {
408                         ++pszOneChar;
409                 }
410
411                 while (*pszOneChar) {
412                         if (!isdigit(*pszOneChar)
413                                         && (*pszOneChar != '*') && (*pszOneChar != '#')
414                                         && (*pszOneChar != ' ')
415                                         && !((*pszOneChar == '-') && digit_count >= 7)) {
416                                 return 0;
417                         }
418
419                         ++pszOneChar;
420                 }
421
422                 return 1;
423         } else {
424                 DBG("invalid address length [%d]", addr_len);
425                 return 0;
426         }
427 }
428
429 static void _char_set(char *dst, char s, int index, int size)
430 {
431         if (index < size) {
432                 *(dst + index) = s;
433         }
434 }
435
436 static void _make_phone_number_tts(char *dst, const char *src, int size)
437 {
438         retif(dst == NULL, , "invalid argument");
439         retif(src == NULL, , "invalid argument");
440
441         int no_op = 0;
442         int i = 0, j = 0, text_len = 0;
443
444         text_len = strlen(src);
445
446         for (i = 0, j= 0; i < text_len; i++) {
447                 if (no_op == 1) {
448                         _char_set(dst, *(src + i), j++, size);
449                 } else {
450                         if (isdigit(*(src + i))) {
451                                 if (i + 1 < text_len) {
452                                         if (*(src + i + 1) == '-' || *(src + i + 1) == _SPACE) {
453                                                 _char_set(dst, *(src + i), j++, size);
454                                         } else {
455                                                 _char_set(dst, *(src + i), j++, size);
456                                                 _char_set(dst, _SPACE, j++, size);
457                                         }
458                                 } else {
459                                         _char_set(dst, *(src + i), j++, size);
460                                         _char_set(dst, _SPACE, j++, size);
461                                 }
462                         } else if (*(src + i) == '-') {
463                                 no_op = 1;
464                                 _char_set(dst, *(src + i), j++, size);
465                         } else {
466                                 _char_set(dst, *(src + i), j++, size);
467                         }
468                 }
469         }
470 }
471
472 static inline void _check_and_add_to_buffer(Eina_Strbuf *str_buf, char *text, int is_check_phonenumber)
473 {
474         char buf_number[TICKER_PHONE_NUMBER_MAX_LEN * 2] = { 0, };
475
476         if (text != NULL) {
477                 if (strlen(text) > 0) {
478                         if (_is_phone_number(text) && is_check_phonenumber) {
479                                 _make_phone_number_tts(buf_number, text,
480                                                 (TICKER_PHONE_NUMBER_MAX_LEN * 2) - 1);
481                                 eina_strbuf_append(str_buf, buf_number);
482                         } else {
483                                 eina_strbuf_append(str_buf, text);
484                         }
485                         eina_strbuf_append_char(str_buf, '\n');
486                 }
487         }
488 }
489
490 static char *_ticker_get_label_layout_default(notification_h noti, int is_screenreader, char **str_line1, char **str_line2)
491 {
492         int len = 0;
493         int num_line = 0;
494         char *domain = NULL;
495         char *dir = NULL;
496         char *title_utf8 = NULL;
497         char *content_utf8 = NULL;
498         char *info1_utf8 = NULL;
499         char *info1_sub_utf8 = NULL;
500         char *info2_utf8 = NULL;
501         char *info2_sub_utf8 = NULL;
502         char *event_count_utf8 = NULL;
503         const char *tmp = NULL;
504         Eina_Strbuf *line1 = NULL;
505         Eina_Strbuf *line2 = NULL;
506         char buf[TICKER_MSG_LEN] = { 0, };
507
508         retif(noti == NULL, NULL, "Invalid parameter!");
509
510         notification_get_text_domain(noti, &domain, &dir);
511         if (domain != NULL && dir != NULL) {
512                 bindtextdomain(domain, dir);
513         }
514
515         title_utf8 = _get_text(noti, NOTIFICATION_TEXT_TYPE_TITLE);
516         if (_ticker_check_displaying_contents_off(noti) == 1) {
517                 content_utf8 = _get_text(noti, NOTIFICATION_TEXT_TYPE_CONTENT_FOR_DISPLAY_OPTION_IS_OFF);
518         } else {
519                 content_utf8 = _get_text(noti, NOTIFICATION_TEXT_TYPE_CONTENT);
520         }
521         info1_utf8 = _get_text(noti, NOTIFICATION_TEXT_TYPE_INFO_1);
522         info1_sub_utf8 = _get_text(noti, NOTIFICATION_TEXT_TYPE_INFO_SUB_1);
523         info2_utf8 = _get_text(noti, NOTIFICATION_TEXT_TYPE_INFO_2);
524         info2_sub_utf8 = _get_text(noti, NOTIFICATION_TEXT_TYPE_INFO_SUB_2);
525
526         if (is_screenreader == 0) {
527                 line1 = eina_strbuf_new();
528                 line2 = eina_strbuf_new();
529
530                 if (line1 != NULL && line2 != NULL) {
531                         if (_is_text_exist(title_utf8) && (_is_text_exist(content_utf8)
532                                         || _is_text_exist(event_count_utf8))) {
533                                 _strbuf_add(line1, title_utf8, NULL);
534                                 _strbuf_add(line2, content_utf8, NULL);
535                                 if (_is_text_exist(content_utf8)) {
536                                         _strbuf_add(line2, event_count_utf8, " ");
537                                 } else {
538                                         _strbuf_add(line2, event_count_utf8, "");
539                                 }
540                                 num_line = 2;
541                         } else if (_is_text_exist(info1_utf8) && (_is_text_exist(content_utf8)
542                                         || _is_text_exist(event_count_utf8))) {
543                                 _strbuf_add(line1, content_utf8, NULL);
544                                 _strbuf_add(line1, event_count_utf8, " ");
545                                 _strbuf_add(line2, info1_utf8, NULL);
546                                 _strbuf_add(line2, info1_sub_utf8, " ");
547                                 num_line = 2;
548                         } else if (_is_text_exist(info1_utf8) && _is_text_exist(info2_utf8)) {
549                                 _strbuf_add(line1, info1_utf8, NULL);
550                                 _strbuf_add(line1, info1_sub_utf8, " ");
551                                 _strbuf_add(line2, info2_utf8, NULL);
552                                 _strbuf_add(line2, info2_sub_utf8, " ");
553                                 num_line = 2;
554                         } else if (_is_text_exist(title_utf8)) {
555                                 _strbuf_add(line1, title_utf8, NULL);
556                                 num_line = 1;
557                         } else if (_is_text_exist(content_utf8)) {
558                                 _strbuf_add(line1, content_utf8, NULL);
559                                 num_line = 1;
560                         }
561
562                         if (num_line == 2) {
563                                 tmp = eina_strbuf_string_get(line1);
564                                 if (str_line1 != NULL && tmp != NULL) {
565                                         *str_line1 = strdup(tmp);
566                                 }
567
568                                 tmp = eina_strbuf_string_get(line2);
569                                 if (str_line2 != NULL && tmp != NULL) {
570                                         *str_line2 = strdup(tmp);
571                                 }
572                         } else {
573                                 tmp = eina_strbuf_string_get(line1);
574                                 if (str_line1 != NULL && tmp != NULL) {
575                                         *str_line1 = strdup(tmp);
576                                 }
577                         }
578
579                         eina_strbuf_free(line1);
580                         eina_strbuf_free(line2);
581                 } else {
582                         _E("failed to allocate string buffer");
583                 }
584         } else {
585                 if (title_utf8 == NULL
586                                 && event_count_utf8 == NULL
587                                 && content_utf8 == NULL
588                                 && info1_utf8 == NULL
589                                 && info1_sub_utf8 == NULL
590                                 && info2_utf8 == NULL
591                                 && info2_sub_utf8 == NULL) {
592                         len = 0;
593                 } else {
594                         Eina_Strbuf *strbuf = eina_strbuf_new();
595                         if (strbuf != NULL) {
596                                 eina_strbuf_append(strbuf, _("IDS_QP_BUTTON_NOTIFICATION"));
597                                 eina_strbuf_append_char(strbuf, '\n');
598                                 _check_and_add_to_buffer(strbuf, title_utf8, 1);
599                                 _check_and_add_to_buffer(strbuf, event_count_utf8, 0);
600                                 _check_and_add_to_buffer(strbuf, content_utf8, 1);
601                                 _check_and_add_to_buffer(strbuf, info1_utf8, 1);
602                                 _check_and_add_to_buffer(strbuf, info1_sub_utf8, 1);
603                                 _check_and_add_to_buffer(strbuf, info2_utf8, 1);
604                                 _check_and_add_to_buffer(strbuf, info2_sub_utf8, 1);
605
606                                 if (eina_strbuf_length_get(strbuf) > 0) {
607                                         len = snprintf(buf, sizeof(buf) - 1, "%s", eina_strbuf_string_get(strbuf));
608                                 }
609                                 eina_strbuf_free(strbuf);
610                         }
611                 }
612         }
613
614         if (title_utf8) {
615                 free(title_utf8);
616         }
617
618         if (content_utf8) {
619                 free(content_utf8);
620         }
621
622 //      if (event_count_utf8) {
623 //              free(event_count_utf8);
624 //      }
625
626         if (info1_utf8) {
627                 free(info1_utf8);
628         }
629         if (info1_sub_utf8) {
630                 free(info1_sub_utf8);
631         }
632         if (info2_utf8) {
633                 free(info2_utf8);
634         }
635         if (info2_sub_utf8) {
636                 free(info2_sub_utf8);
637         }
638         if (len > 0) {
639                 return strdup(buf);
640         }
641         return NULL;
642 }
643
644 static char *_ticker_get_label_layout_single(notification_h noti, int is_screenreader, char **str_line1, char **str_line2)
645 {
646         int num_line = 0;
647         int len = 0;
648         char *domain = NULL;
649         char *dir = NULL;
650         char *title_utf8 = NULL;
651         char *content_utf8 = NULL;
652         char *info1_utf8 = NULL;
653         char *info1_sub_utf8 = NULL;
654         char *info2_utf8 = NULL;
655         char *info2_sub_utf8 = NULL;
656         Eina_Strbuf *line1 = NULL;
657         Eina_Strbuf *line2 = NULL;
658         const char *tmp = NULL;
659         char buf[TICKER_MSG_LEN] = { 0, };
660
661         retif(noti == NULL, NULL, "Invalid parameter!");
662
663         notification_get_text_domain(noti, &domain, &dir);
664         if (domain != NULL && dir != NULL)
665                 bindtextdomain(domain, dir);
666
667         title_utf8 = _get_text(noti, NOTIFICATION_TEXT_TYPE_TITLE);
668         if (_ticker_check_displaying_contents_off(noti) == 1) {
669                 content_utf8 = _get_text(noti, NOTIFICATION_TEXT_TYPE_CONTENT_FOR_DISPLAY_OPTION_IS_OFF);
670         } else {
671                 content_utf8 = _get_text(noti, NOTIFICATION_TEXT_TYPE_CONTENT);
672         }
673         info1_utf8 = _get_text(noti, NOTIFICATION_TEXT_TYPE_INFO_1);
674         info1_sub_utf8 = _get_text(noti, NOTIFICATION_TEXT_TYPE_INFO_SUB_1);
675         info2_utf8 = _get_text(noti, NOTIFICATION_TEXT_TYPE_INFO_2);
676         info2_sub_utf8 = _get_text(noti, NOTIFICATION_TEXT_TYPE_INFO_SUB_2);
677
678         if (is_screenreader == 0) {
679                 line1 = eina_strbuf_new();
680                 line2 = eina_strbuf_new();
681
682                 if (line1 != NULL && line2 != NULL) {
683                         if (_is_text_exist(info1_utf8) && _is_text_exist(content_utf8)) {
684                                 _strbuf_add(line1, content_utf8, NULL);
685                                 _strbuf_add(line2, info1_utf8, NULL);
686                                 _strbuf_add(line2, info1_sub_utf8, " ");
687                                 num_line = 2;
688                         } else if (_is_text_exist(title_utf8) && _is_text_exist(content_utf8)) {
689                                 _strbuf_add(line1, title_utf8, NULL);
690                                 _strbuf_add(line2, content_utf8, NULL);
691                                 num_line = 2;
692                         } else if (_is_text_exist(title_utf8)) {
693                                 _strbuf_add(line1, title_utf8, NULL);
694                                 num_line = 1;
695                         } else if (_is_text_exist(content_utf8)) {
696                                 _strbuf_add(line1, content_utf8, NULL);
697                                 num_line = 1;
698                         }
699
700                         if (num_line == 2) {
701                                 tmp = eina_strbuf_string_get(line1);
702                                 if (str_line1 != NULL && tmp != NULL) {
703                                         *str_line1 = strdup(tmp);
704                                 }
705
706                                 tmp = eina_strbuf_string_get(line2);
707                                 if (str_line2 != NULL && tmp != NULL) {
708                                         *str_line2 = strdup(tmp);
709                                 }
710                         } else {
711                                 tmp = eina_strbuf_string_get(line1);
712                                 if (str_line1 != NULL && tmp != NULL) {
713                                         *str_line1 = strdup(tmp);
714                                 }
715                         }
716
717                         eina_strbuf_free(line1);
718                         eina_strbuf_free(line2);
719                 } else {
720                         _E("failed to allocate string buffer");
721                 }
722         } else {
723                 if (title_utf8 == NULL
724                                 && content_utf8 == NULL
725                                 && info1_utf8 == NULL
726                                 && info1_sub_utf8 == NULL) {
727                         len = 0;
728                 } else {
729                         Eina_Strbuf *strbuf = eina_strbuf_new();
730                         if (strbuf != NULL) {
731                                 eina_strbuf_append(strbuf, _("IDS_QP_BUTTON_NOTIFICATION"));
732                                 eina_strbuf_append_char(strbuf, '\n');
733                                 if (info1_utf8 == NULL) {
734                                         _check_and_add_to_buffer(strbuf, title_utf8, 1);
735                                         _check_and_add_to_buffer(strbuf, content_utf8, 1);
736                                 } else {
737                                         if (content_utf8 == NULL) {
738                                                 _check_and_add_to_buffer(strbuf, title_utf8, 1);
739                                         }
740                                         _check_and_add_to_buffer(strbuf, content_utf8, 1);
741                                         _check_and_add_to_buffer(strbuf, info1_utf8, 1);
742                                         _check_and_add_to_buffer(strbuf, info1_sub_utf8, 1);
743                                 }
744
745                                 if (eina_strbuf_length_get(strbuf) > 0) {
746                                         len = snprintf(buf, sizeof(buf) - 1, "%s", eina_strbuf_string_get(strbuf));
747                                 }
748                                 eina_strbuf_free(strbuf);
749                         }
750                 }
751         }
752
753         if (title_utf8) {
754                 free(title_utf8);
755         }
756         if (content_utf8) {
757                 free(content_utf8);
758         }
759         if (info1_utf8) {
760                 free(info1_utf8);
761         }
762         if (info1_sub_utf8) {
763                 free(info1_sub_utf8);
764         }
765         if (info2_utf8) {
766                 free(info2_utf8);
767         }
768         if (info2_sub_utf8) {
769                 free(info2_sub_utf8);
770         }
771         if (len > 0) {
772                 return strdup(buf);
773         }
774         return NULL;
775 }
776
777 static char *_ticker_get_text(notification_h noti, int is_screenreader, char **line1, char **line2)
778 {
779         char *result = NULL;
780         notification_ly_type_e layout;
781
782         retif(noti == NULL, NULL, "Invalid parameter!");
783
784         notification_get_layout(noti, &layout);
785
786         if (_ticker_check_displaying_contents_off(noti) == 1) {
787                 result = _ticker_get_label_layout_default(noti, is_screenreader, line1, line2);
788         } else if (layout == NOTIFICATION_LY_NOTI_EVENT_SINGLE) {
789                 result = _ticker_get_label_layout_single(noti, is_screenreader, line1, line2);
790         } else {
791                 result = _ticker_get_label_layout_default(noti, is_screenreader, line1, line2);
792         }
793
794         return result;
795 }
796
797 static void _noti_hide_cb(void *data, Evas_Object *obj, const char *emission, const char *source)
798 {
799         ticker_info_s *ticker_info = NULL;
800
801         ret_if(!data);
802
803         ticker_info = data;
804
805         if (ticker_info->timer) {
806                 ecore_timer_del(ticker_info->timer);
807                 ticker_info->timer = NULL;
808         }
809
810         _destroy_tickernoti(ticker_info);
811 }
812
813 static void _mouse_down_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
814 {
815         _noti_hide_cb(data, NULL, NULL, NULL);
816 }
817
818 #define TICKER_EDJ EDJDIR"/ticker.edj"
819 static void _create_tickernoti(notification_h noti, struct appdata *ad, ticker_info_s *ticker_info)
820 {
821         Eina_Bool ret = EINA_FALSE;
822         Evas_Object *detail = NULL;
823         Evas_Object *base = NULL;
824         Evas_Object *icon = NULL;
825         Evas_Object *box = NULL;
826         Evas_Object *textblock = NULL;
827         char *line1 = NULL;
828         char *line2 = NULL;
829         int noti_height = 0;
830         int *is_ticker_executed = NULL;
831
832         ret_if(!ad);
833         ret_if(!ticker_info);
834
835         if (ticker_info->win != NULL) {
836                 _E("ticker notification exists");
837                 return;
838         }
839
840         _D("create ticker notification");
841
842         /* create window */
843         ticker_info->win = noti_win_add(NULL, ad);
844         ret_if(!ticker_info->win);
845         evas_object_data_set(ticker_info->win, PRIVATE_DATA_KEY_APPDATA, ad);
846         evas_object_data_set(ticker_info->win, PRIVATE_DATA_KEY_NOTI, noti);
847
848         /* create layout */
849         detail = elm_layout_add(ticker_info->win);
850         goto_if(!detail, ERROR);
851
852         ret = elm_layout_file_set(detail, TICKER_EDJ, "quickpanel/tickernoti/normal");
853         goto_if(ret == EINA_FALSE, ERROR);
854
855         elm_object_signal_callback_add(detail, "request,hide", "", _noti_hide_cb, ticker_info);
856         evas_object_event_callback_add(detail, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down_cb, ticker_info);
857         evas_object_size_hint_min_set(detail, 1, noti_height);
858         noti_win_content_set(ticker_info->win, detail);
859         evas_object_data_set(ticker_info->win, PRIVATE_DATA_KEY_DETAIL, detail);
860
861         /* create base rectangle */
862         base = evas_object_rectangle_add(evas_object_evas_get(detail));
863         goto_if(!base, ERROR);
864         /* FIXME */
865         evas_object_color_set(base, 0, 0, 0, 0);
866         evas_object_resize(base, ad->win.w, ad->win.h);
867         evas_object_size_hint_min_set(base, ad->win.w, ad->win.h);
868         evas_object_show(base);
869         elm_object_part_content_set(detail, "base", base);
870         evas_object_data_set(ticker_info->win, DATA_KEY_BASE_RECT, base);
871
872         /* create icon */
873         icon = _ticker_create_icon(detail, noti);
874         if (icon) elm_object_part_content_set(detail, "icon", icon);
875         evas_object_data_set(ticker_info->win, PRIVATE_DATA_KEY_ICON, icon);
876
877         /* create scroller */
878         ticker_info->scroller = elm_scroller_add(detail);
879         goto_if(!ticker_info->scroller, ERROR);
880
881         elm_scroller_policy_set(ticker_info->scroller, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_OFF);
882         elm_scroller_page_size_set(ticker_info->scroller, 434, INDICATOR_HEIGHT - 5);
883         elm_scroller_movement_block_set(ticker_info->scroller, ELM_SCROLLER_MOVEMENT_BLOCK_VERTICAL|ELM_SCROLLER_MOVEMENT_BLOCK_HORIZONTAL);
884         elm_object_part_content_set(detail, "text_rect", ticker_info->scroller);
885
886         /* create box */
887         box = elm_box_add(ticker_info->scroller);
888         goto_if(!box, ERROR);
889
890         elm_object_content_set(ticker_info->scroller, box);
891         evas_object_show(box);
892         evas_object_data_set(ticker_info->win, PRIVATE_DATA_KEY_BOX, box);
893
894         /* create textblock */
895         textblock = elm_layout_add(box);
896         goto_if(!textblock, ERROR);
897
898         ret = elm_layout_file_set(textblock, TICKER_EDJ, "quickpanel/tickernoti/text");
899         goto_if(ret == EINA_FALSE, ERROR);
900
901         evas_object_show(textblock);
902
903         elm_box_pack_end(box, textblock);
904
905         /* get noti text */
906         _ticker_get_text(noti, 0, &line1, &line2);
907
908         if (line1 == NULL) {
909                 if (line2 != NULL) {
910                         elm_object_part_text_set(textblock, "elm.text", line2);
911                         free(line2);
912                 }
913         } else if (line2 == NULL) {
914                 elm_object_part_text_set(textblock, "elm.text", line1);
915                 free(line1);
916         } else {
917                 Eina_Strbuf *buffer = eina_strbuf_new();
918
919                 eina_strbuf_append(buffer, line1);
920                 eina_strbuf_append(buffer, "<br/>");
921                 eina_strbuf_append(buffer, line2);
922
923                 elm_object_part_text_set(textblock, "elm.text", eina_strbuf_string_get(buffer));
924
925                 free(line1);
926                 free(line2);
927                 eina_strbuf_free(buffer);
928         }
929         evas_object_data_set(ticker_info->win, DATA_KEY_TICKER_TEXT, textblock);
930
931         is_ticker_executed = (int *)malloc(sizeof(int));
932         if (is_ticker_executed != NULL) {
933                 *is_ticker_executed = 0;
934                 evas_object_data_set(detail, PRIVATE_DATA_KEY_TICKERNOTI_EXECUTED, is_ticker_executed);
935         }
936
937         /* When ticker noti is displayed, indicator window has to be hidden. */
938         if (ad) util_signal_emit_by_win(&ad->win, "message.show.noeffect", "indicator.prog");
939
940         ticker_info->timer = ecore_timer_add(TICKERNOTI_DURATION, _timeout_cb, ticker_info);
941
942         evas_object_data_set(ad->win.win, PRIVATE_DATA_KEY_TICKER_INFO, ticker_info);
943
944         return;
945
946 ERROR:
947         if (ticker_info->win) _destroy_tickernoti(ticker_info);
948
949         return;
950 }
951
952 static void _destroy_tickernoti(ticker_info_s *ticker_info)
953 {
954         struct appdata *ad = NULL;
955         Evas_Object *textblock = NULL;
956         Evas_Object *box = NULL;
957         Evas_Object *icon = NULL;
958         Evas_Object *detail = NULL;
959         Evas_Object *base = NULL;
960         int *is_ticker_executed = NULL;
961         notification_h noti;
962
963         ret_if(!ticker_info);
964         ret_if(!ticker_info->win);
965
966         _D("destroy ticker notification");
967
968         ad = evas_object_data_del(ticker_info->win, PRIVATE_DATA_KEY_APPDATA);
969         /* When ticker noti is hidden, indicator window has to be displayed. */
970         if (ad) util_signal_emit_by_win(&ad->win, "message.hide", "indicator.prog");
971
972         if (ticker_info->timer) {
973                 ecore_timer_del(ticker_info->timer);
974                 ticker_info->timer = NULL;
975         }
976
977         textblock = evas_object_data_del(ticker_info->win, DATA_KEY_TICKER_TEXT);
978         if (textblock) evas_object_del(textblock);
979
980         box = evas_object_data_del(ticker_info->win, PRIVATE_DATA_KEY_BOX);
981         if (box) evas_object_del(box);
982
983         if (ticker_info->scroller) ticker_info->scroller = NULL;
984
985         icon = evas_object_data_del(ticker_info->win, PRIVATE_DATA_KEY_ICON);
986         if (icon) evas_object_del(icon);
987
988         base = evas_object_data_del(ticker_info->win, DATA_KEY_BASE_RECT);
989         if (base) evas_object_del(base);
990
991         detail = evas_object_data_del(ticker_info->win, PRIVATE_DATA_KEY_DETAIL);
992         if (detail) {
993                 is_ticker_executed = evas_object_data_del(detail, PRIVATE_DATA_KEY_TICKERNOTI_EXECUTED);
994                 if (is_ticker_executed != NULL) {
995                         free(is_ticker_executed);
996                 }
997                 evas_object_del(detail);
998         }
999
1000         evas_object_del(ticker_info->win);
1001         ticker_info->win = NULL;
1002
1003         noti = evas_object_data_del(ticker_info->win, PRIVATE_DATA_KEY_NOTI);
1004         if (noti) {
1005                 __ticker_only_noti_del(noti);
1006                 notification_free(noti);
1007         }
1008
1009         if (ticker_info->ticker_list) {
1010                 noti = _get_instant_latest_message_from_list(ticker_info);
1011                 if (noti) {
1012                         _create_tickernoti(noti, ad, ticker_info);
1013                 }
1014         }
1015 }
1016
1017 static void _ticker_noti_detailed_changed_cb(void *data, notification_type_e type, notification_op *op_list, int num_op)
1018 {
1019         notification_h noti = NULL;
1020         notification_h noti_from_master = NULL;
1021         ticker_info_s *ticker_info = NULL;
1022         int flags = 0;
1023         int applist = NOTIFICATION_DISPLAY_APP_ALL;
1024         int ret = 0;
1025         int op_type = 0;
1026         int priv_id = 0;
1027
1028         ret_if(!op_list);
1029
1030         _D("_ticker_noti_changed_cb");
1031
1032         ticker_info = calloc(1, sizeof(ticker_info_s));
1033         ret_if(!ticker_info);
1034
1035         if (num_op == 1) {
1036                 notification_op_get_data(op_list, NOTIFICATION_OP_DATA_TYPE, &op_type);
1037                 notification_op_get_data(op_list, NOTIFICATION_OP_DATA_PRIV_ID, &priv_id);
1038                 notification_op_get_data(op_list, NOTIFICATION_OP_DATA_NOTI, &noti_from_master);
1039                 DBG("op_type:%d", op_type);
1040                 DBG("op_priv_id:%d", priv_id);
1041                 DBG("noti:%p", noti_from_master);
1042
1043                 if (op_type != NOTIFICATION_OP_INSERT &&
1044                                 op_type != NOTIFICATION_OP_UPDATE) {
1045                         return;
1046                 }
1047                 if (noti_from_master == NULL) {
1048                         _E("failed to get a notification from master");
1049                         return;
1050                 }
1051                 if (notification_clone(noti_from_master, &noti) != NOTIFICATION_ERROR_NONE) {
1052                         _E("failed to create a cloned notification");
1053                         return;
1054                 }
1055 #ifdef QP_EMERGENCY_MODE_ENABLE
1056                 if (quickpanel_emergency_mode_is_on()) {
1057                         if (quickpanel_emergency_mode_notification_filter(noti, 1)) {
1058                                 DBG("notification filtered");
1059                                 notification_free(noti);
1060                                 return;
1061                         }
1062                 }
1063 #endif
1064         }
1065
1066         ret_if(!noti);
1067
1068         notification_get_display_applist(noti, &applist);
1069         if (!(applist & NOTIFICATION_DISPLAY_APP_TICKER
1070                                 || applist & NOTIFICATION_DISPLAY_APP_INDICATOR)) {
1071                 DBG("displaying ticker option is off");
1072                 notification_free(noti);
1073                 return;
1074         }
1075
1076         /* Check setting's event notification */
1077         ret = _ticker_check_ticker_off(noti);
1078         if (ret == 1) {
1079                 DBG("Disabled tickernoti ret : %d", ret);
1080                 /* delete temporary here only ticker noti display item */
1081                 __ticker_only_noti_del(noti);
1082                 notification_free(noti);
1083
1084                 return;
1085         }
1086
1087         /* Skip if previous ticker is still shown */
1088 /*
1089         if (ticker_info->win != NULL) {
1090                 DBG("delete ticker noti");
1091                 _destroy_tickernoti();
1092                 ticker_info->win = NULL;
1093         }
1094 */
1095
1096         /* Check tickernoti flag */
1097         notification_get_property(noti, &flags);
1098
1099         if (flags & NOTIFICATION_PROP_DISABLE_TICKERNOTI) {
1100                 DBG("NOTIFICATION_PROP_DISABLE_TICKERNOTI");
1101                 __ticker_only_noti_del(noti);
1102                 notification_free(noti);
1103         } else if (applist & NOTIFICATION_DISPLAY_APP_TICKER
1104                         || applist & NOTIFICATION_DISPLAY_APP_INDICATOR) {
1105                 if (_is_security_lockscreen_launched()) {
1106                         _E("lockscreen or sview launched, creating a ticker canceled");
1107                         notification_free(noti);
1108                         return;
1109                 }
1110
1111                 ticker_info->ticker_list = eina_list_append(ticker_info->ticker_list, noti);
1112                 /* wait when win is not NULL */
1113                 if (ticker_info->win == NULL) {
1114                         _create_tickernoti(noti, data, ticker_info);
1115                 }
1116                 if (ticker_info->win == NULL) {
1117                         _E("Fail to create tickernoti");
1118                         __ticker_only_noti_del(noti);
1119                         notification_free(noti);
1120                         return;
1121                 }
1122         }
1123 }
1124
1125 static Eina_Bool _tickernoti_callback_register_idler_cb(void *data)
1126 {
1127         retv_if(!data, EINA_FALSE);
1128
1129         notification_register_detailed_changed_cb(_ticker_noti_detailed_changed_cb, data);
1130
1131         return EINA_FALSE;
1132 }
1133
1134 int ticker_init(void *data)
1135 {
1136         /* data is ad */
1137         /* Register notification changed cb */
1138         ecore_idler_add(_tickernoti_callback_register_idler_cb, data);
1139
1140         return INDICATOR_ERROR_NONE;
1141 }
1142
1143 int ticker_fini(void *data)
1144 {
1145         struct appdata *ad = NULL;
1146         ticker_info_s *ticker_info = NULL;
1147
1148         retv_if(!data, 0);
1149
1150         ad = data;
1151
1152         ticker_info = evas_object_data_del(ad->win.win, PRIVATE_DATA_KEY_TICKER_INFO);
1153         retv_if(!ticker_info, 0);
1154
1155         if (ticker_info->timer) {
1156                 ecore_timer_del(ticker_info->timer);
1157                 ticker_info->timer = NULL;
1158         }
1159
1160         return INDICATOR_ERROR_NONE;
1161 }
1162
1163 /* End of file */