apply FSL(Flora Software License)
[profile/ivi/download-provider.git] / src / download-provider-item.cpp
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://www.tizenopensource.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 /**
18  * @file        download-provider-item.cpp
19  * @author      Jungki Kwak (jungki.kwak@samsung.com)
20  * @brief       item class for saving download data
21  */
22 // FIXME later : move to util clas
23 #include "download-provider-item.h"
24 #include "download-provider-common.h"
25 #include "download-provider-items.h"
26 #include "download-provider-viewItem.h"
27 #include "download-provider-history-db.h"
28 #include "download-provider-network.h"
29 #include <iostream>
30 #include <time.h>
31
32 Item::Item()
33         : m_state(ITEM::IDLE)
34         , m_errorCode(ERROR::NONE)
35         , m_historyId(-1)
36         , m_contentType(DP_CONTENT_UNKOWN)
37         , m_finishedTime(0)
38         , m_downloadType(DL_TYPE::TYPE_NONE)
39         , m_gotFirstData(false)
40 {
41 // FIXME Later : init private members
42 }
43
44 Item::Item(DownloadRequest &rRequest)
45         : m_state(ITEM::IDLE)
46         , m_errorCode(ERROR::NONE)
47         , m_historyId(-1)
48         , m_contentType(DP_CONTENT_UNKOWN)
49         , m_finishedTime(0)
50         , m_downloadType(DL_TYPE::TYPE_NONE)
51         , m_gotFirstData(false)
52 {
53         m_title = S_("IDS_COM_BODY_NO_NAME");
54         m_iconPath = DP_UNKNOWN_ICON_PATH;
55         m_aptr_request = auto_ptr<DownloadRequest>(new DownloadRequest(rRequest));      // FIXME ???
56 }
57
58 Item::~Item()
59 {
60         DP_LOGD_FUNC();
61 }
62
63 void Item::create(DownloadRequest &rRequest)
64 {
65 //      DP_LOGD_FUNC();
66
67         Item *newItem = new Item(rRequest);
68
69         Items &items = Items::getInstance();
70         items.attachItem(newItem);
71
72         ViewItem::create(newItem);
73         DP_LOGD("newItem[%p]",newItem);
74
75         newItem->download();
76 }
77
78 Item *Item::createHistoryItem()
79 {
80         string url = string();
81         string cookie = string();
82         DownloadRequest request(url,cookie);
83         Item *newItem = new Item(request);
84 //      DP_LOGD_FUNC();
85
86         DP_LOGD("new History Item[%p]",newItem);
87
88         return newItem;
89 }
90
91 void Item::attachHistoryItem()
92 {
93         Items &items = Items::getInstance();
94
95         DP_LOGD("attach History Item[%p]",this);
96         items.attachItem(this);
97         ViewItem::create(this);
98         extractIconPath();
99 }
100
101 void Item::destroy()
102 {
103 //      DP_LOG_FUNC();
104         // FIXME prohibit to destroy if downloading
105         if (!isFinished()) {
106                 DP_LOGE("Cannot delete this item. State[%d]",m_state);
107                 return;
108         }
109         DP_LOGD("Item::destroy() notify()");
110
111         setState(ITEM::DESTROY);
112         notify();
113 //      DP_LOG("Item::destroy() notify()... END");
114         m_aptr_downloadItem->deSubscribe(m_aptr_downloadObserver.get());
115         if (m_aptr_downloadObserver.get())
116                 m_aptr_downloadObserver->clear();
117         else
118                 DP_LOGE("download observer pointer is NULL");
119         /* When deleting item after download is failed */
120         if (m_aptr_netEventObserver.get()) {
121                 NetMgr &netMgrInstance = NetMgr::getInstance();
122                 netMgrInstance.deSubscribe(m_aptr_netEventObserver.get());
123         }
124         Items::getInstance().detachItem(this);
125 }
126
127 void Item::deleteFromDB()
128 {
129         DownloadHistoryDB::deleteItem(m_historyId);
130 }
131
132 void Item::download()
133 {
134         NetMgr &netMgrInstance = NetMgr::getInstance();
135
136 //      DP_LOGD_FUNC();
137
138         setState(ITEM::REQUESTING);
139
140         createSubscribeData();
141
142         netMgrInstance.subscribe(m_aptr_netEventObserver.get());
143
144         m_aptr_downloadItem->start();
145
146         DP_LOG("Item::download() notify()");
147         notify();
148 }
149
150 void Item::createSubscribeData() // autoptr's variable of this class.
151 {
152         m_aptr_downloadObserver = auto_ptr<Observer>(
153                 new Observer(updateCBForDownloadObserver, this, "downloadItemObserver"));
154         m_aptr_netEventObserver = auto_ptr<Observer>(
155                 new Observer(netEventCBObserver, this, "netMgrObserver"));
156         m_aptr_downloadItem = auto_ptr<DownloadItem>(new DownloadItem(m_aptr_request));
157         if (!m_aptr_downloadItem.get()) {
158                 DP_LOGE("Fail to create download item");
159                 return;
160         }
161         m_aptr_downloadItem->subscribe(m_aptr_downloadObserver.get());
162 }
163
164 void Item::startUpdate(void)
165 {
166         if (m_gotFirstData) {
167                 setState(ITEM::DOWNLOADING);
168                 if (!registeredFilePath().empty())
169                         /* need to parse title again, because installed path can be changed */
170                         extractTitle();
171                 return;
172         }
173
174         DP_LOGD_FUNC();
175
176         if (!m_aptr_downloadItem.get()) {
177                 DP_LOGE("Fail to get download item");
178                 return;
179         }
180         m_gotFirstData = true;
181 //      setState(ITEM::DOWNLOADING);
182         setState(ITEM::RECEIVING_DOWNLOAD_INFO);
183
184         extractTitle();
185         DownloadUtil &util = DownloadUtil::getInstance();
186         m_contentType = util.getContentType(
187                 m_aptr_downloadItem->mimeType().c_str(), filePath().c_str());
188         extractIconPath();
189 }
190
191 void Item::updateFromDownloadItem(void)
192 {
193 //      DP_LOGD_FUNC();
194
195         switch (m_aptr_downloadItem->state()) {
196         case DL_ITEM::STARTED:
197                 break;
198         case DL_ITEM::UPDATING:
199                 startUpdate();
200                 break;
201         case DL_ITEM::COMPLETE_DOWNLOAD:
202                 setState(ITEM::REGISTERING_TO_SYSTEM);
203                 /* need to parse title again, because installed path can be changed */
204                 //extractTitle();
205                 break;
206         case DL_ITEM::INSTALL_NOTIFY:
207                 setState(ITEM::NOTIFYING_TO_SERVER);
208                 break;
209         case DL_ITEM::START_DRM_DOMAIN:
210                 setState(ITEM::PROCESSING_DOMAIN);
211                 break;
212         case DL_ITEM::FINISH_DRM_DOMAIN:
213                 setState(ITEM::FINISH_PROCESSING_DOMAIN);
214                 break;
215         case DL_ITEM::WAITING_RO:
216                 setState(ITEM::ACTIVATING);
217                 break;
218         case DL_ITEM::SUSPENDED:
219                 setState(ITEM::SUSPEND);
220                 m_aptr_downloadItem->resume();
221                 break;
222         case DL_ITEM::RESUMED:
223                 //setState(ITEM::RESUMED);
224                 break;
225         case DL_ITEM::FINISHED:
226                 setState(ITEM::FINISH_DOWNLOAD);
227                 handleFinishedItem();
228                 break;
229         case DL_ITEM::CANCELED:
230                 /* Already update for cancel state in case of cancellation from user Response popup */
231                 if (state() == ITEM::CANCEL) {
232                         DP_LOGD("Already cancelled when closing OMA download popup");
233                         return;
234                 } else {
235                         setState(ITEM::CANCEL);
236                         handleFinishedItem();
237                 }
238                 break;
239         case DL_ITEM::FAILED:
240                 setState(ITEM::FAIL_TO_DOWNLOAD);
241                 setErrorCode(m_aptr_downloadItem->errorCode());
242                 handleFinishedItem();
243                 break;
244         case DL_ITEM::WAITING_CONFIRM:
245                 setState(ITEM::WAITING_USER_RESPONSE);
246                 break;
247         default:
248                 break;
249         }
250
251         DP_LOGD("Item[%p]::updateFromDownloadItem() notify() dl_state[%d]state[%d]", this, m_aptr_downloadItem->state(), state());
252         notify();
253 }
254 void Item::handleFinishedItem()
255 {
256         createHistoryId();
257         m_finishedTime = time(NULL);
258         DownloadHistoryDB::addToHistoryDB(this);
259         /* If download is finished, it is not need to get network event */
260         if (m_aptr_netEventObserver.get()) {
261                 NetMgr &netMgrInstance = NetMgr::getInstance();
262                 netMgrInstance.deSubscribe(m_aptr_netEventObserver.get());
263         }
264 }
265
266 const char *Item::getErrorMessage(void)
267 {
268         switch (m_errorCode) {
269         case ERROR::NETWORK_FAIL:
270                 return S_("IDS_COM_POP_CONNECTION_FAILED");
271
272         case ERROR::INVALID_URL:
273                 return S_("IDS_COM_POP_INVALID_URL");
274
275         case ERROR::NOT_ENOUGH_MEMORY:
276                 return S_("IDS_COM_POP_NOT_ENOUGH_MEMORY");
277
278         case ERROR::FAIL_TO_INSTALL:
279                 return __("IDS_BR_POP_INSTALLATION_FAILED");
280
281         case ERROR::OMA_POPUP_TIME_OUT:
282                 return S_("IDS_COM_POP_CANCELLED") ;
283
284         case ERROR::FAIL_TO_PARSE_DESCRIPTOR:
285                 return  __("IDS_BR_POP_INVALIDDESCRIPTOR") ;
286
287         case ERROR::UNKNOWN:
288         case ERROR::ENGINE_FAIL:
289                 return S_("IDS_COM_POP_FAILED") ;
290         default:
291                 return NULL;
292         }
293 }
294
295 void Item::extractTitle(void)
296 {
297         if (!m_aptr_downloadItem.get()) {
298                 DP_LOGE("Fail to get download item");
299                 return;
300         }
301         DP_LOGD("title [%s] filePath [%s]", m_title.c_str(), filePath().c_str());
302         if ((m_aptr_downloadItem->downloadType() == DL_TYPE::OMA_DOWNLOAD || 
303                 m_aptr_downloadItem->downloadType() == DL_TYPE::MIDP_DOWNLOAD) &&
304                 !m_aptr_downloadItem->contentName().empty()) {
305                 m_title = m_aptr_downloadItem->contentName();
306         } else {
307                 size_t found = 0;
308                 string path;
309                 if (!registeredFilePath().empty())
310                         path = registeredFilePath();
311                 else
312                         path = filePath();
313                 found = path.find_last_of("/");
314                 if (found != string::npos)
315                         m_title = path.substr(found+1);
316         }
317 }
318
319 void Item::extractIconPath()
320 {
321         // FIXME Later : change 2 dimension array??
322         switch(m_contentType) {
323         case DP_CONTENT_IMAGE :
324                 m_iconPath = DP_IMAGE_ICON_PATH;
325                 break;
326         case DP_CONTENT_VIDEO :
327                 m_iconPath = DP_VIDEO_ICON_PATH;
328                 break;
329         case DP_CONTENT_MUSIC:
330                 m_iconPath = DP_MUSIC_ICON_PATH;
331                 break;
332         case DP_CONTENT_PDF:
333                 m_iconPath = DP_PDF_ICON_PATH;
334                 break;
335         case DP_CONTENT_WORD:
336                 m_iconPath = DP_WORD_ICON_PATH;
337                 break;
338         case DP_CONTENT_PPT:
339                 m_iconPath = DP_PPT_ICON_PATH;
340                 break;
341         case DP_CONTENT_EXCEL:
342                 m_iconPath = DP_EXCEL_ICON_PATH;
343                 break;
344         case DP_CONTENT_HTML:
345                 m_iconPath = DP_HTML_ICON_PATH;
346                 break;
347         case DP_CONTENT_TEXT:
348                 m_iconPath = DP_TEXT_ICON_PATH;
349                 break;
350         case DP_CONTENT_RINGTONE:
351                 m_iconPath = DP_RINGTONE_ICON_PATH;
352                 break;
353         case DP_CONTENT_DRM:
354                 m_iconPath = DP_DRM_ICON_PATH;
355                 break;
356         case DP_CONTENT_JAVA:
357                 m_iconPath = DP_JAVA_ICON_PATH;
358                 break;
359         case DP_CONTENT_UNKOWN:
360         default:
361                 m_iconPath = DP_UNKNOWN_ICON_PATH;
362         }
363 }
364
365 void Item::updateCBForDownloadObserver(void *data)
366 {
367         DP_LOGD_FUNC();
368         if (data)
369                 static_cast<Item*>(data)->updateFromDownloadItem();
370 }
371
372 void Item::netEventCBObserver(void *data)
373 {
374         /* It is only considerd that there is one network event which is suspend now.
375          * If other network evnet is added,
376          * it is needed to add function accroding to what kinds of network event is
377         **/
378         DP_LOG_FUNC();
379         if (data)
380                 static_cast<Item*>(data)->suspend();
381 }
382
383 void Item::sendUserResponse(bool res)
384 {
385         bool ret = false;
386         DP_LOG_FUNC();
387         if (!m_aptr_downloadItem.get()) {
388                 DP_LOGE("Fail to get download item");
389                 return;
390         }
391         ret = m_aptr_downloadItem->sendUserResponse(res);
392         if (ret) {
393         /* Update UI at once if the user cancel the oma download
394          * But this is really needed??
395          */
396                 if (!res) {
397                         setState(ITEM::CANCEL);
398                         handleFinishedItem();
399                         notify();
400                 } else {
401                         setState(ITEM::RECEIVING_DOWNLOAD_INFO);
402                 }
403         }
404 }
405
406 bool Item::play()
407 {
408         if (m_contentType == DP_CONTENT_JAVA &&
409                         m_aptr_downloadItem->downloadType() == DL_TYPE::MIDP_DOWNLOAD) {
410                 string pkgName;
411                 DownloadUtil &util = DownloadUtil::getInstance();
412                 pkgName = util.getMidletPkgName(m_contentName, m_vendorName);
413                 return m_fileOpener.openApp(pkgName);
414         } else {
415                 return m_fileOpener.openFile(registeredFilePath(), m_contentType);
416         }
417 }
418
419 /* Test code */
420 const char *Item::stateStr(void)
421 {
422         switch((int)state()) {
423         case ITEM::IDLE:
424                 return "IDLE";
425         case ITEM::REQUESTING:
426                 return "REQUESTING";
427         case ITEM::PREPARE_TO_RETRY:
428                 return "PREPARE_TO_RETRY";
429         case ITEM::WAITING_USER_RESPONSE:
430                 return "WAITING_USER_RESPONSE";
431         case ITEM::RECEIVING_DOWNLOAD_INFO:
432                 return "RECEIVING_DOWNLOAD_INFO";
433         case ITEM::DOWNLOADING:
434                 return "DOWNLOADING";
435         case ITEM::REGISTERING_TO_SYSTEM:
436                 return "REGISTERING_TO_SYSTEM";
437         case ITEM::PROCESSING_DOMAIN:
438                 return "PROCESSING_DOMAIN";
439         case ITEM::FINISH_PROCESSING_DOMAIN:
440                 return "FINISH_PROCESSING_DOMAIN";
441         case ITEM::ACTIVATING:
442                 return "ACTIVATING";
443         case ITEM::NOTIFYING_TO_SERVER:
444                 return "NOTIFYING_TO_SERVER";
445         case ITEM::SUSPEND:
446                 return "SUSPEND";
447         case ITEM::FINISH_DOWNLOAD:
448                 return "FINISH_DOWNLOAD";
449         case ITEM::FAIL_TO_DOWNLOAD:
450                 return "FAIL_TO_DOWNLOAD";
451         case ITEM::CANCEL:
452                 return "CANCEL";
453         case ITEM::PLAY:
454                 return "PLAY";
455         case ITEM::DESTROY:
456                 return "DESTROY";
457         }
458         return "Unknown State";
459 }
460
461 DL_TYPE::TYPE Item::downloadType()
462 {
463         if (m_downloadType == DL_TYPE::TYPE_NONE) {
464                 if (!m_aptr_downloadItem.get()) {
465                         DP_LOGE("Fail to get download item");
466                         return DL_TYPE::TYPE_NONE;
467                 }
468                 m_downloadType = m_aptr_downloadItem->downloadType();
469         }
470         return m_downloadType;
471 }
472
473 string &Item::contentName()
474 {
475         if (m_contentName.empty()) {
476                 if (!m_aptr_downloadItem.get()) {
477                         DP_LOGE("Fail to get download item");
478                         return m_emptyString;
479                 }
480                 m_contentName = m_aptr_downloadItem->contentName();
481         }
482         return m_contentName;
483 }
484
485 string &Item::vendorName()
486 {
487         if (m_vendorName.empty()) {
488                 if (!m_aptr_downloadItem.get()) {
489                         DP_LOGE("Fail to get download item");
490                         return m_emptyString;
491                 }
492                 m_vendorName = m_aptr_downloadItem->vendorName();
493         }
494         return m_vendorName;
495 }
496
497 string &Item::registeredFilePath()
498 {
499         if (m_registeredFilePath.empty()) {
500                 if (!m_aptr_downloadItem.get()) {
501                         DP_LOGE("Fail to get download item");
502                         return m_emptyString;
503                 }
504                 m_registeredFilePath = m_aptr_downloadItem->registeredFilePath();
505         }
506         return m_registeredFilePath;
507 }
508
509 string &Item::url()
510 {
511         if (m_url.empty()) {
512                 if (!m_aptr_downloadItem.get()) {
513                         DP_LOGE("Fail to get download item");
514                         return m_emptyString;
515                 }
516                 m_url = m_aptr_downloadItem->url();
517         }
518         return m_url;
519 }
520
521 string &Item::cookie()
522 {
523         if (m_cookie.empty()) {
524                 if (!m_aptr_downloadItem.get()) {
525                         DP_LOGE("Fail to get download item");
526                         return m_emptyString;
527                 }
528                 m_cookie = m_aptr_downloadItem->cookie();
529         }
530         return m_cookie;
531 }
532
533
534 void Item::createHistoryId()
535 {
536         int count = 0;
537         unsigned tempId = time(NULL);
538         while (isExistedHistoryId(tempId)) {
539                 srand((unsigned)(time(NULL)));
540                 tempId = rand();
541                 count++;
542                 if (count > 100) {
543                         DP_LOGE("Fail to create unique ID");
544                         tempId = -1;
545                         break;
546                 }
547                 DP_LOGD("random historyId[%ld]", m_historyId);
548         }
549         m_historyId = tempId;
550 }
551
552 bool Item::isExistedHistoryId(unsigned int id)
553 {
554         Items &items = Items::getInstance();
555         return items.isExistedHistoryId(id);
556 }
557
558 void Item::setRetryData(string &url, string &cookie)
559 {
560
561         m_url = url;
562         m_cookie = cookie;
563         m_aptr_request->setUrl(url);
564         m_aptr_request->setCookie(cookie);
565
566         createSubscribeData();
567
568 }
569
570 bool Item::retry()
571 {
572         DP_LOG_FUNC();
573         if (m_aptr_downloadItem.get()) {
574                 NetMgr &netMgrInstance = NetMgr::getInstance();
575                 setState(ITEM::PREPARE_TO_RETRY);
576                 notify();
577                 DownloadHistoryDB::deleteItem(m_historyId);
578                 netMgrInstance.subscribe(m_aptr_netEventObserver.get());
579                 m_historyId = -1;
580                 m_aptr_downloadItem->retry();
581                 return true;
582         } else {
583                 m_state = ITEM::FAIL_TO_DOWNLOAD;
584                 return false;
585         }
586 }
587
588 void Item::clearForRetry()
589 {
590         m_state = ITEM::IDLE;
591         m_errorCode = ERROR::NONE;
592         m_contentType = DP_CONTENT_UNKOWN;
593         m_finishedTime = 0;
594         m_downloadType = DL_TYPE::TYPE_NONE;
595         m_gotFirstData = false;
596 }
597
598 bool Item::isFinished()
599 {
600         bool ret = false;
601         switch (m_state) {
602         case ITEM::FINISH_DOWNLOAD:
603         case ITEM::FAIL_TO_DOWNLOAD:
604         case ITEM::CANCEL:
605         case ITEM::PLAY:
606         case ITEM::DESTROY:
607                 ret = true;
608                 break;
609         default:
610                 ret = false;
611         }
612         return ret;
613 }
614
615 bool Item::isFinishedWithErr()
616 {
617         bool ret = false;
618         switch (m_state) {
619         case ITEM::FAIL_TO_DOWNLOAD:
620         case ITEM::CANCEL:
621                 ret = true;
622                 break;
623         default:
624                 ret = false;
625         }
626         return ret;
627 }
628
629 bool Item::isPreparingDownload()
630 {
631         bool ret = false;
632         switch (m_state) {
633         case ITEM::IDLE:
634         case ITEM::REQUESTING:
635         case ITEM::PREPARE_TO_RETRY:
636         case ITEM::WAITING_USER_RESPONSE:
637                 ret = true;
638                 break;
639         default:
640                 ret = false;
641         }
642         return ret;
643
644 }
645
646 bool Item::isCompletedDownload()
647 {
648         if (isPreparingDownload() || m_state == ITEM::DOWNLOADING)
649                 return false;
650         else
651                 return true;
652 }
653