From 515abeed2a658d13864d15c80463f53845738912 Mon Sep 17 00:00:00 2001 From: "r.kuznetsov" Date: Wed, 15 Aug 2018 16:20:37 +0300 Subject: [PATCH] [Core] Added subscription --- android/jni/com/mapswithme/maps/Framework.cpp | 6 ++ coding/sha1.cpp | 24 ++++++- coding/sha1.hpp | 3 + drape_frontend/map_data_provider.cpp | 35 +++++++--- drape_frontend/map_data_provider.hpp | 13 ++-- drape_frontend/rule_drawer.cpp | 7 +- drape_frontend/rule_drawer.hpp | 3 + drape_frontend/tile_info.cpp | 4 +- .../Classes/Widgets/MWMMapDownloadDialog.mm | 2 + iphone/Maps/Core/Search/MWMSearch.mm | 10 ++- local_ads/statistics.cpp | 14 ++++ local_ads/statistics.hpp | 3 + map/CMakeLists.txt | 2 + map/framework.cpp | 44 ++++++++++--- map/framework.hpp | 8 +++ map/local_ads_manager.cpp | 64 +++++++++++++++++-- map/local_ads_manager.hpp | 13 +++- map/subscription.cpp | 60 +++++++++++++++++ map/subscription.hpp | 30 +++++++++ partners_api/partners.cpp | 12 ++++ partners_api/partners.hpp | 1 + xcode/map/map.xcodeproj/project.pbxproj | 14 +++- 22 files changed, 332 insertions(+), 40 deletions(-) create mode 100644 map/subscription.cpp create mode 100644 map/subscription.hpp diff --git a/android/jni/com/mapswithme/maps/Framework.cpp b/android/jni/com/mapswithme/maps/Framework.cpp index 593e14ca31..02639254e0 100644 --- a/android/jni/com/mapswithme/maps/Framework.cpp +++ b/android/jni/com/mapswithme/maps/Framework.cpp @@ -1620,6 +1620,9 @@ Java_com_mapswithme_maps_Framework_nativeDeleteSavedRoutePoints() JNIEXPORT jobjectArray JNICALL Java_com_mapswithme_maps_Framework_nativeGetSearchBanners(JNIEnv * env, jclass) { + auto const & subscription = frm()->GetSubscription(); + if (subscription && subscription->IsActive()) + return nullptr; return usermark_helper::ToBannersArray(env, frm()->GetAdsEngine().GetSearchBanners()); } @@ -1708,6 +1711,9 @@ JNIEXPORT jboolean JNICALL Java_com_mapswithme_maps_Framework_nativeHasMegafonDownloaderBanner(JNIEnv * env, jclass, jstring mwmId) { + auto const & subscription = frm()->GetSubscription(); + if (subscription && subscription->IsActive()) + return static_cast(false); return static_cast(ads::HasMegafonDownloaderBanner(frm()->GetStorage(), jni::ToNativeString(env, mwmId), languages::GetCurrentNorm())); diff --git a/coding/sha1.cpp b/coding/sha1.cpp index 4a072e3fc2..7a6c2515db 100644 --- a/coding/sha1.cpp +++ b/coding/sha1.cpp @@ -11,6 +11,7 @@ #include "3party/liboauthcpp/src/base64.h" #include +#include namespace coding { @@ -50,7 +51,28 @@ SHA1::Hash SHA1::Calculate(std::string const & filePath) // static std::string SHA1::CalculateBase64(std::string const & filePath) { - auto sha1 = Calculate(filePath); + auto const sha1 = Calculate(filePath); + return base64_encode(sha1.data(), sha1.size()); +} + +// static +SHA1::Hash SHA1::CalculateForString(std::string const & str) +{ + CSHA1 sha1; + std::vector dat(str.begin(), str.end()); + sha1.Update(dat.data(), static_cast(dat.size())); + sha1.Final(); + + Hash result; + ASSERT_EQUAL(result.size(), ARRAY_SIZE(sha1.m_digest), ()); + std::copy(std::begin(sha1.m_digest), std::end(sha1.m_digest), std::begin(result)); + return result; +} + +// static +std::string SHA1::CalculateBase64ForString(std::string const & str) +{ + auto const sha1 = CalculateForString(str); return base64_encode(sha1.data(), sha1.size()); } } // coding diff --git a/coding/sha1.hpp b/coding/sha1.hpp index d46a718028..e0ad4ad225 100644 --- a/coding/sha1.hpp +++ b/coding/sha1.hpp @@ -13,5 +13,8 @@ public: static Hash Calculate(std::string const & filePath); static std::string CalculateBase64(std::string const & filePath); + + static Hash CalculateForString(std::string const & str); + static std::string CalculateBase64ForString(std::string const & str); }; } // coding diff --git a/drape_frontend/map_data_provider.cpp b/drape_frontend/map_data_provider.cpp index e47d4fd112..b587392042 100644 --- a/drape_frontend/map_data_provider.cpp +++ b/drape_frontend/map_data_provider.cpp @@ -1,16 +1,28 @@ #include "drape_frontend/map_data_provider.hpp" +#include "base/assert.hpp" + +#include + namespace df { -MapDataProvider::MapDataProvider(TReadIDsFn const & idsReader, - TReadFeaturesFn const & featureReader, - TIsCountryLoadedByNameFn const & isCountryLoadedByNameFn, - TUpdateCurrentCountryFn const & updateCurrentCountryFn) - : m_isCountryLoadedByName(isCountryLoadedByNameFn) - , m_featureReader(featureReader) - , m_idsReader(idsReader) - , m_updateCurrentCountry(updateCurrentCountryFn) -{} +MapDataProvider::MapDataProvider(TReadIDsFn && idsReader, + TReadFeaturesFn && featureReader, + TFilterFeatureFn && filterFeatureFn, + TIsCountryLoadedByNameFn && isCountryLoadedByNameFn, + TUpdateCurrentCountryFn && updateCurrentCountryFn) + : m_isCountryLoadedByName(std::move(isCountryLoadedByNameFn)) + , m_featureReader(std::move(featureReader)) + , m_idsReader(std::move(idsReader)) + , m_filterFeature(std::move(filterFeatureFn)) + , m_updateCurrentCountry(std::move(updateCurrentCountryFn)) +{ + CHECK(m_isCountryLoadedByName != nullptr, ()); + CHECK(m_featureReader != nullptr, ()); + CHECK(m_idsReader != nullptr, ()); + CHECK(m_filterFeature != nullptr, ()); + CHECK(m_updateCurrentCountry != nullptr, ()); +} void MapDataProvider::ReadFeaturesID(TReadCallback const & fn, m2::RectD const & r, int scale) const @@ -24,6 +36,11 @@ void MapDataProvider::ReadFeatures(TReadCallback const & fn, m_featureReader(fn, ids); } +MapDataProvider::TFilterFeatureFn const & MapDataProvider::GetFilter() const +{ + return m_filterFeature; +} + MapDataProvider::TUpdateCurrentCountryFn const & MapDataProvider::UpdateCurrentCountryFn() const { return m_updateCurrentCountry; diff --git a/drape_frontend/map_data_provider.hpp b/drape_frontend/map_data_provider.hpp index b3da94b7d2..7424d2c107 100644 --- a/drape_frontend/map_data_provider.hpp +++ b/drape_frontend/map_data_provider.hpp @@ -22,16 +22,20 @@ public: using TIsCountryLoadedFn = std::function; using TIsCountryLoadedByNameFn = std::function; using TUpdateCurrentCountryFn = std::function; + using TFilterFeatureFn = std::function; - MapDataProvider(TReadIDsFn const & idsReader, - TReadFeaturesFn const & featureReader, - TIsCountryLoadedByNameFn const & isCountryLoadedByNameFn, - TUpdateCurrentCountryFn const & updateCurrentCountryFn); + MapDataProvider(TReadIDsFn && idsReader, + TReadFeaturesFn && featureReader, + TFilterFeatureFn && filterFeatureFn, + TIsCountryLoadedByNameFn && isCountryLoadedByNameFn, + TUpdateCurrentCountryFn && updateCurrentCountryFn); void ReadFeaturesID(TReadCallback const & fn, m2::RectD const & r, int scale) const; void ReadFeatures(TReadCallback const & fn, std::vector const & ids) const; + TFilterFeatureFn const & GetFilter() const; + TUpdateCurrentCountryFn const & UpdateCurrentCountryFn() const; TIsCountryLoadedByNameFn m_isCountryLoadedByName; @@ -39,6 +43,7 @@ public: private: TReadFeaturesFn m_featureReader; TReadIDsFn m_idsReader; + TFilterFeatureFn m_filterFeature; TUpdateCurrentCountryFn m_updateCurrentCountry; }; } // namespace df diff --git a/drape_frontend/rule_drawer.cpp b/drape_frontend/rule_drawer.cpp index d5ead86425..31d4243db8 100644 --- a/drape_frontend/rule_drawer.cpp +++ b/drape_frontend/rule_drawer.cpp @@ -173,20 +173,22 @@ bool UsePreciseFeatureCenter(FeatureType & f) namespace df { - RuleDrawer::RuleDrawer(TDrawerCallback const & drawerFn, TCheckCancelledCallback const & checkCancelled, TIsCountryLoadedByNameFn const & isLoadedFn, + TFilterFeatureFn const & filterFn, ref_ptr engineContext) : m_callback(drawerFn) , m_checkCancelled(checkCancelled) , m_isLoadedFn(isLoadedFn) + , m_filter(filterFn) , m_context(engineContext) , m_customFeaturesContext(engineContext->GetCustomFeaturesContext().lock()) , m_wasCancelled(false) { ASSERT(m_callback != nullptr, ()); ASSERT(m_checkCancelled != nullptr, ()); + ASSERT(m_filter != nullptr, ()); m_globalRect = m_context->GetTileKey().GetGlobalRect(); @@ -466,6 +468,9 @@ void RuleDrawer::operator()(FeatureType & f) if (CheckCancelled()) return; + if (m_filter(f)) + return; + Stylist s; m_callback(f, s); diff --git a/drape_frontend/rule_drawer.hpp b/drape_frontend/rule_drawer.hpp index b09b990871..24222e3684 100644 --- a/drape_frontend/rule_drawer.hpp +++ b/drape_frontend/rule_drawer.hpp @@ -33,10 +33,12 @@ public: using TCheckCancelledCallback = std::function; using TIsCountryLoadedByNameFn = std::function; using TInsertShapeFn = function && shape)>; + using TFilterFeatureFn = std::function; RuleDrawer(TDrawerCallback const & drawerFn, TCheckCancelledCallback const & checkCancelled, TIsCountryLoadedByNameFn const & isLoadedFn, + TFilterFeatureFn const & filterFn, ref_ptr engineContext); ~RuleDrawer(); @@ -61,6 +63,7 @@ private: TDrawerCallback m_callback; TCheckCancelledCallback m_checkCancelled; TIsCountryLoadedByNameFn m_isLoadedFn; + TFilterFeatureFn m_filter; ref_ptr m_context; CustomFeaturesContextPtr m_customFeaturesContext; diff --git a/drape_frontend/tile_info.cpp b/drape_frontend/tile_info.cpp index 2836609615..c151c9efa7 100644 --- a/drape_frontend/tile_info.cpp +++ b/drape_frontend/tile_info.cpp @@ -73,8 +73,8 @@ void TileInfo::ReadFeatures(MapDataProvider const & model) std::sort(m_featureInfo.begin(), m_featureInfo.end()); auto const deviceLang = StringUtf8Multilang::GetLangIndex(languages::GetCurrentNorm()); RuleDrawer drawer(std::bind(&TileInfo::InitStylist, this, deviceLang, _1, _2), - std::bind(&TileInfo::IsCancelled, this), - model.m_isCountryLoadedByName, make_ref(m_context)); + std::bind(&TileInfo::IsCancelled, this), model.m_isCountryLoadedByName, + model.GetFilter(), make_ref(m_context)); model.ReadFeatures(std::bind(std::ref(drawer), _1), m_featureInfo); } #if defined(DRAPE_MEASURER) && defined(TILES_STATISTIC) diff --git a/iphone/Maps/Classes/Widgets/MWMMapDownloadDialog.mm b/iphone/Maps/Classes/Widgets/MWMMapDownloadDialog.mm index 466e8ffa93..8fb9409ef6 100644 --- a/iphone/Maps/Classes/Widgets/MWMMapDownloadDialog.mm +++ b/iphone/Maps/Classes/Widgets/MWMMapDownloadDialog.mm @@ -43,6 +43,8 @@ BOOL canAutoDownload(storage::TCountryId const & countryId) BOOL shouldShowBanner(std::string const & mwmId) { + if (GetFramework().GetSubscription()->IsActive()) + return NO; return ads::HasMegafonDownloaderBanner(GetFramework().GetStorage(), mwmId, languages::GetCurrentNorm()); } diff --git a/iphone/Maps/Core/Search/MWMSearch.mm b/iphone/Maps/Core/Search/MWMSearch.mm index a9c3cb715f..de37bd79d1 100644 --- a/iphone/Maps/Core/Search/MWMSearch.mm +++ b/iphone/Maps/Core/Search/MWMSearch.mm @@ -263,7 +263,10 @@ booking::filter::Tasks MakeBookingFilterTasks(booking::filter::Params && availab manager->m_viewportParams.m_query = text; manager.textChanged = YES; auto const & adsEngine = GetFramework().GetAdsEngine(); - if (![MWMSettings adForbidden] && adsEngine.HasSearchBanner()) + auto const & subscription = GetFramework().GetSubscription(); + bool const hasSubscription = subscription && !subscription->IsActive(); + + if (hasSubscription && ![MWMSettings adForbidden] && adsEngine.HasSearchBanner()) { auto coreBanners = banner_helpers::MatchPriorityBanners(adsEngine.GetSearchBanners(), manager.lastQuery); [[MWMBannersCache cache] refreshWithCoreBanners:coreBanners]; @@ -410,7 +413,10 @@ booking::filter::Tasks MakeBookingFilterTasks(booking::filter::Params && availab if (resultsCount > 0) { auto const & adsEngine = GetFramework().GetAdsEngine(); - if (![MWMSettings adForbidden] && adsEngine.HasSearchBanner()) + auto const & subscription = GetFramework().GetSubscription(); + bool const hasSubscription = subscription && !subscription->IsActive(); + + if (hasSubscription && ![MWMSettings adForbidden] && adsEngine.HasSearchBanner()) { self.banners = [[MWMSearchBanners alloc] initWithSearchIndex:itemsIndex]; __weak auto weakSelf = self; diff --git a/local_ads/statistics.cpp b/local_ads/statistics.cpp index 41ce9d9ae6..4c7e5f8599 100644 --- a/local_ads/statistics.cpp +++ b/local_ads/statistics.cpp @@ -245,6 +245,7 @@ Statistics::Statistics() void Statistics::Startup() { + m_isEnabled = true; GetPlatform().RunTask(Platform::Thread::File, [this] { IndexMetadata(); @@ -254,15 +255,25 @@ void Statistics::Startup() void Statistics::RegisterEvent(Event && event) { + if (!m_isEnabled) + return; + RegisterEvents({std::move(event)}); } void Statistics::RegisterEvents(std::list && events) { + if (!m_isEnabled) + return; GetPlatform().RunTask(Platform::Thread::File, std::bind(&Statistics::ProcessEvents, this, std::move(events))); } +void Statistics::SetEnabled(bool isEnabled) +{ + m_isEnabled = isEnabled; +} + std::list Statistics::WriteEvents(std::list & events, std::string & fileNameToRebuild) { try @@ -379,6 +390,9 @@ void Statistics::ProcessEvents(std::list & events) void Statistics::SendToServer() { + if (!m_isEnabled) + return; + if (CanUpload()) { for (auto it = m_metadataCache.begin(); it != m_metadataCache.end(); ++it) diff --git a/local_ads/statistics.hpp b/local_ads/statistics.hpp index 3b8d20068e..2fc8dcc9c4 100644 --- a/local_ads/statistics.hpp +++ b/local_ads/statistics.hpp @@ -4,6 +4,7 @@ #include "base/thread.hpp" +#include #include #include #include @@ -36,6 +37,7 @@ public: void Startup(); void RegisterEvent(Event && event); void RegisterEvents(std::list && events); + void SetEnabled(bool isEnabled); std::list WriteEventsForTesting(std::list const & events, std::string & fileNameToRebuild); @@ -67,6 +69,7 @@ private: void SendFileWithMetadata(MetadataKey && metadataKey, Metadata && metadata); std::string const m_userId; + bool m_isEnabled = false; std::map m_metadataCache; }; } // namespace local_ads diff --git a/map/CMakeLists.txt b/map/CMakeLists.txt index 550ed86213..667095dc12 100644 --- a/map/CMakeLists.txt +++ b/map/CMakeLists.txt @@ -90,6 +90,8 @@ set( search_mark.cpp search_mark.hpp search_product_info.hpp + subscription.cpp + subscription.hpp taxi_delegate.cpp taxi_delegate.hpp track.cpp diff --git a/map/framework.cpp b/map/framework.cpp index 4cae3a1207..bf59ddf866 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -388,6 +388,7 @@ Framework::Framework(FrameworkParams const & params) }) , m_lastReportedCountry(kInvalidCountryId) , m_popularityLoader(m_model.GetDataSource()) + , m_subscription(std::make_unique()) { m_startBackgroundTime = my::Timer::LocalTime(); @@ -468,7 +469,10 @@ Framework::Framework(FrameworkParams const & params) // Local ads manager should be initialized after storage initialization. if (params.m_enableLocalAds) - m_localAdsManager.Startup(m_bmManager.get()); + { + m_localAdsManager.Startup(m_bmManager.get(), m_subscription->IsActive()); + m_subscription->Register(&m_localAdsManager); + } m_routingManager.SetRouterImpl(RouterType::Vehicle); @@ -496,12 +500,18 @@ Framework::Framework(FrameworkParams const & params) InitTransliteration(); LOG(LDEBUG, ("Transliterators initialized")); + + m_subscription->Validate(); } Framework::~Framework() { m_threadRunner.reset(); + // Must be destroyed implicitly at the start of destruction, + // since it stores raw pointers to other subsystems. + m_subscription.reset(); + osm::Editor & editor = osm::Editor::Instance(); editor.SetDelegate({}); @@ -513,7 +523,7 @@ Framework::~Framework() m_model.SetOnMapDeregisteredCallback(nullptr); m_user.ClearSubscribers(); - // Must be destroyed implicitly since it stores reference to m_user. + // Must be destroyed implicitly, since it stores reference to m_user. m_bmManager.reset(); } @@ -865,7 +875,7 @@ void Framework::FillInfoFromFeatureType(FeatureType & ft, place_page::Info & inf info.SetBookingSearchUrl(url); LOG(LINFO, (url)); } - else if (PartnerChecker::Instance()(ft)) + else if (m_subscription && !m_subscription->IsActive() && PartnerChecker::Instance()(ft)) { info.SetSponsoredType(place_page::SponsoredType::Partner); auto const partnerIndex = PartnerChecker::Instance().GetPartnerIndex(ft); @@ -1489,11 +1499,14 @@ search::DisplayedCategories const & Framework::GetDisplayedCategories() city = m_cityFinder->GetCityName(*position, StringUtf8Multilang::kEnglishCode); // Apply sponsored modifiers. - std::tuple modifiers(city); - my::for_each_in_tuple(modifiers, [&](size_t, SponsoredCategoryModifier & modifier) + if (m_subscription && !m_subscription->IsActive()) { - m_displayedCategories->Modify(modifier); - }); + std::tuple modifiers(city); + my::for_each_in_tuple(modifiers, [&](size_t, SponsoredCategoryModifier & modifier) + { + m_displayedCategories->Modify(modifier); + }); + } return *m_displayedCategories; } @@ -1519,7 +1532,9 @@ void Framework::SelectSearchResult(search::Result const & result, bool animation case Result::Type::PureSuggest: ASSERT(false, ("Suggests should not be here.")); return; } - info.SetAdsEngine(m_adsEngine.get()); + if (m_subscription && !m_subscription->IsActive()) + info.SetAdsEngine(m_adsEngine.get()); + SetPlacePageLocation(info); m2::PointD const center = info.GetMercator(); if (m_drapeEngine != nullptr) @@ -1721,6 +1736,13 @@ void Framework::CreateDrapeEngine(ref_ptr contextFac }); }; + auto filterFeatureFn = [this](FeatureType & ft) -> bool + { + if (m_subscription && !m_subscription->IsActive()) + return false; + return PartnerChecker::Instance().IsFakeObject(ft); + }; + auto overlaysShowStatsFn = [this](list && events) { if (events.empty()) @@ -1763,7 +1785,8 @@ void Framework::CreateDrapeEngine(ref_ptr contextFac df::DrapeEngine::Params p( params.m_apiVersion, contextFactory, dp::Viewport(0, 0, params.m_surfaceWidth, params.m_surfaceHeight), - df::MapDataProvider(idReadFn, featureReadFn, isCountryLoadedByNameFn, updateCurrentCountryFn), + df::MapDataProvider(move(idReadFn), move(featureReadFn), move(filterFeatureFn), + move(isCountryLoadedByNameFn), move(updateCurrentCountryFn)), params.m_hints, params.m_visualScale, fontsScaleFactor, move(params.m_widgetsInitInfo), make_pair(params.m_initialMyPositionState, params.m_hasMyPositionState), move(myPositionModeChangedFn), allow3dBuildings, trafficEnabled, @@ -2315,7 +2338,8 @@ df::SelectionShape::ESelectedObject Framework::OnTapEventImpl(TapEvent const & t return df::SelectionShape::OBJECT_MY_POSITION; } - outInfo.SetAdsEngine(m_adsEngine.get()); + if (m_subscription && !m_subscription->IsActive()) + outInfo.SetAdsEngine(m_adsEngine.get()); UserMark const * mark = FindUserMarkInTapPosition(tapInfo); if (mark != nullptr) diff --git a/map/framework.hpp b/map/framework.hpp index c7c3beec1c..5faddb1d88 100644 --- a/map/framework.hpp +++ b/map/framework.hpp @@ -15,6 +15,7 @@ #include "map/routing_mark.hpp" #include "map/search_api.hpp" #include "map/search_mark.hpp" +#include "map/subscription.hpp" #include "map/track.hpp" #include "map/traffic_manager.hpp" #include "map/transit/transit_reader.hpp" @@ -871,4 +872,11 @@ public: private: // m_discoveryManager must be bellow m_searchApi, m_viatorApi, m_localsApi unique_ptr m_discoveryManager; + +public: + std::unique_ptr const & GetSubscription() const { return m_subscription; } + std::unique_ptr & GetSubscription() { return m_subscription; } + +private: + std::unique_ptr m_subscription; }; diff --git a/map/local_ads_manager.cpp b/map/local_ads_manager.cpp index a500b22848..7401ca5206 100644 --- a/map/local_ads_manager.cpp +++ b/map/local_ads_manager.cpp @@ -282,6 +282,7 @@ LocalAdsManager::LocalAdsManager(GetMwmsByRectFn && getMwmsByRectFn, , m_getMwmIdByNameFn(std::move(getMwmIdByName)) , m_readFeaturesFn(std::move(readFeaturesFn)) , m_getFeatureByIdFn(std::move(getFeatureByIDFn)) + , m_isStarted(false) , m_bmManager(nullptr) { CHECK(m_getMwmsByRectFn != nullptr, ()); @@ -290,14 +291,21 @@ LocalAdsManager::LocalAdsManager(GetMwmsByRectFn && getMwmsByRectFn, CHECK(m_getFeatureByIdFn != nullptr, ()); } -void LocalAdsManager::Startup(BookmarkManager * bmManager) +void LocalAdsManager::Startup(BookmarkManager * bmManager, bool isEnabled) { + m_isEnabled = isEnabled; FillSupportedTypes(); + m_bmManager = bmManager; - GetPlatform().RunTask(Platform::Thread::File, [this, bmManager] + if (isEnabled) + Start(); +} + +void LocalAdsManager::Start() +{ + m_isStarted = true; + GetPlatform().RunTask(Platform::Thread::File, [this] { - m_bmManager = bmManager; - local_ads::IconsInfo::Instance().SetSourceFile(kLocalAdsSymbolsFile); std::string const campaignFile = GetPath(kCampaignFile); @@ -319,8 +327,9 @@ void LocalAdsManager::SetDrapeEngine(ref_ptr engine) void LocalAdsManager::UpdateViewport(ScreenBase const & screen) { auto const connectionStatus = GetPlatform().ConnectionStatus(); - if (kServerUrl.empty() || connectionStatus == Platform::EConnectionType::CONNECTION_NONE || - df::GetZoomLevel(screen.GetScale()) < kRequestMinZoomLevel) + if (!m_isStarted || !m_isEnabled || kServerUrl.empty() || + connectionStatus == Platform::EConnectionType::CONNECTION_NONE || + df::GetZoomLevel(screen.GetScale()) < kRequestMinZoomLevel) { return; } @@ -646,6 +655,49 @@ std::string LocalAdsManager::GetCompanyUrl(FeatureID const & featureId) const return MakeCampaignPageURL(featureId); } +void LocalAdsManager::OnSubscriptionChanged(bool isActive) +{ + bool enabled = !isActive; + if (m_isEnabled == enabled) + return; + + m_isEnabled = enabled; + if (enabled) + { + if (!m_isStarted) + Start(); + else + Invalidate(); + } + else + { + GetPlatform().RunTask(Platform::Thread::File, [this] + { + // Clear campaigns data. + { + std::lock_guard lock(m_campaignsMutex); + m_campaigns.clear(); + m_info.clear(); + m_failedDownloads.clear(); + m_downloadingMwms.clear(); + } + + // Clear features cache. + { + std::lock_guard lock(m_featuresCacheMutex); + m_featuresCache.clear(); + } + + // Clear all graphics. + DeleteAllLocalAdsMarks(m_bmManager); + m_drapeEngine.SafeCall(&df::DrapeEngine::RemoveAllCustomFeatures); + }); + + // Disable statistics collection. + m_statistics.SetEnabled(false); + } +} + bool LocalAdsManager::BackoffStats::CanRetry() const { return !m_fileIsAbsent && m_attemptsCount < kMaxDownloadingAttempts && diff --git a/map/local_ads_manager.hpp b/map/local_ads_manager.hpp index 6a28ba4eb8..e46bd00776 100644 --- a/map/local_ads_manager.hpp +++ b/map/local_ads_manager.hpp @@ -1,5 +1,7 @@ #pragma once +#include "map/subscription.hpp" + #include "local_ads/statistics.hpp" #include "drape_frontend/custom_features_context.hpp" @@ -32,7 +34,7 @@ class TypesHolder; class BookmarkManager; -class LocalAdsManager final +class LocalAdsManager : public SubscriptionListener { public: using GetMwmsByRectFn = std::function(m2::RectD const &)>; @@ -47,7 +49,7 @@ public: ReadFeaturesFn && readFeaturesFn, GetFeatureByIdFn && getFeatureByIDFn); LocalAdsManager(LocalAdsManager && /* localAdsManager */) = default; - void Startup(BookmarkManager * bmManager); + void Startup(BookmarkManager * bmManager, bool isEnabled); void SetDrapeEngine(ref_ptr engine); void UpdateViewport(ScreenBase const & screen); @@ -64,6 +66,8 @@ public: std::string GetCompanyUrl(FeatureID const & featureId) const; + void OnSubscriptionChanged(bool isActive) override; + private: enum class RequestType { @@ -72,6 +76,8 @@ private: }; using Request = std::pair; + void Start(); + void ProcessRequests(std::set && campaignMwms); void ReadCampaignFile(std::string const & campaignFile); @@ -93,6 +99,8 @@ private: ReadFeaturesFn const m_readFeaturesFn; GetFeatureByIdFn const m_getFeatureByIdFn; + std::atomic m_isStarted; + std::atomic m_bmManager; df::DrapeEngineSafePtr m_drapeEngine; @@ -134,4 +142,5 @@ private: std::set m_downloadingMwms; local_ads::Statistics m_statistics; + std::atomic m_isEnabled; }; diff --git a/map/subscription.cpp b/map/subscription.cpp new file mode 100644 index 0000000000..437f232589 --- /dev/null +++ b/map/subscription.cpp @@ -0,0 +1,60 @@ +#include "map/subscription.hpp" + +#include "platform/platform.hpp" + +#include "coding/sha1.hpp" + +#include "base/assert.hpp" + +namespace +{ +std::string const kSubscriptionId = "SubscriptionId"; + +std::string GetSubscriptionId() +{ + return coding::SHA1::CalculateBase64ForString(GetPlatform().UniqueClientId()); +} +} // namespace + +Subscription::Subscription() +{ + std::string id; + if (GetPlatform().GetSecureStorage().Load(kSubscriptionId, id)) + m_subscriptionId = id; + m_isActive = (GetSubscriptionId() == m_subscriptionId); +} + +void Subscription::Register(SubscriptionListener * listener) +{ + CHECK(listener != nullptr, ()); + CHECK_THREAD_CHECKER(m_threadChecker, ()); + m_listeners.emplace_back(listener); + listener->OnSubscriptionChanged(IsActive()); +} + +bool Subscription::IsActive() const +{ + return m_isActive; +} + +void Subscription::Validate() +{ + CHECK_THREAD_CHECKER(m_threadChecker, ()); + + //TODO: check on server. + bool isValid = false; + + m_isActive = isValid; + if (isValid) + { + m_subscriptionId = GetSubscriptionId(); + GetPlatform().GetSecureStorage().Save(kSubscriptionId, m_subscriptionId); + } + else + { + GetPlatform().GetSecureStorage().Remove(kSubscriptionId); + } + + for (auto & listener : m_listeners) + listener->OnSubscriptionChanged(isValid); +} diff --git a/map/subscription.hpp b/map/subscription.hpp new file mode 100644 index 0000000000..793135c231 --- /dev/null +++ b/map/subscription.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include "base/thread_checker.hpp" + +#include +#include +#include + +class SubscriptionListener +{ +public: + virtual ~SubscriptionListener() = default; + virtual void OnSubscriptionChanged(bool isActive) = 0; +}; + +class Subscription +{ +public: + Subscription(); + void Register(SubscriptionListener * listener); + bool IsActive() const; + void Validate(); + +private: + std::atomic m_isActive; + std::string m_subscriptionId; + std::vector m_listeners; + + ThreadChecker m_threadChecker; +}; diff --git a/partners_api/partners.cpp b/partners_api/partners.cpp index b70ce77495..8e4a0309ef 100644 --- a/partners_api/partners.cpp +++ b/partners_api/partners.cpp @@ -87,6 +87,18 @@ int PartnerChecker::GetPartnerIndex(FeatureType & ft) const return kFakePartnerIndex; } +bool PartnerChecker::IsFakeObject(FeatureType & ft) const +{ + // An object is fake one if it contains only sponsored-partnerX types. + auto const types = feature::TypesHolder(ft); + for (auto t : types) + { + if (std::find(m_types.begin(), m_types.end(), PrepareToMatch(t, 2 /* level */)) == m_types.end()) + return false; + } + return true; +} + std::vector const & GetPartners() { return kPartners; diff --git a/partners_api/partners.hpp b/partners_api/partners.hpp index 7c90b33418..0b51bdae81 100644 --- a/partners_api/partners.hpp +++ b/partners_api/partners.hpp @@ -41,6 +41,7 @@ protected: public: int GetPartnerIndex(FeatureType & ft) const; + bool IsFakeObject(FeatureType & ft) const; DECLARE_CHECKER_INSTANCE(PartnerChecker); }; diff --git a/xcode/map/map.xcodeproj/project.pbxproj b/xcode/map/map.xcodeproj/project.pbxproj index 63203d9184..8731c2a877 100644 --- a/xcode/map/map.xcodeproj/project.pbxproj +++ b/xcode/map/map.xcodeproj/project.pbxproj @@ -75,6 +75,8 @@ 3DA5723120C195ED007BDE27 /* everywhere_search_callback.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3DA5722D20C195EC007BDE27 /* everywhere_search_callback.hpp */; }; 3DA5723220C195ED007BDE27 /* everywhere_search_callback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DA5722E20C195EC007BDE27 /* everywhere_search_callback.cpp */; }; 3DA5723320C195ED007BDE27 /* viewport_search_callback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DA5722F20C195EC007BDE27 /* viewport_search_callback.cpp */; }; + 4503559A21245A4100FDFEA5 /* subscription.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 4503559821245A4000FDFEA5 /* subscription.hpp */; }; + 4503559B21245A4100FDFEA5 /* subscription.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4503559921245A4000FDFEA5 /* subscription.cpp */; }; 45201E931CE4AC90008A4842 /* api_mark_point.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 45201E921CE4AC90008A4842 /* api_mark_point.cpp */; }; 454523A9202A0068009275C1 /* cloud.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 454523A7202A0067009275C1 /* cloud.cpp */; }; 454523AA202A0068009275C1 /* cloud.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 454523A8202A0067009275C1 /* cloud.hpp */; }; @@ -292,6 +294,8 @@ 3DA5722D20C195EC007BDE27 /* everywhere_search_callback.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = everywhere_search_callback.hpp; sourceTree = ""; }; 3DA5722E20C195EC007BDE27 /* everywhere_search_callback.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = everywhere_search_callback.cpp; sourceTree = ""; }; 3DA5722F20C195EC007BDE27 /* viewport_search_callback.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = viewport_search_callback.cpp; sourceTree = ""; }; + 4503559821245A4000FDFEA5 /* subscription.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = subscription.hpp; sourceTree = ""; }; + 4503559921245A4000FDFEA5 /* subscription.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = subscription.cpp; sourceTree = ""; }; 45201E921CE4AC90008A4842 /* api_mark_point.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = api_mark_point.cpp; sourceTree = ""; }; 454523A7202A0067009275C1 /* cloud.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cloud.cpp; sourceTree = ""; }; 454523A8202A0067009275C1 /* cloud.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = cloud.hpp; sourceTree = ""; }; @@ -708,9 +712,6 @@ 675345BD1A4054AD00A0A8C3 /* map */ = { isa = PBXGroup; children = ( - 3D62CBCB20F4DFD600E7BB6E /* search_product_info.hpp */, - 56C1165E2090E5670068BBC0 /* extrapolator.cpp */, - 56C1165F2090E5670068BBC0 /* extrapolator.hpp */, 675345CB1A4054E800A0A8C3 /* address_finder.cpp */, 45201E921CE4AC90008A4842 /* api_mark_point.cpp */, 34921F611BFA0A6900737D6E /* api_mark_point.hpp */, @@ -745,6 +746,8 @@ 3DA5722E20C195EC007BDE27 /* everywhere_search_callback.cpp */, 3DA5722D20C195EC007BDE27 /* everywhere_search_callback.hpp */, 3D4E99801FB462B60025B48C /* everywhere_search_params.hpp */, + 56C1165E2090E5670068BBC0 /* extrapolator.cpp */, + 56C1165F2090E5670068BBC0 /* extrapolator.hpp */, 675345F31A4054E800A0A8C3 /* feature_vec_model.cpp */, 675345F41A4054E800A0A8C3 /* feature_vec_model.hpp */, F6D67CE22063F4980032FD38 /* framework_light.hpp */, @@ -785,6 +788,9 @@ 45F6EE9A1FB1C77500019892 /* search_api.hpp */, 456E1B381F9A3C29009C32E1 /* search_mark.cpp */, 456E1B391F9A3C2A009C32E1 /* search_mark.hpp */, + 3D62CBCB20F4DFD600E7BB6E /* search_product_info.hpp */, + 4503559921245A4000FDFEA5 /* subscription.cpp */, + 4503559821245A4000FDFEA5 /* subscription.hpp */, 3D47B2901F054BC5000828D2 /* taxi_delegate.cpp */, 3D47B2911F054BC5000828D2 /* taxi_delegate.hpp */, 6753462C1A4054E800A0A8C3 /* track.cpp */, @@ -852,6 +858,7 @@ 3D62CBCC20F4DFD600E7BB6E /* search_product_info.hpp in Headers */, F69687C8201B4A3600457650 /* discovery_search_params.hpp in Headers */, 3D4E99831FB462B60025B48C /* viewport_search_params.hpp in Headers */, + 4503559A21245A4100FDFEA5 /* subscription.hpp in Headers */, 34583BD01C88556800F94664 /* place_page_info.hpp in Headers */, 34921F661BFA0A6900737D6E /* api_mark_point.hpp in Headers */, 3D4E99821FB462B60025B48C /* everywhere_search_params.hpp in Headers */, @@ -1089,6 +1096,7 @@ BBA014B220754997007402E4 /* user_mark_id_storage.cpp in Sources */, 6753464A1A4054E800A0A8C3 /* bookmark.cpp in Sources */, 45580ABE1E2CBD5E00CD535D /* benchmark_tools.cpp in Sources */, + 4503559B21245A4100FDFEA5 /* subscription.cpp in Sources */, 3DA5723220C195ED007BDE27 /* everywhere_search_callback.cpp in Sources */, BBD9E2C61EE9D01900DF189A /* routing_mark.cpp in Sources */, );