diff --git a/map/framework.cpp b/map/framework.cpp index 46b7c68f4..25a63094e 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -374,6 +374,8 @@ Framework::Framework(FrameworkParams const & params, bool loadMaps) editor.SetDelegate(make_unique(m_featuresFetcher.GetDataSource())); editor.SetInvalidateFn([this](){ InvalidateRect(GetCurrentViewport()); }); + if (params.m_trafficTestMode) + m_trafficManager.SetTestMode(); m_trafficManager.SetCurrentDataVersion(m_storage.GetCurrentDataVersion()); m_trafficManager.SetSimplifiedColorScheme(LoadTrafficSimplifiedColors()); diff --git a/map/framework.hpp b/map/framework.hpp index 51ad421cc..c98d03490 100644 --- a/map/framework.hpp +++ b/map/framework.hpp @@ -98,11 +98,22 @@ class Loader; /// build version for screenshots. //#define FIXED_LOCATION +/** + * @brief Initialization parameters for the framework. + * + * `FrameworkParams` is intended for parameters which are hardcoded rather than read from a + * configuration. It allows test cases to run on a tailored configuration. + */ struct FrameworkParams { bool m_enableDiffs = true; size_t m_numSearchAPIThreads = 1; + /** + * @brief Whether the traffic manager should start in test mode. + */ + bool m_trafficTestMode = false; + FrameworkParams() = default; FrameworkParams(bool enableDiffs) : m_enableDiffs(enableDiffs) diff --git a/map/traffic_manager.cpp b/map/traffic_manager.cpp index a439210e4..82f9b983c 100644 --- a/map/traffic_manager.cpp +++ b/map/traffic_manager.cpp @@ -126,7 +126,10 @@ void TrafficManager::SetEnabled(bool enabled) m_drapeEngine.SafeCall(&df::DrapeEngine::EnableTraffic, enabled); if (enabled) + { Invalidate(); + m_canSetMode = false; + } else m_observer.OnTrafficInfoClear(); } @@ -477,27 +480,30 @@ void TrafficManager::ThreadRoutine() // TODO clean out expired messages - LOG(LINFO, ("start loop, active MWMs changed:", m_activeMwmsChanged, ", poll needed:", m_isPollNeeded)); - - // this is a no-op if active MWMs have not changed - if (!SetSubscriptionArea()) + if (!IsTestMode()) { - LOG(LWARNING, ("SetSubscriptionArea failed.")); - if (!IsSubscribed()) - // do not skip out of the loop, we may need to process pushed feeds - LOG(LWARNING, ("No subscription, no traffic data will be retrieved.")); - } + LOG(LINFO, ("start loop, active MWMs changed:", m_activeMwmsChanged, ", poll needed:", m_isPollNeeded)); - /* + // this is a no-op if active MWMs have not changed + if (!SetSubscriptionArea()) + { + LOG(LWARNING, ("SetSubscriptionArea failed.")); + if (!IsSubscribed()) + // do not skip out of the loop, we may need to process pushed feeds + LOG(LWARNING, ("No subscription, no traffic data will be retrieved.")); + } + + /* * Fetch traffic data if needed and we have a subscription. * m_isPollNeeded may be set by WaitForRequest() and set/unset by SetSubscriptionArea(). */ - if (m_isPollNeeded && IsSubscribed()) - { - if (!Poll()) + if (m_isPollNeeded && IsSubscribed()) { - LOG(LWARNING, ("Poll failed.")); - // TODO set failed status somewhere and retry + if (!Poll()) + { + LOG(LWARNING, ("Poll failed.")); + // TODO set failed status somewhere and retry + } } } LOG(LINFO, (m_feedQueue.size(), "feed(s) in queue")); @@ -568,21 +574,24 @@ bool TrafficManager::WaitForRequest() return true; } - // if update interval has elapsed, return immediately - auto const currentTime = steady_clock::now(); - auto const passedSeconds = currentTime - m_lastResponseTime; - if (passedSeconds >= kUpdateInterval) + if (!IsTestMode()) { - LOG(LINFO, ("last response was", passedSeconds, "ago, returning immediately")); - m_isPollNeeded = true; - return true; + // if update interval has elapsed, return immediately + auto const currentTime = steady_clock::now(); + auto const passedSeconds = currentTime - m_lastResponseTime; + if (passedSeconds >= kUpdateInterval) + { + LOG(LINFO, ("last response was", passedSeconds, "ago, returning immediately")); + m_isPollNeeded = true; + return true; + } } } LOG(LINFO, ("nothing to do for now, waiting for timeout or notification")); bool const timeout = !m_condition.wait_for(lock, kUpdateInterval, [this] { - return !m_isRunning || m_activeMwmsChanged; + return !m_isRunning || (m_activeMwmsChanged && !IsTestMode()); }); // check again if we got terminated while waiting (or woken up because we got terminated) @@ -593,7 +602,7 @@ bool TrafficManager::WaitForRequest() if (IsEnabled()) m_isPollNeeded |= timeout; - LOG(LINFO, ("timeout:", timeout, "active MWMs changed:", m_activeMwmsChanged)); + LOG(LINFO, ("timeout:", timeout, "active MWMs changed:", m_activeMwmsChanged, "test mode:", IsTestMode())); return true; } @@ -960,6 +969,16 @@ void TrafficManager::SetSimplifiedColorScheme(bool simplified) m_drapeEngine.SafeCall(&df::DrapeEngine::SetSimplifiedTrafficColors, simplified); } +void TrafficManager::SetTestMode() +{ + if (!m_canSetMode) + { + LOG(LWARNING, ("Mode cannot be set once the traffic manager has been enabled")); + return; + } + m_mode = Mode::Test; +} + std::string DebugPrint(TrafficManager::TrafficState state) { switch (state) diff --git a/map/traffic_manager.hpp b/map/traffic_manager.hpp index 1a87ef717..43b8cc1f9 100644 --- a/map/traffic_manager.hpp +++ b/map/traffic_manager.hpp @@ -62,6 +62,31 @@ public: ExpiredApp }; + /** + * @brief The mode for the traffic manager. + * + * Future versions may introduce further test modes. Therefore, always use `TrafficManager::IsTestMode()` + * to verify if the traffic manager is running in test mode. + */ + enum class Mode + { + /** + * Traffic manager mode for normal operation. + * + * This is the default mode unless something else is explicitly set. + */ + Normal, + /** + * Test mode. + * + * This mode will prevent the traffic manager from automatically subscribing to sources and + * polling them. It will still receive and process push feeds. + * + * Future versions may introduce further behavior changes, and/or introduce more test modes. + */ + Test + }; + struct MyPosition { m2::PointD m_position = m2::PointD(0.0, 0.0); @@ -161,6 +186,24 @@ public: void SetSimplifiedColorScheme(bool simplified); bool HasSimplifiedColorScheme() const { return m_hasSimplifiedColorScheme; } + /** + * @brief Whether the traffic manager is operating in test mode. + */ + bool IsTestMode() { return m_mode != Mode::Normal; } + + /** + * @brief Switches the traffic manager into test mode. + * + * The mode can only be set before the traffic manager is first enabled. After that, this method + * will log a warning but otherwise do nothing. + * + * In test mode, the traffic manager will not subscribe to sources or poll them automatically. + * It will still receive and process push feeds. + * + * Future versions may introduce further behavior changes. + */ + void SetTestMode(); + private: /** * @brief Holds information about pending or previous traffic requests pertaining to an MWM. @@ -481,6 +524,18 @@ private: std::pair m_currentPosition = {MyPosition(), false}; std::pair m_currentModelView = {ScreenBase(), false}; + /** + * The mode in which the traffic manager is running. + */ + Mode m_mode = Mode::Normal; + + /** + * Whether the traffic manager accepts mode changes. + * + * Mode cannt be set after the traffic manager has been enabled for the first time. + */ + bool m_canSetMode = true; + std::atomic m_state; TrafficStateChangedFn m_onStateChangedFn; diff --git a/traffxml/traff_assessment_tool/main.cpp b/traffxml/traff_assessment_tool/main.cpp index 810d7bb4f..188c5adb6 100644 --- a/traffxml/traff_assessment_tool/main.cpp +++ b/traffxml/traff_assessment_tool/main.cpp @@ -32,6 +32,8 @@ int main(int argc, char * argv[]) FrameworkParams params; + params.m_trafficTestMode = true; + Framework framework(params); traffxml::MainWindow mainWindow(framework);