diff --git a/map/framework.cpp b/map/framework.cpp index e9b6316adf..3d4a020aa9 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -275,8 +275,8 @@ void Framework::Migrate(bool keepDownloaded) Storage().DeleteAllLocalMaps(&existedCountries); DeregisterAllMaps(); m_model.Clear(); - Storage().Migrate(keepDownloaded ? existedCountries : TCountriesVec()); InitCountryInfoGetter(); + Storage().Migrate(keepDownloaded ? existedCountries : TCountriesVec()); InitSearchEngine(); RegisterAllMaps(); SetRenderingEnabled(true); @@ -332,7 +332,9 @@ Framework::Framework() LOG(LDEBUG, ("Maps initialized")); // Init storage with needed callback. - m_storage.Init(bind(&Framework::UpdateLatestCountryFile, this, _1)); + m_storage.Init( + bind(&Framework::OnCountryFileDownloaded, this, _1, _2), + bind(&Framework::OnCountryFileDelete, this, _1, _2)); LOG(LDEBUG, ("Storage initialized")); auto const routingStatisticsFn = [](map const & statistics) @@ -464,21 +466,46 @@ void Framework::ShowNode(storage::TCountryId const & countryId) ShowRect(CalcLimitRect(countryId, Storage(), CountryInfoGetter())); } -void Framework::UpdateLatestCountryFile(LocalCountryFile const & localFile) +void Framework::OnCountryFileDownloaded(storage::TCountryId const & countryId, storage::Storage::TLocalFilePtr const localFile) { // Soft reset to signal that mwm file may be out of date in routing caches. m_routingSession.Reset(); - if (!HasOptions(localFile.GetFiles(), MapOptions::Map)) - return; + m2::RectD rect = MercatorBounds::FullRect(); - // Add downloaded map. - auto p = m_model.RegisterMap(localFile); - MwmSet::MwmId const & id = p.first; - if (id.IsAlive()) - InvalidateRect(id.GetInfo()->m_limitRect); + if (localFile && HasOptions(localFile->GetFiles(), MapOptions::Map)) + { + // Add downloaded map. + auto p = m_model.RegisterMap(*localFile); + MwmSet::MwmId const & id = p.first; + if (id.IsAlive()) + rect = id.GetInfo()->m_limitRect; + } + InvalidateRect(rect); + m_searchEngine->ClearCaches(); +} + +bool Framework::OnCountryFileDelete(storage::TCountryId const & countryId, storage::Storage::TLocalFilePtr const localFile) +{ + // Soft reset to signal that mwm file may be out of date in routing caches. + m_routingSession.Reset(); + + if(auto handle = m_lastQueryHandle.lock()) + handle->Cancel(); + + m2::RectD rect = MercatorBounds::FullRect(); + + bool deferredDelete = false; + if (localFile) + { + rect = m_infoGetter->GetLimitRectForLeaf(countryId); + m_model.DeregisterMap(platform::CountryFile(countryId)); + deferredDelete = true; + } + InvalidateRect(rect); m_searchEngine->ClearCaches(); + return deferredDelete; } void Framework::OnMapDeregistered(platform::LocalCountryFile const & localFile) diff --git a/map/framework.hpp b/map/framework.hpp index a34dfba39f..6129a4df4d 100644 --- a/map/framework.hpp +++ b/map/framework.hpp @@ -132,9 +132,13 @@ protected: BookmarkManager m_bmManager; - /// This function is called by m_storage when latest local files - /// were changed. - void UpdateLatestCountryFile(platform::LocalCountryFile const & localFile); + /// 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); + + /// This function will be called by m_storage before latest local files + /// is deleted. + bool OnCountryFileDelete(storage::TCountryId const & countryId, storage::Storage::TLocalFilePtr const localFile); /// This function is called by m_model when the map file is deregistered. void OnMapDeregistered(platform::LocalCountryFile const & localFile); diff --git a/storage/storage.cpp b/storage/storage.cpp index 11b9c94561..2da8724b74 100644 --- a/storage/storage.cpp +++ b/storage/storage.cpp @@ -127,11 +127,12 @@ Storage::Storage(string const & referenceCountriesTxtJsonForTesting, CHECK_LESS_OR_EQUAL(0, m_currentVersion, ("Can't load test countries file")); } -void Storage::Init(TUpdate const & update) +void Storage::Init(TUpdateCallback const & didDownload, TDeleteCallback const & willDelete) { ASSERT_THREAD_CHECKER(m_threadChecker, ()); - m_update = update; + m_didDownload = didDownload; + m_willDelete = willDelete; } void Storage::DeleteAllLocalMaps(TCountriesVec * existedCountries /* = nullptr */) @@ -172,7 +173,9 @@ void Storage::PrefetchMigrateData() m_prefetchStorage.reset(new Storage(COUNTRIES_FILE, "migrate")); m_prefetchStorage->EnableKeepDownloadingQueue(false); - m_prefetchStorage->Init([](LocalCountryFile const &){}); + m_prefetchStorage->Init( + [](TCountryId const &, TLocalFilePtr const){}, + [](TCountryId const &, TLocalFilePtr const){return false;}); if (!m_downloadingUrlsForTesting.empty()) m_prefetchStorage->SetDownloadingUrlsForTesting(m_downloadingUrlsForTesting); } @@ -473,16 +476,15 @@ void Storage::DownloadCountry(TCountryId const & countryId, MapOptions opt) void Storage::DeleteCountry(TCountryId const & countryId, MapOptions opt) { - ASSERT(m_update != nullptr, ("Storage::Init wasn't called")); - - opt = NormalizeDeleteFileSet(opt); - DeleteCountryFiles(countryId, opt); - DeleteCountryFilesFromDownloader(countryId, opt); + ASSERT(m_willDelete != nullptr, ("Storage::Init wasn't called")); TLocalFilePtr localFile = GetLatestLocalFile(countryId); - if (localFile) - m_update(*localFile); - + if(!m_willDelete(countryId, localFile)) + { + opt = NormalizeDeleteFileSet(opt); + DeleteCountryFiles(countryId, opt); + DeleteCountryFilesFromDownloader(countryId, opt); + } NotifyStatusChangedForHierarchy(countryId); } @@ -812,7 +814,7 @@ bool Storage::RegisterDownloadedFiles(TCountryId const & countryId, MapOptions f void Storage::OnMapDownloadFinished(TCountryId const & countryId, bool success, MapOptions files) { - ASSERT(m_update != nullptr, ("Storage::Init wasn't called")); + ASSERT(m_didDownload != nullptr, ("Storage::Init wasn't called")); ASSERT_NOT_EQUAL(MapOptions::Nothing, files, ("This method should not be called for empty files set.")); { @@ -834,7 +836,7 @@ void Storage::OnMapDownloadFinished(TCountryId const & countryId, bool success, TLocalFilePtr localFile = GetLocalFile(countryId, GetCurrentDataVersion()); ASSERT(localFile, ()); DeleteCountryIndexes(*localFile); - m_update(*localFile); + m_didDownload(countryId, localFile); } string Storage::GetFileDownloadUrl(string const & baseUrl, TCountryId const & countryId, diff --git a/storage/storage.hpp b/storage/storage.hpp index 42cd918d8e..afc108f787 100644 --- a/storage/storage.hpp +++ b/storage/storage.hpp @@ -106,7 +106,9 @@ class Storage { public: struct StatusCallback; - using TUpdate = function; + using TLocalFilePtr = shared_ptr; + using TUpdateCallback = function; + using TDeleteCallback = function; using TChangeCountryFunction = function; using TProgressFunction = function; using TQueue = list; @@ -141,7 +143,6 @@ private: /// stores countries whose download has failed recently TCountriesSet m_failedCountries; - using TLocalFilePtr = shared_ptr; map> m_localFiles; // Our World.mwm and WorldCoasts.mwm are fake countries, together with any custom mwm in data @@ -171,8 +172,12 @@ private: //@} // This function is called each time all files requested for a - // country were successfully downloaded. - TUpdate m_update; + // country are successfully downloaded. + TUpdateCallback m_didDownload; + + // This function is called each time all files for a + // country are deleted. + TDeleteCallback m_willDelete; // If |m_dataDir| is not empty Storage will create version directories and download maps in // platform::WritableDir/|m_dataDir|/. Not empty |m_dataDir| can be used only for @@ -246,7 +251,7 @@ public: Storage(string const & referenceCountriesTxtJsonForTesting, unique_ptr mapDownloaderForTesting); - void Init(TUpdate const & update); + void Init(TUpdateCallback const & didDownload, TDeleteCallback const & willDelete); /// @name Interface with clients (Android/iOS). /// \brief It represents the interface which can be used by clients (Android/iOS).