diff --git a/libs/drape_frontend/drape_engine.cpp b/libs/drape_frontend/drape_engine.cpp index 50e3372c3..58c978bf1 100644 --- a/libs/drape_frontend/drape_engine.cpp +++ b/libs/drape_frontend/drape_engine.cpp @@ -19,6 +19,7 @@ using namespace std::placeholders; namespace { std::string_view constexpr kLocationStateMode = "LastLocationStateMode"; +std::string_view constexpr kPreferredRoutingMode = "PreferredRoutingMode"; std::string_view constexpr kLastEnterBackground = "LastEnterBackground"; } // namespace @@ -39,16 +40,20 @@ DrapeEngine::DrapeEngine(Params && params) m_requestedTiles = make_unique_dp(); using namespace location; - EMyPositionMode mode = PendingPosition; - if (settings::Get(kLocationStateMode, mode) && mode == FollowAndRotate) + EMyPositionMode lastMode = PendingPosition; + if (settings::Get(kLocationStateMode, lastMode) && lastMode == FollowAndRotate) { // If the screen rect setting in follow and rotate mode is missing or invalid, it could cause // invalid animations, so the follow and rotate mode should be discarded. m2::AnyRectD rect; if (!(settings::Get("ScreenClipRect", rect) && df::GetWorldRect().IsRectInside(rect.GetGlobalRect()))) - mode = Follow; + lastMode = Follow; } + EMyPositionMode preferredRoutingMode; + if (!settings::Get(kPreferredRoutingMode, preferredRoutingMode)) + preferredRoutingMode = FollowAndRotate; + if (!settings::Get(kLastEnterBackground, m_startBackgroundTime)) m_startBackgroundTime = base::Timer::LocalTime(); @@ -65,9 +70,10 @@ DrapeEngine::DrapeEngine(Params && params) // effects.push_back(PostprocessRenderer::Antialiasing); //} - MyPositionController::Params mpParams(mode, base::Timer::LocalTime() - m_startBackgroundTime, params.m_hints, + MyPositionController::Params mpParams(lastMode, preferredRoutingMode, + base::Timer::LocalTime() - m_startBackgroundTime, params.m_hints, params.m_isRoutingActive, params.m_isAutozoomEnabled, - std::bind(&DrapeEngine::MyPositionModeChanged, this, _1, _2)); + std::bind(&DrapeEngine::MyPositionModeChanged, this, _1, _2, _3)); FrontendRenderer::Params frParams( params.m_apiVersion, make_ref(m_threadCommutator), params.m_factory, make_ref(m_textureManager), @@ -404,9 +410,11 @@ void DrapeEngine::ModelViewChanged(ScreenBase const & screen) m_modelViewChangedHandler(screen); } -void DrapeEngine::MyPositionModeChanged(location::EMyPositionMode mode, bool routingActive) +void DrapeEngine::MyPositionModeChanged(location::EMyPositionMode mode, bool routingActive, bool shouldPersistMode) { settings::Set(kLocationStateMode, mode); + if (shouldPersistMode && routingActive) + settings::Set(kPreferredRoutingMode, mode); if (m_myPositionModeChanged) m_myPositionModeChanged(mode, routingActive); } @@ -458,6 +466,12 @@ void DrapeEngine::SwitchMyPositionNextMode() MessagePriority::Normal); } +void DrapeEngine::StartPendingPositionMode() +{ + m_threadCommutator->PostMessage(ThreadsCommutator::RenderThread, make_unique_dp(), + MessagePriority::Normal); +} + void DrapeEngine::LoseLocation() { using Mode = ChangeMyPositionModeMessage::EChangeType; diff --git a/libs/drape_frontend/drape_engine.hpp b/libs/drape_frontend/drape_engine.hpp index 9b83c1959..4ea43f891 100644 --- a/libs/drape_frontend/drape_engine.hpp +++ b/libs/drape_frontend/drape_engine.hpp @@ -157,6 +157,7 @@ public: void SetGpsInfo(location::GpsInfo const & info, bool isNavigable, double distToNextTurn, double speedLimit, location::RouteMatchingInfo const & routeInfo); void SwitchMyPositionNextMode(); + void StartPendingPositionMode(); void LoseLocation(); void StopLocationFollow(); @@ -250,7 +251,7 @@ private: void AddUserEvent(drape_ptr && e); void PostUserEvent(drape_ptr && e); void ModelViewChanged(ScreenBase const & screen); - void MyPositionModeChanged(location::EMyPositionMode mode, bool routingActive); + void MyPositionModeChanged(location::EMyPositionMode mode, bool routingActive, bool shouldPersistMode); void TapEvent(TapInfo const & tapInfo); void UserPositionChanged(m2::PointD const & position, bool hasPosition); diff --git a/libs/drape_frontend/frontend_renderer.cpp b/libs/drape_frontend/frontend_renderer.cpp index 27025db09..8f081ee71 100644 --- a/libs/drape_frontend/frontend_renderer.cpp +++ b/libs/drape_frontend/frontend_renderer.cpp @@ -425,6 +425,12 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) break; } + case Message::Type::StartPendingPositionMode: + { + m_myPositionController->StartPendingPositionMode(); + break; + } + case Message::Type::CompassInfo: { ref_ptr msg = message; diff --git a/libs/drape_frontend/message.cpp b/libs/drape_frontend/message.cpp index 65ee7bc7e..c65982033 100644 --- a/libs/drape_frontend/message.cpp +++ b/libs/drape_frontend/message.cpp @@ -33,6 +33,7 @@ std::string DebugPrint(Message::Type msgType) case Message::Type::MapShapesRecache: return "MapShapesRecache"; case Message::Type::MapShapes: return "MapShapes"; case Message::Type::ChangeMyPositionMode: return "ChangeMyPositionMode"; + case Message::Type::StartPendingPositionMode: return "StartPendingPositionMode"; case Message::Type::CompassInfo: return "CompassInfo"; case Message::Type::GpsInfo: return "GpsInfo"; case Message::Type::SelectObject: return "SelectObject"; diff --git a/libs/drape_frontend/message.hpp b/libs/drape_frontend/message.hpp index b0ce44799..00d810259 100644 --- a/libs/drape_frontend/message.hpp +++ b/libs/drape_frontend/message.hpp @@ -34,6 +34,7 @@ public: MapShapesRecache, MapShapes, ChangeMyPositionMode, + StartPendingPositionMode, CompassInfo, GpsInfo, SelectObject, diff --git a/libs/drape_frontend/message_subclasses.hpp b/libs/drape_frontend/message_subclasses.hpp index 7a0fe6ed3..4fd7c0ef6 100644 --- a/libs/drape_frontend/message_subclasses.hpp +++ b/libs/drape_frontend/message_subclasses.hpp @@ -459,6 +459,12 @@ private: EChangeType const m_changeType; }; +class StartPendingPositionModeMessage : public Message +{ +public: + Type GetType() const override { return Type::StartPendingPositionMode; } +}; + class CompassInfoMessage : public Message { public: diff --git a/libs/drape_frontend/my_position_controller.cpp b/libs/drape_frontend/my_position_controller.cpp index f46fa8879..050594f66 100644 --- a/libs/drape_frontend/my_position_controller.cpp +++ b/libs/drape_frontend/my_position_controller.cpp @@ -9,6 +9,7 @@ #include "geometry/mercator.hpp" +#include "platform/location.hpp" #include "platform/measurement_utils.hpp" #include "base/math.hpp" @@ -203,8 +204,10 @@ MyPositionController::MyPositionController(Params && params, ref_ptr follow-and-rotate, otherwise not-follow -> follow. if (m_mode == location::NotFollow) { - ChangeMode(m_isInRouting ? location::FollowAndRotate : location::Follow); + if ((IsRotationAvailable() || m_isInRouting) && m_preferredRoutingMode == location::FollowAndRotate) + ChangeMode(location::FollowAndRotate, true); + else + ChangeMode(location::Follow, true); + UpdateViewport(preferredZoomLevel); return; } @@ -409,7 +416,7 @@ void MyPositionController::NextMode(ScreenBase const & screen) { if (IsRotationAvailable() || m_isInRouting) { - ChangeMode(location::FollowAndRotate); + ChangeMode(location::FollowAndRotate, true); UpdateViewport(preferredZoomLevel); } return; @@ -420,11 +427,20 @@ void MyPositionController::NextMode(ScreenBase const & screen) { if (m_isInRouting && screen.isPerspective()) preferredZoomLevel = static_cast(GetZoomLevel(ScreenBase::GetStartPerspectiveScale() * 1.1)); - ChangeMode(location::Follow); + ChangeMode(location::Follow, true); ChangeModelView(m_position, 0.0, m_visiblePixelRect.Center(), preferredZoomLevel); } } +void MyPositionController::StartPendingPositionMode() +{ + if (m_mode == location::NotFollowNoPosition) + { + ChangeMode(location::PendingPosition); + return; + } +} + void MyPositionController::OnLocationUpdate(location::GpsInfo const & info, bool isNavigable, double distanceToNextTurn, double speedLimit, ScreenBase const & screen) { @@ -478,8 +494,7 @@ void MyPositionController::OnLocationUpdate(location::GpsInfo const & info, bool if (!m_isPositionAssigned) { - location::EMyPositionMode newMode = m_desiredInitMode; - ChangeMode(newMode); + ChangeMode(m_isInRouting ? m_preferredRoutingMode : m_desiredInitMode, true); if (!m_hints.m_isFirstLaunch || !AnimationSystem::Instance().AnimationExists(Animation::Object::MapPlane)) { @@ -497,14 +512,14 @@ void MyPositionController::OnLocationUpdate(location::GpsInfo const & info, bool } else if (m_mode == location::PendingPosition) { - if (m_isInRouting) + if (m_isInRouting && m_preferredRoutingMode == location::FollowAndRotate) { - ChangeMode(location::FollowAndRotate); + ChangeMode(location::FollowAndRotate, true); UpdateViewport(kMaxScaleZoomLevel); } else { - ChangeMode(location::Follow); + ChangeMode(location::Follow, true); if (m_hints.m_isFirstLaunch) { if (!AnimationSystem::Instance().AnimationExists(Animation::Object::MapPlane)) @@ -523,15 +538,15 @@ void MyPositionController::OnLocationUpdate(location::GpsInfo const & info, bool } else if (m_mode == location::NotFollowNoPosition) { - if (m_isInRouting) + if (m_isInRouting && m_preferredRoutingMode == location::FollowAndRotate) { - ChangeMode(location::FollowAndRotate); + ChangeMode(location::FollowAndRotate, true); UpdateViewport(kMaxScaleZoomLevel); } else { // Here we silently get the position and go to NotFollow mode. - ChangeMode(location::NotFollow); + ChangeMode(location::NotFollow, true); } } @@ -653,13 +668,24 @@ void MyPositionController::SetDirection(double bearing) } void MyPositionController::ChangeMode(location::EMyPositionMode newMode) +{ + ChangeMode(newMode, false); +} + +void MyPositionController::ChangeMode(location::EMyPositionMode newMode, bool shouldPersist) { if (m_isInRouting && (m_mode != newMode) && (newMode == location::FollowAndRotate)) ResetBlockAutoZoomTimer(); m_mode = newMode; + + // We should remember this mode if the user intentionally caused the mode change + // (e.g. tapping the mode button) + if (m_isInRouting && shouldPersist) + m_preferredRoutingMode = newMode; + if (m_modeChangeCallback) - m_modeChangeCallback(m_mode, m_isInRouting); + m_modeChangeCallback(m_mode, m_isInRouting, shouldPersist); } bool MyPositionController::IsWaitingForLocation() const @@ -690,7 +716,8 @@ void MyPositionController::OnEnterForeground(double backgroundTime) // When location was active during previous session the app will try to follow the user. if (m_mode == location::NotFollow) { - ChangeMode(m_isInRouting ? location::FollowAndRotate : location::Follow); + ChangeMode((m_isInRouting && m_preferredRoutingMode == location::FollowAndRotate) ? location::FollowAndRotate + : location::Follow); UpdateViewport(kDoNotChangeZoom); } @@ -876,9 +903,17 @@ void MyPositionController::ActivateRouting(int zoomLevel, bool enableAutoZoom, b m_isArrowGluedInRouting = isArrowGlued; m_enableAutoZoomInRouting = enableAutoZoom; - ChangeMode(location::FollowAndRotate); - ChangeModelView(m_position, m_isDirectionAssigned ? m_drawDirection : 0.0, GetRoutingRotationPixelCenter(), - zoomLevel, [this](ref_ptr anim) { UpdateViewport(kDoNotChangeZoom); }); + if (m_preferredRoutingMode == location::Follow) + { + ChangeMode(location::Follow); + ChangeModelView(m_position, kDoNotChangeZoom); + } + else + { + ChangeMode(location::FollowAndRotate); + ChangeModelView(m_position, m_isDirectionAssigned ? m_drawDirection : 0.0, GetRoutingRotationPixelCenter(), + zoomLevel, [this](ref_ptr anim) { UpdateViewport(kDoNotChangeZoom); }); + } ResetRoutingNotFollowTimer(); } } @@ -919,7 +954,7 @@ void MyPositionController::CheckNotFollowRouting() CHECK_ON_TIMEOUT(m_routingNotFollowNotifyId, kMaxNotFollowRoutingTimeSec, CheckNotFollowRouting); if (m_routingNotFollowTimer.ElapsedSeconds() >= kMaxNotFollowRoutingTimeSec) { - ChangeMode(location::FollowAndRotate); + ChangeMode(m_preferredRoutingMode); UpdateViewport(kDoNotChangeZoom); } } diff --git a/libs/drape_frontend/my_position_controller.hpp b/libs/drape_frontend/my_position_controller.hpp index 0ac4a638e..80f7e7158 100644 --- a/libs/drape_frontend/my_position_controller.hpp +++ b/libs/drape_frontend/my_position_controller.hpp @@ -22,6 +22,8 @@ namespace df { using TAnimationCreator = std::function(ref_ptr)>; +using TMyPositionModeChanged = std::function; + class DrapeNotifier; class MyPositionController @@ -49,9 +51,10 @@ public: struct Params { - Params(location::EMyPositionMode initMode, double timeInBackground, Hints const & hints, bool isRoutingActive, - bool isAutozoomEnabled, location::TMyPositionModeChanged && fn) + Params(location::EMyPositionMode initMode, location::EMyPositionMode preferredRoutingMode, double timeInBackground, + Hints const & hints, bool isRoutingActive, bool isAutozoomEnabled, TMyPositionModeChanged && fn) : m_initMode(initMode) + , m_preferredRoutingMode(preferredRoutingMode) , m_timeInBackground(timeInBackground) , m_hints(hints) , m_isRoutingActive(isRoutingActive) @@ -60,11 +63,12 @@ public: {} location::EMyPositionMode m_initMode; + location::EMyPositionMode m_preferredRoutingMode; double m_timeInBackground; Hints m_hints; bool m_isRoutingActive; bool m_isAutozoomEnabled; - location::TMyPositionModeChanged m_myPositionModeCallback; + TMyPositionModeChanged m_myPositionModeCallback; }; MyPositionController(Params && params, ref_ptr notifier); @@ -112,6 +116,7 @@ public: void NextMode(ScreenBase const & screen); void LoseLocation(); location::EMyPositionMode GetCurrentMode() const { return m_mode; } + void StartPendingPositionMode(); void OnEnterForeground(double backgroundTime); void OnEnterBackground(); @@ -134,6 +139,7 @@ public: void UpdateRoutingOffsetY(bool useDefault, int offsetY); private: + void ChangeMode(location::EMyPositionMode newMode, bool persist); void ChangeMode(location::EMyPositionMode newMode); void SetDirection(double bearing); @@ -163,7 +169,8 @@ private: location::EMyPositionMode m_mode; location::EMyPositionMode m_desiredInitMode; - location::TMyPositionModeChanged m_modeChangeCallback; + location::EMyPositionMode m_preferredRoutingMode; + TMyPositionModeChanged m_modeChangeCallback; Hints m_hints; bool m_isInRouting = false; diff --git a/libs/map/framework.cpp b/libs/map/framework.cpp index 7549e952a..c9ebc56d3 100644 --- a/libs/map/framework.cpp +++ b/libs/map/framework.cpp @@ -206,6 +206,12 @@ void Framework::SwitchMyPositionNextMode() m_drapeEngine->SwitchMyPositionNextMode(); } +void Framework::StartPendingPositionMode() +{ + if (m_drapeEngine != nullptr) + m_drapeEngine->StartPendingPositionMode(); +} + void Framework::SetMyPositionModeListener(TMyPositionModeChanged && fn) { m_myPositionListener = std::move(fn); diff --git a/libs/map/framework.hpp b/libs/map/framework.hpp index 7f90d0134..5f140b37e 100644 --- a/libs/map/framework.hpp +++ b/libs/map/framework.hpp @@ -390,6 +390,7 @@ public: void OnLocationUpdate(location::GpsInfo const & info); void OnCompassUpdate(location::CompassInfo const & info); void SwitchMyPositionNextMode(); + void StartPendingPositionMode(); /// Should be set before Drape initialization. Guarantees that fn is called in main thread context. void SetMyPositionModeListener(location::TMyPositionModeChanged && fn);