diff --git a/platform/http_thread_tizen.cpp b/platform/http_thread_tizen.cpp new file mode 100644 index 0000000000..c57e2f60da --- /dev/null +++ b/platform/http_thread_tizen.cpp @@ -0,0 +1,283 @@ +#include "http_thread_tizen.hpp" +#include"../base/logging.hpp" + +#include "platform.hpp" +#include "http_thread_callback.hpp" +#include "tizen_string_utils.hpp" + +#include + +using namespace std; +using namespace Tizen::Net::Http; + +using Tizen::Base::String; +using Tizen::Base::LongLong; +using Tizen::Base::ByteBuffer; +using Tizen::Base::Collection::IEnumerator; + +HttpThread::HttpThread(std::string const & url, + downloader::IHttpThreadCallback & callback, + int64_t beg, + int64_t end, + int64_t size, + string const & pb) + : m_callback(callback), + m_begRange(beg), m_endRange(end), + m_downloadedBytes(0), m_expectedSize(size), + m_url(url), m_pb(pb), + m_pTransaction(null) +{ + result r = E_SUCCESS; + + String * pProxyAddr = null; + String hostAddr(m_url.c_str()); + HttpHeader * header = NULL; + + LOG(LDEBUG, ("Creating HttpSession", m_url)); + m_pSession = new HttpSession(); + r = m_pSession->Construct(NET_HTTP_SESSION_MODE_NORMAL, pProxyAddr, hostAddr, header); + if (r != E_SUCCESS) + { + LOG(LERROR, ("HttpSession Construction error:", r)); + return; + } + + // Open a new HttpTransaction. + m_pTransaction = m_pSession->OpenTransactionN(); + if ((r = GetLastResult()) != E_SUCCESS) + { + LOG(LERROR, ("OpenTransactionN", GetLastResult())); + return; + } + + m_pTransaction->AddHttpTransactionListener(*this); + m_pTransaction->SetHttpProgressListener(*this); + + HttpRequest* pRequest = m_pTransaction->GetRequest(); + pRequest->SetUri(m_url.c_str()); + + HttpHeader* pHeader = pRequest->GetHeader(); + + // use Range header only if we don't download whole file from start + if (!(m_begRange == 0 && m_endRange < 0)) + { + if (m_endRange > 0) + { + LOG(LDEBUG, (m_url, "downloading range [", m_begRange, ",", m_endRange, "]")); + String range("bytes="); + range.Append(m_begRange); + range.Append('-'); + range.Append(m_endRange); + pHeader->AddField(L"Range", range); + } + else + { + LOG(LDEBUG, (m_url, "resuming download from position", m_begRange)); + String range("bytes="); + range.Append(m_begRange); + range.Append('-'); + pHeader->AddField("Range", range); + } + } + + // set user-agent with unique client id only for mapswithme requests + if (m_url.find("mapswithme.com") != string::npos) + { + static string const uid = GetPlatform().UniqueClientId(); + pHeader->AddField("User-Agent", uid.c_str()); + } + + if (m_pb.empty()) + { + pRequest->SetMethod(NET_HTTP_METHOD_GET); + } + else + { + pRequest->SetMethod(NET_HTTP_METHOD_POST); + pHeader->AddField("Content-Type", "application/json"); + long long sz = m_pb.size(); + String lenght; + lenght.Append(sz); + pHeader->AddField("Content-Length", lenght); + ByteBuffer body; + body.Construct((const byte *)m_pb.c_str(), 0, sz, sz); + pRequest->WriteBody(body); + } + LOG(LDEBUG, ("Connecting to", m_url, "[", m_begRange, ",", m_endRange, "]", "size=", m_expectedSize)); + r = m_pTransaction->Submit(); +} + +HttpThread::~HttpThread() +{ + m_pTransaction->RemoveHttpTransactionListener(*this); + m_pSession->CloseTransaction(*m_pTransaction); + delete m_pTransaction; + delete m_pSession; +} + + +void HttpThread::OnTransactionHeaderCompleted (HttpSession &httpSession, + HttpTransaction &httpTransaction, + int headerLen, bool bAuthRequired) +{ + result r = E_SUCCESS; + HttpResponse* pResponse = httpTransaction.GetResponse(); + if ((r = GetLastResult()) != E_SUCCESS) + { + LOG(LWARNING, ("httpTransaction.GetResponse error", r)); + return; + } + + int const httpStatusCode = pResponse->GetHttpStatusCode(); + // When we didn't ask for chunks, code should be 200 + // When we asked for a chunk, code should be 206 + bool const isChunk = !(m_begRange == 0 && m_endRange < 0); + if ((isChunk && httpStatusCode != 206) || (!isChunk && httpStatusCode != 200)) + { + LOG(LWARNING, ("Http request to", m_url, " aborted with HTTP code", httpStatusCode)); + r = httpSession.CancelTransaction(httpTransaction); + r = httpSession.CloseTransaction(httpTransaction); + LOG(LDEBUG, ("CloseTransaction result", r)); + return; + } + else if (m_expectedSize > 0) + { + bool bGoodSize = false; + // try to get content length from Content-Range header first + HttpHeader * pHeader = pResponse->GetHeader(); + LOG(LDEBUG, ("Header:", FromTizenString(*pHeader->GetRawHeaderN()))); + IEnumerator * pValues = pHeader->GetFieldValuesN("Content-Range"); + if (GetLastResult() == E_SUCCESS) + { + bGoodSize = true; + pValues->MoveNext(); // strange, but works + String const * pString = dynamic_cast(pValues->GetCurrent()); + + if (pString->GetLength()) + { + int lastInd; + pString->LastIndexOf ('/', pString->GetLength()-1, lastInd); + long long value = -1; + String tail; + pString->SubString(lastInd + 1, tail); + LOG(LDEBUG, ("tail value:",FromTizenString(tail))); + LongLong::Parse(tail, value); + if (value != m_expectedSize) + { + LOG(LWARNING, ("Http request to", m_url, + "aborted - invalid Content-Range:", value, " expected:" ,m_expectedSize )); + r = httpSession.CancelTransaction(httpTransaction); + r = httpSession.CloseTransaction(httpTransaction); + LOG(LDEBUG, ("CloseTransaction result", r)); + } + } + } + else + { + + pValues = pHeader->GetFieldValuesN("Content-Length"); + if (GetLastResult() == E_SUCCESS) + { + bGoodSize = true; + pValues->MoveNext(); // strange, but works + String const * pString = dynamic_cast(pValues->GetCurrent()); + + if (pString) + { + long long value = -1; + LongLong::Parse(*pString, value); + if (value != m_expectedSize) + { + LOG(LWARNING, ("Http request to", m_url, + "aborted - invalid Content-Length:", value, " expected:" ,m_expectedSize )); + r = httpSession.CancelTransaction(httpTransaction); + r = httpSession.CloseTransaction(httpTransaction); + LOG(LDEBUG, ("CloseTransaction result", r)); + } + } + } + } + + if (!bGoodSize) + { + + LOG(LWARNING, ("Http request to", m_url, + "aborted, server didn't send any valid file size")); + r = httpSession.CancelTransaction(httpTransaction); + r = httpSession.CloseTransaction(httpTransaction); + LOG(LDEBUG, ("CloseTransaction result", r)); + } + } +} + +void HttpThread::OnHttpDownloadInProgress (HttpSession &/*httpSession*/, + Tizen::Net::Http::HttpTransaction &httpTransaction, + long long currentLength, + long long totalLength) +{ + HttpResponse* pResponse = httpTransaction.GetResponse(); + + if (pResponse->GetHttpStatusCode() == HTTP_STATUS_OK + || pResponse->GetHttpStatusCode() == HTTP_STATUS_PARTIAL_CONTENT) + { + ByteBuffer* pBuffer = null; + pBuffer = pResponse->ReadBodyN(); + int chunkSize = pBuffer->GetLimit(); + m_downloadedBytes += chunkSize; + m_callback.OnWrite(m_begRange + m_downloadedBytes - chunkSize, pBuffer->GetPointer(), chunkSize); + delete pBuffer; + } + else + LOG(LERROR, ("OnHttpDownloadInProgress ERROR", FromTizenString(pResponse->GetStatusText()))); +} + +void HttpThread::OnTransactionCompleted (HttpSession &/*httpSession*/, + HttpTransaction & httpTransaction) +{ + HttpResponse* pResponse = httpTransaction.GetResponse(); + if (pResponse->GetHttpStatusCode() == HTTP_STATUS_OK + || pResponse->GetHttpStatusCode() == HTTP_STATUS_PARTIAL_CONTENT) + { + m_callback.OnFinish(200, m_begRange, m_endRange); + } + else + { + LOG(LWARNING, ("Download has finished with status code:", pResponse->GetHttpStatusCode(), + " and text:", FromTizenString(pResponse->GetStatusText() ))); + m_callback.OnFinish(-100, m_begRange, m_endRange); + } +} + +void HttpThread::OnTransactionAborted (HttpSession &/*httpSession*/, + HttpTransaction &/*httpTransaction*/, + result r) +{ + LOG(LINFO, ("OnTransactionAborted result:", r)); + m_callback.OnFinish(-100, m_begRange, m_endRange); +} + +void HttpThread::OnTransactionCertVerificationRequiredN (HttpSession &/*httpSession*/, + HttpTransaction &/*httpTransaction*/, + String */*pCert*/) +{ + LOG(LERROR, ("OnTransactionCertVerificationRequiredN")); +} + +void HttpThread::OnTransactionReadyToRead (HttpSession &/*httpSession*/, + HttpTransaction &/*httpTransaction*/, + int /*availableBodyLen*/) +{ +} + +void HttpThread::OnTransactionReadyToWrite (HttpSession &/*httpSession*/, + HttpTransaction &/*httpTransaction*/, + int /*recommendedChunkSize*/) +{ +} + +void HttpThread::OnHttpUploadInProgress (Tizen::Net::Http::HttpSession &/*httpSession*/, + Tizen::Net::Http::HttpTransaction &/*httpTransaction*/, + long long /*currentLength*/, + long long /*totalLength*/) +{ +} diff --git a/platform/http_thread_tizen.hpp b/platform/http_thread_tizen.hpp new file mode 100644 index 0000000000..24232cc1c1 --- /dev/null +++ b/platform/http_thread_tizen.hpp @@ -0,0 +1,77 @@ +#pragma once +#include "../../std/target_os.hpp" +#include "../../std/noncopyable.hpp" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wignored-qualifiers" +#include +#pragma clang diagnostic pop + +namespace downloader +{ +class IHttpThreadCallback; +} +using namespace Tizen::Net::Http; + +class HttpThread + : public Tizen::Net::Http::IHttpTransactionEventListener + , public Tizen::Net::Http::IHttpProgressEventListener + , noncopyable +{ +public: + + HttpThread(std::string const & url, + downloader::IHttpThreadCallback & callback, + int64_t beg, int64_t end, + int64_t size, + std::string const & pb); + ~HttpThread(); + + bool OnStart(void); + + /// + ///Tizen::Net::Http::IHttpTransactionEventListener + /// + virtual void OnTransactionAborted (HttpSession &httpSession, + HttpTransaction &httpTransaction, + result r); + virtual void OnTransactionCertVerificationRequiredN (HttpSession &httpSession, + HttpTransaction &httpTransaction, + Tizen::Base::String *pCert); + virtual void OnTransactionCompleted (HttpSession &httpSession, + HttpTransaction &httpTransaction); + virtual void OnTransactionHeaderCompleted (HttpSession &httpSession, + HttpTransaction &httpTransaction, + int headerLen, bool bAuthRequired); + virtual void OnTransactionReadyToRead (HttpSession &httpSession, + HttpTransaction &httpTransaction, + int availableBodyLen); + virtual void OnTransactionReadyToWrite (HttpSession &httpSession, + HttpTransaction &httpTransaction, + int recommendedChunkSize); + + /// + ///Tizen::Net::Http::IHttpProgressEventListener + /// + virtual void OnHttpDownloadInProgress (HttpSession &httpSession, + HttpTransaction &httpTransaction, + long long currentLength, + long long totalLength); + virtual void OnHttpUploadInProgress (HttpSession &httpSession, + HttpTransaction &httpTransaction, + long long currentLength, + long long totalLength); + +private: + downloader::IHttpThreadCallback & m_callback; + + int64_t m_begRange; + int64_t m_endRange; + int64_t m_downloadedBytes; + int64_t m_expectedSize; + std::string const m_url; + std::string const & m_pb; + + HttpSession * m_pSession; + HttpTransaction* m_pTransaction; +}; diff --git a/platform/platform.pro b/platform/platform.pro index f04e1092b9..8739a15896 100644 --- a/platform/platform.pro +++ b/platform/platform.pro @@ -41,10 +41,12 @@ INCLUDEPATH += $$ROOT_DIR/3party/jansson/src SOURCES += platform_android.cpp \ pthread_video_timer.cpp } else:tizen* { - HEADERS += tizen_string_utils.hpp + HEADERS += tizen_string_utils.hpp \ + http_thread_tizen.hpp SOURCES += platform_tizen.cpp \ tizen_string_utils.cpp \ - pthread_video_timer.cpp + pthread_video_timer.cpp \ + http_thread_tizen.cpp \ } macx-*|iphone* { diff --git a/platform/platform_tizen.cpp b/platform/platform_tizen.cpp index 3591bbca4d..694843fb4b 100644 --- a/platform/platform_tizen.cpp +++ b/platform/platform_tizen.cpp @@ -1,23 +1,22 @@ #include "platform.hpp" -#include - -#include "../../tizen/inc/FIo.hpp" - -#include "constants.hpp" -#include "platform_unix_impl.hpp" +#include +#include +#include +#include #include "../base/logging.hpp" #include "../coding/file_reader.hpp" -#include -#include - -#include -#include +#include "constants.hpp" +#include "platform_unix_impl.hpp" #include "tizen_string_utils.hpp" +#include "http_thread_tizen.hpp" + +#include +#include "../../tizen/inc/FIo.hpp" Platform::Platform() { @@ -121,13 +120,14 @@ HttpThread * CreateNativeHttpThread(string const & url, int64_t size, string const & pb) { - // todo; - return 0; + + HttpThread * pRes = new HttpThread(url, cb, beg, end, size, pb); + return pRes; } void DeleteNativeHttpThread(HttpThread * request) { - // todo; + delete request; } } diff --git a/tizen/MapsWithMe/inc/MapsWithMeForm.hpp b/tizen/MapsWithMe/inc/MapsWithMeForm.hpp index ed5cd56922..ec057ad6de 100644 --- a/tizen/MapsWithMe/inc/MapsWithMeForm.hpp +++ b/tizen/MapsWithMe/inc/MapsWithMeForm.hpp @@ -2,20 +2,23 @@ #include #include +#include "../../../std/vector.hpp" class MapsWithMeApp; class MapsWithMeForm - : public Tizen::Ui::Controls::Form +: public Tizen::Ui::Controls::Form , public Tizen::Ui::ITouchEventListener + , public Tizen::Ui::IActionEventListener { public: MapsWithMeForm(MapsWithMeApp* pApp); virtual ~MapsWithMeForm(void); virtual result OnDraw(void); + bool Initialize(void); + virtual result OnInitializing(void); - // virtual void OnTouchCanceled (const Tizen::Ui::Control &source, const Tizen::Graphics::Point ¤tPosition, const Tizen::Ui::TouchEventInfo &touchInfo) virtual void OnTouchFocusIn (const Tizen::Ui::Control &source, const Tizen::Graphics::Point ¤tPosition, const Tizen::Ui::TouchEventInfo &touchInfo); @@ -31,6 +34,9 @@ public: virtual void OnTouchReleased (const Tizen::Ui::Control &source, const Tizen::Graphics::Point ¤tPosition, const Tizen::Ui::TouchEventInfo &touchInfo); + + virtual void OnActionPerformed(const Tizen::Ui::Control& source, int actionId); private: + std::vector > m_prev_pts; MapsWithMeApp* m_pApp; }; diff --git a/tizen/MapsWithMe/manifest.xml b/tizen/MapsWithMe/manifest.xml index a395c48ae8..add8532982 100644 --- a/tizen/MapsWithMe/manifest.xml +++ b/tizen/MapsWithMe/manifest.xml @@ -1,24 +1,27 @@ - + - 3BMaQARPoL - 1.0.0 - C++App - - 2.2 - - - 2.2 - - - - - - MapsWithMe - - - mainmenu.png - - - - + 3BMaQARPoL + 1.0.0 + C++App + + 2.2 + + + 2.2 + + http://tizen.org/privilege/http + http://tizen.org/privilege/download + + + + + + MapsWithMe + + + mainmenu.png + + + + diff --git a/tizen/MapsWithMe/src/MapsWithMeApp.cpp b/tizen/MapsWithMe/src/MapsWithMeApp.cpp index 144a604fbb..b471d4f50c 100644 --- a/tizen/MapsWithMe/src/MapsWithMeApp.cpp +++ b/tizen/MapsWithMe/src/MapsWithMeApp.cpp @@ -35,7 +35,7 @@ bool MapsWithMeApp::OnAppInitializing(AppRegistry& appRegistry) MapsWithMeForm * pForm = new MapsWithMeForm(this); TryReturn(pForm != null, false, "The memory is insufficient."); - pForm->Construct(Tizen::Ui::Controls::FORM_STYLE_NORMAL); + pForm->Initialize(); pMapsWithMeFrame->AddControl(pForm); pForm->AddTouchEventListener(*pForm); diff --git a/tizen/MapsWithMe/src/MapsWithMeForm.cpp b/tizen/MapsWithMe/src/MapsWithMeForm.cpp index e1231b11c2..4dbbf5d503 100644 --- a/tizen/MapsWithMe/src/MapsWithMeForm.cpp +++ b/tizen/MapsWithMe/src/MapsWithMeForm.cpp @@ -2,6 +2,19 @@ #include "MapsWithMeApp.h" #include "Framework.hpp" #include "../../../map/framework.hpp" +#include "../../../gui/controller.hpp" +#include +#include +#include +#include + +using namespace Tizen::Ui; +using namespace Tizen::Ui::Controls; +using namespace Tizen::Graphics; +using namespace Tizen::Media; +using namespace Tizen::Base; +using namespace Tizen::Base::Collection; +using namespace Tizen::Base::Utility; MapsWithMeForm::MapsWithMeForm(MapsWithMeApp* pApp) : m_pApp(pApp) @@ -13,34 +26,117 @@ MapsWithMeForm::~MapsWithMeForm(void) { } +bool MapsWithMeForm::Initialize(void) +{ + LOG(LDEBUG, ("MapsWithMeForm::Initialize")); + Construct(Tizen::Ui::Controls::FORM_STYLE_NORMAL); + return true; +} + +result MapsWithMeForm::OnInitializing(void) +{ + LOG(LDEBUG, ("MapsWithMeForm::OnInitializing")); + return E_SUCCESS; +} + +void MapsWithMeForm::OnActionPerformed(const Tizen::Ui::Control& source, int actionId) +{ +} + result MapsWithMeForm::OnDraw(void) { return m_pApp->Draw(); } +namespace detail +{ + std::vector > GetTouchedPoints() + { + std::vector > res; + IListT * pList = TouchEventManager::GetInstance()->GetTouchInfoListN(); + if (pList) + { + int count = pList->GetCount(); + for (int i = 0; i < count; ++i) + { + + TouchEventInfo * pTouchInfo; + pList->GetAt(i, pTouchInfo); + Point pt = pTouchInfo->GetCurrentPosition(); + res.push_back(std::make_pair(pt.x, pt.y)); + } + + pList->RemoveAll(); + delete pList; + } + return res; + } +} + void MapsWithMeForm::OnTouchPressed(const Tizen::Ui::Control& source, const Tizen::Graphics::Point& currentPosition, const Tizen::Ui::TouchEventInfo& touchInfo) { - LOG(LINFO, ("OnTouchPressed")); + std::vector > pts = detail::GetTouchedPoints(); + ::Framework * pFramework = tizen::Framework::GetInstance(); - pFramework->StartDrag(DragEvent(currentPosition.x, currentPosition.y)); + if (!pFramework->GetGuiController()->OnTapStarted(m2::PointD(pts[0].first, pts[0].second))) + { + if (pts.size() == 1) + pFramework->StartDrag(DragEvent(pts[0].first, pts[0].second)); + else if (pts.size() > 1) + pFramework->StartScale(ScaleEvent(pts[0].first, pts[0].second, pts[1].first, pts[1].second)); + } + + std::swap(m_prev_pts, pts); } void MapsWithMeForm::OnTouchMoved(const Tizen::Ui::Control& source, const Tizen::Graphics::Point& currentPosition, const Tizen::Ui::TouchEventInfo& touchInfo) { + std::vector > pts = detail::GetTouchedPoints(); ::Framework * pFramework = tizen::Framework::GetInstance(); - pFramework->DoDrag(DragEvent(currentPosition.x, currentPosition.y)); + + if (!pFramework->GetGuiController()->OnTapMoved(m2::PointD(pts[0].first, pts[0].second))) + { + if (pts.size() == 1) + pFramework->DoDrag(DragEvent(pts[0].first, pts[0].second)); + else if (pts.size() > 1) + { + if (m_prev_pts.size() > 1) + { + pFramework->DoScale(ScaleEvent(pts[0].first, pts[0].second, pts[1].first, pts[1].second)); + } + else if (!m_prev_pts.empty()) + { + pFramework->StopDrag(DragEvent(m_prev_pts[0].first, m_prev_pts[0].second)); + pFramework->StartScale(ScaleEvent(pts[0].first, pts[0].second, pts[1].first, pts[1].second)); + } + } + } + std::swap(m_prev_pts, pts); } void MapsWithMeForm::OnTouchReleased(const Tizen::Ui::Control& source, const Tizen::Graphics::Point& currentPosition, const Tizen::Ui::TouchEventInfo& touchInfo) { + std::vector > pts = detail::GetTouchedPoints(); ::Framework * pFramework = tizen::Framework::GetInstance(); - pFramework->StopDrag(DragEvent(currentPosition.x, currentPosition.y)); + + //using prev_pts because pts contains not all points + if (!m_prev_pts.empty()) + { + if (!pFramework->GetGuiController()->OnTapEnded(m2::PointD(m_prev_pts[0].first, m_prev_pts[0].second))) + { + if (m_prev_pts.size() == 1) + pFramework->StopDrag(DragEvent(m_prev_pts[0].first, m_prev_pts[0].second)); + else if (m_prev_pts.size() > 1) + pFramework->StopScale(ScaleEvent(m_prev_pts[0].first, m_prev_pts[0].second, m_prev_pts[1].first, m_prev_pts[1].second)); + } + m_prev_pts.clear(); + } } void MapsWithMeForm::OnTouchFocusIn(const Tizen::Ui::Control& source, @@ -54,6 +150,3 @@ void MapsWithMeForm::OnTouchFocusOut(const Tizen::Ui::Control& source, const Tizen::Ui::TouchEventInfo& touchInfo) { } - - - diff --git a/tools/mkspecs/tizen-simulator/qmake.conf b/tools/mkspecs/tizen-simulator/qmake.conf index 9297041f3c..5a34b81452 100644 --- a/tools/mkspecs/tizen-simulator/qmake.conf +++ b/tools/mkspecs/tizen-simulator/qmake.conf @@ -277,6 +277,7 @@ QMAKE_LINK_SHLIB = $${QMAKE_CXX} QMAKE_CFLAGS += -g -Wall -c --sysroot="/Users/Sergey/tizen-sdk/platforms/tizen2.2/rootstraps/tizen-emulator-2.2.native" QMAKE_CFLAGS += -I"/Users/Sergey/tizen-sdk/platforms/tizen2.2/rootstraps/tizen-emulator-2.2.native/usr/include" QMAKE_CFLAGS += -I"/Users/Sergey/tizen-sdk/platforms/tizen2.2/rootstraps/tizen-emulator-2.2.native/usr/include/osp" +QMAKE_CFLAGS += -I"/Users/Sergey/tizen-sdk/platforms/tizen2.2/rootstraps/tizen-emulator-2.2.native/usr/include/libxml2" # TODO: fix paths QMAKE_CFLAGS_RELEASE += -O3