2 // Open Service Platform
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
9 // http://www.apache.org/licenses/LICENSE-2.0
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
19 * @file FCnt_DownloadManagerImpl.cpp
20 * @brief This is the implementation file for the _DownloadManagerImpl class.
28 #include <unique_ptr.h>
32 #include <FBaseSysLog.h>
33 #include <FBase_StringConverter.h>
34 #include <FBaseInteger.h>
35 #include <FBaseRtIEventArg.h>
36 #include <FBaseColIMap.h>
37 #include <FApp_AppInfo.h>
39 #include <FCntDownloadRequest.h>
40 #include <FCntIDownloadListener.h>
42 #include <FCnt_DownloadRequestImpl.h>
43 #include "FCnt_DownloadManagerImpl.h"
47 using namespace Tizen::Base;
48 using namespace Tizen::Base::Runtime;
49 using namespace Tizen::Base::Collection;
51 namespace Tizen { namespace Content
54 static const int STATE_NONE = 0;
55 static const int STATE_QUEUED = 1;
56 static const int STATE_DOWNLOADING = 2;
57 static const int STATE_PAUSED = 3;
58 static const int STATE_CANCELLED = 4;
59 static const int STATE_COMPLETED = 5;
60 static const int STATE_FAILED = 6;
63 static const int SLP_STATE_NONE = 0;
64 static const int SLP_STATE_READY = 1;
65 static const int SLP_STATE_QUEUED = 2;
66 static const int SLP_STATE_DOWNLOADING = 3;
67 static const int SLP_STATE_PAUSED = 4;
68 static const int SLP_STATE_COMPLETED = 5;
69 static const int SLP_STATE_FAILED = 6;
70 static const int SLP_STATE_CANCELLED = 7;
72 _DownloadManagerImpl* _DownloadManagerImpl::__pInstance = null;
74 class _DownloadEventArg
91 unsigned long long __received;
92 unsigned long long __total;
99 virtual void FireImpl(IEventListener& listener, const IEventArg& arg)
101 IDownloadListener* pListener = dynamic_cast<IDownloadListener*> (&listener);
102 if (pListener != null)
104 const _DownloadEventArg* pArg = dynamic_cast<const _DownloadEventArg*>(&arg);
107 switch(pArg->__state)
113 case STATE_DOWNLOADING:
114 pListener->OnDownloadInProgress(pArg->__id, pArg->__received, pArg->__total);
118 pListener->OnDownloadPaused(pArg->__id);
121 case STATE_COMPLETED:
122 pListener->OnDownloadCompleted(pArg->__id, pArg->__path);
126 pListener->OnDownloadFailed(pArg->__id, pArg->__result, pArg->__errorCode);
129 case STATE_CANCELLED:
130 pListener->OnDownloadCanceled(pArg->__id);
142 OnStateChanged(int download_id, download_state_e state, void* data)
144 SysLog(NID_CNT, "OnStateChanged, id = %d, state = %d", download_id, state);
146 RequestId reqId = (long)download_id;
148 _DownloadManagerImpl* pDMImpl = (_DownloadManagerImpl*)data;
150 if (!data || !pDMImpl->__pEvent)
158 case SLP_STATE_QUEUED:
159 case SLP_STATE_DOWNLOADING:
162 case SLP_STATE_PAUSED:
164 _DownloadEventArg* pEventArg = new (std::nothrow) _DownloadEventArg();
165 pEventArg->__id = reqId;
166 pEventArg->__state = STATE_PAUSED;
168 pDMImpl->__pEvent->Fire(*pEventArg);
173 case SLP_STATE_COMPLETED:
175 _DownloadEventArg* pEventArg = new (std::nothrow) _DownloadEventArg();
176 pEventArg->__id = reqId;
177 pEventArg->__state = STATE_COMPLETED;
180 download_get_downloaded_file_path(download_id, &path);
181 pEventArg->__path = path;
185 pDMImpl->__pEvent->Fire(*pEventArg);
187 // Remove the resource from url_download
188 pDMImpl->DestroyResources(reqId);
193 case SLP_STATE_FAILED:
195 _DownloadEventArg* pEventArg = new (std::nothrow) _DownloadEventArg();
196 pEventArg->__id = reqId;
197 pEventArg->__state = STATE_FAILED;
199 download_error_e error;
200 download_get_error(download_id, &error);
201 pEventArg->__result = pDMImpl->ConvertToResult(error);
204 download_get_http_status(download_id, &http_status);
205 pEventArg->__errorCode = Integer::ToString(http_status);
207 pDMImpl->__pEvent->Fire(*pEventArg);
209 // Comment out due to resume the failed request
210 //pDMImpl->DestroyResources(reqId);
215 case SLP_STATE_CANCELLED:
217 _DownloadEventArg* pEventArg = new (std::nothrow) _DownloadEventArg();
218 pEventArg->__id = reqId;
219 pEventArg->__state = STATE_CANCELLED;
221 pDMImpl->__pEvent->Fire(*pEventArg);
223 // Remove the resource from url_download
224 pDMImpl->DestroyResources(reqId);
236 OnProgress(int download_id, unsigned long long received, void* data)
238 RequestId reqId = (long)download_id;
240 _DownloadManagerImpl* pDMImpl = (_DownloadManagerImpl*)data;
242 if (data && pDMImpl->__pEvent)
244 _DownloadEventArg* pEventArg = new (std::nothrow) _DownloadEventArg();
245 pEventArg->__id = reqId;
246 pEventArg->__state = STATE_DOWNLOADING;
247 pEventArg->__received = received;
249 unsigned long long total = 0;
250 download_get_content_size(download_id, &total);
251 pEventArg->__total = total;
253 SysLog(NID_CNT, "OnProgress, id = %d, received = %lld, total = %lld", download_id, received, total);
255 pDMImpl->__pEvent->Fire(*pEventArg);
260 _DownloadManagerImpl::_DownloadManagerImpl(void)
265 _DownloadManagerImpl::~_DownloadManagerImpl(void)
274 _DownloadManagerImpl::Construct(void)
276 result r = E_SUCCESS;
278 r = __handleMap.Construct(100, 0);
279 SysTryReturnResult(NID_IO, r == E_SUCCESS, r, "Failed to initialize a download manager.");
285 _DownloadManagerImpl::InitSingleton(void)
287 unique_ptr<_DownloadManagerImpl> pImpl(new (std::nothrow) _DownloadManagerImpl);
288 SysTryReturnVoidResult(NID_CNT, pImpl != null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
290 result r = pImpl->Construct();
291 SysTryReturnVoidResult(NID_CNT, r == E_SUCCESS, E_SYSTEM, "[E_SYSTEM] Failed to initialize download manager.");
293 __pInstance = pImpl.release();
295 std::atexit(DestroySingleton);
299 _DownloadManagerImpl::DestroySingleton(void)
304 _DownloadManagerImpl*
305 _DownloadManagerImpl::GetInstance(void)
307 static pthread_once_t onceBlock = PTHREAD_ONCE_INIT;
308 if (__pInstance == null)
312 pthread_once(&onceBlock, InitSingleton);
313 result r = GetLastResult();
316 onceBlock = PTHREAD_ONCE_INIT;
324 _DownloadManagerImpl::Start(const DownloadRequest& request, RequestId& reqId)
326 SysLog(NID_CNT, "Start a download from Url = %ls, Path = %ls", request.GetUrl().GetPointer(), request.GetDirectoryPath().GetPointer());
328 result r = E_SUCCESS;
333 String url = request.GetUrl();
334 String dirPath = request.GetDirectoryPath();
335 String fileName = request.GetFileName();
336 NetworkType networkType = (NetworkType)request.GetNetworkType();
338 SysTryReturnResult(NID_CNT, !url.IsEmpty(), E_INVALID_ARG, "The url of the download request is empty.");
340 // Create a download id
341 ret = download_create(&download_id);
342 SysTryReturnResult(NID_CNT, ret >= 0, E_SYSTEM, "The internal system service is not available. %d", ret);
345 unique_ptr<char[]> pUrl(_StringConverter::CopyToCharArrayN(url));
347 ret = download_set_url(download_id, pUrl.get());
348 SysTryReturnResult(NID_CNT, ret >= 0, E_SYSTEM, "The internal system service is not available. %d", ret);
351 if (networkType == NETWORK_ALL)
353 ret = download_set_network_type(download_id, (download_network_type_e)DOWNLOAD_NETWORK_ALL);
357 ret = download_set_network_type(download_id, (download_network_type_e)networkType);
359 SysTryReturnResult(NID_CNT, ret >= 0, E_SYSTEM, "The internal system service is not available. %d", ret);
362 ret = download_set_notification(download_id, request.IsNotificationEnabled());
363 SysTryReturnResult(NID_CNT, ret >= 0, E_SYSTEM, "The internal system service is not available. %d", ret);
365 //Set notification extra data
366 std::unique_ptr<IMapEnumerator> pMapEnum(const_cast< IMap* >(request.GetNotificationExtraData())->GetMapEnumeratorN());
367 while (pMapEnum->MoveNext() == E_SUCCESS)
369 String* pMapKey = dynamic_cast<String*>(pMapEnum->GetKey());
370 unique_ptr<char[]> pKey(_StringConverter::CopyToCharArrayN(*pMapKey));
371 String* pMapValue = dynamic_cast<String*>(pMapEnum->GetValue());
372 const char* pValue = _StringConverter::CopyToCharArrayN(*pMapValue);
374 ret = download_add_notification_extra_param(download_id, pKey.get(), &pValue, 1);
376 SysTryReturnResult(NID_CNT, ret >= 0, E_SYSTEM, "The internal system service is not available. %d", ret);
380 IMap* pRequestHeader = _DownloadRequestImpl::GetInstance(&request)->GetRequestHeader();
381 std::unique_ptr<IMapEnumerator> pMapEnume(const_cast< IMap* >(pRequestHeader)->GetMapEnumeratorN());
382 while (pMapEnume->MoveNext() == E_SUCCESS)
384 String* pMapKey = dynamic_cast<String*>(pMapEnume->GetKey());
385 unique_ptr<char[]> pKey(_StringConverter::CopyToCharArrayN(*pMapKey));
386 String* pMapValue = dynamic_cast<String*>(pMapEnume->GetValue());
387 unique_ptr<char[]> pValue(_StringConverter::CopyToCharArrayN(*pMapValue));
389 ret = download_add_http_header_field(download_id, pKey.get(), pValue.get());
390 SysTryReturnResult(NID_CNT, ret >= 0, E_SYSTEM, "The internal system service is not available. %d", ret);
393 // Check the download path
394 if (!dirPath.IsEmpty())
396 unique_ptr<char[]> pStr(_StringConverter::CopyToCharArrayN(dirPath));
398 ret = access(pStr.get(), F_OK);
401 ret = access(pStr.get(), W_OK);
402 SysTryReturnResult(NID_CNT, ret == 0, E_ILLEGAL_ACCESS, "Access to the requested path is denied due to insufficient permission.");
405 ret = download_set_destination(download_id, pStr.get());
406 SysTryReturnResult(NID_CNT, ret >= 0, E_SYSTEM, "The internal system service is not available. %d", ret);
410 if (!fileName.IsEmpty())
412 unique_ptr<char[]> pStr(_StringConverter::CopyToCharArrayN(fileName));
414 ret = download_set_file_name(download_id, pStr.get());
415 SysTryReturnResult(NID_CNT, ret >= 0, E_SYSTEM, "The internal system service is not available. %d", ret);
418 // Set the callback functions
419 r = RegisterCallback((long)download_id);
420 SysTryReturnResult(NID_CNT, r == E_SUCCESS, E_SYSTEM, "The internal system service is not available.");
422 // Start the download request
423 ret = download_start(download_id);
424 SysTryCatch(NID_CNT, ret != DOWNLOAD_ERROR_INVALID_PARAMETER, r = E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] The argument is not valid");
425 SysTryCatch(NID_CNT, ret >= 0, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] The internal system service is not available. %d", ret);
428 reqId = (long)download_id;
430 // Add a request Id to the handle map
431 __handleMap.Add(reqId, new DownloadRequest(request));
436 UnregisterCallback((long)download_id);
442 _DownloadManagerImpl::Pause(RequestId reqId)
444 result r = E_SUCCESS;
447 int state = STATE_NONE;
449 // Pause the download request
450 ret = download_pause((int)reqId);
451 SysTryReturnResult(NID_CNT, ret != DOWNLOAD_ERROR_INVALID_PARAMETER, E_INVALID_ARG, "There is no download request for the request.");
452 SysTryReturnResult(NID_CNT, ret != DOWNLOAD_ERROR_ID_NOT_FOUND, E_INVALID_ARG, "The request ID is not valid.");
453 SysTryReturnResult(NID_CNT, ret != DOWNLOAD_ERROR_INVALID_STATE, E_INVALID_OPERATION, "The current download state is not downloading.");
454 SysTryReturnResult(NID_CNT, ret >= 0, E_SYSTEM, "The internal system service is not available. %d", ret);
460 _DownloadManagerImpl::Resume(RequestId reqId)
462 result r = E_SUCCESS;
465 int state = STATE_NONE;
467 // Resume the download request
468 ret = download_start((int)reqId);
469 SysTryReturnResult(NID_CNT, ret != DOWNLOAD_ERROR_INVALID_PARAMETER, E_INVALID_ARG, "There is no download request for the request.");
470 SysTryReturnResult(NID_CNT, ret != DOWNLOAD_ERROR_ID_NOT_FOUND, E_INVALID_ARG, "The request ID is not valid.");
471 SysTryReturnResult(NID_CNT, ret != DOWNLOAD_ERROR_INVALID_STATE, E_INVALID_OPERATION, "The current download state is not paused or has failed.");
472 SysTryReturnResult(NID_CNT, ret >= 0, E_SYSTEM, "The internal system service is not available. %d", ret);
478 _DownloadManagerImpl::Cancel(RequestId reqId)
481 int state = STATE_NONE;
483 // Stop the download request
484 ret = download_cancel((int)reqId);
485 SysTryReturnResult(NID_CNT, ret != DOWNLOAD_ERROR_INVALID_PARAMETER, E_INVALID_ARG, "There is no download request for the request.");
486 SysTryReturnResult(NID_CNT, ret != DOWNLOAD_ERROR_ID_NOT_FOUND, E_INVALID_ARG, "The request ID is not valid.");
487 SysTryReturnResult(NID_CNT, ret >= 0, E_SYSTEM, "The internal system service is not available. %d", ret);
493 _DownloadManagerImpl::GetDownloadRequestN(RequestId reqId)
495 result r = E_SUCCESS;
496 DownloadRequest* pRequest = null;
498 r = __handleMap.GetValue(reqId, pRequest);
499 SysTryReturn(NID_CNT, r == E_SUCCESS, null, E_INVALID_ARG, "[E_INVALID_ARG] There is no download request for the request ID.");
501 pRequest = new (std::nothrow) DownloadRequest(*pRequest);
502 SysTryReturn(NID_CNT, pRequest != null, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY]");
504 SetLastResult(E_SUCCESS);
509 _DownloadManagerImpl::GetMimeType(RequestId reqId, String& mimeType)
511 result r = E_SUCCESS;
515 DownloadRequest* pRequest = null;
517 // Check the request is valid
518 pRequest = GetDownloadRequestN(reqId);
522 SysPropagate(NID_CNT, r);
528 ret = download_get_mime_type((int)reqId, &pStr);
529 SysTryReturnResult(NID_CNT, ret != DOWNLOAD_ERROR_INVALID_STATE, E_INVALID_OPERATION, "The current download state is not downloading or paused.");
530 SysTryReturnResult(NID_CNT, ret >= 0, E_SYSTEM, "The internal system service is not available. %d", ret);
539 _DownloadManagerImpl::GetState(RequestId reqId) const
543 download_state_e download_state = (download_state_e)SLP_STATE_NONE;
544 int state = STATE_NONE;
546 ret = download_get_state((int)reqId, &download_state);
547 SysTryReturn(NID_CNT, ret != DOWNLOAD_ERROR_ID_NOT_FOUND, STATE_NONE, E_INVALID_ARG, "[E_INVALID_ARG] The request ID is not valid.");
548 SysTryReturn(NID_CNT, ret >= 0, STATE_NONE, E_SYSTEM, "[E_SYSTEM] The internal system service is not available. %d", ret);
550 switch(download_state)
556 case SLP_STATE_READY:
557 state = STATE_QUEUED;
560 case SLP_STATE_QUEUED:
561 state = STATE_QUEUED;
564 case SLP_STATE_DOWNLOADING:
565 state = STATE_DOWNLOADING;
568 case SLP_STATE_PAUSED:
569 state = STATE_PAUSED;
572 case SLP_STATE_COMPLETED:
573 state = STATE_COMPLETED;
576 case SLP_STATE_CANCELLED:
577 state = STATE_CANCELLED;
580 case SLP_STATE_FAILED:
581 state = STATE_FAILED;
589 SysLog(NID_CNT, "download_state = %d, state = %d", download_state, state);
595 _DownloadManagerImpl::GetProgress(RequestId reqId, int& progress)
601 _DownloadManagerImpl::SetAllowedNetwork(unsigned long flags)
607 _DownloadManagerImpl::SetDownloadListener(IDownloadListener* pListener)
609 if (pListener != null)
611 _DownloadEvent* pEvent = new (std::nothrow) _DownloadEvent();
612 SysTryReturnVoidResult(NID_IO, pEvent != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
614 pEvent->AddListener(*pListener);
620 if (__pEvent != null)
630 _DownloadManagerImpl::DestroyResources(RequestId reqId)
633 result r = E_SUCCESS;
634 DownloadRequest* pRequest = null;
636 // Cancel the callback
637 UnregisterCallback(reqId);
639 // Remove the resource from url_download
640 ret = download_destroy((int)reqId);
641 SysTryLog(NID_CNT, ret >= 0, "url_download_destory fails %d", ret);
643 // Remove DownloadRequest from __handleMap
644 r = __handleMap.GetValue(reqId, pRequest);
645 SysTryLog(NID_CNT, r == E_SUCCESS, "[%s]", GetErrorMessage(r));
647 r = __handleMap.Remove(reqId);
648 SysTryLog(NID_CNT, r == E_SUCCESS, "[%s]", GetErrorMessage(r));
654 _DownloadManagerImpl::RegisterCallback(RequestId reqId)
658 ret = download_set_state_changed_cb(reqId, OnStateChanged, this);
659 SysTryCatch(NID_CNT, ret >= 0, , E_SYSTEM, "[E_SYSTEM] Fails to set state_changed_cb: %d, id = %d", ret, reqId);
661 ret = download_set_progress_cb(reqId, OnProgress, this);
662 SysTryCatch(NID_CNT, ret >= 0, , E_SYSTEM, "[E_SYSTEM] Fails to set progress_cb: %d, id = %d", ret, reqId);
667 UnregisterCallback(reqId);
673 _DownloadManagerImpl::UnregisterCallback(RequestId reqId)
677 ret = download_unset_state_changed_cb(reqId);
678 SysTryLog(NID_CNT, ret >= 0, "download_unset_state_changed_cb fails %d, id = %d", ret, reqId);
680 ret = download_unset_progress_cb(reqId);
681 SysTryLog(NID_CNT, ret >= 0, "download_unset_progress_cb fails %d, id = %d", ret, reqId);
685 _DownloadManagerImpl::ConvertToResult(int error)
687 result r = E_SUCCESS;
688 download_error_e download_error = (download_error_e)error;
690 SysLog(NID_CNT, "Download error = %d", download_error);
692 switch(download_error)
694 case DOWNLOAD_ERROR_NONE:
698 case DOWNLOAD_ERROR_OUT_OF_MEMORY:
702 case DOWNLOAD_ERROR_IO_ERROR:
706 case DOWNLOAD_ERROR_INVALID_URL:
710 case DOWNLOAD_ERROR_ID_NOT_FOUND:
714 case DOWNLOAD_ERROR_CONNECTION_FAILED:
715 case DOWNLOAD_ERROR_NETWORK_UNREACHABLE:
716 r = E_CONNECTION_FAILED;
719 case DOWNLOAD_ERROR_CONNECTION_TIMED_OUT:
723 case DOWNLOAD_ERROR_TOO_MANY_DOWNLOADS:
727 case DOWNLOAD_ERROR_NO_SPACE:
731 case DOWNLOAD_ERROR_QUEUE_FULL:
733 //case URL_DOWNLOAD_ERROR_INVALID_STATE:
734 //case URL_DOWNLOAD_ERROR_INVALID_PARAMETER:
735 //case URL_DOWNLOAD_ERROR_INVALID_DESTINATION:
736 //case URL_DOWNLOAD_ERROR_ALREADY_COMPLETED:
744 } } // Tizen::Content