modules/information/ext_storage: fix sigsegv
[apps/core/preloaded/indicator-win.git] / src / message.c
1 /*
2  *  Indicator
3  *
4  * Copyright (c) 2000 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19
20
21
22 #include <notification.h>
23 #include <notification_status_internal.h>
24
25 #include "main.h"
26 #include "common.h"
27 #include "util.h"
28 #include "tts.h"
29 #include "box.h"
30
31
32 #define MSG_TIMEOUT 3
33 #define STR_BUF_SIZE 256
34 #define QUEUE_TIMEOUT 1
35 #define QUEUE_TIMEOUT2 5
36 #define QUEUE_SIZE 5
37
38 #define MESSAGE_LINE1 "message.text"
39 #define MESSAGE_LINE2 "message.text2"
40
41
42 typedef struct _str_buf {
43         char *data;
44         int index;
45         double timer_val;
46 } MsgBuf;
47
48
49 static int msg_type = 0;
50 static Ecore_Timer *msg_timer = NULL;
51 static Ecore_Timer *ani_temp_timer = NULL;
52
53 extern int current_angle;
54 static int block_width = 0;
55 static int string_width = 0;
56 static char* message_buf = NULL;
57 static Ecore_Timer *retry_timer=NULL;
58 static int msg_retry = 0;
59 static struct appdata *app_data = NULL;
60 static Ecore_Timer *queue_timer=NULL;
61 static int current_buf_index = 0;
62 static int current_buf_cnt = 0;
63 static MsgBuf msg_queue[QUEUE_SIZE];
64
65
66
67 static Eina_Bool _ani_temp_timeout_cb(void *data)
68 {
69         retif(data == NULL, ECORE_CALLBACK_CANCEL, "Invalid parameter!");
70
71         if (ani_temp_timer)
72         {
73                 ecore_timer_del(ani_temp_timer);
74                 ani_temp_timer = NULL;
75         }
76
77         return ECORE_CALLBACK_CANCEL;
78 }
79
80
81
82 void start_temp_ani_timer(void* data)
83 {
84         retif(data == NULL, , "Invalid parameter!");
85         win_info* win = (win_info*)data;
86
87         if(ani_temp_timer != NULL)
88         {
89                 ecore_timer_del(ani_temp_timer);
90                 ani_temp_timer = NULL;
91         }
92         ani_temp_timer = ecore_timer_add(0.3, (Ecore_Task_Cb)_ani_temp_timeout_cb, (void*)win);
93
94 }
95
96
97
98 static void _hide_message(void* data)
99 {
100         retif(data == NULL, , "Invalid parameter!");
101         win_info* win = NULL;
102         win = (win_info*)data;
103
104         box_update_display(win);
105
106         start_temp_ani_timer(data);
107         util_signal_emit_by_win(win,"message.hide", "indicator.prog");
108 }
109
110
111
112 static void _hide_message_all(void* data)
113 {
114         retif(data == NULL, , "Invalid parameter!");
115
116         util_signal_emit(data,"message.line2.hide.noeffect","indicator.prog");
117 }
118
119
120
121 static void _show_message(void* data)
122 {
123         retif(data == NULL, , "Invalid parameter!");
124         win_info* win = NULL;
125         win = (win_info*)data;
126         struct appdata* ad = (struct appdata*)win->data;
127
128         start_temp_ani_timer(data);
129         if(ad->opacity_mode==INDICATOR_OPACITY_TRANSPARENT)
130         {
131                 DBG("Transparent");
132                 util_signal_emit_by_win(win,"message.show.noeffect", "indicator.prog");
133                 evas_object_show(win->win);
134         }
135         else
136         {
137                 util_signal_emit_by_win(win,"message.show", "indicator.prog");
138         }
139 }
140
141
142
143 static void _show_message_line2(void* data)
144 {
145         retif(data == NULL, , "Invalid parameter!");
146         win_info* win = NULL;
147         win = (win_info*)data;
148
149         if (win)
150         {
151                 util_signal_emit_by_win(win,"message.line2.show", "indicator.prog");
152         }
153 }
154
155
156
157 static Eina_Bool _msg_timeout_cb(void *data)
158 {
159         retif(data == NULL, ECORE_CALLBACK_CANCEL, "Invalid parameter!");
160
161         win_info* win = (win_info*)data;
162
163         if(msg_type == 1)
164         {
165                 msg_timer = NULL;
166                 _hide_message(win);
167                 return ECORE_CALLBACK_CANCEL;
168         }
169         else if(msg_type == 2)
170         {
171
172                 msg_type = 0;
173                 if (msg_timer)
174                 {
175                         ecore_timer_del(msg_timer);
176                 }
177                 msg_timer = ecore_timer_add(3, (Ecore_Task_Cb)_msg_timeout_cb, (void*)win);
178                 _show_message_line2(win);
179                 return ECORE_CALLBACK_CANCEL;
180         }
181         else
182         {
183                 msg_type = 0;
184                 msg_timer = NULL;
185                 _hide_message(win);
186                 return ECORE_CALLBACK_CANCEL;
187         }
188 }
189
190
191
192 static Eina_Bool _retry_timeout_cb(void *data)
193 {
194         retif(data == NULL, EINA_TRUE , "Invalid parameter!");
195
196         if(message_buf!=NULL)
197         {
198                 free(message_buf);
199                 message_buf = NULL;
200         }
201
202         if (retry_timer!=NULL)
203         {
204                 ecore_timer_del(retry_timer);
205                 retry_timer = NULL;
206         }
207         return EINA_TRUE;
208
209 }
210
211
212
213 static int __get_block_width(void* data, const char* part)
214 {
215         Evas_Object * eo = NULL;
216         int geo_dx = 0;
217         int geo_dy = 0;
218         retif(data == NULL,-1, "Invalid parameter!");
219         retif(part == NULL,-1, "Invalid parameter!");
220
221         win_info* win = (win_info*)data;
222
223         eo = (Evas_Object *) edje_object_part_object_get(elm_layout_edje_get(win->layout), part);
224
225         evas_object_geometry_get(eo, NULL, NULL, &geo_dx, &geo_dy);
226
227         return geo_dx;
228 }
229
230
231
232 static int __get_string_width(void* data, const char* part)
233 {
234         Evas_Object * eo = NULL;
235         int text_dx = 0;
236         int text_dy = 0;
237         retif(data == NULL,-1, "Invalid parameter!");
238         retif(part == NULL,-1, "Invalid parameter!");
239
240         win_info* win = (win_info*)data;
241
242         eo = (Evas_Object *) edje_object_part_object_get(elm_layout_edje_get(win->layout), part);
243
244         evas_object_textblock_size_formatted_get(eo, &text_dx, &text_dy);
245
246         return text_dx;
247 }
248
249
250
251 static void __handle_2line(win_info* win,char* origin, char* part1, char* part2)
252 {
253         retif(origin == NULL, , "Invalid parameter!");
254         retif(part1 == NULL, , "Invalid parameter!");
255         retif(part2 == NULL, , "Invalid parameter!");
256         int index = 0;
257         Eina_Unicode *uni_out = NULL;
258         Eina_Unicode buf[STR_BUF_SIZE] = {0,};
259         int len = 0;
260         int len2 = 0;
261         Eina_Unicode temp1[STR_BUF_SIZE] = {0,};
262         Eina_Unicode temp2[STR_BUF_SIZE] = {0,};
263         char* out1 = NULL;
264         char* out2 = NULL;
265         int char_len1 = 0;
266         int char_len2 = 0;
267
268         uni_out = eina_unicode_utf8_to_unicode(origin, &len);
269
270         if(len >= STR_BUF_SIZE)
271         {
272                 len2 = STR_BUF_SIZE-1;
273         }
274         else
275         {
276                 len2 = len;
277         }
278
279         eina_unicode_strncpy(buf,uni_out,len2);
280
281         int exceed_index = len2 * block_width / string_width;
282         {
283                 int i = 0;
284                 for(i=0;i<100;i++)
285                 {
286                         Eina_Unicode temp1[STR_BUF_SIZE] = {0,};
287                         int char_len1 = 0;
288                         char* out1 = NULL;
289                         int width = 0;
290                         eina_unicode_strncpy(temp1,buf,exceed_index);
291                         out1 = eina_unicode_unicode_to_utf8(temp1,&char_len1);
292                         util_part_text_emit_by_win(win,"message.text.compare", out1);
293
294                         width = __get_string_width(win,"message.text.compare");
295
296                         if(width > block_width)
297                         {
298                                 exceed_index = exceed_index -1;
299                                 DBG("reduce exceed index(%d)",exceed_index,width);
300                         }
301                         else
302                         {
303                                 if(out1!=NULL)
304                                         free(out1);
305                                 break;
306                         }
307
308                         if(out1!=NULL)
309                                 free(out1);
310                 }
311                 for(i=0;i<100;i++)
312                 {
313                         Eina_Unicode temp1[STR_BUF_SIZE] = {0,};
314                         int char_len1 = 0;
315                         char* out1 = NULL;
316                         int width = 0;
317                         eina_unicode_strncpy(temp1,buf,exceed_index);
318                         out1 = eina_unicode_unicode_to_utf8(temp1,&char_len1);
319                         util_part_text_emit_by_win(win,"message.text.compare", out1);
320
321                         width = __get_string_width(win,"message.text.compare");
322
323                         if(width < block_width)
324                         {
325                                 exceed_index = exceed_index +1;
326                                 DBG("increase exceed index(%d)",exceed_index,width);
327                         }
328                         else
329                         {
330                                 exceed_index = exceed_index -1;
331                                 if(out1)
332                                         free(out1);
333                                 break;
334                         }
335
336                         if(out1)
337                                 free(out1);
338                 }
339
340         }
341
342         if(exceed_index<0)
343         {
344                 ERR("INDEX %d",exceed_index);
345                 goto __CATCH;
346         }
347
348         int i = exceed_index;
349
350         while(i>0)
351         {
352                 if(buf[i-1]==' ')
353                 {
354                         index = i-1;
355                         break;
356                 }
357                 i--;
358         }
359
360         if(index>0)
361         {
362                 Eina_Unicode *temp3 = NULL;
363                 eina_unicode_strncpy(temp1,buf,index);
364                 temp3 = &(buf[index]);
365                 eina_unicode_strncpy(temp2,temp3,len2-index);
366         }
367         else
368         {
369                 Eina_Unicode *temp3 = NULL;
370                 eina_unicode_strncpy(temp1,buf,exceed_index);
371                 temp3 = &(buf[exceed_index]);
372                 eina_unicode_strncpy(temp2,temp3,len2-exceed_index);
373         }
374
375         out1 = eina_unicode_unicode_to_utf8(temp1,&char_len1);
376         out2 = eina_unicode_unicode_to_utf8(temp2,&char_len2);
377
378         if(char_len1>=STR_BUF_SIZE)
379                 char_len1 = STR_BUF_SIZE-1;
380         if(char_len2>=STR_BUF_SIZE)
381                 char_len2 = STR_BUF_SIZE-1;
382         strncpy(part1,out1,char_len1);
383         strncpy(part2,out2,char_len2);
384
385 __CATCH:
386         if(uni_out!=NULL)
387                 free(uni_out);
388         if(out1!=NULL)
389                 free(out1);
390         if(out2!=NULL)
391                 free(out2);
392 }
393
394
395
396 static void _handle_message_by_win(char *message, void *data)
397 {
398         win_info* win = NULL;
399         char part1[256] = {0,};
400         char part2[256] = {0,};
401         char *text = NULL;
402         double time_clk = 0;
403         char* temp = NULL;
404         retif(message == NULL, , "Invalid parameter!");
405         retif(data == NULL, , "Invalid parameter!");
406
407         win = data;
408
409         if (msg_timer)
410         {
411                 ecore_timer_del(msg_timer);
412         }
413         msg_type = 0;
414
415         SECURE_DBG("message %s", message);
416
417         temp = strdup(message);
418
419         util_char_replace(temp,'\n',' ');
420
421         text = evas_textblock_text_utf8_to_markup(NULL, temp);
422         if (!text)
423         {
424                 if(temp)
425                         free(temp);
426
427                 return;
428         }
429         block_width = __get_block_width(win,"message.text");
430         util_part_text_emit_by_win(win,"message.text.compare", text);
431         string_width = __get_string_width(win,"message.text.compare");
432
433         if(block_width > string_width)
434         {
435                 msg_type = 1;
436         }
437         else
438         {
439                 msg_type = 2;
440         }
441
442         DBG("msg_type %d",  msg_type);
443
444         _show_message(win);
445
446         if(msg_type == 1)
447         {
448                 time_clk = 3;
449                 util_part_text_emit_by_win(win,"message.text", text);
450                 util_send_status_message_start(win,2.5);
451         }
452         else
453         {
454                 time_clk = 2.5;
455                 __handle_2line(win,text,part1,part2);
456                 util_part_text_emit_by_win(win,"message.text", part1);
457                 util_part_text_emit_by_win(win,"message.line2.text", part2);
458                 util_send_status_message_start(win,5);
459         }
460
461         if(text!=NULL)
462                 free(text);
463
464         msg_timer = ecore_timer_add(time_clk, (Ecore_Task_Cb)_msg_timeout_cb, (void*)win);
465
466         if(temp!=NULL)
467                 free(temp);
468 }
469
470
471
472 static void __message_callback(const char *message, void *data)
473 {
474         struct appdata *ad = NULL;
475         win_info* win = NULL;
476
477         if (!data)
478                 return;
479
480         ad = data;
481
482         char buf[256] = {0,};
483         strncpy(buf,message,256-1);
484 #ifdef _SUPPORT_SCREEN_READER2
485         indicator_service_tts_play(buf);
486 #endif
487
488         if(message_buf!=NULL)
489         {
490                 free(message_buf);
491                 message_buf = NULL;
492         }
493
494         message_buf = strdup(message);
495         msg_retry = 0;
496
497         _hide_message_all(data);
498
499         win = &(ad->win);
500         _handle_message_by_win(message_buf,win);
501
502         if(retry_timer!=NULL)
503         {
504                 ecore_timer_del(retry_timer);
505         }
506         retry_timer = ecore_timer_add(0.5, (Ecore_Task_Cb)_retry_timeout_cb, (void*)win);
507
508 }
509
510
511
512 static void _buf_timeout_callback(void* data)
513 {
514
515         if(current_buf_index<QUEUE_SIZE)
516         if(msg_queue[current_buf_index].data!=NULL)
517         {
518                 DBG("index %d,%s",current_buf_index,msg_queue[current_buf_index].data);
519                 __message_callback(msg_queue[current_buf_index].data,data);
520                 if(msg_queue[current_buf_index].data!=NULL)
521                 {
522                         free(msg_queue[current_buf_index].data);
523                         msg_queue[current_buf_index].data = NULL;
524                 }
525                 if(current_buf_index+1<QUEUE_SIZE)
526                 {
527                         if(msg_queue[current_buf_index+1].data!=NULL)
528                         {
529                                 if(queue_timer!=NULL)
530                                 {
531                                         ecore_timer_del(queue_timer);
532                                         queue_timer = NULL;
533                                 }
534                                 current_buf_index = current_buf_index+1;
535                                 queue_timer = ecore_timer_add(msg_queue[current_buf_index].timer_val, (Ecore_Task_Cb)_buf_timeout_callback, data);
536                                 return;
537                         }
538                 }
539         }
540
541         if(queue_timer!=NULL)
542         {
543                 ecore_timer_del(queue_timer);
544                 queue_timer = NULL;
545         }
546         current_buf_cnt = 0;
547         current_buf_index = 0;
548         DBG("quit buffering..");
549 }
550
551
552
553 static void __buffer_msg_callback(const char *message, void *data)
554 {
555         struct appdata *ad = NULL;
556         retif(data == NULL, , "Invalid parameter!");
557         ad = data;
558
559         win_info *win = NULL;
560         double timer_val;
561
562         win = &(ad->win);
563
564         block_width = __get_block_width(win,"message.text");
565         util_part_text_emit_by_win(win,"message.text.compare", message);
566         string_width = __get_string_width(win,"message.text.compare");
567
568         if(block_width > string_width)
569         {
570                 timer_val = QUEUE_TIMEOUT;
571         }
572         else
573         {
574                 timer_val = QUEUE_TIMEOUT2;
575         }
576
577         if(queue_timer!=NULL)
578         {
579                 if(current_buf_cnt>=QUEUE_SIZE)
580                 {
581                         ERR("QUEUE FULL");
582                         return;
583                 }
584                 SECURE_DBG("buffering... %d,%s",current_buf_cnt,message);
585                 if(msg_queue[current_buf_cnt].data!=NULL)
586                 {
587                         free(msg_queue[current_buf_cnt].data);
588                         msg_queue[current_buf_cnt].data = NULL;
589                 }
590                 msg_queue[current_buf_cnt].data = strdup(message);
591                 msg_queue[current_buf_cnt].index = current_buf_cnt;
592                 msg_queue[current_buf_cnt].timer_val = timer_val;
593                 current_buf_cnt++;
594                 return;
595         }
596
597         queue_timer = ecore_timer_add(timer_val, (Ecore_Task_Cb)_buf_timeout_callback, data);
598         __message_callback(message,data);
599 }
600
601
602
603 int indicator_message_disp_check(void)
604 {
605         if (msg_timer != NULL)
606                 return 1;
607         else
608                 return 0;
609 }
610
611
612
613 int message_ani_playing_check(void)
614 {
615         if(ani_temp_timer != NULL)
616                 return 1;
617         else
618                 return 0;
619 }
620
621
622
623 int indicator_message_retry_check(void)
624 {
625         if(retry_timer!=NULL)
626                 return 1;
627         else
628                 return 0;
629 }
630
631
632
633 void indicator_message_display_trigger(void)
634 {
635         win_info* win = NULL;
636
637         if(msg_retry==1)
638         {
639                 return;
640         }
641
642         DBG("retry message");
643
644         msg_retry = 1;
645
646         win = &(app_data->win);
647         _handle_message_by_win(message_buf,win);
648
649 }
650
651
652
653 int indicator_message_init(void *data)
654 {
655         int ret = 0;
656         int i =0;
657         for(i=0;i<QUEUE_SIZE;i++)
658         {
659                 memset(&msg_queue[i],0x00,sizeof(MsgBuf));
660         }
661         ret = notification_status_monitor_message_cb_set(__buffer_msg_callback, data);
662         app_data = data;
663
664
665         return ret;
666 }
667
668
669
670 int indicator_message_fini(void)
671 {
672         int ret = 0;
673
674         ret = notification_status_monitor_message_cb_unset();
675
676         return ret;
677 }