2 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
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
8 // http://www.apache.org/licenses/LICENSE-2.0
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.
18 * @file FCnt_DownloadManagerImpl.cpp
19 * @brief This is the implementation file for the _DownloadManagerImpl class.
27 #include <unique_ptr.h>
31 #include <FBaseSysLog.h>
32 #include <FBase_StringConverter.h>
33 #include <FBaseInteger.h>
34 #include <FBaseRtIEventArg.h>
35 #include <FBaseColIMap.h>
36 #include <FApp_AppInfo.h>
38 #include <FCntDownloadRequest.h>
39 #include <FCntIDownloadListener.h>
41 #include <FCnt_DownloadRequestImpl.h>
42 #include "FCnt_DownloadManagerImpl.h"
46 using namespace Tizen::Base;
47 using namespace Tizen::Base::Runtime;
48 using namespace Tizen::Base::Collection;
50 namespace Tizen { namespace Content
53 static const int STATE_NONE = 0;
54 static const int STATE_QUEUED = 1;
55 static const int STATE_DOWNLOADING = 2;
56 static const int STATE_PAUSED = 3;
57 static const int STATE_CANCELLED = 4;
58 static const int STATE_COMPLETED = 5;
59 static const int STATE_FAILED = 6;
62 static const int SLP_STATE_NONE = 0;
63 static const int SLP_STATE_READY = 1;
64 static const int SLP_STATE_QUEUED = 2;
65 static const int SLP_STATE_DOWNLOADING = 3;
66 static const int SLP_STATE_PAUSED = 4;
67 static const int SLP_STATE_COMPLETED = 5;
68 static const int SLP_STATE_FAILED = 6;
69 static const int SLP_STATE_CANCELLED = 7;
71 _DownloadManagerImpl* _DownloadManagerImpl::__pInstance = null;
73 class _DownloadEventArg
90 unsigned long long __received;
91 unsigned long long __total;
98 virtual void FireImpl(IEventListener& listener, const IEventArg& arg)
100 IDownloadListener* pListener = dynamic_cast<IDownloadListener*> (&listener);
101 if (pListener != null)
103 const _DownloadEventArg* pArg = dynamic_cast<const _DownloadEventArg*>(&arg);
106 switch(pArg->__state)
112 case STATE_DOWNLOADING:
113 pListener->OnDownloadInProgress(pArg->__id, pArg->__received, pArg->__total);
117 pListener->OnDownloadPaused(pArg->__id);
120 case STATE_COMPLETED:
121 pListener->OnDownloadCompleted(pArg->__id, pArg->__path);
125 pListener->OnDownloadFailed(pArg->__id, pArg->__result, pArg->__errorCode);
128 case STATE_CANCELLED:
129 pListener->OnDownloadCanceled(pArg->__id);
141 OnStateChanged(int download_id, download_state_e state, void* data)
143 SysLog(NID_CNT, "OnStateChanged, id = %d, state = %d", download_id, state);
145 RequestId reqId = (long)download_id;
147 _DownloadManagerImpl* pDMImpl = (_DownloadManagerImpl*)data;
149 if (!data || !pDMImpl->__pEvent)
157 case SLP_STATE_QUEUED:
158 case SLP_STATE_DOWNLOADING:
161 case SLP_STATE_PAUSED:
163 _DownloadEventArg* pEventArg = new (std::nothrow) _DownloadEventArg();
164 pEventArg->__id = reqId;
165 pEventArg->__state = STATE_PAUSED;
167 pDMImpl->__pEvent->Fire(*pEventArg);
172 case SLP_STATE_COMPLETED:
174 _DownloadEventArg* pEventArg = new (std::nothrow) _DownloadEventArg();
175 pEventArg->__id = reqId;
176 pEventArg->__state = STATE_COMPLETED;
179 download_get_downloaded_file_path(download_id, &path);
180 pEventArg->__path = path;
184 pDMImpl->__pEvent->Fire(*pEventArg);
186 // Remove the resource from url_download
187 pDMImpl->DestroyResources(reqId);
192 case SLP_STATE_FAILED:
194 _DownloadEventArg* pEventArg = new (std::nothrow) _DownloadEventArg();
195 pEventArg->__id = reqId;
196 pEventArg->__state = STATE_FAILED;
198 download_error_e error;
199 download_get_error(download_id, &error);
200 pEventArg->__result = pDMImpl->ConvertToResult(error);
203 download_get_http_status(download_id, &http_status);
204 pEventArg->__errorCode = Integer::ToString(http_status);
206 pDMImpl->__pEvent->Fire(*pEventArg);
208 // Comment out due to resume the failed request
209 //pDMImpl->DestroyResources(reqId);
214 case SLP_STATE_CANCELLED:
216 _DownloadEventArg* pEventArg = new (std::nothrow) _DownloadEventArg();
217 pEventArg->__id = reqId;
218 pEventArg->__state = STATE_CANCELLED;
220 pDMImpl->__pEvent->Fire(*pEventArg);
222 // Remove the resource from url_download
223 pDMImpl->DestroyResources(reqId);
235 OnProgress(int download_id, unsigned long long received, void* data)
237 RequestId reqId = (long)download_id;
239 _DownloadManagerImpl* pDMImpl = (_DownloadManagerImpl*)data;
241 if (data && pDMImpl->__pEvent)
243 _DownloadEventArg* pEventArg = new (std::nothrow) _DownloadEventArg();
244 pEventArg->__id = reqId;
245 pEventArg->__state = STATE_DOWNLOADING;
246 pEventArg->__received = received;
248 unsigned long long total = 0;
249 download_get_content_size(download_id, &total);
250 pEventArg->__total = total;
252 SysLog(NID_CNT, "OnProgress, id = %d, received = %lld, total = %lld", download_id, received, total);
254 pDMImpl->__pEvent->Fire(*pEventArg);
259 _DownloadManagerImpl::_DownloadManagerImpl(void)
264 _DownloadManagerImpl::~_DownloadManagerImpl(void)
273 _DownloadManagerImpl::InitSingleton(void)
275 unique_ptr<_DownloadManagerImpl> pImpl(new (std::nothrow) _DownloadManagerImpl);
276 SysTryReturnVoidResult(NID_CNT, pImpl != null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
278 __pInstance = pImpl.release();
280 std::atexit(DestroySingleton);
284 _DownloadManagerImpl::DestroySingleton(void)
289 _DownloadManagerImpl*
290 _DownloadManagerImpl::GetInstance(void)
292 static pthread_once_t onceBlock = PTHREAD_ONCE_INIT;
293 if (__pInstance == null)
297 pthread_once(&onceBlock, InitSingleton);
298 result r = GetLastResult();
301 onceBlock = PTHREAD_ONCE_INIT;
309 _DownloadManagerImpl::Start(const DownloadRequest& request, RequestId& reqId)
311 SysLog(NID_CNT, "Start a download from Url = %ls, Path = %ls", request.GetUrl().GetPointer(), request.GetDirectoryPath().GetPointer());
313 result r = E_SUCCESS;
318 String url = request.GetUrl();
319 String dirPath = request.GetDirectoryPath();
320 String fileName = request.GetFileName();
321 NetworkType networkType = (NetworkType)request.GetNetworkType();
323 SysTryReturnResult(NID_CNT, !url.IsEmpty(), E_INVALID_ARG, "The url of the download request is empty.");
325 // Create a download id
326 ret = download_create(&download_id);
327 SysTryReturnResult(NID_CNT, ret >= 0, E_SYSTEM, "The internal system service is not available. %d", ret);
330 unique_ptr<char[]> pUrl(_StringConverter::CopyToCharArrayN(url));
332 ret = download_set_url(download_id, pUrl.get());
333 SysTryReturnResult(NID_CNT, ret >= 0, E_SYSTEM, "The internal system service is not available. %d", ret);
336 if (networkType == NETWORK_ALL)
338 ret = download_set_network_type(download_id, (download_network_type_e)DOWNLOAD_NETWORK_ALL);
342 ret = download_set_network_type(download_id, (download_network_type_e)networkType);
344 SysTryReturnResult(NID_CNT, ret >= 0, E_SYSTEM, "The internal system service is not available. %d", ret);
347 ret = download_set_notification(download_id, request.IsNotificationEnabled());
348 SysTryReturnResult(NID_CNT, ret >= 0, E_SYSTEM, "The internal system service is not available. %d", ret);
350 //Set notification extra data
351 std::unique_ptr<IMapEnumerator> pMapEnum(const_cast< IMap* >(request.GetNotificationExtraData())->GetMapEnumeratorN());
353 while (pMapEnum->MoveNext() == E_SUCCESS)
355 String* pMapKey = dynamic_cast<String*>(pMapEnum->GetKey());
356 String* pMapValue = dynamic_cast<String*>(pMapEnum->GetValue());
358 if (pMapKey && pMapValue)
360 unique_ptr<char[]> pKey(_StringConverter::CopyToCharArrayN(*pMapKey));
361 const char* pValue = _StringConverter::CopyToCharArrayN(*pMapValue);
363 ret = download_add_notification_extra_param(download_id, pKey.get(), &pValue, 1);
365 SysTryReturnResult(NID_CNT, ret >= 0, E_SYSTEM, "The internal system service is not available. %d", ret);
370 IMap* pRequestHeader = _DownloadRequestImpl::GetInstance(&request)->GetRequestHeader();
371 std::unique_ptr<IMapEnumerator> pMapEnume(const_cast< IMap* >(pRequestHeader)->GetMapEnumeratorN());
372 while (pMapEnume->MoveNext() == E_SUCCESS)
374 String* pMapKey = dynamic_cast<String*>(pMapEnume->GetKey());
375 String* pMapValue = dynamic_cast<String*>(pMapEnume->GetValue());
376 if (pMapKey && pMapValue)
378 unique_ptr<char[]> pKey(_StringConverter::CopyToCharArrayN(*pMapKey));
379 unique_ptr<char[]> pValue(_StringConverter::CopyToCharArrayN(*pMapValue));
381 ret = download_add_http_header_field(download_id, pKey.get(), pValue.get());
382 SysTryReturnResult(NID_CNT, ret >= 0, E_SYSTEM, "The internal system service is not available. %d", ret);
387 // Check the download path
388 if (!dirPath.IsEmpty())
390 unique_ptr<char[]> pStr(_StringConverter::CopyToCharArrayN(dirPath));
392 ret = access(pStr.get(), F_OK);
395 ret = access(pStr.get(), W_OK);
396 SysTryReturnResult(NID_CNT, ret == 0, E_ILLEGAL_ACCESS, "Access to the requested path is denied due to insufficient permission.");
399 ret = download_set_destination(download_id, pStr.get());
400 SysTryReturnResult(NID_CNT, ret >= 0, E_SYSTEM, "The internal system service is not available. %d", ret);
404 if (!fileName.IsEmpty())
406 unique_ptr<char[]> pStr(_StringConverter::CopyToCharArrayN(fileName));
408 ret = download_set_file_name(download_id, pStr.get());
409 SysTryReturnResult(NID_CNT, ret >= 0, E_SYSTEM, "The internal system service is not available. %d", ret);
412 // Set the callback functions
413 r = RegisterCallback((long)download_id);
414 SysTryReturnResult(NID_CNT, r == E_SUCCESS, E_SYSTEM, "The internal system service is not available.");
416 // Start the download request
417 ret = download_start(download_id);
418 SysTryCatch(NID_CNT, ret != DOWNLOAD_ERROR_INVALID_PARAMETER, r = E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] The argument is not valid");
419 SysTryCatch(NID_CNT, ret >= 0, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] The internal system service is not available. %d", ret);
422 reqId = (long)download_id;
427 UnregisterCallback((long)download_id);
433 _DownloadManagerImpl::Pause(RequestId reqId)
435 result r = E_SUCCESS;
438 int state = STATE_NONE;
440 // Pause the download request
441 ret = download_pause((int)reqId);
442 SysTryReturnResult(NID_CNT, ret != DOWNLOAD_ERROR_INVALID_PARAMETER, E_INVALID_ARG, "There is no download request for the request.");
443 SysTryReturnResult(NID_CNT, ret != DOWNLOAD_ERROR_ID_NOT_FOUND, E_INVALID_ARG, "The request ID is not valid.");
444 SysTryReturnResult(NID_CNT, ret != DOWNLOAD_ERROR_INVALID_STATE, E_INVALID_OPERATION, "The current download state is not downloading.");
445 SysTryReturnResult(NID_CNT, ret >= 0, E_SYSTEM, "The internal system service is not available. %d", ret);
451 _DownloadManagerImpl::Resume(RequestId reqId)
453 result r = E_SUCCESS;
456 int state = STATE_NONE;
458 // Resume the download request
459 ret = download_start((int)reqId);
460 SysTryReturnResult(NID_CNT, ret != DOWNLOAD_ERROR_INVALID_PARAMETER, E_INVALID_ARG, "There is no download request for the request.");
461 SysTryReturnResult(NID_CNT, ret != DOWNLOAD_ERROR_ID_NOT_FOUND, E_INVALID_ARG, "The request ID is not valid.");
462 SysTryReturnResult(NID_CNT, ret != DOWNLOAD_ERROR_INVALID_STATE, E_INVALID_OPERATION, "The current download state is not paused or has failed.");
463 SysTryReturnResult(NID_CNT, ret >= 0, E_SYSTEM, "The internal system service is not available. %d", ret);
469 _DownloadManagerImpl::Cancel(RequestId reqId)
472 int state = STATE_NONE;
474 // Stop the download request
475 ret = download_cancel((int)reqId);
476 SysTryReturnResult(NID_CNT, ret != DOWNLOAD_ERROR_INVALID_PARAMETER, E_INVALID_ARG, "There is no download request for the request.");
477 SysTryReturnResult(NID_CNT, ret != DOWNLOAD_ERROR_ID_NOT_FOUND, E_INVALID_ARG, "The request ID is not valid.");
478 SysTryReturnResult(NID_CNT, ret >= 0, E_SYSTEM, "The internal system service is not available. %d", ret);
484 _DownloadManagerImpl::GetDownloadRequestN(RequestId reqId)
486 result r = E_SUCCESS;
487 DownloadRequest* pRequest = null;
491 bool notification = false;
493 char** pFields = null;
495 char* pFileName = null;
496 download_network_type_e netType = (download_network_type_e)DOWNLOAD_NETWORK_DATA_NETWORK;
498 ret = download_get_url(reqId, &pUrl);
499 SysTryCatch(NID_CNT, (ret != DOWNLOAD_ERROR_ID_NOT_FOUND) && (ret != DOWNLOAD_ERROR_INVALID_PARAMETER), r = E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] The argument is not valid");
500 ret = download_get_network_type(reqId, &netType);
501 SysTryCatch(NID_CNT, (ret != DOWNLOAD_ERROR_ID_NOT_FOUND) && (ret != DOWNLOAD_ERROR_INVALID_PARAMETER), r = E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] The argument is not valid");
502 ret = download_get_destination(reqId, &pPath);
503 SysTryCatch(NID_CNT, (ret != DOWNLOAD_ERROR_ID_NOT_FOUND) && (ret != DOWNLOAD_ERROR_INVALID_PARAMETER), r = E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] The argument is not valid");
504 ret = download_get_file_name(reqId, &pFileName);
505 SysTryCatch(NID_CNT, (ret != DOWNLOAD_ERROR_ID_NOT_FOUND) && (ret != DOWNLOAD_ERROR_INVALID_PARAMETER), r = E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] The argument is not valid");
506 ret = download_get_notification(reqId, ¬ification);
507 SysTryCatch(NID_CNT, (ret != DOWNLOAD_ERROR_ID_NOT_FOUND) && (ret != DOWNLOAD_ERROR_INVALID_PARAMETER), r = E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] The argument is not valid");
508 ret = download_get_http_header_field_list(reqId, &pFields, &length);
509 SysTryCatch(NID_CNT, (ret != DOWNLOAD_ERROR_ID_NOT_FOUND) && (ret != DOWNLOAD_ERROR_INVALID_PARAMETER), r = E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] The argument is not valid");
510 pRequest = new (std::nothrow) DownloadRequest(pUrl, pPath);
511 SysTryCatch(NID_CNT, pRequest != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
512 pRequest->SetFileName(pFileName);
513 pRequest->SetNotification(notification);
514 pRequest->SetNetworkType((DownloadNetworkType)netType);
515 //Get all the field values
516 for (int i = 0; i < length; i++)
518 ret = download_get_http_header_field(reqId, pFields[i], &pValue);
519 SysTryCatch(NID_CNT, (ret != DOWNLOAD_ERROR_ID_NOT_FOUND) && (ret != DOWNLOAD_ERROR_INVALID_PARAMETER), r = E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] The argument is not valid");
520 pRequest->AddRequestHeader(pFields[i], pValue);
535 _DownloadManagerImpl::GetMimeType(RequestId reqId, String& mimeType)
540 ret = download_get_mime_type((int)reqId, &pStr);
541 SysTryReturnResult(NID_CNT, (ret != DOWNLOAD_ERROR_ID_NOT_FOUND) && (ret != DOWNLOAD_ERROR_INVALID_PARAMETER), E_INVALID_ARG, "There is no download request for the request ID.");
542 SysTryReturnResult(NID_CNT, ret != DOWNLOAD_ERROR_INVALID_STATE, E_INVALID_OPERATION, "The current download state is not downloading or paused.");
543 SysTryReturnResult(NID_CNT, ret >= 0, E_SYSTEM, "The internal system service is not available. %d", ret);
552 _DownloadManagerImpl::GetState(RequestId reqId) const
556 download_state_e download_state = (download_state_e)SLP_STATE_NONE;
557 int state = STATE_NONE;
559 ret = download_get_state((int)reqId, &download_state);
560 SysTryReturn(NID_CNT, ret != DOWNLOAD_ERROR_ID_NOT_FOUND, STATE_NONE, E_INVALID_ARG, "[E_INVALID_ARG] The request ID is not valid.");
561 SysTryReturn(NID_CNT, ret >= 0, STATE_NONE, E_SYSTEM, "[E_SYSTEM] The internal system service is not available. %d", ret);
563 switch(download_state)
569 case SLP_STATE_READY:
570 state = STATE_QUEUED;
573 case SLP_STATE_QUEUED:
574 state = STATE_QUEUED;
577 case SLP_STATE_DOWNLOADING:
578 state = STATE_DOWNLOADING;
581 case SLP_STATE_PAUSED:
582 state = STATE_PAUSED;
585 case SLP_STATE_COMPLETED:
586 state = STATE_COMPLETED;
589 case SLP_STATE_CANCELLED:
590 state = STATE_CANCELLED;
593 case SLP_STATE_FAILED:
594 state = STATE_FAILED;
602 SysLog(NID_CNT, "download_state = %d, state = %d", download_state, state);
608 _DownloadManagerImpl::GetProgress(RequestId reqId, int& progress)
614 _DownloadManagerImpl::SetAllowedNetwork(unsigned long flags)
620 _DownloadManagerImpl::SetDownloadListener(IDownloadListener* pListener)
622 if (pListener != null)
624 _DownloadEvent* pEvent = new (std::nothrow) _DownloadEvent();
625 SysTryReturnVoidResult(NID_IO, pEvent != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
627 pEvent->AddListener(*pListener);
633 if (__pEvent != null)
643 _DownloadManagerImpl::DestroyResources(RequestId reqId)
646 result r = E_SUCCESS;
648 // Cancel the callback
649 UnregisterCallback(reqId);
651 // Remove the resource from url_download
652 ret = download_destroy((int)reqId);
653 SysTryLog(NID_CNT, ret >= 0, "url_download_destory fails %d", ret);
657 _DownloadManagerImpl::RegisterCallback(RequestId reqId)
661 ret = download_set_state_changed_cb(reqId, OnStateChanged, this);
662 SysTryCatch(NID_CNT, ret >= 0, , E_SYSTEM, "[E_SYSTEM] Fails to set state_changed_cb: %d, id = %d", ret, reqId);
664 ret = download_set_progress_cb(reqId, OnProgress, this);
665 SysTryCatch(NID_CNT, ret >= 0, , E_SYSTEM, "[E_SYSTEM] Fails to set progress_cb: %d, id = %d", ret, reqId);
670 UnregisterCallback(reqId);
676 _DownloadManagerImpl::UnregisterCallback(RequestId reqId)
680 ret = download_unset_state_changed_cb(reqId);
681 SysTryLog(NID_CNT, ret >= 0, "download_unset_state_changed_cb fails %d, id = %d", ret, reqId);
683 ret = download_unset_progress_cb(reqId);
684 SysTryLog(NID_CNT, ret >= 0, "download_unset_progress_cb fails %d, id = %d", ret, reqId);
688 _DownloadManagerImpl::ConvertToResult(int error)
690 result r = E_SUCCESS;
691 download_error_e download_error = (download_error_e)error;
693 SysLog(NID_CNT, "Download error = %d", download_error);
695 switch(download_error)
697 case DOWNLOAD_ERROR_NONE:
701 case DOWNLOAD_ERROR_OUT_OF_MEMORY:
705 case DOWNLOAD_ERROR_IO_ERROR:
709 case DOWNLOAD_ERROR_INVALID_URL:
713 case DOWNLOAD_ERROR_ID_NOT_FOUND:
717 case DOWNLOAD_ERROR_CONNECTION_FAILED:
718 case DOWNLOAD_ERROR_NETWORK_UNREACHABLE:
719 r = E_CONNECTION_FAILED;
722 case DOWNLOAD_ERROR_CONNECTION_TIMED_OUT:
726 case DOWNLOAD_ERROR_TOO_MANY_DOWNLOADS:
730 case DOWNLOAD_ERROR_NO_SPACE:
734 case DOWNLOAD_ERROR_QUEUE_FULL:
736 //case URL_DOWNLOAD_ERROR_INVALID_STATE:
737 //case URL_DOWNLOAD_ERROR_INVALID_PARAMETER:
738 //case URL_DOWNLOAD_ERROR_INVALID_DESTINATION:
739 //case URL_DOWNLOAD_ERROR_ALREADY_COMPLETED:
747 } } // Tizen::Content