9cb71c4917bd57a4456004884019e6392c69d286
[profile/tv/apps/native/air_home.git] / src / data / data_recent.c
1 /*
2  * Copyright (c) 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 #include <app_debug.h>
18 #include <Eina.h>
19 #include <stdbool.h>
20 #include <app_contents.h>
21 #include <glib.h>
22 #include <pkgmgr-info.h>
23 #include <tv_service_proxy_channel_info.h>
24 #include <tv_service_proxy_epg.h>
25 #include <media_content.h>
26 #include <app_media.h>
27 #include <app_define.h>
28 #include <app_contents.h>
29 #include <time.h>
30 #include <ctype.h>
31
32 #include "data_recent.h"
33 #include "datamgr.h"
34 #include "utils.h"
35 #include "defs.h"
36
37 #define BUF_TITLE_MAX 128
38 #define MAX_BUF 64
39
40 static struct datamgr_item *_new_datamgr_item(char *title, char *thumb,
41                 char *subtitle, char *parameter, char *key, char *value,
42                 char *icon, int type, time_t time)
43 {
44         struct datamgr_item *di;
45
46         di = calloc(1, sizeof(*di));
47         if (!di) {
48                 _ERR("failed to calloc datamgr item");
49                 return NULL;
50         }
51
52         di->title = strdup(title);
53         di->focus_icon = strdup(icon);
54         di->type = type;
55         di->parameter = strdup(parameter);
56         di->action = ITEM_SELECT_ACTION_LAUNCH;
57         di->time = time;
58         if (thumb)
59                 di->icon = strdup(thumb);
60         if (subtitle)
61                 di->subtitle = strdup(subtitle);
62         if (key && value) {
63                 di->key = strdup(key);
64                 di->value = strdup(value);
65         }
66
67         return di;
68 }
69
70 static void _app_list_foreach(gpointer data, gpointer user_data)
71 {
72         struct recent_data *rdata;
73         char *label, *thumb;
74         pkgmgrinfo_appinfo_h handle;
75         int r;
76         struct datamgr_item *di;
77         struct datamgr *dm;
78         bool nodisplay;
79
80         if (!data) {
81                 _ERR("Invalid argument");
82                 return;
83         }
84
85         rdata = data;
86         dm = user_data;
87
88         if (!strcmp(rdata->id, APP_ID_BROWSER))
89                 return;
90
91         r = pkgmgrinfo_appinfo_get_usr_appinfo(rdata->id, getuid(), &handle);
92         if (r != PMINFO_R_OK) {
93                 _ERR("failed to get app info");
94                 return;
95         }
96
97         r = pkgmgrinfo_appinfo_is_nodisplay(handle, &nodisplay);
98         if (r != PMINFO_R_OK || nodisplay) {
99                 pkgmgrinfo_appinfo_destroy_appinfo(handle);
100                 return;
101         }
102
103         label = NULL;
104         thumb = NULL;
105         r = pkgmgrinfo_appinfo_get_label(handle, &label);
106         if (r != PMINFO_R_OK)
107                 _ERR("failed to get app label");
108
109         r = pkgmgrinfo_appinfo_get_icon(handle, &thumb);
110         if (r != PMINFO_R_OK)
111                 _ERR("failed to get app icon");
112
113         if (!thumb || !strcmp(thumb, ""))
114                 thumb = IMAGE_RECENT_THUMB_APP;
115
116         di = _new_datamgr_item(label, thumb, NULL, rdata->id, NULL, NULL,
117                         IMAGE_RECENT_ICON_APP, 0, rdata->time);
118         if (di)
119                 dm->list = eina_list_append(dm->list, di);
120
121         pkgmgrinfo_appinfo_destroy_appinfo(handle);
122 }
123
124 static void _get_program(int service_id, char **program)
125 {
126         TvServiceEpg epg_svc;
127         TvServiceEpgEventData epg_data;
128         int r;
129
130         r = tv_service_epg_create(&epg_svc);
131         if (r != TVS_ERROR_OK)
132                 return;
133
134         r = tv_service_epg_get_cache_current_program(epg_svc, service_id,
135                         &epg_data);
136         if (r != TVS_ERROR_OK) {
137                 _ERR("failed to get epg data: %d", service_id);
138                 tv_service_epg_destroy(epg_svc);
139                 return;
140         }
141
142         *program = (char *)epg_data.title_text;
143
144         tv_service_epg_destroy(epg_svc);
145 }
146
147 static void _channel_list_foreach(gpointer data, gpointer user_data)
148 {
149         struct recent_data *rdata;
150         struct datamgr_item *di;
151         struct datamgr *dm;
152         TvServiceChannel channel;
153         int r;
154         char buf[BUF_TITLE_MAX];
155         char *thumb = NULL, *program = NULL;
156
157         if (!data || !user_data) {
158                 _ERR("Invalid argument");
159                 return;
160         }
161
162         rdata = data;
163         dm = user_data;
164
165         r = tv_service_get_channel(atoi(rdata->id), &channel);
166         if (r != TVS_ERROR_OK) {
167                 _ERR("failed to get channel");
168                 return;
169         }
170
171         if (channel.minor > 0)
172                 snprintf(buf, sizeof(buf), "%ld-%ld %s",
173                                 channel.major, channel.minor,
174                                 channel.program_name ?
175                                                 channel.program_name : "");
176         else
177                 snprintf(buf, sizeof(buf), "%ld %s", channel.major,
178                                 channel.program_name ?
179                                                 channel.program_name : "");
180
181         _get_program(atoi(rdata->id), &program);
182
183         di = _new_datamgr_item(buf, thumb ? thumb : IMAGE_RECENT_THUMB_CHANNEL,
184                         program, APP_ID_LIVETV, PARAM_SERVICE_ID,
185                         rdata->id, IMAGE_RECENT_ICON_CHANNEL, 1, rdata->time);
186         if (di)
187                 dm->list = eina_list_append(dm->list, di);
188 }
189
190 static void _set_up_string(char *str)
191 {
192         while (*str) {
193                 *str = toupper(*str);
194                 str++;
195         }
196 }
197
198 static void _gallery_list_foreach(gpointer data, gpointer user_data)
199 {
200         struct recent_data *rdata;
201         struct datamgr_item *di;
202         struct datamgr *dm;
203         app_media *am;
204         app_media_info *aminfo;
205         media_info_h media;
206         int r;
207         char buf[BUF_TITLE_MAX], day[BUF_TITLE_MAX], date[BUF_TITLE_MAX];
208
209         if (!data || !user_data) {
210                 _ERR("Invalid arguement");
211                 return;
212         }
213
214         rdata = data;
215         dm = user_data;
216
217         r = media_info_get_media_from_db(rdata->id, &media);
218         if (r != MEDIA_CONTENT_ERROR_NONE) {
219                 _ERR("failed to get media");
220                 return;
221         }
222
223         am = app_media_create(media);
224         if (!am) {
225                 _ERR("failed to create media");
226                 media_info_destroy(media);
227                 return;
228         }
229
230         aminfo = app_media_get_info(am);
231         if (!aminfo) {
232                 _ERR("failed to get media info");
233                 app_media_destroy(am);
234                 media_info_destroy(media);
235                 return;
236         }
237
238         strftime(date, sizeof(date), "%d %b, %Y", aminfo->content_time);
239         strftime(day, sizeof(day), "%a", aminfo->content_time);
240         _set_up_string(day);
241         snprintf(buf, sizeof(buf), "%s, %s", day, date);
242
243         di = _new_datamgr_item(buf, aminfo->thumbnail_path, NULL,
244                         APP_ID_MEDIAHUB, PARAM_MEDIA_ID, rdata->id,
245                         IMAGE_RECENT_ICON_GALLERY, 1, rdata->time);
246         if (di)
247                 dm->list = eina_list_append(dm->list, di);
248
249         app_media_destroy(am);
250         media_info_destroy(media);
251 }
252
253 static void _get_duration(int duration, char *str, size_t length)
254 {
255         int h, m, s, sec;
256
257         sec = duration / 1000;
258         h = sec / 3600;
259         m = (sec % 3600) / 60;
260         s = sec % 60;
261
262         if (h)
263                 snprintf(str, length, "%d:%02d:%02d", h, m, s);
264         else
265                 snprintf(str, length, "%d:%02d", m, s);
266 }
267
268 static void _movie_list_foreach(gpointer data, gpointer user_data)
269 {
270         struct recent_data *rdata;
271         struct datamgr_item *di;
272         struct datamgr *dm;
273         app_media *am;
274         app_media_info *aminfo;
275         media_info_h media;
276         int r;
277         char dur[BUF_TITLE_MAX];
278
279         if (!data || !user_data) {
280                 _ERR("Invalid arguement");
281                 return;
282         }
283
284         rdata = data;
285         dm = user_data;
286
287         r = media_info_get_media_from_db(rdata->id, &media);
288         if (r != MEDIA_CONTENT_ERROR_NONE) {
289                 _ERR("failed to get media");
290                 return;
291         }
292
293         am = app_media_create(media);
294         if (!am) {
295                 _ERR("failed to create media");
296                 media_info_destroy(media);
297                 return;
298         }
299
300         aminfo = app_media_get_info(am);
301         if (!aminfo) {
302                 _ERR("failed to get media info");
303                 app_media_destroy(am);
304                 media_info_destroy(media);
305                 return;
306         }
307
308         if (aminfo->video && aminfo->video->duration)
309                 _get_duration(aminfo->video->duration, dur, sizeof(dur));
310
311         di = _new_datamgr_item(aminfo->title, aminfo->thumbnail_path,
312                         dur, APP_ID_MEDIAHUB, PARAM_MEDIA_ID,
313                         rdata->id, IMAGE_RECENT_ICON_MOVIE, 1, rdata->time);
314         if (di)
315                 dm->list = eina_list_append(dm->list, di);
316
317         app_media_destroy(am);
318         media_info_destroy(media);
319 }
320
321 static void _music_list_foreach(gpointer data, gpointer user_data)
322 {
323         struct recent_data *rdata;
324         struct datamgr_item *di;
325         struct datamgr *dm;
326         app_media *am;
327         app_media_info *aminfo;
328         media_info_h media;
329         int r;
330
331         if (!data || !user_data) {
332                 _ERR("Invalid arguement");
333                 return;
334         }
335
336         rdata = data;
337         dm = user_data;
338
339         r = media_info_get_media_from_db(rdata->id, &media);
340         if (r != MEDIA_CONTENT_ERROR_NONE) {
341                 _ERR("failed to get media");
342                 return;
343         }
344
345         am = app_media_create(media);
346         if (!am) {
347                 _ERR("failed to create media");
348                 media_info_destroy(media);
349                 return;
350         }
351
352         aminfo = app_media_get_info(am);
353         if (!aminfo) {
354                 _ERR("failed to get media info");
355                 app_media_destroy(am);
356                 media_info_destroy(media);
357                 return;
358         }
359
360         di = _new_datamgr_item(aminfo->title, aminfo->thumbnail_path,
361                         aminfo->audio->artist, APP_ID_MEDIAHUB, PARAM_MEDIA_ID,
362                         rdata->id, IMAGE_RECENT_ICON_MUSIC, 1, rdata->time);
363         if (di)
364                 dm->list = eina_list_append(dm->list, di);
365
366         app_media_destroy(am);
367         media_info_destroy(media);
368 }
369
370 static bool _load_recent(struct datamgr *dm, enum app_contents_type type,
371                 int count, GFunc func)
372 {
373         GList *rlist = NULL;
374         int r;
375
376         r = app_contents_get_recent_list(type, count, &rlist);
377         if (r != APP_CONTENTS_ERROR_NONE) {
378                 _ERR("failed to get recent list");
379                 return false;
380         }
381
382         g_list_foreach(rlist, func, dm);
383
384         app_contents_free_recent_list(rlist);
385
386         return true;
387 }
388
389 static void _unload_recent(struct datamgr *dm)
390 {
391         struct datamgr_item *di;
392
393         EINA_LIST_FREE(dm->list, di) {
394                 free(di->title);
395                 free(di->subtitle);
396                 free(di->icon);
397                 free(di->focus_icon);
398                 free(di->parameter);
399                 free(di->key);
400                 free(di->value);
401
402                 free(di);
403         }
404
405         dm->list = NULL;
406 }
407
408 static int _sort_list(const void *data1, const void *data2)
409 {
410         struct datamgr_item *di1, *di2;
411
412         di1 = (struct datamgr_item *)data1;
413         di2 = (struct datamgr_item *)data2;
414
415         if (!di1 || !di2)
416                 return -1;
417
418         if (di1->time < di2->time)
419                 return 1;
420
421         return -1;
422 }
423
424 static bool _load_recent_notification(struct datamgr *dm)
425 {
426         struct datamgr_item *di;
427         int time;
428         char buf[MAX_BUF];
429
430         snprintf(buf, sizeof(buf), "%d", utils_get_notification_count());
431
432         app_contents_get_basis_time(CONTENTS_NOTI, &time);
433         if (time < 0) {
434                 _ERR("Invalid time");
435                 return false;
436         }
437
438         di = _new_datamgr_item(MESSAGE_NOTIFICATION, IMAGE_RECENT_THUMB_NOTI,
439                         buf, APP_ID_INFOSQUARE, NULL, NULL,
440                         IMAGE_RECENT_ICON_APP, 0, time);
441         if (di)
442                 dm->list = eina_list_append(dm->list, di);
443
444         return true;
445 }
446
447 static Eina_List *_get_items(struct datamgr *dm)
448 {
449         if (!dm) {
450                 _ERR("Invalid argument");
451                 return NULL;
452         }
453
454         _unload_recent(dm);
455
456         if (!_load_recent(dm, CONTENTS_APP, -1, _app_list_foreach))
457                 _ERR("failed to load recent app contents");
458
459         if (!_load_recent(dm, CONTENTS_CHANNEL, 1, _channel_list_foreach))
460                 _ERR("failed to load recent channel contents");
461
462         if (!_load_recent(dm, CONTENTS_GALLERY, 1, _gallery_list_foreach))
463                 _ERR("failed to load recent gallery contents");
464
465         if (!_load_recent(dm, CONTENTS_MOVIE, 1, _movie_list_foreach))
466                 _ERR("failed to load recent movie contents");
467
468         if (!_load_recent(dm, CONTENTS_MUSIC, 1, _music_list_foreach))
469                 _ERR("failed to load recent music contents");
470
471         if (!_load_recent_notification(dm))
472                 _ERR("failed to load recent notification contents");
473
474         dm->list = eina_list_sort(dm->list, 0, _sort_list);
475
476         return dm->list;
477 }
478
479 static void _fini(struct datamgr *dm)
480 {
481         if (!dm) {
482                 _ERR("Invalid argument");
483                 return;
484         }
485
486         _unload_recent(dm);
487
488         media_content_disconnect();
489         tv_service_channel_info_destroy();
490 }
491
492 static bool _init(struct datamgr *dm)
493 {
494         int r;
495
496         if (!dm) {
497                 _ERR("Invalid argument");
498                 return false;
499         }
500
501         r = tv_service_channel_info_create();
502         if (r != TVS_ERROR_OK) {
503                 _ERR("failed to create tv service");
504                 return false;
505         }
506
507         r = media_content_connect();
508         if (r != MEDIA_CONTENT_ERROR_NONE) {
509                 tv_service_channel_info_destroy();
510                 _ERR("failed to connect media content");
511                 return false;
512         }
513
514         return true;
515 }
516
517 static bool _select(struct datamgr_item *di)
518 {
519         bool r;
520
521         if (!di || !di->parameter)
522                 return false;
523
524         r = false;
525         switch (di->action) {
526         case ITEM_SELECT_ACTION_LAUNCH:
527                 r = utils_launch_app(di->parameter, di->key, di->value);
528                 break;
529         default:
530                 _ERR("Invalid state");
531                 break;
532         }
533
534         return r;
535 }
536
537 static void _clear(struct datamgr *dm)
538 {
539         if (!app_contents_recent_clear_all())
540                 _ERR("failed to clear all recents");
541 }
542
543 static struct data_class dclass = {
544         .init = _init,
545         .fini = _fini,
546         .get_items = _get_items,
547         .select = _select,
548         .clear = _clear
549 };
550
551 struct data_class *datamgr_recent_get_dclass(void)
552 {
553         return &dclass;
554 }