Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormpimenov <mpimenov@users.noreply.github.com>2017-04-03 14:22:49 +0300
committerGitHub <noreply@github.com>2017-04-03 14:22:49 +0300
commit1e457847cd1499d3d2e347fb46ab859e8a7aa2e3 (patch)
tree033cc7f929079029aac5efe3fd09644f86602827
parentb0014ce5e73f7919aab1bd6f1a3fad000b2cbfec (diff)
parent3890a4c172d40470eee8995b01773caf2eab959d (diff)
Merge pull request #5729 from rokuz/hla-managerbeta-725
Added Hyper Local Ads (HLA) manager
-rw-r--r--.gitignore1
-rw-r--r--coding/file_container.cpp8
-rw-r--r--coding/file_container.hpp1
-rw-r--r--drape_frontend/backend_renderer.cpp24
-rw-r--r--drape_frontend/drape_engine.cpp18
-rw-r--r--drape_frontend/drape_engine.hpp4
-rwxr-xr-xdrape_frontend/frontend_renderer.cpp27
-rwxr-xr-xdrape_frontend/frontend_renderer.hpp3
-rw-r--r--drape_frontend/message.hpp3
-rw-r--r--drape_frontend/message_subclasses.hpp23
-rwxr-xr-xdrape_frontend/read_manager.cpp38
-rwxr-xr-xdrape_frontend/read_manager.hpp14
-rwxr-xr-xdrape_frontend/requested_tiles.cpp13
-rwxr-xr-xdrape_frontend/requested_tiles.hpp9
-rw-r--r--map/CMakeLists.txt2
-rw-r--r--map/framework.cpp21
-rw-r--r--map/framework.hpp8
-rw-r--r--map/local_ads_manager.cpp357
-rw-r--r--map/local_ads_manager.hpp80
-rw-r--r--map/map.pro2
20 files changed, 593 insertions, 63 deletions
diff --git a/.gitignore b/.gitignore
index d8f2b9c31a..bc975bd19f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,6 +16,7 @@ data/*.mwm.osm2ft
data/*.mwm.routing
data/*.mwmmeta
data/[!W]*.mwm
+data/local_ads*.dat
# Compiled Python
*.pyc
diff --git a/coding/file_container.cpp b/coding/file_container.cpp
index 2598fa299a..69d4a698f7 100644
--- a/coding/file_container.cpp
+++ b/coding/file_container.cpp
@@ -440,7 +440,13 @@ void FilesContainerW::Write(ModelReaderPtr reader, Tag const & tag)
void FilesContainerW::Write(vector<char> const & buffer, Tag const & tag)
{
if (!buffer.empty())
- GetWriter(tag).Write(&buffer[0], buffer.size());
+ GetWriter(tag).Write(buffer.data(), buffer.size());
+}
+
+void FilesContainerW::Write(vector<uint8_t> const & buffer, Tag const & tag)
+{
+ if (!buffer.empty())
+ GetWriter(tag).Write(buffer.data(), buffer.size());
}
void FilesContainerW::Finish()
diff --git a/coding/file_container.hpp b/coding/file_container.hpp
index 01e3fd8c0e..1307e8e8cd 100644
--- a/coding/file_container.hpp
+++ b/coding/file_container.hpp
@@ -238,6 +238,7 @@ public:
void Write(string const & fPath, Tag const & tag);
void Write(ModelReaderPtr reader, Tag const & tag);
void Write(vector<char> const & buffer, Tag const & tag);
+ void Write(vector<uint8_t> const & buffer, Tag const & tag);
void Finish();
diff --git a/drape_frontend/backend_renderer.cpp b/drape_frontend/backend_renderer.cpp
index 51d8415a1c..67a9e84e91 100644
--- a/drape_frontend/backend_renderer.cpp
+++ b/drape_frontend/backend_renderer.cpp
@@ -114,9 +114,9 @@ void BackendRenderer::AcceptMessage(ref_ptr<Message> message)
{
ScreenBase screen;
bool have3dBuildings;
- bool needRegenerateTraffic;
- m_requestedTiles->GetParams(screen, have3dBuildings, needRegenerateTraffic);
- m_readManager->UpdateCoverage(screen, have3dBuildings, needRegenerateTraffic, tiles, m_texMng);
+ bool forceRequest;
+ m_requestedTiles->GetParams(screen, have3dBuildings, forceRequest);
+ m_readManager->UpdateCoverage(screen, have3dBuildings, forceRequest, tiles, m_texMng);
m_updateCurrentCountryFn(screen.ClipRect().Center(), (*tiles.begin()).m_zoomLevel);
}
break;
@@ -428,9 +428,9 @@ void BackendRenderer::AcceptMessage(ref_ptr<Message> message)
break;
}
- case Message::SetCustomSymbols:
+ case Message::AddCustomSymbols:
{
- ref_ptr<SetCustomSymbolsMessage> msg = message;
+ ref_ptr<AddCustomSymbolsMessage> msg = message;
CustomSymbols customSymbols = msg->AcceptSymbols();
std::vector<FeatureID> features;
for (auto const & symbol : customSymbols)
@@ -442,6 +442,20 @@ void BackendRenderer::AcceptMessage(ref_ptr<Message> message)
break;
}
+ case Message::RemoveCustomSymbols:
+ {
+ ref_ptr<RemoveCustomSymbolsMessage> msg = message;
+ std::vector<FeatureID> leftoverIds;
+ if (msg->NeedRemoveAll())
+ m_readManager->RemoveAllCustomSymbols();
+ else
+ m_readManager->RemoveCustomSymbols(msg->GetMwmId(), leftoverIds);
+ m_commutator->PostMessage(ThreadsCommutator::RenderThread,
+ make_unique_dp<UpdateCustomSymbolsMessage>(std::move(leftoverIds)),
+ MessagePriority::Normal);
+ break;
+ }
+
default:
ASSERT(false, ());
break;
diff --git a/drape_frontend/drape_engine.cpp b/drape_frontend/drape_engine.cpp
index 8b02efd2b1..e359f731e8 100644
--- a/drape_frontend/drape_engine.cpp
+++ b/drape_frontend/drape_engine.cpp
@@ -580,10 +580,24 @@ void DrapeEngine::RunScenario(ScenarioManager::ScenarioData && scenarioData,
manager->RunScenario(move(scenarioData), onStartFn, onFinishFn);
}
-void DrapeEngine::SetCustomSymbols(CustomSymbols && symbols)
+void DrapeEngine::AddCustomSymbols(CustomSymbols && symbols)
{
m_threadCommutator->PostMessage(ThreadsCommutator::ResourceUploadThread,
- make_unique_dp<SetCustomSymbolsMessage>(std::move(symbols)),
+ make_unique_dp<AddCustomSymbolsMessage>(std::move(symbols)),
+ MessagePriority::Normal);
+}
+
+void DrapeEngine::RemoveCustomSymbols(MwmSet::MwmId const & mwmId)
+{
+ m_threadCommutator->PostMessage(ThreadsCommutator::ResourceUploadThread,
+ make_unique_dp<RemoveCustomSymbolsMessage>(mwmId),
+ MessagePriority::Normal);
+}
+
+void DrapeEngine::RemoveAllCustomSymbols()
+{
+ m_threadCommutator->PostMessage(ThreadsCommutator::ResourceUploadThread,
+ make_unique_dp<RemoveCustomSymbolsMessage>(),
MessagePriority::Normal);
}
diff --git a/drape_frontend/drape_engine.hpp b/drape_frontend/drape_engine.hpp
index 6e5075866b..f7e346f93b 100644
--- a/drape_frontend/drape_engine.hpp
+++ b/drape_frontend/drape_engine.hpp
@@ -192,7 +192,9 @@ public:
ScenarioManager::ScenarioCallback const & onStartFn,
ScenarioManager::ScenarioCallback const & onFinishFn);
- void SetCustomSymbols(CustomSymbols && symbols);
+ void AddCustomSymbols(CustomSymbols && symbols);
+ void RemoveCustomSymbols(MwmSet::MwmId const & mwmId);
+ void RemoveAllCustomSymbols();
private:
void AddUserEvent(drape_ptr<UserEvent> && e);
diff --git a/drape_frontend/frontend_renderer.cpp b/drape_frontend/frontend_renderer.cpp
index 4fb766c64f..7da63bf1f7 100755
--- a/drape_frontend/frontend_renderer.cpp
+++ b/drape_frontend/frontend_renderer.cpp
@@ -135,10 +135,10 @@ FrontendRenderer::FrontendRenderer(Params && params)
, m_requestedTiles(params.m_requestedTiles)
, m_maxGeneration(0)
, m_needRestoreSize(false)
- , m_needRegenerateTraffic(false)
, m_trafficEnabled(params.m_trafficEnabled)
, m_overlaysTracker(new OverlaysTracker())
, m_overlaysShowStatsCallback(move(params.m_overlaysShowStatsCallback))
+ , m_forceUpdateScene(false)
#ifdef SCENARIO_ENABLE
, m_scenarioManager(new ScenarioManager(this))
#endif
@@ -339,7 +339,7 @@ void FrontendRenderer::AcceptMessage(ref_ptr<Message> message)
ScreenBase const & screen = m_userEventStream.GetCurrentScreen();
CheckIsometryMinScale(screen);
UpdateDisplacementEnabled();
- InvalidateRect(screen.ClipRect());
+ m_forceUpdateScene = true;
}
if (m_guiRenderer->HasWidget(gui::WIDGET_RULER))
@@ -623,7 +623,7 @@ void FrontendRenderer::AcceptMessage(ref_ptr<Message> message)
{
m_enable3dBuildings = msg->Allow3dBuildings();
CheckIsometryMinScale(screen);
- InvalidateRect(screen.ClipRect());
+ m_forceUpdateScene = true;
}
if (m_enablePerspectiveInNavigation != msg->AllowPerspective())
@@ -731,7 +731,7 @@ void FrontendRenderer::AcceptMessage(ref_ptr<Message> message)
ref_ptr<EnableTrafficMessage> msg = message;
m_trafficEnabled = msg->IsTrafficEnabled();
if (msg->IsTrafficEnabled())
- m_needRegenerateTraffic = true;
+ m_forceUpdateScene = true;
else
m_trafficRenderer->ClearGLDependentResources();
break;
@@ -740,7 +740,7 @@ void FrontendRenderer::AcceptMessage(ref_ptr<Message> message)
case Message::RegenerateTraffic:
case Message::SetSimplifiedTrafficColors:
{
- m_needRegenerateTraffic = true;
+ m_forceUpdateScene = true;
break;
}
@@ -781,8 +781,7 @@ void FrontendRenderer::AcceptMessage(ref_ptr<Message> message)
{
ref_ptr<UpdateCustomSymbolsMessage> msg = message;
m_overlaysTracker->SetTrackedOverlaysFeatures(msg->AcceptSymbolsFeatures());
- ScreenBase const & screen = m_userEventStream.GetCurrentScreen();
- InvalidateRect(screen.ClipRect());
+ m_forceUpdateScene = true;
break;
}
@@ -835,7 +834,7 @@ void FrontendRenderer::UpdateGLResources()
// Request new tiles.
ScreenBase screen = m_userEventStream.GetCurrentScreen();
m_lastReadedModelView = screen;
- m_requestedTiles->Set(screen, m_isIsometry || screen.isPerspective(), m_needRegenerateTraffic, ResolveTileKeys(screen));
+ m_requestedTiles->Set(screen, m_isIsometry || screen.isPerspective(), m_forceUpdateScene, ResolveTileKeys(screen));
m_commutator->PostMessage(ThreadsCommutator::ResourceUploadThread,
make_unique_dp<UpdateReadManagerMessage>(),
MessagePriority::UberHighSingleton);
@@ -890,8 +889,8 @@ void FrontendRenderer::InvalidateRect(m2::RectD const & gRect)
// Request new tiles.
m_lastReadedModelView = screen;
- m_requestedTiles->Set(screen, m_isIsometry || screen.isPerspective(),
- m_needRegenerateTraffic, ResolveTileKeys(screen));
+ m_requestedTiles->Set(screen, m_isIsometry || screen.isPerspective(), m_forceUpdateScene,
+ ResolveTileKeys(screen));
m_commutator->PostMessage(ThreadsCommutator::ResourceUploadThread,
make_unique_dp<UpdateReadManagerMessage>(),
MessagePriority::UberHighSingleton);
@@ -1748,7 +1747,7 @@ void FrontendRenderer::Routine::Do()
isActiveFrame |= m_renderer.m_texMng->UpdateDynamicTextures();
m_renderer.RenderScene(modelView);
- if (modelViewChanged || m_renderer.m_needRegenerateTraffic)
+ if (modelViewChanged || m_renderer.m_forceUpdateScene)
m_renderer.UpdateScene(modelView);
isActiveFrame |= InterpolationHolder::Instance().Advance(frameTime);
@@ -1911,16 +1910,16 @@ void FrontendRenderer::UpdateScene(ScreenBase const & modelView)
for (RenderLayer & layer : m_layers)
layer.m_isDirty |= RemoveGroups(removePredicate, layer.m_renderGroups, make_ref(m_overlayTree));
- if (m_needRegenerateTraffic || m_lastReadedModelView != modelView)
+ if (m_forceUpdateScene || m_lastReadedModelView != modelView)
{
EmitModelViewChanged(modelView);
m_lastReadedModelView = modelView;
- m_requestedTiles->Set(modelView, m_isIsometry || modelView.isPerspective(), m_needRegenerateTraffic,
+ m_requestedTiles->Set(modelView, m_isIsometry || modelView.isPerspective(), m_forceUpdateScene,
ResolveTileKeys(modelView));
m_commutator->PostMessage(ThreadsCommutator::ResourceUploadThread,
make_unique_dp<UpdateReadManagerMessage>(),
MessagePriority::UberHighSingleton);
- m_needRegenerateTraffic = false;
+ m_forceUpdateScene = false;
}
}
diff --git a/drape_frontend/frontend_renderer.hpp b/drape_frontend/frontend_renderer.hpp
index 7da2399699..6f6666108f 100755
--- a/drape_frontend/frontend_renderer.hpp
+++ b/drape_frontend/frontend_renderer.hpp
@@ -333,12 +333,13 @@ private:
bool m_needRestoreSize;
- bool m_needRegenerateTraffic;
bool m_trafficEnabled;
drape_ptr<OverlaysTracker> m_overlaysTracker;
OverlaysShowStatsCallback m_overlaysShowStatsCallback;
+ bool m_forceUpdateScene;
+
drape_ptr<ScenarioManager> m_scenarioManager;
#ifdef DEBUG
diff --git a/drape_frontend/message.hpp b/drape_frontend/message.hpp
index 7c615e1674..69ee6c4172 100644
--- a/drape_frontend/message.hpp
+++ b/drape_frontend/message.hpp
@@ -75,7 +75,8 @@ public:
DrapeApiAddLines,
DrapeApiRemove,
DrapeApiFlush,
- SetCustomSymbols,
+ AddCustomSymbols,
+ RemoveCustomSymbols,
UpdateCustomSymbols,
};
diff --git a/drape_frontend/message_subclasses.hpp b/drape_frontend/message_subclasses.hpp
index 1052847afd..ec2388fb1e 100644
--- a/drape_frontend/message_subclasses.hpp
+++ b/drape_frontend/message_subclasses.hpp
@@ -1151,14 +1151,14 @@ private:
TProperties m_properties;
};
-class SetCustomSymbolsMessage : public Message
+class AddCustomSymbolsMessage : public Message
{
public:
- explicit SetCustomSymbolsMessage(CustomSymbols && symbols)
+ explicit AddCustomSymbolsMessage(CustomSymbols && symbols)
: m_symbols(std::move(symbols))
{}
- Type GetType() const override { return Message::SetCustomSymbols; }
+ Type GetType() const override { return Message::AddCustomSymbols; }
CustomSymbols && AcceptSymbols() { return std::move(m_symbols); }
@@ -1166,6 +1166,23 @@ private:
CustomSymbols m_symbols;
};
+class RemoveCustomSymbolsMessage : public Message
+{
+public:
+ RemoveCustomSymbolsMessage() = default;
+ explicit RemoveCustomSymbolsMessage(MwmSet::MwmId const & mwmId)
+ : m_mwmId(mwmId), m_removeAll(false)
+ {}
+
+ Type GetType() const override { return Message::RemoveCustomSymbols; }
+ bool NeedRemoveAll() const { return m_removeAll; }
+ MwmSet::MwmId const & GetMwmId() const { return m_mwmId; }
+
+private:
+ MwmSet::MwmId m_mwmId;
+ bool m_removeAll = true;
+};
+
class UpdateCustomSymbolsMessage : public Message
{
public:
diff --git a/drape_frontend/read_manager.cpp b/drape_frontend/read_manager.cpp
index 3f4205edb6..7d500ff7c7 100755
--- a/drape_frontend/read_manager.cpp
+++ b/drape_frontend/read_manager.cpp
@@ -87,13 +87,13 @@ void ReadManager::OnTaskFinished(threads::IRoutine * task)
myPool.Return(t);
}
-void ReadManager::UpdateCoverage(ScreenBase const & screen, bool have3dBuildings, bool needRegenerateTraffic,
+void ReadManager::UpdateCoverage(ScreenBase const & screen, bool have3dBuildings, bool forceUpdate,
TTilesCollection const & tiles, ref_ptr<dp::TextureManager> texMng)
{
m_modeChanged |= (m_have3dBuildings != have3dBuildings);
m_have3dBuildings = have3dBuildings;
- if (m_modeChanged || needRegenerateTraffic || MustDropAllTiles(screen))
+ if (m_modeChanged || forceUpdate || MustDropAllTiles(screen))
{
m_modeChanged = false;
@@ -280,18 +280,36 @@ void ReadManager::SetTrafficEnabled(bool trafficEnabled)
}
}
-void ReadManager::UpdateCustomSymbols(CustomSymbols && symbols)
+void ReadManager::UpdateCustomSymbols(CustomSymbols const & symbols)
{
- auto customSymbolsContext = std::make_shared<CustomSymbolsContext>(std::move(symbols));
+ CustomSymbols currentSymbols = m_customSymbolsContext ? m_customSymbolsContext->m_symbols :
+ CustomSymbols();
+ for (auto const & s : symbols)
+ currentSymbols[s.first] = s.second;
+ m_customSymbolsContext = std::make_shared<CustomSymbolsContext>(std::move(currentSymbols));
+}
-#if !defined(OMIM_OS_LINUX)
- std::atomic_exchange(&m_customSymbolsContext, customSymbolsContext);
-#else
+void ReadManager::RemoveCustomSymbols(MwmSet::MwmId const & mwmId, std::vector<FeatureID> & leftoverIds)
+{
+ if (!m_customSymbolsContext)
+ return;
+
+ CustomSymbols currentSymbols;
+ leftoverIds.reserve(m_customSymbolsContext->m_symbols.size());
+ for (auto const & s : m_customSymbolsContext->m_symbols)
{
- lock_guard<mutex> guard(m_customSymbolsContextMutex);
- std::swap(m_customSymbolsContext, customSymbolsContext);
+ if (s.first.m_mwmId != mwmId)
+ {
+ currentSymbols.insert(std::make_pair(s.first, s.second));
+ leftoverIds.push_back(s.first);
+ }
}
-#endif
+ m_customSymbolsContext = std::make_shared<CustomSymbolsContext>(std::move(currentSymbols));
+}
+
+void ReadManager::RemoveAllCustomSymbols()
+{
+ m_customSymbolsContext = std::make_shared<CustomSymbolsContext>(CustomSymbols());
}
} // namespace df
diff --git a/drape_frontend/read_manager.hpp b/drape_frontend/read_manager.hpp
index e4d3903d8c..e8ced849fe 100755
--- a/drape_frontend/read_manager.hpp
+++ b/drape_frontend/read_manager.hpp
@@ -32,7 +32,7 @@ public:
ReadManager(ref_ptr<ThreadsCommutator> commutator, MapDataProvider & model,
bool allow3dBuildings, bool trafficEnabled);
- void UpdateCoverage(ScreenBase const & screen, bool have3dBuildings, bool needRegenerateTraffic,
+ void UpdateCoverage(ScreenBase const & screen, bool have3dBuildings, bool forceUpdate,
TTilesCollection const & tiles, ref_ptr<dp::TextureManager> texMng);
void Invalidate(TTilesCollection const & keyStorage);
void InvalidateAll();
@@ -43,7 +43,9 @@ public:
void SetTrafficEnabled(bool trafficEnabled);
- void UpdateCustomSymbols(CustomSymbols && symbols);
+ void UpdateCustomSymbols(CustomSymbols const & symbols);
+ void RemoveCustomSymbols(MwmSet::MwmId const & mwmId, std::vector<FeatureID> & leftoverIds);
+ void RemoveAllCustomSymbols();
static uint32_t ReadCount();
@@ -53,7 +55,6 @@ private:
void PushTaskBackForTileKey(TileKey const & tileKey, ref_ptr<dp::TextureManager> texMng);
-private:
ref_ptr<ThreadsCommutator> m_commutator;
MapDataProvider & m_model;
@@ -88,13 +89,6 @@ private:
CustomSymbolsContextPtr m_customSymbolsContext;
- // TODO (@y): unfortunately on Debian Jessie libstdc++ does not
- // support atomic_exchange for shared pointers, so mutex is used
- // instead. Get rid of this as soon as new libstdc++ is released.
-#if defined(OMIM_OS_LINUX)
- mutex m_customSymbolsContextMutex;
-#endif
-
void CancelTileInfo(shared_ptr<TileInfo> const & tileToCancel);
void ClearTileInfo(shared_ptr<TileInfo> const & tileToClear);
void IncreaseCounter(int value);
diff --git a/drape_frontend/requested_tiles.cpp b/drape_frontend/requested_tiles.cpp
index 64c6932862..4624dc9b56 100755
--- a/drape_frontend/requested_tiles.cpp
+++ b/drape_frontend/requested_tiles.cpp
@@ -3,14 +3,14 @@
namespace df
{
-void RequestedTiles::Set(ScreenBase const & screen, bool have3dBuildings,
- bool needRegenerateTraffic, TTilesCollection && tiles)
+void RequestedTiles::Set(ScreenBase const & screen, bool have3dBuildings, bool forceRequest,
+ TTilesCollection && tiles)
{
lock_guard<mutex> lock(m_mutex);
m_tiles = move(tiles);
m_screen = screen;
m_have3dBuildings = have3dBuildings;
- m_needRegenerateTraffic = needRegenerateTraffic;
+ m_forceRequest = forceRequest;
}
TTilesCollection RequestedTiles::GetTiles()
@@ -23,13 +23,12 @@ TTilesCollection RequestedTiles::GetTiles()
return tiles;
}
-void RequestedTiles::GetParams(ScreenBase & screen, bool & have3dBuildings,
- bool & needRegenerateTraffic)
+void RequestedTiles::GetParams(ScreenBase & screen, bool & have3dBuildings, bool & forceRequest)
{
lock_guard<mutex> lock(m_mutex);
screen = m_screen;
have3dBuildings = m_have3dBuildings;
- needRegenerateTraffic = m_needRegenerateTraffic;
+ forceRequest = m_forceRequest;
}
bool RequestedTiles::CheckTileKey(TileKey const & tileKey) const
@@ -41,4 +40,4 @@ bool RequestedTiles::CheckTileKey(TileKey const & tileKey) const
return m_tiles.find(tileKey) != m_tiles.end();
}
-} //namespace df
+} // namespace df
diff --git a/drape_frontend/requested_tiles.hpp b/drape_frontend/requested_tiles.hpp
index a5945bee8d..90f6a830f7 100755
--- a/drape_frontend/requested_tiles.hpp
+++ b/drape_frontend/requested_tiles.hpp
@@ -13,18 +13,17 @@ class RequestedTiles
{
public:
RequestedTiles() = default;
- void Set(ScreenBase const & screen, bool have3dBuildings,
- bool needRegenerateTraffic, TTilesCollection && tiles);
+ void Set(ScreenBase const & screen, bool have3dBuildings, bool forceRequest,
+ TTilesCollection && tiles);
TTilesCollection GetTiles();
- void GetParams(ScreenBase & screen, bool & have3dBuildings,
- bool & needRegenerateTraffic);
+ void GetParams(ScreenBase & screen, bool & have3dBuildings, bool & forceRequest);
bool CheckTileKey(TileKey const & tileKey) const;
private:
TTilesCollection m_tiles;
ScreenBase m_screen;
bool m_have3dBuildings = false;
- bool m_needRegenerateTraffic = false;
+ bool m_forceRequest = false;
mutable mutex m_mutex;
};
diff --git a/map/CMakeLists.txt b/map/CMakeLists.txt
index c62a9dccf9..198302b6f1 100644
--- a/map/CMakeLists.txt
+++ b/map/CMakeLists.txt
@@ -43,6 +43,8 @@ set(
gps_track.hpp
gps_tracker.cpp
gps_tracker.hpp
+ local_ads_manager.cpp
+ local_ads_manager.hpp
mwm_url.cpp
mwm_url.hpp
place_page_info.cpp
diff --git a/map/framework.cpp b/map/framework.cpp
index 1e86acd3db..ead18ca55f 100644
--- a/map/framework.cpp
+++ b/map/framework.cpp
@@ -276,6 +276,11 @@ TrafficManager & Framework::GetTrafficManager()
return m_trafficManager;
}
+LocalAdsManager & Framework::GetLocalAdsManager()
+{
+ return m_localAdsManager;
+}
+
bool Framework::IsTrackingReporterEnabled() const
{
if (m_currentRouterType != routing::RouterType::Vehicle)
@@ -309,6 +314,7 @@ void Framework::OnViewportChanged(ScreenBase const & screen)
m_currentModelView = screen;
m_trafficManager.UpdateViewport(m_currentModelView);
+ m_localAdsManager.UpdateViewport(m_currentModelView);
if (m_viewportChanged != nullptr)
m_viewportChanged(screen);
@@ -393,6 +399,7 @@ Framework::Framework()
, m_trafficManager(bind(&Framework::GetMwmsByRect, this, _1), kMaxTrafficCacheSizeBytes,
// Note. |m_routingSession| should be declared before |m_trafficManager|.
m_routingSession)
+ , m_localAdsManager(bind(&Framework::GetMwmsByRect, this, _1), bind(&Framework::GetMwmIdByName, this, _1))
, m_displacementModeManager([this](bool show) {
int const mode = show ? dp::displacement::kHotelMode : dp::displacement::kDefaultMode;
CallDrapeFunction(bind(&df::DrapeEngine::SetDisplacementMode, _1, mode));
@@ -499,6 +506,7 @@ Framework::Framework()
Framework::~Framework()
{
m_trafficManager.Teardown();
+ m_localAdsManager.Teardown();
DestroyDrapeEngine();
m_model.SetOnMapDeregisteredCallback(nullptr);
}
@@ -615,6 +623,7 @@ void Framework::OnCountryFileDownloaded(storage::TCountryId const & countryId, s
rect = id.GetInfo()->m_limitRect;
}
m_trafficManager.Invalidate();
+ m_localAdsManager.OnDownloadCountry(countryId);
InvalidateRect(rect);
m_searchEngine->ClearCaches();
}
@@ -639,6 +648,7 @@ bool Framework::OnCountryFileDelete(storage::TCountryId const & countryId, stora
m_model.DeregisterMap(platform::CountryFile(countryId));
deferredDelete = true;
m_trafficManager.OnMwmDelete(mwmId);
+ m_localAdsManager.OnDeleteCountry(countryId);
}
InvalidateRect(rect);
@@ -1785,6 +1795,7 @@ void Framework::CreateDrapeEngine(ref_ptr<dp::OGLContextFactory> contextFactory,
m_drapeApi.SetEngine(make_ref(m_drapeEngine));
m_trafficManager.SetDrapeEngine(make_ref(m_drapeEngine));
+ m_localAdsManager.SetDrapeEngine(make_ref(m_drapeEngine));
benchmark::RunGraphicsBenchmark(this);
}
@@ -1821,6 +1832,7 @@ void Framework::DestroyDrapeEngine()
{
m_drapeApi.SetEngine(nullptr);
m_trafficManager.Teardown();
+ m_localAdsManager.Teardown();
GpsTracker::Instance().Disconnect();
m_drapeEngine.reset();
}
@@ -3432,7 +3444,7 @@ void Framework::VisualizeRoadsInRect(m2::RectD const & rect)
}, kScale);
}
-vector<MwmSet::MwmId> Framework::GetMwmsByRect(m2::RectD const & rect)
+vector<MwmSet::MwmId> Framework::GetMwmsByRect(m2::RectD const & rect) const
{
vector<MwmSet::MwmId> result;
if (!m_infoGetter)
@@ -3440,7 +3452,12 @@ vector<MwmSet::MwmId> Framework::GetMwmsByRect(m2::RectD const & rect)
auto countryIds = m_infoGetter->GetRegionsCountryIdByRect(rect);
for (auto const & countryId : countryIds)
- result.push_back(m_model.GetIndex().GetMwmIdByCountryFile(platform::CountryFile(countryId)));
+ result.push_back(GetMwmIdByName(countryId));
return result;
}
+
+MwmSet::MwmId Framework::GetMwmIdByName(std::string const & name) const
+{
+ return m_model.GetIndex().GetMwmIdByCountryFile(platform::CountryFile(name));
+}
diff --git a/map/framework.hpp b/map/framework.hpp
index bda5373a16..d0b2c6ec1f 100644
--- a/map/framework.hpp
+++ b/map/framework.hpp
@@ -6,6 +6,7 @@
#include "map/city_finder.hpp"
#include "map/displacement_mode_manager.hpp"
#include "map/feature_vec_model.hpp"
+#include "map/local_ads_manager.hpp"
#include "map/mwm_url.hpp"
#include "map/place_page_info.hpp"
#include "map/track.hpp"
@@ -176,6 +177,8 @@ protected:
TrafficManager m_trafficManager;
+ LocalAdsManager m_localAdsManager;
+
/// This function will be called by m_storage when latest local files
/// is downloaded.
void OnCountryFileDownloaded(storage::TCountryId const & countryId, storage::Storage::TLocalFilePtr const localFile);
@@ -369,7 +372,8 @@ public:
/// Guarantees that listener is called in the main thread context.
void SetCurrentCountryChangedListener(TCurrentCountryChanged const & listener);
- vector<MwmSet::MwmId> GetMwmsByRect(m2::RectD const & rect);
+ vector<MwmSet::MwmId> GetMwmsByRect(m2::RectD const & rect) const;
+ MwmSet::MwmId GetMwmIdByName(std::string const & name) const;
private:
struct TapEvent
@@ -789,6 +793,8 @@ public:
TrafficManager & GetTrafficManager();
+ LocalAdsManager & GetLocalAdsManager();
+
bool LoadTrafficEnabled();
void SaveTrafficEnabled(bool trafficEnabled);
diff --git a/map/local_ads_manager.cpp b/map/local_ads_manager.cpp
new file mode 100644
index 0000000000..1a0ce69540
--- /dev/null
+++ b/map/local_ads_manager.cpp
@@ -0,0 +1,357 @@
+#include "map/local_ads_manager.hpp"
+
+#include "drape_frontend/drape_engine.hpp"
+#include "drape_frontend/visual_params.hpp"
+
+#include "indexer/scales.hpp"
+
+#include "platform/http_client.hpp"
+#include "platform/platform.hpp"
+
+#include "coding/file_container.hpp"
+#include "coding/file_name_utils.hpp"
+
+#include "base/bits.hpp"
+
+namespace
+{
+std::string const kCampaignFile = "local_ads_campaigns.dat";
+std::string const kExpirationFile = "local_ads_expiration.dat";
+auto constexpr kWWanUpdateTimeout = std::chrono::hours(12);
+
+std::vector<uint8_t> SerializeTimestamp(std::chrono::steady_clock::time_point ts)
+{
+ auto hours = std::chrono::duration_cast<std::chrono::hours>(ts.time_since_epoch()).count();
+ uint64_t const encodedHours = bits::ZigZagEncode(static_cast<int64_t>(hours));
+
+ std::vector<uint8_t> result;
+ MemWriter<decltype(result)> writer(result);
+ writer.Write(&encodedHours, sizeof(encodedHours));
+
+ return result;
+}
+
+std::chrono::steady_clock::time_point DeserializeTimestamp(ModelReaderPtr const & reader)
+{
+ ASSERT_EQUAL(reader.Size(), sizeof(long), ());
+
+ std::vector<uint8_t> bytes(reader.Size());
+ reader.Read(0, bytes.data(), bytes.size());
+
+ MemReaderWithExceptions memReader(bytes.data(), bytes.size());
+ ReaderSource<decltype(memReader)> src(memReader);
+ uint64_t hours = ReadPrimitiveFromSource<uint64_t>(src);
+ int64_t const decodedHours = bits::ZigZagDecode(hours);
+
+ return std::chrono::steady_clock::time_point(std::chrono::hours(decodedHours));
+}
+
+std::string GetPath(std::string const & fileName)
+{
+ return my::JoinFoldersToPath(GetPlatform().WritableDir(), fileName);
+}
+} // namespace
+
+LocalAdsManager::LocalAdsManager(GetMwmsByRectFn const & getMwmsByRectFn,
+ GetMwmIdByName const & getMwmIdByName)
+ : m_getMwmsByRectFn(getMwmsByRectFn)
+ , m_getMwmIdByNameFn(getMwmIdByName)
+ , m_thread(&LocalAdsManager::ThreadRoutine, this)
+{
+ CHECK(m_getMwmsByRectFn != nullptr, ());
+ CHECK(m_getMwmIdByNameFn != nullptr, ());
+}
+
+LocalAdsManager::~LocalAdsManager()
+{
+#ifdef DEBUG
+ {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ ASSERT(!m_isRunning, ());
+ }
+#endif
+}
+
+void LocalAdsManager::Teardown()
+{
+ {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ if (!m_isRunning)
+ return;
+ m_isRunning = false;
+ }
+ m_condition.notify_one();
+ m_thread.join();
+}
+
+void LocalAdsManager::SetDrapeEngine(ref_ptr<df::DrapeEngine> engine)
+{
+ m_drapeEngine = engine;
+ {
+ std::lock_guard<std::mutex> lock(m_symbolsCacheMutex);
+ if (!m_symbolsCache.empty())
+ m_drapeEngine->AddCustomSymbols(std::move(m_symbolsCache));
+ }
+}
+
+void LocalAdsManager::UpdateViewport(ScreenBase const & screen)
+{
+ auto connectionStatus = GetPlatform().ConnectionStatus();
+ if (connectionStatus == Platform::EConnectionType::CONNECTION_NONE ||
+ df::GetZoomLevel(screen.GetScale()) <= scales::GetUpperWorldScale())
+ {
+ return;
+ }
+
+ std::vector<std::string> requestedCampaigns;
+ auto mwms = m_getMwmsByRectFn(screen.ClipRect());
+ if (mwms.empty())
+ return;
+
+ // Request local ads campaigns.
+ {
+ std::lock_guard<std::mutex> lock(m_mutex);
+
+ for (auto const & mwm : mwms)
+ {
+ auto info = mwm.GetInfo();
+ if (!info)
+ continue;
+ std::string const & mwmName = info->GetCountryName();
+ auto campaignIt = m_campaigns.find(mwmName);
+ if (campaignIt == m_campaigns.end())
+ {
+ requestedCampaigns.push_back(mwmName);
+ continue;
+ }
+
+ // If a campaign has not been requested from server this session.
+ if (!campaignIt->second)
+ {
+ auto const it = m_expiration.find(mwmName);
+ bool needUpdateByTimeout = (connectionStatus == Platform::EConnectionType::CONNECTION_WIFI);
+ if (!needUpdateByTimeout && it != m_expiration.end())
+ {
+ auto const currentTime = std::chrono::steady_clock::now();
+ needUpdateByTimeout = currentTime > (it->second + kWWanUpdateTimeout);
+ }
+
+ if (needUpdateByTimeout || it == m_expiration.end())
+ requestedCampaigns.push_back(mwmName);
+ }
+ }
+
+ if (!requestedCampaigns.empty())
+ {
+ m_requestedCampaigns.reserve(m_requestedCampaigns.size() + requestedCampaigns.size());
+ for (auto const & campaign : requestedCampaigns)
+ m_requestedCampaigns.push_back(std::make_pair(m_getMwmIdByNameFn(campaign), RequestType::Download));
+ m_condition.notify_one();
+ }
+ }
+}
+
+void LocalAdsManager::ThreadRoutine()
+{
+ std::string const campaignFile = GetPath(kCampaignFile);
+ std::string const expirationFile = GetPath(kExpirationFile);
+
+ // Read persistence data (expiration file must be read first).
+ ReadExpirationFile(expirationFile);
+ ReadCampaignFile(campaignFile);
+
+ std::vector<Request> campaignMwms;
+ while (WaitForRequest(campaignMwms))
+ {
+ try
+ {
+ FilesContainerW campaignsContainer(campaignFile, FileWriter::OP_WRITE_EXISTING);
+ FilesContainerW expirationContainer(expirationFile, FileWriter::OP_WRITE_EXISTING);
+ for (auto const & mwm : campaignMwms)
+ {
+ if (!mwm.first.IsAlive())
+ continue;
+
+ std::string const countryName = mwm.first.GetInfo()->GetCountryName();
+ if (mwm.second == RequestType::Download)
+ {
+ // Download campaign data from server.
+ std::vector<uint8_t> rawData = DownloadCampaign(mwm.first);
+ if (rawData.empty())
+ continue;
+
+ // Save data persistently.
+ campaignsContainer.Write(rawData, countryName);
+ auto ts = std::chrono::steady_clock::now();
+ expirationContainer.Write(SerializeTimestamp(ts), countryName);
+
+ // Update run-time data.
+ {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ m_campaigns[countryName] = true;
+ m_expiration[countryName] = ts;
+ }
+
+ // Deserialize and send data to rendering.
+ auto symbols = DeserializeCampaign(std::move(rawData), ts);
+ if (symbols.empty())
+ DeleteSymbolsFromRendering(mwm.first);
+ else
+ SendSymbolsToRendering(std::move(symbols));
+ }
+ else if (mwm.second == RequestType::Delete)
+ {
+ campaignsContainer.DeleteSection(countryName);
+ expirationContainer.DeleteSection(countryName);
+ DeleteSymbolsFromRendering(mwm.first);
+ }
+ }
+ campaignsContainer.Finish();
+ expirationContainer.Finish();
+ }
+ catch (RootException const & ex)
+ {
+ LOG(LWARNING, (ex.Msg()));
+ }
+ campaignMwms.clear();
+ }
+}
+
+bool LocalAdsManager::WaitForRequest(std::vector<Request> & campaignMwms)
+{
+ std::unique_lock<std::mutex> lock(m_mutex);
+
+ m_condition.wait(lock, [this] {return !m_isRunning || !m_requestedCampaigns.empty();});
+
+ if (!m_isRunning)
+ return false;
+
+ if (!m_requestedCampaigns.empty())
+ campaignMwms.swap(m_requestedCampaigns);
+
+ return true;
+}
+
+void LocalAdsManager::OnDownloadCountry(std::string const & countryName)
+{
+ std::lock_guard<std::mutex> lock(m_mutex);
+ m_campaigns.erase(countryName);
+ m_expiration.erase(countryName);
+}
+
+void LocalAdsManager::OnDeleteCountry(std::string const & countryName)
+{
+ std::lock_guard<std::mutex> lock(m_mutex);
+ m_campaigns.erase(countryName);
+ m_expiration.erase(countryName);
+ m_requestedCampaigns.push_back(std::make_pair(m_getMwmIdByNameFn(countryName), RequestType::Delete));
+ m_condition.notify_one();
+}
+
+string LocalAdsManager::MakeRemoteURL(MwmSet::MwmId const &mwmId) const
+{
+ // TODO: build correct URL after server completion.
+
+ return "http://172.27.15.68/campaigns.data";
+}
+
+std::vector<uint8_t> LocalAdsManager::DownloadCampaign(MwmSet::MwmId const & mwmId) const
+{
+ platform::HttpClient request(MakeRemoteURL(mwmId));
+ if (!request.RunHttpRequest() || request.ErrorCode() != 200)
+ return std::vector<uint8_t>();
+ string const & response = request.ServerResponse();
+ return std::vector<uint8_t>(response.cbegin(), response.cend());
+}
+
+df::CustomSymbols LocalAdsManager::DeserializeCampaign(std::vector<uint8_t> && rawData,
+ std::chrono::steady_clock::time_point timestamp)
+{
+ df::CustomSymbols symbols;
+ // TODO: Deserialize campaign.
+ // TODO: Filter by timestamp.
+
+ // TEMP!
+ //auto mwmId = m_getMwmIdByNameFn("Russia_Moscow");
+ //symbols.insert(std::make_pair(FeatureID(mwmId, 371323), df::CustomSymbol("test-m", true)));
+ //symbols.insert(std::make_pair(FeatureID(mwmId, 371363), df::CustomSymbol("test-m", true)));
+ //symbols.insert(std::make_pair(FeatureID(mwmId, 373911), df::CustomSymbol("test-m", true)));
+
+ return symbols;
+}
+
+void LocalAdsManager::ReadExpirationFile(std::string const & expirationFile)
+{
+ if (!GetPlatform().IsFileExistsByFullPath(expirationFile))
+ {
+ FilesContainerW f(expirationFile);
+ return;
+ }
+
+ try
+ {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ FilesContainerR expirationContainer(expirationFile);
+ expirationContainer.ForEachTag([this, &expirationContainer](FilesContainerR::Tag const & tag)
+ {
+ m_expiration[tag] = DeserializeTimestamp(expirationContainer.GetReader(tag));
+ });
+ }
+ catch (Reader::Exception const & ex)
+ {
+ LOG(LWARNING, ("Error reading file:", expirationFile, ex.Msg()));
+ }
+}
+
+void LocalAdsManager::ReadCampaignFile(std::string const & campaignFile)
+{
+ if (!GetPlatform().IsFileExistsByFullPath(campaignFile))
+ {
+ FilesContainerW f(campaignFile);
+ return;
+ }
+
+ try
+ {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ df::CustomSymbols allSymbols;
+ FilesContainerR campaignContainer(campaignFile);
+ campaignContainer.ForEachTag([this, &campaignContainer, &allSymbols](FilesContainerR::Tag const & tag)
+ {
+ auto const & reader = campaignContainer.GetReader(tag);
+ std::vector<uint8_t> rawData(reader.Size());
+ reader.Read(0, rawData.data(), rawData.size());
+ m_campaigns[tag] = false;
+
+ ASSERT(m_expiration.find(tag) != m_expiration.end(), ());
+ auto ts = m_expiration[tag];
+ auto const symbols = DeserializeCampaign(std::move(rawData), ts);
+ allSymbols.insert(symbols.begin(), symbols.end());
+ });
+ SendSymbolsToRendering(std::move(allSymbols));
+ }
+ catch (Reader::Exception const & ex)
+ {
+ LOG(LWARNING, ("Error reading file:", campaignFile, ex.Msg()));
+ }
+}
+
+void LocalAdsManager::SendSymbolsToRendering(df::CustomSymbols && symbols)
+{
+ if (symbols.empty())
+ return;
+
+ if (m_drapeEngine == nullptr)
+ {
+ std::lock_guard<std::mutex> lock(m_symbolsCacheMutex);
+ m_symbolsCache.insert(symbols.begin(), symbols.end());
+ return;
+ }
+ m_drapeEngine->AddCustomSymbols(std::move(symbols));
+}
+
+void LocalAdsManager::DeleteSymbolsFromRendering(MwmSet::MwmId const & mwmId)
+{
+ if (m_drapeEngine != nullptr)
+ m_drapeEngine->RemoveCustomSymbols(mwmId);
+}
diff --git a/map/local_ads_manager.hpp b/map/local_ads_manager.hpp
new file mode 100644
index 0000000000..72b64d3115
--- /dev/null
+++ b/map/local_ads_manager.hpp
@@ -0,0 +1,80 @@
+#pragma once
+
+#include "drape_frontend/custom_symbol.hpp"
+
+#include "drape/pointers.hpp"
+
+#include "geometry/rect2d.hpp"
+#include "geometry/screenbase.hpp"
+
+#include "indexer/index.hpp"
+#include "indexer/mwm_set.hpp"
+
+#include "base/thread.hpp"
+
+#include <chrono>
+#include <map>
+#include <mutex>
+#include <string>
+#include <vector>
+
+namespace df
+{
+class DrapeEngine;
+} // namespace df
+
+class LocalAdsManager final
+{
+public:
+ using GetMwmsByRectFn = function<std::vector<MwmSet::MwmId>(m2::RectD const &)>;
+ using GetMwmIdByName = function<MwmSet::MwmId(std::string const &)>;
+
+ LocalAdsManager(GetMwmsByRectFn const & getMwmsByRectFn, GetMwmIdByName const & getMwmIdByName);
+ LocalAdsManager(LocalAdsManager && /* localAdsManager */) = default;
+ ~LocalAdsManager();
+
+ void Teardown();
+ void SetDrapeEngine(ref_ptr<df::DrapeEngine> engine);
+ void UpdateViewport(ScreenBase const & screen);
+
+ void OnDownloadCountry(std::string const & countryName);
+ void OnDeleteCountry(std::string const & countryName);
+
+private:
+ enum class RequestType
+ {
+ Download,
+ Delete
+ };
+ using Request = std::pair<MwmSet::MwmId, RequestType>;
+
+ void ThreadRoutine();
+ bool WaitForRequest(std::vector<Request> & campaignMwms);
+
+ std::string MakeRemoteURL(MwmSet::MwmId const & mwmId) const;
+ std::vector<uint8_t> DownloadCampaign(MwmSet::MwmId const & mwmId) const;
+ df::CustomSymbols DeserializeCampaign(std::vector<uint8_t> && rawData,
+ std::chrono::steady_clock::time_point timestamp);
+ void SendSymbolsToRendering(df::CustomSymbols && symbols);
+ void DeleteSymbolsFromRendering(MwmSet::MwmId const & mwmId);
+
+ void ReadExpirationFile(std::string const & expirationFile);
+ void ReadCampaignFile(std::string const & campaignFile);
+
+ GetMwmsByRectFn m_getMwmsByRectFn;
+ GetMwmIdByName m_getMwmIdByNameFn;
+
+ ref_ptr<df::DrapeEngine> m_drapeEngine;
+
+ std::map<std::string, bool> m_campaigns;
+ std::map<std::string, std::chrono::steady_clock::time_point> m_expiration;
+
+ df::CustomSymbols m_symbolsCache;
+ std::mutex m_symbolsCacheMutex;
+
+ bool m_isRunning = true;
+ std::condition_variable m_condition;
+ std::vector<Request> m_requestedCampaigns;
+ std::mutex m_mutex;
+ threads::SimpleThread m_thread;
+};
diff --git a/map/map.pro b/map/map.pro
index 0d6f9f60fb..6cf25d1408 100644
--- a/map/map.pro
+++ b/map/map.pro
@@ -27,6 +27,7 @@ HEADERS += \
gps_track_filter.hpp \
gps_track_storage.hpp \
gps_tracker.hpp \
+ local_ads_manager.hpp \
mwm_url.hpp \
place_page_info.hpp \
reachable_by_taxi_checker.hpp \
@@ -53,6 +54,7 @@ SOURCES += \
gps_track_filter.cpp \
gps_track_storage.cpp \
gps_tracker.cpp \
+ local_ads_manager.cpp \
mwm_url.cpp \
place_page_info.cpp \
reachable_by_taxi_checker.cpp \