diff --git a/android/jni/com/mapswithme/maps/guides/Guides.cpp b/android/jni/com/mapswithme/maps/guides/Guides.cpp index e7d68c35ba..b7af4fda5b 100644 --- a/android/jni/com/mapswithme/maps/guides/Guides.cpp +++ b/android/jni/com/mapswithme/maps/guides/Guides.cpp @@ -1,4 +1,6 @@ -#include "com/mapswithme/maps/guides/Guides.hpp" +#include "android/jni/com/mapswithme/maps/guides/Guides.hpp" + +#include "android/jni/com/mapswithme/platform/Platform.hpp" namespace { @@ -83,3 +85,32 @@ jobject CreateGallery(JNIEnv *env, GuidesManager::GuidesGallery const & gallery) return env->NewObject(g_galleryClass, g_galleryConstructor, items.get()); } } // namespace guides + +namespace platform +{ +bool IsGuidesLayerFirstLaunch() +{ + JNIEnv * env = jni::GetEnv(); + static jclass sharedPropertiesClass = jni::GetGlobalClassRef(env, "com/mapswithme/util/SharedPropertiesUtils"); + static jmethodID getter = jni::GetStaticMethodID(env, sharedPropertiesClass, + "shouldShowNewMarkerForLayerMode", + "(Landroid/content/Context;Ljava/lang/String;)Z"); + jobject context = android::Platform::Instance().GetContext(); + jni::ScopedLocalRef mode(env, jni::ToJavaString(env, "GUIDES")); + + return env->CallStaticBooleanMethod(sharedPropertiesClass, getter, context, mode.get()); +} + +void SetGuidesLayerFirstLaunch(bool /* isFirstLaunch */) +{ + JNIEnv * env = jni::GetEnv(); + static jclass sharedPropertiesClass = jni::GetGlobalClassRef(env, "com/mapswithme/util/SharedPropertiesUtils"); + static jmethodID setter = jni::GetStaticMethodID(env, sharedPropertiesClass, + "setLayerMarkerShownForLayerMode", + "(Landroid/content/Context;Ljava/lang/String;)V"); + jobject context = android::Platform::Instance().GetContext(); + jni::ScopedLocalRef mode(env, jni::ToJavaString(env, "GUIDES")); + + env->CallStaticVoidMethod(sharedPropertiesClass, setter, context, mode.get()); +} +} // namespace platform diff --git a/android/jni/com/mapswithme/maps/guides/Guides.hpp b/android/jni/com/mapswithme/maps/guides/Guides.hpp index dfcb815d52..4a8d393f86 100644 --- a/android/jni/com/mapswithme/maps/guides/Guides.hpp +++ b/android/jni/com/mapswithme/maps/guides/Guides.hpp @@ -7,3 +7,9 @@ namespace guides { jobject CreateGallery(JNIEnv * env, GuidesManager::GuidesGallery const & gallery); } // namespace + +namespace platform +{ +bool IsGuidesLayerFirstLaunch(); +void SetGuidesLayerFirstLaunch(bool isFirstLaunch); +} // namespace platform diff --git a/android/multidex-config.txt b/android/multidex-config.txt index 23fd0d18d9..ec4eaa7e21 100644 --- a/android/multidex-config.txt +++ b/android/multidex-config.txt @@ -18,6 +18,7 @@ com/mapswithme/util/HttpPayload.class com/mapswithme/util/HttpUploader$Result.class com/mapswithme/util/HttpUploader.class com/mapswithme/util/KeyValue.class +com/mapswithme/util/SharedPropertiesUtils.class com/mapswithme/util/log/BaseLogger.class com/mapswithme/util/log/FileLoggerStrategy.class com/mapswithme/util/log/LogCatStrategy.class diff --git a/android/src/com/mapswithme/maps/MwmActivity.java b/android/src/com/mapswithme/maps/MwmActivity.java index c6eeb8d592..9b83aa2d00 100644 --- a/android/src/com/mapswithme/maps/MwmActivity.java +++ b/android/src/com/mapswithme/maps/MwmActivity.java @@ -1526,10 +1526,17 @@ public class MwmActivity extends BaseMwmFragmentActivity onGuidesFatalError(); else if (state == GuidesState.DISABLED) onGuidesDisabled(); + else if (state == GuidesState.ENABLED) + onGuidesEnabled(); else state.activate(getApplicationContext()); } + private void onGuidesEnabled() + { + mToggleMapLayerController.turnOnView(Mode.GUIDES); + } + private void onGuidesDisabled() { mToggleMapLayerController.turnOffCurrentView(); diff --git a/android/src/com/mapswithme/maps/maplayer/MapLayerCompositeController.java b/android/src/com/mapswithme/maps/maplayer/MapLayerCompositeController.java index be17e298ac..72247ae53a 100644 --- a/android/src/com/mapswithme/maps/maplayer/MapLayerCompositeController.java +++ b/android/src/com/mapswithme/maps/maplayer/MapLayerCompositeController.java @@ -237,23 +237,6 @@ public class MapLayerCompositeController implements MapLayerController ToggleMapLayerDialog.show(mActivity); } - public void turnOn(@NonNull Mode mode) - { - ControllerAndMode entry = findModeMapLayerController(mode); - entry.getMode().setEnabled(mActivity, true); - entry.getController().turnOn(); - entry.getController().showImmediately(); - } - - public void turnOff(@NonNull Mode mode) - { - ControllerAndMode entry = findModeMapLayerController(mode); - entry.getMode().setEnabled(mActivity, false); - entry.getController().turnOff(); - entry.getController().hideImmediately(); - turnInitialMode(); - } - @NonNull private ControllerAndMode findModeMapLayerController(@NonNull Mode mode) { @@ -266,6 +249,13 @@ public class MapLayerCompositeController implements MapLayerController throw new IllegalArgumentException("Mode not found : " + mode); } + public void turnOnView(@NonNull Mode mode) + { + setMasterController(mode); + mCurrentLayer.getController().showImmediately(); + mCurrentLayer.getController().turnOn(); + } + public void turnOffCurrentView() { mCurrentLayer.getController().turnOff(); diff --git a/android/src/com/mapswithme/util/SharedPropertiesUtils.java b/android/src/com/mapswithme/util/SharedPropertiesUtils.java index d34ead367e..b252b309b7 100644 --- a/android/src/com/mapswithme/util/SharedPropertiesUtils.java +++ b/android/src/com/mapswithme/util/SharedPropertiesUtils.java @@ -149,6 +149,11 @@ public final class SharedPropertiesUtils } } + public static boolean shouldShowNewMarkerForLayerMode(@NonNull Context context, @NonNull String mode) + { + return shouldShowNewMarkerForLayerMode(context, Mode.valueOf(mode)); + } + public static boolean shouldShowLayerTutorialToast(@NonNull Context context) { boolean result = getBoolean(context, PREFS_SHOULD_SHOW_LAYER_TUTORIAL_TOAST, true); @@ -169,6 +174,11 @@ public final class SharedPropertiesUtils .toLowerCase(Locale.ENGLISH), false); } + public static void setLayerMarkerShownForLayerMode(@NonNull Context context, @NonNull String mode) + { + setLayerMarkerShownForLayerMode(context, Mode.valueOf(mode)); + } + private static boolean getBoolean(@NonNull Context context, @NonNull String key) { return getBoolean(context, key, false); diff --git a/map/framework.cpp b/map/framework.cpp index aed46f260a..a4a3b3fc96 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -82,6 +82,7 @@ #include "platform/preferred_languages.hpp" #include "platform/settings.hpp" #include "platform/socket.hpp" +#include "platform/utils.hpp" #include "coding/endianness.hpp" #include "coding/point_coding.hpp" @@ -1969,9 +1970,12 @@ void Framework::CreateDrapeEngine(ref_ptr contextFac Load3dMode(allow3d, allow3dBuildings); auto const isAutozoomEnabled = LoadAutoZoom(); + + EnableGuidesOnce(params.m_hints.m_isFirstLaunch, params.m_hints.m_isLaunchByDeepLink); auto const trafficEnabled = m_trafficManager.IsEnabled(); auto const isolinesEnabled = m_isolinesManager.IsEnabled(); auto const guidesEnabled = m_guidesManager.IsEnabled(); + auto const simplifiedTrafficColors = m_trafficManager.HasSimplifiedColorScheme(); auto const fontsScaleFactor = LoadLargeFontsSize() ? kLargeFontsScaleFactor : 1.0; @@ -4400,3 +4404,25 @@ notifications::NotificationManager & Framework::GetNotificationManager() { return m_notificationManager; } + +void Framework::EnableGuidesOnce(bool isFirstLaunch, bool isLaunchByDeeplink) +{ + if (m_guidesManager.IsEnabled() || !GetPlatform().IsConnected() || !platform::IsGuidesLayerFirstLaunch()) + return; + + GetTrafficManager().SetEnabled(false); + SaveTrafficEnabled(false); + + GetIsolinesManager().SetEnabled(false); + SaveIsolinesEnabled(false); + + GetTransitManager().EnableTransitSchemeMode(false); + SaveTransitSchemeEnabled(false); + + platform::SetGuidesLayerFirstLaunch(true); + SaveGuidesEnabled(true); + + bool suggestZoom = !m_routingManager.IsRoutingActive() && !isFirstLaunch && !isLaunchByDeeplink; + m_guidesManager.SetEnabled(true /* enabled */, true /* silentMode */, suggestZoom); + +} diff --git a/map/framework.hpp b/map/framework.hpp index 23ec3f052e..7254133d4c 100644 --- a/map/framework.hpp +++ b/map/framework.hpp @@ -907,6 +907,8 @@ private: TipsApi m_tipsApi; notifications::NotificationManager m_notificationManager; + void EnableGuidesOnce(bool isFirstLaunch, bool isLaunchByDeeplink); + public: TipsApi const & GetTipsApi() const; diff --git a/map/guides_manager.cpp b/map/guides_manager.cpp index 319cc0118b..3374c030b1 100644 --- a/map/guides_manager.cpp +++ b/map/guides_manager.cpp @@ -126,7 +126,8 @@ void GuidesManager::Reconnect() RequestGuides(); } -void GuidesManager::SetEnabled(bool enabled) +void GuidesManager::SetEnabled(bool enabled, bool silentMode /* = false */, + bool suggestZoom /* = true */) { auto const newState = enabled ? GuidesState::Enabled : GuidesState::Disabled; if (newState == m_state) @@ -140,13 +141,18 @@ void GuidesManager::SetEnabled(bool enabled) if (!enabled) return; + m_silentMode = silentMode; + if (!GetPlatform().IsConnected()) { - ChangeState(GuidesState::FatalNetworkError); + if (m_silentMode) + ChangeState(GuidesState::Disabled); + else + ChangeState(GuidesState::FatalNetworkError); return; } - RequestGuides(true /* suggestZoom */); + RequestGuides(suggestZoom); } bool GuidesManager::IsEnabled() const @@ -154,12 +160,12 @@ bool GuidesManager::IsEnabled() const return m_state != GuidesState::Disabled; } -void GuidesManager::ChangeState(GuidesState newState, bool force /* = false */) +void GuidesManager::ChangeState(GuidesState newState, bool force /* = false */, bool needNotify /* = true */) { if (m_state == newState && !force) return; m_state = newState; - if (m_onStateChanged != nullptr) + if (m_onStateChanged != nullptr && needNotify) m_onStateChanged(newState); if (m_shownGuides.empty()) @@ -232,7 +238,8 @@ void GuidesManager::OnRequestSucceed(guides_on_map::GuidesOnMap const & guides, } else { - ChangeState(GuidesState::NoData); + if (!m_silentMode) + ChangeState(GuidesState::NoData, false /* force */, !m_silentMode /* needNotify */); } } @@ -260,11 +267,14 @@ void GuidesManager::OnRequestError() if (++m_errorRequestsCount >= kRequestAttemptsCount) { Clear(); - ChangeState(GuidesState::FatalNetworkError); + if (m_silentMode) + ChangeState(GuidesState::Disabled); + else + ChangeState(GuidesState::FatalNetworkError); return; } - ChangeState(GuidesState::NetworkError, true /* force */); + ChangeState(GuidesState::NetworkError, true /* force */, !m_silentMode /* needNotify */); m_retryAfterErrorRequestId = GetPlatform().RunDelayedTask(Platform::Thread::Background, kErrorTimeout, [this]() { @@ -470,12 +480,14 @@ bool GuidesManager::IsRequestParamsInitialized() const void GuidesManager::TrackStatistics() const { + auto const initType = m_silentMode ? LayersStatistics::InitType::Auto + : LayersStatistics::InitType::User; if (m_state == GuidesState::HasData) - m_statistics.LogActivate(LayersStatistics::Status::Success); + m_statistics.LogActivate(LayersStatistics::Status::Success, {} /* mwmVersions */, initType); else if (m_state == GuidesState::NoData) - m_statistics.LogActivate(LayersStatistics::Status::Unavailable); + m_statistics.LogActivate(LayersStatistics::Status::Unavailable, {} /* mwmVersions */, initType); else if (m_state == GuidesState::NetworkError || m_state == GuidesState::FatalNetworkError) - m_statistics.LogActivate(LayersStatistics::Status::Error); + m_statistics.LogActivate(LayersStatistics::Status::Error, {} /* mwmVersions */, initType); } GalleryItem GuidesManager::MakeGalleryItem(guides_on_map::GuidesNode const & guide) const diff --git a/map/guides_manager.hpp b/map/guides_manager.hpp index 52bcc48dda..76f85d8b26 100644 --- a/map/guides_manager.hpp +++ b/map/guides_manager.hpp @@ -92,7 +92,7 @@ public: void UpdateViewport(ScreenBase const & screen); void Reconnect(); - void SetEnabled(bool enabled); + void SetEnabled(bool enabled, bool silentMode = false, bool suggestZoom = true); bool IsEnabled() const; GuidesGallery GetGallery() const; @@ -116,7 +116,7 @@ public: void LogGuideSelectedStatistic(); private: - void ChangeState(GuidesState newState, bool force = false); + void ChangeState(GuidesState newState, bool force = false, bool needNotify = true); void RequestGuides(bool suggestZoom = false); void Clear(); @@ -159,6 +159,8 @@ private: std::unordered_set m_shownGuides; LayersStatistics m_statistics; + + bool m_silentMode = false; }; std::string DebugPrint(GuidesManager::GuidesState state); diff --git a/map/layers_statistics.cpp b/map/layers_statistics.cpp index 301c4fa2aa..2f367d38d2 100644 --- a/map/layers_statistics.cpp +++ b/map/layers_statistics.cpp @@ -27,6 +27,16 @@ std::string ToString(LayersStatistics::LayerItemType itemType) } UNREACHABLE(); } + +std::string ToString(LayersStatistics::InitType initType) +{ + switch (initType) + { + case LayersStatistics::InitType::User: return "user"; + case LayersStatistics::InitType::Auto: return "auto"; + } + UNREACHABLE(); +} } // namespace LayersStatistics::LayersStatistics(std::string const & layerName) @@ -35,9 +45,11 @@ LayersStatistics::LayersStatistics(std::string const & layerName) } void LayersStatistics::LogActivate(Status status, - std::set const & mwmVersions /* = {} */) const + std::set const & mwmVersions /* = {} */, + InitType initType /* = InitType::User */) const { - alohalytics::TStringMap params = {{"name", m_layerName}, {"status", ToString(status)}}; + alohalytics::TStringMap params = {{"name", m_layerName}, {"status", ToString(status)}, + {"init", ToString(initType)}}; if (!mwmVersions.empty()) params.emplace("dataversion", strings::JoinAny(mwmVersions)); diff --git a/map/layers_statistics.hpp b/map/layers_statistics.hpp index d6a831af09..cfc530265d 100644 --- a/map/layers_statistics.hpp +++ b/map/layers_statistics.hpp @@ -20,9 +20,16 @@ public: Cluster, }; + enum class InitType + { + User, + Auto, + }; + explicit LayersStatistics(std::string const & layerName); - void LogActivate(Status status, std::set const & mwmVersions = {}) const; + void LogActivate(Status status, std::set const & mwmVersions = {}, + InitType initType = InitType::User) const; void LogItemSelected(LayerItemType itemType) const; private: diff --git a/platform/CMakeLists.txt b/platform/CMakeLists.txt index a3db89b1cb..61327077c2 100644 --- a/platform/CMakeLists.txt +++ b/platform/CMakeLists.txt @@ -61,6 +61,7 @@ set( socket.hpp string_storage_base.cpp string_storage_base.hpp + utils.hpp ) if(${PLATFORM_IPHONE}) @@ -82,6 +83,7 @@ if(${PLATFORM_IPHONE}) platform_unix_impl.hpp secure_storage_ios.mm socket_apple.mm + utils.mm ) elseif(${PLATFORM_ANDROID}) append( @@ -137,6 +139,7 @@ else() # neither iPhone nor Android secure_storage_qt.cpp socket_apple.mm http_session_manager.mm + utils.cpp ) elseif(${PLATFORM_LINUX}) append( @@ -154,6 +157,7 @@ else() # neither iPhone nor Android platform_unix_impl.cpp platform_unix_impl.hpp secure_storage_qt.cpp + utils.cpp ) endif() endif() diff --git a/platform/utils.cpp b/platform/utils.cpp new file mode 100644 index 0000000000..cb811d031b --- /dev/null +++ b/platform/utils.cpp @@ -0,0 +1,13 @@ +#include "platform/utils.hpp" + +namespace platform +{ +bool IsGuidesLayerFirstLaunch() +{ + return false; +} + +void SetGuidesLayerFirstLaunch(bool isFirstLaunch) +{ +} +} // namespace platform diff --git a/platform/utils.hpp b/platform/utils.hpp new file mode 100644 index 0000000000..8500df552b --- /dev/null +++ b/platform/utils.hpp @@ -0,0 +1,7 @@ +#pragma once + +namespace platform +{ +bool IsGuidesLayerFirstLaunch(); +void SetGuidesLayerFirstLaunch(bool isFirstLaunch); +} // namespace platform diff --git a/platform/utils.mm b/platform/utils.mm new file mode 100644 index 0000000000..fd6bb7c69a --- /dev/null +++ b/platform/utils.mm @@ -0,0 +1,19 @@ +#include "platform/utils.hpp" + +#import "iphone/CoreApi/CoreApi/Traffic/MWMMapOverlayManager.h" + +namespace platform +{ +bool IsGuidesLayerFirstLaunch() +{ + NSUserDefaults *ud = NSUserDefaults.standardUserDefaults; + return ![ud boolForKey:@"guidesWasShown"]; +} + +void SetGuidesLayerFirstLaunch(bool isFirstLaunch) +{ + NSUserDefaults *ud = NSUserDefaults.standardUserDefaults; + [ud setBool:isFirstLaunch forKey:@"guidesWasShown"]; + [ud synchronize]; +} +} // namespace platform diff --git a/xcode/platform/platform.xcodeproj/project.pbxproj b/xcode/platform/platform.xcodeproj/project.pbxproj index 61ed5cc33f..a78b61d125 100644 --- a/xcode/platform/platform.xcodeproj/project.pbxproj +++ b/xcode/platform/platform.xcodeproj/project.pbxproj @@ -24,6 +24,8 @@ 3D78156E1F3A14090068B6AC /* gui_thread_apple.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3D78156B1F3A14090068B6AC /* gui_thread_apple.mm */; }; 3D78156F1F3A14090068B6AC /* gui_thread.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3D78156C1F3A14090068B6AC /* gui_thread.hpp */; }; 3D78157D1F3D8A0A0068B6AC /* safe_callback.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3D78157C1F3D8A0A0068B6AC /* safe_callback.hpp */; }; + 3D921BB62514CD56002EDB00 /* utils.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3D921BB42514CD56002EDB00 /* utils.hpp */; }; + 3D921BB72514CD56002EDB00 /* utils.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3D921BB52514CD56002EDB00 /* utils.mm */; }; 3D97F64B1D9C05E800380945 /* http_client.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D97F64A1D9C05E800380945 /* http_client.cpp */; }; 3DE28A7524BE01A30009465C /* locale.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3DE28A7424BE01A30009465C /* locale.mm */; }; 3DE8B98F1DEC3115000E6083 /* network_policy.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3DE8B98E1DEC3115000E6083 /* network_policy.hpp */; }; @@ -156,6 +158,8 @@ 3D78156B1F3A14090068B6AC /* gui_thread_apple.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = gui_thread_apple.mm; sourceTree = ""; }; 3D78156C1F3A14090068B6AC /* gui_thread.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = gui_thread.hpp; sourceTree = ""; }; 3D78157C1F3D8A0A0068B6AC /* safe_callback.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = safe_callback.hpp; sourceTree = ""; }; + 3D921BB42514CD56002EDB00 /* utils.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = utils.hpp; sourceTree = ""; }; + 3D921BB52514CD56002EDB00 /* utils.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = utils.mm; sourceTree = ""; }; 3D97F64A1D9C05E800380945 /* http_client.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = http_client.cpp; sourceTree = ""; }; 3DE28A7424BE01A30009465C /* locale.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = locale.mm; sourceTree = ""; }; 3DE8B98E1DEC3115000E6083 /* network_policy.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = network_policy.hpp; sourceTree = ""; }; @@ -393,6 +397,8 @@ 6753437A1A3F5CF500A0A8C3 /* platform */ = { isa = PBXGroup; children = ( + 3D921BB42514CD56002EDB00 /* utils.hpp */, + 3D921BB52514CD56002EDB00 /* utils.mm */, 3DE28A7424BE01A30009465C /* locale.mm */, D593E50323CDBC5F004D6B89 /* http_uploader_background_dummy.cpp */, 3DF528EA238BFFC1000ED0D5 /* downloader_defines.hpp */, @@ -531,6 +537,7 @@ EB60B4DE204C175700E4953B /* network_policy_ios.h in Headers */, 56EB1EDF1C6B6E6C0022D831 /* mwm_traits.hpp in Headers */, 675343C21A3F5D5A00A0A8C3 /* location.hpp in Headers */, + 3D921BB62514CD56002EDB00 /* utils.hpp in Headers */, 3DEE1AE821F7091100054A91 /* battery_tracker.hpp in Headers */, 67AB92EB1B7B3E9100AB5194 /* get_text_by_id.hpp in Headers */, 675343D41A3F5D5A00A0A8C3 /* settings.hpp in Headers */, @@ -699,6 +706,7 @@ buildActionMask = 2147483647; files = ( 3DEE1AE721F7091100054A91 /* battery_tracker.cpp in Sources */, + 3D921BB72514CD56002EDB00 /* utils.mm in Sources */, 675343D11A3F5D5A00A0A8C3 /* servers_list.cpp in Sources */, 675343C91A3F5D5A00A0A8C3 /* platform_unix_impl.cpp in Sources */, 67AB92DC1B7B3D7300AB5194 /* mwm_version.cpp in Sources */,