diff --git a/.gitignore b/.gitignore index eabc43ecf4a..cf296c9d454 100644 --- a/.gitignore +++ b/.gitignore @@ -187,3 +187,4 @@ screenshots/ android/src/google/play/listings/ keywords/ iphone/metadata/**/keywords.txt +*.cache \ No newline at end of file diff --git a/README.md b/README.md index a685f7db655..33000137a7f 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [Organic Maps](https://organicmaps.app) is a free Android & iOS offline maps app for travellers, tourists, drivers, hikers, and cyclists. It uses crowd-sourced [OpenStreetMap](https://www.openstreetmap.org) data and is developed with love by the creators of **MapsWithMe** (later renamed to **Maps.Me**) and by our community. -No ads, no tracking, no data collection, no crapware. Your [donations](https://organicmaps.app/donate/) and positive reviews motivate and inspire us, thanks ❤️! +No ads, no tracking, no crapware. Your [donations](https://organicmaps.app/donate/) and positive reviews motivate and inspire us, thanks ❤️!

@@ -54,7 +54,6 @@ Organic Maps is free from trackers and other bad stuff: - No ads - No tracking -- No data collection - No phoning home - No annoying registration - No mandatory tutorials diff --git a/android/app/build.gradle b/android/app/build.gradle index 3b7dc6cff76..797b911f686 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -24,9 +24,9 @@ buildscript { dependencies { classpath 'com.android.tools.build:gradle:8.4.1' - if (googleFirebaseServicesEnabled) { - println('Building with Google Firebase Services') classpath 'com.google.gms:google-services:4.4.1' + println('Building with Google Firebase Services') + if (googleFirebaseServicesEnabled) { classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.9' classpath 'com.google.firebase:firebase-appdistribution-gradle:4.2.0' } else { @@ -46,8 +46,8 @@ repositories { apply plugin: 'com.android.application' apply from: 'secure.properties' -if (googleFirebaseServicesEnabled) { apply plugin: 'com.google.gms.google-services' +if (googleFirebaseServicesEnabled) { apply plugin: 'com.google.firebase.crashlytics' apply plugin: 'com.google.firebase.appdistribution' } @@ -82,7 +82,7 @@ def getCommitMessage() { def osName = System.properties['os.name'].toLowerCase() project.ext.appId = 'app.organicmaps' -project.ext.appName = 'Organic Maps' +project.ext.appName = 'DRIMS' java { toolchain { @@ -263,7 +263,7 @@ android { jniDebuggable true // Enable jni debug build zipAlignEnabled true signingConfig signingConfigs.debug - resValue 'string', 'app_name', 'Debug Organic Maps' + resValue 'string', 'app_name', 'DRIMS' // Do not generate separate debug symbols for debug apps, because we don't distribute them. ndk.debugSymbolLevel = 'none' @@ -347,7 +347,10 @@ android { } dependencies { - coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4' + implementation 'com.google.firebase:firebase-messaging:24.0.0' + implementation 'androidx.activity:activity:1.8.0' + coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4' + implementation 'com.google.android.flexbox:flexbox:3.0.0' // Google Play Location Services // @@ -361,16 +364,17 @@ dependencies { webImplementation 'com.google.android.gms:play-services-location:21.2.0' googleImplementation 'com.google.android.gms:play-services-location:21.2.0' huaweiImplementation 'com.google.android.gms:play-services-location:21.2.0' - + implementation platform('com.google.firebase:firebase-bom:33.1.2') // Google Firebase Services if (googleFirebaseServicesEnabled) { // Import the BoM for the Firebase platform - implementation platform('com.google.firebase:firebase-bom:32.8.0') + // Add the dependencies for the Crashlytics and Analytics libraries // When using the BoM, you don't specify versions in Firebase library dependencies implementation 'com.google.firebase:firebase-crashlytics' implementation 'com.google.firebase:firebase-crashlytics-ndk' } + implementation 'com.google.firebase:firebase-messaging' // This line is added as a workaround for duplicate classes error caused by some outdated dependency: // > A failure occurred while executing com.android.build.gradle.internal.tasks.CheckDuplicatesRunnable diff --git a/android/app/src/debug/res/mipmap-hdpi/ic_launcher.png b/android/app/src/debug/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index 25cea1a699b..00000000000 Binary files a/android/app/src/debug/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/android/app/src/debug/res/mipmap-hdpi/ic_launcher_foreground.png b/android/app/src/debug/res/mipmap-hdpi/ic_launcher_foreground.png deleted file mode 100644 index 7c95ae3b834..00000000000 Binary files a/android/app/src/debug/res/mipmap-hdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/android/app/src/debug/res/mipmap-mdpi/ic_launcher.png b/android/app/src/debug/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index c39a6ea6e14..00000000000 Binary files a/android/app/src/debug/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/android/app/src/debug/res/mipmap-mdpi/ic_launcher_foreground.png b/android/app/src/debug/res/mipmap-mdpi/ic_launcher_foreground.png deleted file mode 100644 index e049c0bc1e9..00000000000 Binary files a/android/app/src/debug/res/mipmap-mdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/android/app/src/debug/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/debug/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index d0aeb2ccc8a..00000000000 Binary files a/android/app/src/debug/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/android/app/src/debug/res/mipmap-xhdpi/ic_launcher_foreground.png b/android/app/src/debug/res/mipmap-xhdpi/ic_launcher_foreground.png deleted file mode 100644 index bead024b021..00000000000 Binary files a/android/app/src/debug/res/mipmap-xhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/android/app/src/debug/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/debug/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index bcf93bd22ff..00000000000 Binary files a/android/app/src/debug/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/android/app/src/debug/res/mipmap-xxhdpi/ic_launcher_foreground.png b/android/app/src/debug/res/mipmap-xxhdpi/ic_launcher_foreground.png deleted file mode 100644 index caff93fb958..00000000000 Binary files a/android/app/src/debug/res/mipmap-xxhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/android/app/src/debug/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/debug/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 856ae7f43ad..00000000000 Binary files a/android/app/src/debug/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/android/app/src/debug/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/android/app/src/debug/res/mipmap-xxxhdpi/ic_launcher_foreground.png deleted file mode 100644 index c21da8b401f..00000000000 Binary files a/android/app/src/debug/res/mipmap-xxxhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 5edfb32bb28..8a22371e8ef 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,31 +1,30 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // + --> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/cpp/app/organicmaps/Framework.cpp b/android/app/src/main/cpp/app/organicmaps/Framework.cpp index 8f377c6b245..addf8a2a2f4 100644 --- a/android/app/src/main/cpp/app/organicmaps/Framework.cpp +++ b/android/app/src/main/cpp/app/organicmaps/Framework.cpp @@ -1,19 +1,13 @@ #include "app/organicmaps/Framework.hpp" -#include "app/organicmaps/core/jni_helper.hpp" -#include "app/organicmaps/UserMarkHelper.hpp" -#include "app/organicmaps/opengl/androidoglcontextfactory.hpp" -#include "app/organicmaps/platform/AndroidPlatform.hpp" -#include "app/organicmaps/util/Distance.hpp" -#include "app/organicmaps/util/FeatureIdBuilder.hpp" -#include "app/organicmaps/util/NetworkPolicy.hpp" -#include "app/organicmaps/vulkan/android_vulkan_context_factory.hpp" - #include "map/bookmark_helpers.hpp" #include "map/chart_generator.hpp" #include "map/everywhere_search_params.hpp" #include "map/user_mark.hpp" +#include "routing/following_info.hpp" +#include "routing/speed_camera_manager.hpp" + #include "storage/storage_defines.hpp" #include "storage/storage_helpers.hpp" @@ -24,25 +18,16 @@ #include "drape/support_manager.hpp" #include "drape/visual_scale.hpp" -#include "coding/files_container.hpp" - -#include "geometry/angles.hpp" -#include "geometry/mercator.hpp" -#include "geometry/point_with_altitude.hpp" - #include "indexer/feature_altitude.hpp" #include "indexer/kayak.hpp" #include "indexer/validate_and_format_contacts.hpp" -#include "routing/following_info.hpp" -#include "routing/speed_camera_manager.hpp" - #include "platform/country_file.hpp" #include "platform/local_country_file.hpp" #include "platform/local_country_file_utils.hpp" #include "platform/locale.hpp" -#include "platform/location.hpp" #include "platform/localization.hpp" +#include "platform/location.hpp" #include "platform/measurement_utils.hpp" #include "platform/network_policy.hpp" #include "platform/platform.hpp" @@ -50,19 +35,38 @@ #include "platform/settings.hpp" #include "platform/utm_mgrs_utils.hpp" +#include "coding/files_container.hpp" + +#include "geometry/angles.hpp" +#include "geometry/mercator.hpp" +#include "geometry/point_with_altitude.hpp" + #include "base/assert.hpp" #include "base/file_name_utils.hpp" #include "base/logging.hpp" #include "base/math.hpp" #include "base/sunrise_sunset.hpp" -#include "3party/open-location-code/openlocationcode.h" +#include "app/organicmaps/util/Distance.hpp" +#include "app/organicmaps/util/FeatureIdBuilder.hpp" +#include "app/organicmaps/util/NetworkPolicy.hpp" + +#include "app/organicmaps/platform/AndroidPlatform.hpp" + +#include "app/organicmaps/opengl/androidoglcontextfactory.hpp" + +#include "app/organicmaps/vulkan/android_vulkan_context_factory.hpp" + +#include "app/organicmaps/core/jni_helper.hpp" +#include #include #include #include -#include +#include "3party/open-location-code/openlocationcode.h" + +#include "app/organicmaps/UserMarkHelper.hpp" using namespace std; using namespace std::placeholders; @@ -102,14 +106,13 @@ namespace android enum MultiTouchAction { - MULTITOUCH_UP = 0x00000001, - MULTITOUCH_DOWN = 0x00000002, - MULTITOUCH_MOVE = 0x00000003, - MULTITOUCH_CANCEL = 0x00000004 + MULTITOUCH_UP = 0x00000001, + MULTITOUCH_DOWN = 0x00000002, + MULTITOUCH_MOVE = 0x00000003, + MULTITOUCH_CANCEL = 0x00000004 }; -Framework::Framework(std::function && afterMapsLoaded) -: m_work({} /* params */, false /* loadMaps */) +Framework::Framework(std::function && afterMapsLoaded) : m_work({} /* params */, false /* loadMaps */) { m_work.LoadMapsAsync(std::move(afterMapsLoaded)); @@ -124,10 +127,7 @@ void Framework::OnLocationError(int errorCode) m_work.OnLocationError(static_cast(errorCode)); } -void Framework::OnLocationUpdated(location::GpsInfo const & info) -{ - m_work.OnLocationUpdate(info); -} +void Framework::OnLocationUpdated(location::GpsInfo const & info) { m_work.OnLocationUpdate(info); } void Framework::OnCompassUpdated(location::CompassInfo const & info, bool forceRedraw) { @@ -181,15 +181,14 @@ bool Framework::CreateDrapeEngine(JNIEnv * env, jobject jSurface, int densityDpi int constexpr kMinSdkVersionForVulkan = 26; int const sdkVersion = android_get_device_api_level(); LOG(LINFO, ("Android SDK version in the Drape Engine:", sdkVersion)); - auto const vulkanForbidden = sdkVersion < kMinSdkVersionForVulkan || - dp::SupportManager::Instance().IsVulkanForbidden(); + auto const vulkanForbidden = + sdkVersion < kMinSdkVersionForVulkan || dp::SupportManager::Instance().IsVulkanForbidden(); if (vulkanForbidden) LOG(LWARNING, ("Vulkan API is forbidden on this device.")); if (m_work.LoadPreferredGraphicsAPI() == dp::ApiVersion::Vulkan && !vulkanForbidden) { - m_vulkanContextFactory = - make_unique_dp(appVersionCode, sdkVersion); + m_vulkanContextFactory = make_unique_dp(appVersionCode, sdkVersion); if (!CastFactory(m_vulkanContextFactory)->IsVulkanSupported()) { LOG(LWARNING, ("Vulkan API is not supported.")); @@ -211,8 +210,7 @@ bool Framework::CreateDrapeEngine(JNIEnv * env, jobject jSurface, int densityDpi AndroidOGLContextFactory * oglFactory = nullptr; if (!m_vulkanContextFactory) { - m_oglContextFactory = make_unique_dp( - new AndroidOGLContextFactory(env, jSurface)); + m_oglContextFactory = make_unique_dp(new AndroidOGLContextFactory(env, jSurface)); oglFactory = m_oglContextFactory->CastFactory(); if (!oglFactory->IsValid()) { @@ -232,8 +230,7 @@ bool Framework::CreateDrapeEngine(JNIEnv * env, jobject jSurface, int densityDpi else { CHECK(oglFactory != nullptr, ()); - p.m_apiVersion = oglFactory->IsSupportedOpenGLES3() ? dp::ApiVersion::OpenGLES3 : - dp::ApiVersion::OpenGLES2; + p.m_apiVersion = oglFactory->IsSupportedOpenGLES3() ? dp::ApiVersion::OpenGLES3 : dp::ApiVersion::OpenGLES2; p.m_surfaceWidth = oglFactory->GetWidth(); p.m_surfaceHeight = oglFactory->GetHeight(); } @@ -256,10 +253,7 @@ bool Framework::CreateDrapeEngine(JNIEnv * env, jobject jSurface, int densityDpi return true; } -bool Framework::IsDrapeEngineCreated() const -{ - return m_work.IsDrapeEngineCreated(); -} +bool Framework::IsDrapeEngineCreated() const { return m_work.IsDrapeEngineCreated(); } void Framework::UpdateDpi(int dpi) { @@ -413,10 +407,7 @@ void Framework::ResumeSurfaceRendering() LOG(LINFO, ("Resume surface rendering.")); } -void Framework::SetMapStyle(MapStyle mapStyle) -{ - m_work.SetMapStyle(mapStyle); -} +void Framework::SetMapStyle(MapStyle mapStyle) { m_work.SetMapStyle(mapStyle); } void Framework::MarkMapStyle(MapStyle mapStyle) { @@ -428,43 +419,25 @@ void Framework::MarkMapStyle(MapStyle mapStyle) m_work.MarkMapStyle(mapStyle); } -MapStyle Framework::GetMapStyle() const -{ - return m_work.GetMapStyle(); -} +MapStyle Framework::GetMapStyle() const { return m_work.GetMapStyle(); } -void Framework::Save3dMode(bool allow3d, bool allow3dBuildings) -{ - m_work.Save3dMode(allow3d, allow3dBuildings); -} +void Framework::Save3dMode(bool allow3d, bool allow3dBuildings) { m_work.Save3dMode(allow3d, allow3dBuildings); } -void Framework::Set3dMode(bool allow3d, bool allow3dBuildings) -{ - m_work.Allow3dMode(allow3d, allow3dBuildings); -} +void Framework::Set3dMode(bool allow3d, bool allow3dBuildings) { m_work.Allow3dMode(allow3d, allow3dBuildings); } -void Framework::Get3dMode(bool & allow3d, bool & allow3dBuildings) -{ - m_work.Load3dMode(allow3d, allow3dBuildings); -} +void Framework::Get3dMode(bool & allow3d, bool & allow3dBuildings) { m_work.Load3dMode(allow3d, allow3dBuildings); } -void Framework::SetChoosePositionMode(ChoosePositionMode mode, bool isBusiness, - bool hasPosition, m2::PointD const & position) +void Framework::SetChoosePositionMode(ChoosePositionMode mode, bool isBusiness, bool hasPosition, + m2::PointD const & position) { m_isChoosePositionMode = mode; m_work.BlockTapEvents(mode != ChoosePositionMode::None); m_work.EnableChoosePositionMode(mode != ChoosePositionMode::None, isBusiness, hasPosition, position); } -ChoosePositionMode Framework::GetChoosePositionMode() -{ - return m_isChoosePositionMode; -} +ChoosePositionMode Framework::GetChoosePositionMode() { return m_isChoosePositionMode; } -Storage & Framework::GetStorage() -{ - return m_work.GetStorage(); -} +Storage & Framework::GetStorage() { return m_work.GetStorage(); } DataSource const & Framework::GetDataSource() { return m_work.GetDataSource(); } @@ -481,37 +454,22 @@ void Framework::ShowNode(CountryId const & idx, bool zoomToDownloadButton) } } -void Framework::Scale(double factor, m2::PointD const & pxPoint, bool isAnim) -{ - m_work.Scale(factor, pxPoint, isAnim); -} +void Framework::Scale(double factor, m2::PointD const & pxPoint, bool isAnim) { m_work.Scale(factor, pxPoint, isAnim); } -void Framework::Scroll(double distanceX, double distanceY) -{ - m_work.Scroll(distanceX, distanceY); -} +void Framework::Scroll(double distanceX, double distanceY) { m_work.Scroll(distanceX, distanceY); } void Framework::Touch(int action, Finger const & f1, Finger const & f2, uint8_t maskedPointer) { MultiTouchAction eventType = static_cast(action); df::TouchEvent event; - switch(eventType) + switch (eventType) { - case MULTITOUCH_DOWN: - event.SetTouchType(df::TouchEvent::TOUCH_DOWN); - break; - case MULTITOUCH_MOVE: - event.SetTouchType(df::TouchEvent::TOUCH_MOVE); - break; - case MULTITOUCH_UP: - event.SetTouchType(df::TouchEvent::TOUCH_UP); - break; - case MULTITOUCH_CANCEL: - event.SetTouchType(df::TouchEvent::TOUCH_CANCEL); - break; - default: - return; + case MULTITOUCH_DOWN: event.SetTouchType(df::TouchEvent::TOUCH_DOWN); break; + case MULTITOUCH_MOVE: event.SetTouchType(df::TouchEvent::TOUCH_MOVE); break; + case MULTITOUCH_UP: event.SetTouchType(df::TouchEvent::TOUCH_UP); break; + case MULTITOUCH_CANCEL: event.SetTouchType(df::TouchEvent::TOUCH_CANCEL); break; + default: return; } df::Touch touch; @@ -527,20 +485,11 @@ void Framework::Touch(int action, Finger const & f1, Finger const & f2, uint8_t m_work.TouchEvent(event); } -m2::PointD Framework::GetViewportCenter() const -{ - return m_work.GetViewportCenter(); -} +m2::PointD Framework::GetViewportCenter() const { return m_work.GetViewportCenter(); } -void Framework::AddString(string const & name, string const & value) -{ - m_work.AddString(name, value); -} +void Framework::AddString(string const & name, string const & value) { m_work.AddString(name, value); } -void Framework::Scale(::Framework::EScaleMode mode) -{ - m_work.Scale(mode, true); -} +void Framework::Scale(::Framework::EScaleMode mode) { m_work.Scale(mode, true); } void Framework::Scale(m2::PointD const & centerPt, int targetZoom, bool animate) { @@ -549,10 +498,7 @@ void Framework::Scale(m2::PointD const & centerPt, int targetZoom, bool animate) engine->SetModelViewCenter(centerPt, targetZoom, animate, false); } -::Framework * Framework::NativeFramework() -{ - return &m_work; -} +::Framework * Framework::NativeFramework() { return &m_work; } bool Framework::Search(search::EverywhereSearchParams const & params) { @@ -560,15 +506,11 @@ bool Framework::Search(search::EverywhereSearchParams const & params) return m_work.GetSearchAPI().SearchEverywhere(params); } -void Framework::AddLocalMaps() -{ - m_work.RegisterAllMaps(); -} +void Framework::SendDeviceToken(std::string const & token) { m_work.HandleDeviceToken(token); } -void Framework::RemoveLocalMaps() -{ - m_work.DeregisterAllMaps(); -} +void Framework::AddLocalMaps() { m_work.RegisterAllMaps(); } + +void Framework::RemoveLocalMaps() { m_work.DeregisterAllMaps(); } void Framework::ReloadWorldMaps() { @@ -587,15 +529,9 @@ void Framework::MoveBookmark(kml::MarkId markId, kml::MarkGroupId curCat, kml::M m_work.GetBookmarkManager().GetEditSession().MoveBookmark(markId, curCat, newCat); } -void Framework::ExecuteMapApiRequest() -{ - return m_work.ExecuteMapApiRequest(); -} +void Framework::ExecuteMapApiRequest() { return m_work.ExecuteMapApiRequest(); } -void Framework::DeactivatePopup() -{ - m_work.DeactivateMapSelection(); -} +void Framework::DeactivatePopup() { m_work.DeactivateMapSelection(); } /* string Framework::GetOutdatedCountriesString() @@ -636,10 +572,7 @@ void Framework::SetIsolinesListener(IsolinesManager::IsolinesStateChangedFn cons m_onIsolinesStateChangedFn = function; } -bool Framework::IsTrafficEnabled() -{ - return m_work.GetTrafficManager().IsEnabled(); -} +bool Framework::IsTrafficEnabled() { return m_work.GetTrafficManager().IsEnabled(); } void Framework::EnableTraffic() { @@ -653,15 +586,12 @@ void Framework::DisableTraffic() NativeFramework()->SaveTrafficEnabled(false); } -void Framework::SetMyPositionModeListener(location::TMyPositionModeChanged const & fn) -{ - m_myPositionModeSignal = fn; -} +void Framework::SetMyPositionModeListener(location::TMyPositionModeChanged const & fn) { m_myPositionModeSignal = fn; } location::EMyPositionMode Framework::GetMyPositionMode() const { // No need in assertion here, return location::PendingPosition if no engine created. - //ASSERT(IsDrapeEngineCreated(), ()); + // ASSERT(IsDrapeEngineCreated(), ()); return m_work.GetMyPositionMode(); } @@ -691,35 +621,17 @@ void Framework::ApplyWidgets() m_work.SetWidgetLayout(std::move(layout)); } -void Framework::CleanWidgets() -{ - m_guiPositions.clear(); -} +void Framework::CleanWidgets() { m_guiPositions.clear(); } -void Framework::SetupMeasurementSystem() -{ - m_work.SetupMeasurementSystem(); -} +void Framework::SetupMeasurementSystem() { m_work.SetupMeasurementSystem(); } -place_page::Info & Framework::GetPlacePageInfo() -{ - return m_work.GetCurrentPlacePageInfo(); -} +place_page::Info & Framework::GetPlacePageInfo() { return m_work.GetCurrentPlacePageInfo(); } -bool Framework::IsAutoRetryDownloadFailed() -{ - return m_work.GetDownloadingPolicy().IsAutoRetryDownloadFailed(); -} +bool Framework::IsAutoRetryDownloadFailed() { return m_work.GetDownloadingPolicy().IsAutoRetryDownloadFailed(); } -bool Framework::IsDownloadOn3gEnabled() -{ - return m_work.GetDownloadingPolicy().IsCellularDownloadEnabled(); -} +bool Framework::IsDownloadOn3gEnabled() { return m_work.GetDownloadingPolicy().IsCellularDownloadEnabled(); } -void Framework::EnableDownloadOn3g() -{ - m_work.GetDownloadingPolicy().EnableCellularDownload(true); -} +void Framework::EnableDownloadOn3g() { m_work.GetDownloadingPolicy().EnableCellularDownload(true); } /* int Framework::ToDoAfterUpdate() const @@ -759,233 +671,230 @@ FeatureID Framework::BuildFeatureId(JNIEnv * env, jobject featureId) extern "C" { -void CallRoutingListener(shared_ptr listener, int errorCode, - storage::CountriesSet const & absentMaps) -{ - JNIEnv * env = jni::GetEnv(); - jmethodID const method = jni::GetMethodID(env, *listener, "onRoutingEvent", "(I[Ljava/lang/String;)V"); - ASSERT(method, ()); + void CallRoutingListener(shared_ptr listener, int errorCode, storage::CountriesSet const & absentMaps) + { + JNIEnv * env = jni::GetEnv(); + jmethodID const method = jni::GetMethodID(env, *listener, "onRoutingEvent", "(I[Ljava/lang/String;)V"); + ASSERT(method, ()); - env->CallVoidMethod(*listener, method, errorCode, jni::TScopedLocalObjectArrayRef(env, jni::ToJavaStringArray(env, absentMaps)).get()); -} + env->CallVoidMethod(*listener, method, errorCode, + jni::TScopedLocalObjectArrayRef(env, jni::ToJavaStringArray(env, absentMaps)).get()); + } -void CallRouteProgressListener(shared_ptr listener, float progress) -{ - JNIEnv * env = jni::GetEnv(); - jmethodID const methodId = jni::GetMethodID(env, *listener, "onRouteBuildingProgress", "(F)V"); - env->CallVoidMethod(*listener, methodId, progress); -} + void CallRouteProgressListener(shared_ptr listener, float progress) + { + JNIEnv * env = jni::GetEnv(); + jmethodID const methodId = jni::GetMethodID(env, *listener, "onRouteBuildingProgress", "(F)V"); + env->CallVoidMethod(*listener, methodId, progress); + } -void CallRouteRecommendationListener(shared_ptr listener, - RoutingManager::Recommendation recommendation) -{ - JNIEnv * env = jni::GetEnv(); - jmethodID const methodId = jni::GetMethodID(env, *listener, "onRecommend", "(I)V"); - env->CallVoidMethod(*listener, methodId, static_cast(recommendation)); -} + void CallRouteRecommendationListener(shared_ptr listener, RoutingManager::Recommendation recommendation) + { + JNIEnv * env = jni::GetEnv(); + jmethodID const methodId = jni::GetMethodID(env, *listener, "onRecommend", "(I)V"); + env->CallVoidMethod(*listener, methodId, static_cast(recommendation)); + } -void CallSetRoutingLoadPointsListener(shared_ptr listener, bool success) -{ - JNIEnv * env = jni::GetEnv(); - jmethodID const methodId = jni::GetMethodID(env, *listener, "onRoutePointsLoaded", "(Z)V"); - env->CallVoidMethod(*listener, methodId, static_cast(success)); -} + void CallSetRoutingLoadPointsListener(shared_ptr listener, bool success) + { + JNIEnv * env = jni::GetEnv(); + jmethodID const methodId = jni::GetMethodID(env, *listener, "onRoutePointsLoaded", "(Z)V"); + env->CallVoidMethod(*listener, methodId, static_cast(success)); + } -RoutingManager::LoadRouteHandler g_loadRouteHandler; + RoutingManager::LoadRouteHandler g_loadRouteHandler; -/// @name JNI EXPORTS -JNIEXPORT jstring JNICALL -Java_app_organicmaps_Framework_nativeGetAddress(JNIEnv * env, jclass clazz, jdouble lat, jdouble lon) -{ - auto const info = frm()->GetAddressAtPoint(mercator::FromLatLon(lat, lon)); - return jni::ToJavaString(env, info.FormatAddress()); -} + /// @name JNI EXPORTS + JNIEXPORT jstring JNICALL Java_app_organicmaps_Framework_nativeGetAddress(JNIEnv * env, jclass clazz, jdouble lat, + jdouble lon) + { + auto const info = frm()->GetAddressAtPoint(mercator::FromLatLon(lat, lon)); + return jni::ToJavaString(env, info.FormatAddress()); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeClearApiPoints(JNIEnv * env, jclass clazz) -{ - frm()->GetBookmarkManager().GetEditSession().ClearGroup(UserMark::Type::API); -} + JNIEXPORT void JNICALL Java_app_organicmaps_PushNotificationService_nativeSendTokenToCpp(JNIEnv * env, jobject thiz, + jstring token) + { + g_framework->SendDeviceToken(jni::ToNativeString(env, token)); + } -JNIEXPORT jint JNICALL -Java_app_organicmaps_Framework_nativeParseAndSetApiUrl(JNIEnv * env, jclass clazz, jstring url) -{ - return static_cast(frm()->ParseAndSetApiURL(jni::ToNativeString(env, url))); -} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeClearApiPoints(JNIEnv * env, jclass clazz) + { + frm()->GetBookmarkManager().GetEditSession().ClearGroup(UserMark::Type::API); + } -JNIEXPORT jobject JNICALL -Java_app_organicmaps_Framework_nativeGetParsedRoutingData(JNIEnv * env, jclass clazz) -{ - using namespace url_scheme; - static jclass const pointClazz = jni::GetGlobalClassRef(env, "app/organicmaps/api/RoutePoint"); - // Java signature : RoutePoint(double lat, double lon, String name) - static jmethodID const pointConstructor = jni::GetConstructorID(env, pointClazz, "(DDLjava/lang/String;)V"); - - static jclass const routeDataClazz = jni::GetGlobalClassRef(env, "app/organicmaps/api/ParsedRoutingData"); - // Java signature : ParsedRoutingData(RoutePoint[] points, int routerType) { - static jmethodID const routeDataConstructor = jni::GetConstructorID(env, routeDataClazz, "([Lapp/organicmaps/api/RoutePoint;I)V"); - - auto const & routingData = frm()->GetParsedRoutingData(); - jobjectArray points = jni::ToJavaArray(env, pointClazz, routingData.m_points, - [](JNIEnv * env, RoutePoint const & point) - { - jni::TScopedLocalRef const name(env, jni::ToJavaString(env, point.m_name)); - return env->NewObject(pointClazz, pointConstructor, - mercator::YToLat(point.m_org.y), - mercator::XToLon(point.m_org.x), name.get()); - }); - - return env->NewObject(routeDataClazz, routeDataConstructor, points, routingData.m_type); -} + JNIEXPORT jint JNICALL Java_app_organicmaps_Framework_nativeParseAndSetApiUrl(JNIEnv * env, jclass clazz, jstring url) + { + return static_cast(frm()->ParseAndSetApiURL(jni::ToNativeString(env, url))); + } -JNIEXPORT jobject JNICALL -Java_app_organicmaps_Framework_nativeGetParsedSearchRequest(JNIEnv * env, jclass clazz) -{ - using namespace url_scheme; - static jclass const cl = jni::GetGlobalClassRef(env, "app/organicmaps/api/ParsedSearchRequest"); - // Java signature : ParsedSearchRequest(String query, String locale, double lat, double lon, boolean isSearchOnMap) - static jmethodID const ctor = jni::GetConstructorID(env, cl, "(Ljava/lang/String;Ljava/lang/String;DDZ)V"); - auto const & r = frm()->GetParsedSearchRequest(); - ms::LatLon const center = frm()->GetParsedCenterLatLon(); - return env->NewObject(cl, ctor, jni::ToJavaString(env, r.m_query), jni::ToJavaString(env, r.m_locale), center.m_lat, center.m_lon, r.m_isSearchOnMap); -} + JNIEXPORT jobject JNICALL Java_app_organicmaps_Framework_nativeGetParsedRoutingData(JNIEnv * env, jclass clazz) + { + using namespace url_scheme; + static jclass const pointClazz = jni::GetGlobalClassRef(env, "app/organicmaps/api/RoutePoint"); + // Java signature : RoutePoint(double lat, double lon, String name) + static jmethodID const pointConstructor = jni::GetConstructorID(env, pointClazz, "(DDLjava/lang/String;)V"); + + static jclass const routeDataClazz = jni::GetGlobalClassRef(env, "app/organicmaps/api/ParsedRoutingData"); + // Java signature : ParsedRoutingData(RoutePoint[] points, int routerType) { + static jmethodID const routeDataConstructor = + jni::GetConstructorID(env, routeDataClazz, "([Lapp/organicmaps/api/RoutePoint;I)V"); + + auto const & routingData = frm()->GetParsedRoutingData(); + jobjectArray points = + jni::ToJavaArray(env, pointClazz, routingData.m_points, + [](JNIEnv * env, RoutePoint const & point) + { + jni::TScopedLocalRef const name(env, jni::ToJavaString(env, point.m_name)); + return env->NewObject(pointClazz, pointConstructor, mercator::YToLat(point.m_org.y), + mercator::XToLon(point.m_org.x), name.get()); + }); + + return env->NewObject(routeDataClazz, routeDataConstructor, points, routingData.m_type); + } -JNIEXPORT jstring JNICALL -Java_app_organicmaps_Framework_nativeGetParsedAppName(JNIEnv * env, jclass) -{ - std::string const & appName = frm()->GetParsedAppName(); - return (appName.empty()) ? nullptr : jni::ToJavaString(env, appName); -} + JNIEXPORT jobject JNICALL Java_app_organicmaps_Framework_nativeGetParsedSearchRequest(JNIEnv * env, jclass clazz) + { + using namespace url_scheme; + static jclass const cl = jni::GetGlobalClassRef(env, "app/organicmaps/api/ParsedSearchRequest"); + // Java signature : ParsedSearchRequest(String query, String locale, double lat, double lon, boolean isSearchOnMap) + static jmethodID const ctor = jni::GetConstructorID(env, cl, "(Ljava/lang/String;Ljava/lang/String;DDZ)V"); + auto const & r = frm()->GetParsedSearchRequest(); + ms::LatLon const center = frm()->GetParsedCenterLatLon(); + return env->NewObject(cl, ctor, jni::ToJavaString(env, r.m_query), jni::ToJavaString(env, r.m_locale), center.m_lat, + center.m_lon, r.m_isSearchOnMap); + } -JNIEXPORT jstring JNICALL -Java_app_organicmaps_Framework_nativeGetParsedBackUrl(JNIEnv * env, jclass) -{ - std::string const & backUrl = frm()->GetParsedBackUrl(); - return (backUrl.empty()) ? nullptr : jni::ToJavaString(env, backUrl); -} + JNIEXPORT jstring JNICALL Java_app_organicmaps_Framework_nativeGetParsedAppName(JNIEnv * env, jclass) + { + std::string const & appName = frm()->GetParsedAppName(); + return (appName.empty()) ? nullptr : jni::ToJavaString(env, appName); + } -JNIEXPORT jdoubleArray JNICALL -Java_app_organicmaps_Framework_nativeGetParsedCenterLatLon(JNIEnv * env, jclass) -{ - ms::LatLon const center = frm()->GetParsedCenterLatLon(); - if (!center.IsValid()) - return nullptr; + JNIEXPORT jstring JNICALL Java_app_organicmaps_Framework_nativeGetParsedBackUrl(JNIEnv * env, jclass) + { + std::string const & backUrl = frm()->GetParsedBackUrl(); + return (backUrl.empty()) ? nullptr : jni::ToJavaString(env, backUrl); + } - double latlon[] = {center.m_lat, center.m_lon}; - jdoubleArray jLatLon = env->NewDoubleArray(2); - env->SetDoubleArrayRegion(jLatLon, 0, 2, latlon); + JNIEXPORT jdoubleArray JNICALL Java_app_organicmaps_Framework_nativeGetParsedCenterLatLon(JNIEnv * env, jclass) + { + ms::LatLon const center = frm()->GetParsedCenterLatLon(); + if (!center.IsValid()) + return nullptr; - return jLatLon; -} + double latlon[] = {center.m_lat, center.m_lon}; + jdoubleArray jLatLon = env->NewDoubleArray(2); + env->SetDoubleArrayRegion(jLatLon, 0, 2, latlon); -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativePlacePageActivationListener(JNIEnv *env, jclass, jobject jListener) -{ - LOG(LINFO, ("Set global map object listener")); - g_placePageActivationListener = env->NewGlobalRef(jListener); - // void onPlacePageActivated(MapObject object); - jmethodID const activatedId = jni::GetMethodID(env, g_placePageActivationListener, - "onPlacePageActivated", - "(Lapp/organicmaps/widget/placepage/PlacePageData;)V"); - // void onPlacePageDeactivated(); - jmethodID const deactivateId = jni::GetMethodID(env, g_placePageActivationListener, - "onPlacePageDeactivated", "()V"); - // void onPlacePageDeactivated(); - jmethodID const switchFullscreenId = jni::GetMethodID(env, g_placePageActivationListener, - "onSwitchFullScreenMode", "()V"); - auto const fillPlacePage = [activatedId]() + return jLatLon; + } + + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativePlacePageActivationListener(JNIEnv * env, jclass, + jobject jListener) { - JNIEnv * env = jni::GetEnv(); - auto const & info = frm()->GetCurrentPlacePageInfo(); - jni::TScopedLocalRef placePageDataRef(env, nullptr); - if (info.IsTrack()) + LOG(LINFO, ("Set global map object listener")); + g_placePageActivationListener = env->NewGlobalRef(jListener); + // void onPlacePageActivated(MapObject object); + jmethodID const activatedId = jni::GetMethodID(env, g_placePageActivationListener, "onPlacePageActivated", + "(Lapp/organicmaps/widget/placepage/PlacePageData;)V"); + // void onPlacePageDeactivated(); + jmethodID const deactivateId = + jni::GetMethodID(env, g_placePageActivationListener, "onPlacePageDeactivated", "()V"); + // void onPlacePageDeactivated(); + jmethodID const switchFullscreenId = + jni::GetMethodID(env, g_placePageActivationListener, "onSwitchFullScreenMode", "()V"); + auto const fillPlacePage = [activatedId]() { - auto const elevationInfo = frm()->GetBookmarkManager().MakeElevationInfo(info.GetTrackId()); - placePageDataRef.reset(usermark_helper::CreateElevationInfo(env, elevationInfo)); - } - else + JNIEnv * env = jni::GetEnv(); + auto const & info = frm()->GetCurrentPlacePageInfo(); + jni::TScopedLocalRef placePageDataRef(env, nullptr); + if (info.IsTrack()) + { + auto const elevationInfo = frm()->GetBookmarkManager().MakeElevationInfo(info.GetTrackId()); + placePageDataRef.reset(usermark_helper::CreateElevationInfo(env, elevationInfo)); + } + else + { + placePageDataRef.reset(usermark_helper::CreateMapObject(env, info)); + } + env->CallVoidMethod(g_placePageActivationListener, activatedId, placePageDataRef.get()); + }; + auto const closePlacePage = [deactivateId]() { - placePageDataRef.reset(usermark_helper::CreateMapObject(env, info)); - } - env->CallVoidMethod(g_placePageActivationListener, activatedId, placePageDataRef.get()); - }; - auto const closePlacePage = [deactivateId]() - { - JNIEnv * env = jni::GetEnv(); - env->CallVoidMethod(g_placePageActivationListener, deactivateId); - }; - auto const switchFullscreen = [switchFullscreenId]() - { - JNIEnv * env = jni::GetEnv(); - env->CallVoidMethod(g_placePageActivationListener, switchFullscreenId); - }; + JNIEnv * env = jni::GetEnv(); + env->CallVoidMethod(g_placePageActivationListener, deactivateId); + }; + auto const switchFullscreen = [switchFullscreenId]() + { + JNIEnv * env = jni::GetEnv(); + env->CallVoidMethod(g_placePageActivationListener, switchFullscreenId); + }; - frm()->SetPlacePageListeners(fillPlacePage, closePlacePage, fillPlacePage, switchFullscreen); -} + frm()->SetPlacePageListeners(fillPlacePage, closePlacePage, fillPlacePage, switchFullscreen); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeRemovePlacePageActivationListener(JNIEnv *env, jclass, jobject jListener) -{ - if (g_placePageActivationListener == nullptr) - return; + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeRemovePlacePageActivationListener(JNIEnv * env, jclass, + jobject jListener) + { + if (g_placePageActivationListener == nullptr) + return; - if (!env->IsSameObject(g_placePageActivationListener, jListener)) - return; + if (!env->IsSameObject(g_placePageActivationListener, jListener)) + return; - frm()->SetPlacePageListeners({} /* onOpen */, {} /* onClose */, {} /* onUpdate */, {} /* onSwitchFullScreen */); - LOG(LINFO, ("Remove global map object listener")); - env->DeleteGlobalRef(g_placePageActivationListener); - g_placePageActivationListener = nullptr; -} + frm()->SetPlacePageListeners({} /* onOpen */, {} /* onClose */, {} /* onUpdate */, {} /* onSwitchFullScreen */); + LOG(LINFO, ("Remove global map object listener")); + env->DeleteGlobalRef(g_placePageActivationListener); + g_placePageActivationListener = nullptr; + } -JNIEXPORT jstring JNICALL -Java_app_organicmaps_Framework_nativeGetGe0Url(JNIEnv * env, jclass, jdouble lat, jdouble lon, jdouble zoomLevel, jstring name) -{ - ::Framework * fr = frm(); - double const scale = (zoomLevel > 0 ? zoomLevel : fr->GetDrawScale()); - string const url = fr->CodeGe0url(lat, lon, scale, jni::ToNativeString(env, name)); - return jni::ToJavaString(env, url); -} + JNIEXPORT jstring JNICALL Java_app_organicmaps_Framework_nativeGetGe0Url(JNIEnv * env, jclass, jdouble lat, + jdouble lon, jdouble zoomLevel, jstring name) + { + ::Framework * fr = frm(); + double const scale = (zoomLevel > 0 ? zoomLevel : fr->GetDrawScale()); + string const url = fr->CodeGe0url(lat, lon, scale, jni::ToNativeString(env, name)); + return jni::ToJavaString(env, url); + } -JNIEXPORT jobject JNICALL -Java_app_organicmaps_Framework_nativeGetDistanceAndAzimuth( - JNIEnv * env, jclass, jdouble merX, jdouble merY, jdouble cLat, jdouble cLon, jdouble north) -{ - platform::Distance distance; - double azimut = -1.0; - frm()->GetDistanceAndAzimut(m2::PointD(merX, merY), cLat, cLon, north, distance, azimut); + JNIEXPORT jobject JNICALL Java_app_organicmaps_Framework_nativeGetDistanceAndAzimuth(JNIEnv * env, jclass, + jdouble merX, jdouble merY, + jdouble cLat, jdouble cLon, + jdouble north) + { + platform::Distance distance; + double azimut = -1.0; + frm()->GetDistanceAndAzimut(m2::PointD(merX, merY), cLat, cLon, north, distance, azimut); - static jclass const daClazz = jni::GetGlobalClassRef(env, "app/organicmaps/bookmarks/data/DistanceAndAzimut"); - // Java signature : DistanceAndAzimut(Distance distance, double azimuth) - static jmethodID const methodID = jni::GetConstructorID(env, daClazz, "(Lapp/organicmaps/util/Distance;D)V"); + static jclass const daClazz = jni::GetGlobalClassRef(env, "app/organicmaps/bookmarks/data/DistanceAndAzimut"); + // Java signature : DistanceAndAzimut(Distance distance, double azimuth) + static jmethodID const methodID = jni::GetConstructorID(env, daClazz, "(Lapp/organicmaps/util/Distance;D)V"); - return env->NewObject(daClazz, methodID, - ToJavaDistance(env, distance), - static_cast(azimut)); -} + return env->NewObject(daClazz, methodID, ToJavaDistance(env, distance), static_cast(azimut)); + } -JNIEXPORT jobject JNICALL -Java_app_organicmaps_Framework_nativeGetDistanceAndAzimuthFromLatLon( - JNIEnv * env, jclass clazz, jdouble lat, jdouble lon, jdouble cLat, jdouble cLon, jdouble north) -{ - double const merY = mercator::LatToY(lat); - double const merX = mercator::LonToX(lon); - return Java_app_organicmaps_Framework_nativeGetDistanceAndAzimuth(env, clazz, merX, merY, cLat, cLon, north); -} + JNIEXPORT jobject JNICALL Java_app_organicmaps_Framework_nativeGetDistanceAndAzimuthFromLatLon( + JNIEnv * env, jclass clazz, jdouble lat, jdouble lon, jdouble cLat, jdouble cLon, jdouble north) + { + double const merY = mercator::LatToY(lat); + double const merX = mercator::LonToX(lon); + return Java_app_organicmaps_Framework_nativeGetDistanceAndAzimuth(env, clazz, merX, merY, cLat, cLon, north); + } -JNIEXPORT jstring JNICALL -Java_app_organicmaps_Framework_nativeFormatLatLon(JNIEnv * env, jclass, jdouble lat, jdouble lon, int coordsFormat) -{ - switch (static_cast(coordsFormat)) + JNIEXPORT jstring JNICALL Java_app_organicmaps_Framework_nativeFormatLatLon(JNIEnv * env, jclass, jdouble lat, + jdouble lon, int coordsFormat) { + switch (static_cast(coordsFormat)) + { default: - case android::CoordinatesFormat::LatLonDMS: // DMS, comma separated + case android::CoordinatesFormat::LatLonDMS: // DMS, comma separated return jni::ToJavaString(env, measurement_utils::FormatLatLonAsDMS(lat, lon, true /*withComma*/, 2)); - case android::CoordinatesFormat::LatLonDecimal: // Decimal, comma separated + case android::CoordinatesFormat::LatLonDecimal: // Decimal, comma separated return jni::ToJavaString(env, measurement_utils::FormatLatLon(lat, lon, true /* withComma */, 6)); - case android::CoordinatesFormat::OLCFull: // Open location code, long format + case android::CoordinatesFormat::OLCFull: // Open location code, long format return jni::ToJavaString(env, openlocationcode::Encode({lat, lon})); - case android::CoordinatesFormat::OSMLink: // Link to osm.org + case android::CoordinatesFormat::OSMLink: // Link to osm.org return jni::ToJavaString(env, measurement_utils::FormatOsmLink(lat, lon, 14)); case android::CoordinatesFormat::UTM: // Universal Transverse Mercator { @@ -995,951 +904,867 @@ Java_app_organicmaps_Framework_nativeFormatLatLon(JNIEnv * env, jclass, jdouble else return nullptr; } - case android::CoordinatesFormat::MGRS: // Military Grid Reference System + case android::CoordinatesFormat::MGRS: // Military Grid Reference System { string mgrsFormat = utm_mgrs_utils::FormatMGRS(lat, lon, 5); if (!mgrsFormat.empty()) - return jni::ToJavaString(env, mgrsFormat); + return jni::ToJavaString(env, mgrsFormat); else - return nullptr; + return nullptr; + } } } -} -JNIEXPORT jstring JNICALL -Java_app_organicmaps_Framework_nativeFormatAltitude(JNIEnv * env, jclass, jdouble alt) -{ - return jni::ToJavaString(env, platform::Distance::FormatAltitude(alt)); -} + JNIEXPORT jstring JNICALL Java_app_organicmaps_Framework_nativeFormatAltitude(JNIEnv * env, jclass, jdouble alt) + { + return jni::ToJavaString(env, platform::Distance::FormatAltitude(alt)); + } -JNIEXPORT jstring JNICALL -Java_app_organicmaps_Framework_nativeFormatSpeed(JNIEnv * env, jclass, jdouble speed) -{ - auto const units = measurement_utils::GetMeasurementUnits(); - return jni::ToJavaString(env, measurement_utils::FormatSpeedNumeric(speed, units) + " " + - platform::GetLocalizedSpeedUnits(units)); -} + JNIEXPORT jstring JNICALL Java_app_organicmaps_Framework_nativeFormatSpeed(JNIEnv * env, jclass, jdouble speed) + { + auto const units = measurement_utils::GetMeasurementUnits(); + return jni::ToJavaString( + env, measurement_utils::FormatSpeedNumeric(speed, units) + " " + platform::GetLocalizedSpeedUnits(units)); + } -/* -JNIEXPORT jobject JNICALL -Java_app_organicmaps_Framework_nativeGetOutdatedCountriesString(JNIEnv * env, jclass) -{ - return jni::ToJavaString(env, g_framework->GetOutdatedCountriesString()); -} + /* + JNIEXPORT jobject JNICALL + Java_app_organicmaps_Framework_nativeGetOutdatedCountriesString(JNIEnv * env, jclass) + { + return jni::ToJavaString(env, g_framework->GetOutdatedCountriesString()); + } -JNIEXPORT jobjectArray JNICALL -Java_app_organicmaps_Framework_nativeGetOutdatedCountries(JNIEnv * env, jclass) -{ - vector countries; - Storage const & storage = g_framework->GetStorage(); - storage.GetOutdatedCountries(countries); + JNIEXPORT jobjectArray JNICALL + Java_app_organicmaps_Framework_nativeGetOutdatedCountries(JNIEnv * env, jclass) + { + vector countries; + Storage const & storage = g_framework->GetStorage(); + storage.GetOutdatedCountries(countries); - vector ids; - for (auto country : countries) - ids.push_back(country->Name()); + vector ids; + for (auto country : countries) + ids.push_back(country->Name()); - return jni::ToJavaStringArray(env, ids); -} + return jni::ToJavaStringArray(env, ids); + } -JNIEXPORT jint JNICALL -Java_app_organicmaps_Framework_nativeToDoAfterUpdate(JNIEnv * env, jclass) -{ - return g_framework->ToDoAfterUpdate(); -} + JNIEXPORT jint JNICALL + Java_app_organicmaps_Framework_nativeToDoAfterUpdate(JNIEnv * env, jclass) + { + return g_framework->ToDoAfterUpdate(); + } -JNIEXPORT jboolean JNICALL -Java_app_organicmaps_Framework_nativeIsDataVersionChanged(JNIEnv * env, jclass) -{ - return frm()->IsDataVersionUpdated() ? JNI_TRUE : JNI_FALSE; -} + JNIEXPORT jboolean JNICALL + Java_app_organicmaps_Framework_nativeIsDataVersionChanged(JNIEnv * env, jclass) + { + return frm()->IsDataVersionUpdated() ? JNI_TRUE : JNI_FALSE; + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeUpdateSavedDataVersion(JNIEnv * env, jclass) -{ - frm()->UpdateSavedDataVersion(); -} -*/ + JNIEXPORT void JNICALL + Java_app_organicmaps_Framework_nativeUpdateSavedDataVersion(JNIEnv * env, jclass) + { + frm()->UpdateSavedDataVersion(); + } + */ -JNIEXPORT jlong JNICALL -Java_app_organicmaps_Framework_nativeGetDataVersion(JNIEnv * env, jclass) -{ - return frm()->GetCurrentDataVersion(); -} + JNIEXPORT jlong JNICALL Java_app_organicmaps_Framework_nativeGetDataVersion(JNIEnv * env, jclass) + { + return frm()->GetCurrentDataVersion(); + } -JNIEXPORT jint JNICALL -Java_app_organicmaps_Framework_nativeGetDrawScale(JNIEnv * env, jclass) -{ - return static_cast(frm()->GetDrawScale()); -} + JNIEXPORT jint JNICALL Java_app_organicmaps_Framework_nativeGetDrawScale(JNIEnv * env, jclass) + { + return static_cast(frm()->GetDrawScale()); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativePokeSearchInViewport(JNIEnv * env, jclass) -{ - frm()->GetSearchAPI().PokeSearchInViewport(); -} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativePokeSearchInViewport(JNIEnv * env, jclass) + { + frm()->GetSearchAPI().PokeSearchInViewport(); + } -JNIEXPORT jdoubleArray JNICALL -Java_app_organicmaps_Framework_nativeGetScreenRectCenter(JNIEnv * env, jclass) -{ - m2::PointD const center = frm()->GetViewportCenter(); + JNIEXPORT jdoubleArray JNICALL Java_app_organicmaps_Framework_nativeGetScreenRectCenter(JNIEnv * env, jclass) + { + m2::PointD const center = frm()->GetViewportCenter(); - double latlon[] = {mercator::YToLat(center.y), mercator::XToLon(center.x)}; - jdoubleArray jLatLon = env->NewDoubleArray(2); - env->SetDoubleArrayRegion(jLatLon, 0, 2, latlon); + double latlon[] = {mercator::YToLat(center.y), mercator::XToLon(center.x)}; + jdoubleArray jLatLon = env->NewDoubleArray(2); + env->SetDoubleArrayRegion(jLatLon, 0, 2, latlon); - return jLatLon; -} + return jLatLon; + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeShowTrackRect(JNIEnv * env, jclass, jlong track) -{ - frm()->ShowTrack(static_cast(track)); -} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeShowTrackRect(JNIEnv * env, jclass, jlong track) + { + frm()->ShowTrack(static_cast(track)); + } -JNIEXPORT jstring JNICALL -Java_app_organicmaps_Framework_nativeGetBookmarkDir(JNIEnv * env, jclass) -{ - return jni::ToJavaString(env, GetPlatform().SettingsDir().c_str()); -} + JNIEXPORT jstring JNICALL Java_app_organicmaps_Framework_nativeGetBookmarkDir(JNIEnv * env, jclass) + { + return jni::ToJavaString(env, GetPlatform().SettingsDir().c_str()); + } -JNIEXPORT jstring JNICALL -Java_app_organicmaps_Framework_nativeGetWritableDir(JNIEnv * env, jclass) -{ - return jni::ToJavaString(env, GetPlatform().WritableDir().c_str()); -} + JNIEXPORT jstring JNICALL Java_app_organicmaps_Framework_nativeGetWritableDir(JNIEnv * env, jclass) + { + return jni::ToJavaString(env, GetPlatform().WritableDir().c_str()); + } -JNIEXPORT jstring JNICALL -Java_app_organicmaps_Framework_nativeGetSettingsDir(JNIEnv * env, jclass) -{ - return jni::ToJavaString(env, GetPlatform().SettingsDir().c_str()); -} + JNIEXPORT jstring JNICALL Java_app_organicmaps_Framework_nativeGetSettingsDir(JNIEnv * env, jclass) + { + return jni::ToJavaString(env, GetPlatform().SettingsDir().c_str()); + } -JNIEXPORT jstring JNICALL -Java_app_organicmaps_Framework_nativeGetDataFileExt(JNIEnv * env, jclass) -{ - return jni::ToJavaString(env, DATA_FILE_EXTENSION); -} + JNIEXPORT jstring JNICALL Java_app_organicmaps_Framework_nativeGetDataFileExt(JNIEnv * env, jclass) + { + return jni::ToJavaString(env, DATA_FILE_EXTENSION); + } -JNIEXPORT jobjectArray JNICALL -Java_app_organicmaps_Framework_nativeGetMovableFilesExts(JNIEnv * env, jclass) -{ - vector exts = { DATA_FILE_EXTENSION, FONT_FILE_EXTENSION }; - platform::CountryIndexes::GetIndexesExts(exts); - return jni::ToJavaStringArray(env, exts); -} + JNIEXPORT jobjectArray JNICALL Java_app_organicmaps_Framework_nativeGetMovableFilesExts(JNIEnv * env, jclass) + { + vector exts = {DATA_FILE_EXTENSION, FONT_FILE_EXTENSION}; + platform::CountryIndexes::GetIndexesExts(exts); + return jni::ToJavaStringArray(env, exts); + } -JNIEXPORT jobjectArray JNICALL -Java_app_organicmaps_Framework_nativeGetBookmarksFilesExts(JNIEnv * env, jclass) -{ - static std::array const kBookmarkExtensions = { - std::string{kKmzExtension}, - std::string{kKmlExtension}, - std::string{kKmbExtension}, - std::string{kGpxExtension} - }; - - return jni::ToJavaStringArray(env, kBookmarkExtensions); -} + JNIEXPORT jobjectArray JNICALL Java_app_organicmaps_Framework_nativeGetBookmarksFilesExts(JNIEnv * env, jclass) + { + static std::array const kBookmarkExtensions = { + std::string{kKmzExtension}, std::string{kKmlExtension}, std::string{kKmbExtension}, std::string{kGpxExtension}}; -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeChangeWritableDir(JNIEnv * env, jclass, jstring jNewPath) -{ - string newPath = jni::ToNativeString(env, jNewPath); - g_framework->RemoveLocalMaps(); - android::Platform::Instance().SetWritableDir(newPath); - g_framework->AddLocalMaps(); -} + return jni::ToJavaStringArray(env, kBookmarkExtensions); + } -JNIEXPORT jboolean JNICALL -Java_app_organicmaps_Framework_nativeIsRoutingActive(JNIEnv * env, jclass) -{ - return frm()->GetRoutingManager().IsRoutingActive(); -} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeChangeWritableDir(JNIEnv * env, jclass, jstring jNewPath) + { + string newPath = jni::ToNativeString(env, jNewPath); + g_framework->RemoveLocalMaps(); + android::Platform::Instance().SetWritableDir(newPath); + g_framework->AddLocalMaps(); + } -JNIEXPORT jboolean JNICALL -Java_app_organicmaps_Framework_nativeIsRouteBuilding(JNIEnv * env, jclass) -{ - return frm()->GetRoutingManager().IsRouteBuilding(); -} + JNIEXPORT jboolean JNICALL Java_app_organicmaps_Framework_nativeIsRoutingActive(JNIEnv * env, jclass) + { + return frm()->GetRoutingManager().IsRoutingActive(); + } -JNIEXPORT jboolean JNICALL -Java_app_organicmaps_Framework_nativeIsRouteBuilt(JNIEnv * env, jclass) -{ - return frm()->GetRoutingManager().IsRouteBuilt(); -} + JNIEXPORT jboolean JNICALL Java_app_organicmaps_Framework_nativeIsRouteBuilding(JNIEnv * env, jclass) + { + return frm()->GetRoutingManager().IsRouteBuilding(); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeCloseRouting(JNIEnv * env, jclass) -{ - frm()->GetRoutingManager().CloseRouting(true /* remove route points */); -} + JNIEXPORT jboolean JNICALL Java_app_organicmaps_Framework_nativeIsRouteBuilt(JNIEnv * env, jclass) + { + return frm()->GetRoutingManager().IsRouteBuilt(); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeBuildRoute(JNIEnv * env, jclass) -{ - frm()->GetRoutingManager().BuildRoute(); -} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeCloseRouting(JNIEnv * env, jclass) + { + frm()->GetRoutingManager().CloseRouting(true /* remove route points */); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeRemoveRoute(JNIEnv * env, jclass) -{ - frm()->GetRoutingManager().RemoveRoute(false /* deactivateFollowing */); -} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeBuildRoute(JNIEnv * env, jclass) + { + frm()->GetRoutingManager().BuildRoute(); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeFollowRoute(JNIEnv * env, jclass) -{ - frm()->GetRoutingManager().FollowRoute(); -} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeRemoveRoute(JNIEnv * env, jclass) + { + frm()->GetRoutingManager().RemoveRoute(false /* deactivateFollowing */); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeDisableFollowing(JNIEnv * env, jclass) -{ - frm()->GetRoutingManager().DisableFollowMode(); -} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeFollowRoute(JNIEnv * env, jclass) + { + frm()->GetRoutingManager().FollowRoute(); + } -JNIEXPORT jobjectArray JNICALL -Java_app_organicmaps_Framework_nativeGenerateNotifications(JNIEnv * env, jclass, bool announceStreets) -{ - ::Framework * fr = frm(); - if (!fr->GetRoutingManager().IsRoutingActive()) - return nullptr; + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeDisableFollowing(JNIEnv * env, jclass) + { + frm()->GetRoutingManager().DisableFollowMode(); + } - vector notifications; - fr->GetRoutingManager().GenerateNotifications(notifications, announceStreets); - if (notifications.empty()) - return nullptr; + JNIEXPORT jobjectArray JNICALL Java_app_organicmaps_Framework_nativeGenerateNotifications(JNIEnv * env, jclass, + bool announceStreets) + { + ::Framework * fr = frm(); + if (!fr->GetRoutingManager().IsRoutingActive()) + return nullptr; - return jni::ToJavaStringArray(env, notifications); -} + vector notifications; + fr->GetRoutingManager().GenerateNotifications(notifications, announceStreets); + if (notifications.empty()) + return nullptr; -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeSetSpeedCamManagerMode(JNIEnv * env, jclass, jint mode) -{ - frm()->GetRoutingManager().GetSpeedCamManager().SetMode( - static_cast(mode)); -} + return jni::ToJavaStringArray(env, notifications); + } -JNIEXPORT jint JNICALL -Java_app_organicmaps_Framework_nativeGetSpeedCamManagerMode(JNIEnv * env, jclass) -{ - return static_cast(frm()->GetRoutingManager().GetSpeedCamManager().GetMode()); -} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeSetSpeedCamManagerMode(JNIEnv * env, jclass, jint mode) + { + frm()->GetRoutingManager().GetSpeedCamManager().SetMode(static_cast(mode)); + } -JNIEXPORT jobject JNICALL -Java_app_organicmaps_Framework_nativeGetRouteFollowingInfo(JNIEnv * env, jclass) -{ - ::Framework * fr = frm(); - if (!fr->GetRoutingManager().IsRoutingActive()) - return nullptr; - - routing::FollowingInfo info; - fr->GetRoutingManager().GetRouteFollowingInfo(info); - if (!info.IsValid()) - return nullptr; - - static jclass const klass = jni::GetGlobalClassRef(env, "app/organicmaps/routing/RoutingInfo"); - // Java signature : RoutingInfo(Distance distToTarget, Distance distToTurn, - // String currentStreet, String nextStreet, - // double completionPercent, int vehicleTurnOrdinal, int - // vehicleNextTurnOrdinal, int pedestrianTurnOrdinal, int exitNum, - // int totalTime, SingleLaneInfo[] lanes) - static jmethodID const ctorRouteInfoID = - jni::GetConstructorID(env, klass, - "(Lapp/organicmaps/util/Distance;Lapp/organicmaps/util/Distance;" - "Ljava/lang/String;Ljava/lang/String;DIIIII" - "[Lapp/organicmaps/routing/SingleLaneInfo;ZZ)V"); - - vector const & lanes = info.m_lanes; - jobjectArray jLanes = nullptr; - if (!lanes.empty()) - { - static jclass const laneClass = jni::GetGlobalClassRef(env, "app/organicmaps/routing/SingleLaneInfo"); - auto const lanesSize = static_cast(lanes.size()); - jLanes = env->NewObjectArray(lanesSize, laneClass, nullptr); - ASSERT(jLanes, (jni::DescribeException())); - static jmethodID const ctorSingleLaneInfoID = jni::GetConstructorID(env, laneClass, "([BZ)V"); - - for (jsize j = 0; j < lanesSize; ++j) + JNIEXPORT jint JNICALL Java_app_organicmaps_Framework_nativeGetSpeedCamManagerMode(JNIEnv * env, jclass) + { + return static_cast(frm()->GetRoutingManager().GetSpeedCamManager().GetMode()); + } + + JNIEXPORT jobject JNICALL Java_app_organicmaps_Framework_nativeGetRouteFollowingInfo(JNIEnv * env, jclass) + { + ::Framework * fr = frm(); + if (!fr->GetRoutingManager().IsRoutingActive()) + return nullptr; + + routing::FollowingInfo info; + fr->GetRoutingManager().GetRouteFollowingInfo(info); + if (!info.IsValid()) + return nullptr; + + static jclass const klass = jni::GetGlobalClassRef(env, "app/organicmaps/routing/RoutingInfo"); + // Java signature : RoutingInfo(Distance distToTarget, Distance distToTurn, + // String currentStreet, String nextStreet, + // double completionPercent, int vehicleTurnOrdinal, int + // vehicleNextTurnOrdinal, int pedestrianTurnOrdinal, int exitNum, + // int totalTime, SingleLaneInfo[] lanes) + static jmethodID const ctorRouteInfoID = + jni::GetConstructorID(env, klass, + "(Lapp/organicmaps/util/Distance;Lapp/organicmaps/util/Distance;" + "Ljava/lang/String;Ljava/lang/String;DIIIII" + "[Lapp/organicmaps/routing/SingleLaneInfo;ZZ)V"); + + vector const & lanes = info.m_lanes; + jobjectArray jLanes = nullptr; + if (!lanes.empty()) { - auto const laneSize = static_cast(lanes[j].m_lane.size()); - jni::TScopedLocalByteArrayRef singleLane(env, env->NewByteArray(laneSize)); - ASSERT(singleLane.get(), (jni::DescribeException())); - env->SetByteArrayRegion(singleLane.get(), 0, laneSize, lanes[j].m_lane.data()); - - jni::TScopedLocalRef singleLaneInfo( - env, env->NewObject(laneClass, ctorSingleLaneInfoID, singleLane.get(), - lanes[j].m_isRecommended)); - ASSERT(singleLaneInfo.get(), (jni::DescribeException())); - env->SetObjectArrayElement(jLanes, j, singleLaneInfo.get()); + static jclass const laneClass = jni::GetGlobalClassRef(env, "app/organicmaps/routing/SingleLaneInfo"); + auto const lanesSize = static_cast(lanes.size()); + jLanes = env->NewObjectArray(lanesSize, laneClass, nullptr); + ASSERT(jLanes, (jni::DescribeException())); + static jmethodID const ctorSingleLaneInfoID = jni::GetConstructorID(env, laneClass, "([BZ)V"); + + for (jsize j = 0; j < lanesSize; ++j) + { + auto const laneSize = static_cast(lanes[j].m_lane.size()); + jni::TScopedLocalByteArrayRef singleLane(env, env->NewByteArray(laneSize)); + ASSERT(singleLane.get(), (jni::DescribeException())); + env->SetByteArrayRegion(singleLane.get(), 0, laneSize, lanes[j].m_lane.data()); + + jni::TScopedLocalRef singleLaneInfo( + env, env->NewObject(laneClass, ctorSingleLaneInfoID, singleLane.get(), lanes[j].m_isRecommended)); + ASSERT(singleLaneInfo.get(), (jni::DescribeException())); + env->SetObjectArrayElement(jLanes, j, singleLaneInfo.get()); + } } - } - auto const & rm = frm()->GetRoutingManager(); - auto const isSpeedCamLimitExceeded = rm.IsRoutingActive() ? rm.IsSpeedCamLimitExceeded() : false; - auto const shouldPlaySignal = frm()->GetRoutingManager().GetSpeedCamManager().ShouldPlayBeepSignal(); - jobject const result = env->NewObject( - klass, ctorRouteInfoID, ToJavaDistance(env, info.m_distToTarget), - ToJavaDistance(env, info.m_distToTurn), jni::ToJavaString(env, info.m_sourceName), - jni::ToJavaString(env, info.m_displayedStreetName), info.m_completionPercent, info.m_turn, - info.m_nextTurn, info.m_pedestrianTurn, info.m_exitNum, info.m_time, jLanes, - static_cast(isSpeedCamLimitExceeded), static_cast(shouldPlaySignal)); - ASSERT(result, (jni::DescribeException())); - return result; -} + auto const & rm = frm()->GetRoutingManager(); + auto const isSpeedCamLimitExceeded = rm.IsRoutingActive() ? rm.IsSpeedCamLimitExceeded() : false; + auto const shouldPlaySignal = frm()->GetRoutingManager().GetSpeedCamManager().ShouldPlayBeepSignal(); + jobject const result = env->NewObject( + klass, ctorRouteInfoID, ToJavaDistance(env, info.m_distToTarget), ToJavaDistance(env, info.m_distToTurn), + jni::ToJavaString(env, info.m_sourceName), jni::ToJavaString(env, info.m_displayedStreetName), + info.m_completionPercent, info.m_turn, info.m_nextTurn, info.m_pedestrianTurn, info.m_exitNum, info.m_time, + jLanes, static_cast(isSpeedCamLimitExceeded), static_cast(shouldPlaySignal)); + ASSERT(result, (jni::DescribeException())); + return result; + } -JNIEXPORT jobjectArray JNICALL -Java_app_organicmaps_Framework_nativeGetRouteJunctionPoints(JNIEnv * env, jclass) -{ - vector junctionPoints; - if (!frm()->GetRoutingManager().RoutingSession().GetRouteJunctionPoints(junctionPoints)) + JNIEXPORT jobjectArray JNICALL Java_app_organicmaps_Framework_nativeGetRouteJunctionPoints(JNIEnv * env, jclass) { - LOG(LWARNING, ("Can't get the route junction points")); - return nullptr; + vector junctionPoints; + if (!frm()->GetRoutingManager().RoutingSession().GetRouteJunctionPoints(junctionPoints)) + { + LOG(LWARNING, ("Can't get the route junction points")); + return nullptr; + } + + static jclass const junctionClazz = jni::GetGlobalClassRef(env, "app/organicmaps/routing/JunctionInfo"); + // Java signature : JunctionInfo(double lat, double lon) + static jmethodID const junctionConstructor = jni::GetConstructorID(env, junctionClazz, "(DD)V"); + + return jni::ToJavaArray(env, junctionClazz, junctionPoints, + [](JNIEnv * env, m2::PointD const & point) { + return env->NewObject(junctionClazz, junctionConstructor, mercator::YToLat(point.y), + mercator::XToLon(point.x)); + }); } - static jclass const junctionClazz = jni::GetGlobalClassRef(env, "app/organicmaps/routing/JunctionInfo"); - // Java signature : JunctionInfo(double lat, double lon) - static jmethodID const junctionConstructor = jni::GetConstructorID(env, junctionClazz, "(DD)V"); + JNIEXPORT jintArray JNICALL Java_app_organicmaps_Framework_nativeGenerateRouteAltitudeChartBits( + JNIEnv * env, jclass, jint width, jint height, jobject routeAltitudeLimits) + { + RoutingManager::DistanceAltitude altitudes; + if (!frm()->GetRoutingManager().GetRouteAltitudesAndDistancesM(altitudes)) + { + LOG(LWARNING, ("Can't get distance to route points and altitude.")); + return nullptr; + } - return jni::ToJavaArray(env, junctionClazz, junctionPoints, - [](JNIEnv * env, m2::PointD const & point) + altitudes.Simplify(); + + vector imageRGBAData; + if (!altitudes.GenerateRouteAltitudeChart(width, height, imageRGBAData)) { - return env->NewObject(junctionClazz, junctionConstructor, - mercator::YToLat(point.y), - mercator::XToLon(point.x)); - }); -} + LOG(LWARNING, ("Can't generate route altitude image.")); + return nullptr; + } -JNIEXPORT jintArray JNICALL -Java_app_organicmaps_Framework_nativeGenerateRouteAltitudeChartBits(JNIEnv * env, jclass, jint width, jint height, jobject routeAltitudeLimits) -{ - RoutingManager::DistanceAltitude altitudes; - if (!frm()->GetRoutingManager().GetRouteAltitudesAndDistancesM(altitudes)) - { - LOG(LWARNING, ("Can't get distance to route points and altitude.")); - return nullptr; - } + uint32_t totalAscent, totalDescent; + altitudes.CalculateAscentDescent(totalAscent, totalDescent); + + // Android platform code has specific result string formatting, so make conversion here. + using namespace measurement_utils; + auto units = Units::Metric; + if (settings::Get(settings::kMeasurementUnits, units) && units == Units::Imperial) + { + totalAscent = measurement_utils::MetersToFeet(totalAscent); + totalDescent = measurement_utils::MetersToFeet(totalDescent); + } - altitudes.Simplify(); + jni::TScopedLocalRef const totalAscentString(env, jni::ToJavaString(env, ToStringPrecision(totalAscent, 0))); - vector imageRGBAData; - if (!altitudes.GenerateRouteAltitudeChart(width, height, imageRGBAData)) - { - LOG(LWARNING, ("Can't generate route altitude image.")); - return nullptr; - } + jni::TScopedLocalRef const totalDescentString(env, jni::ToJavaString(env, ToStringPrecision(totalDescent, 0))); - uint32_t totalAscent, totalDescent; - altitudes.CalculateAscentDescent(totalAscent, totalDescent); + // Passing route limits. + // Do not use jni::GetGlobalClassRef, because this class is used only to init static fieldId vars. + static jclass const routeAltitudeLimitsClass = env->GetObjectClass(routeAltitudeLimits); + ASSERT(routeAltitudeLimitsClass, ()); - // Android platform code has specific result string formatting, so make conversion here. - using namespace measurement_utils; - auto units = Units::Metric; - if (settings::Get(settings::kMeasurementUnits, units) && units == Units::Imperial) - { - totalAscent = measurement_utils::MetersToFeet(totalAscent); - totalDescent = measurement_utils::MetersToFeet(totalDescent); - } + static jfieldID const totalAscentField = env->GetFieldID(routeAltitudeLimitsClass, "totalAscent", "I"); + ASSERT(totalAscentField, ()); + env->SetIntField(routeAltitudeLimits, totalAscentField, static_cast(totalAscent)); - jni::TScopedLocalRef const totalAscentString(env, jni::ToJavaString(env, ToStringPrecision(totalAscent, 0))); + static jfieldID const totalDescentField = env->GetFieldID(routeAltitudeLimitsClass, "totalDescent", "I"); + ASSERT(totalDescentField, ()); + env->SetIntField(routeAltitudeLimits, totalDescentField, static_cast(totalDescent)); - jni::TScopedLocalRef const totalDescentString(env, jni::ToJavaString(env, ToStringPrecision(totalDescent, 0))); + static jfieldID const totalAscentStringField = + env->GetFieldID(routeAltitudeLimitsClass, "totalAscentString", "Ljava/lang/String;"); + ASSERT(totalAscentStringField, ()); + env->SetObjectField(routeAltitudeLimits, totalAscentStringField, totalAscentString.get()); - // Passing route limits. - // Do not use jni::GetGlobalClassRef, because this class is used only to init static fieldId vars. - static jclass const routeAltitudeLimitsClass = env->GetObjectClass(routeAltitudeLimits); - ASSERT(routeAltitudeLimitsClass, ()); + static jfieldID const totalDescentStringField = + env->GetFieldID(routeAltitudeLimitsClass, "totalDescentString", "Ljava/lang/String;"); + ASSERT(totalDescentStringField, ()); + env->SetObjectField(routeAltitudeLimits, totalDescentStringField, totalDescentString.get()); - static jfieldID const totalAscentField = env->GetFieldID(routeAltitudeLimitsClass, "totalAscent", "I"); - ASSERT(totalAscentField, ()); - env->SetIntField(routeAltitudeLimits, totalAscentField, static_cast(totalAscent)); + static jfieldID const isMetricUnitsField = env->GetFieldID(routeAltitudeLimitsClass, "isMetricUnits", "Z"); + ASSERT(isMetricUnitsField, ()); + env->SetBooleanField(routeAltitudeLimits, isMetricUnitsField, units == Units::Metric); - static jfieldID const totalDescentField = env->GetFieldID(routeAltitudeLimitsClass, "totalDescent", "I"); - ASSERT(totalDescentField, ()); - env->SetIntField(routeAltitudeLimits, totalDescentField, static_cast(totalDescent)); + size_t const imageRGBADataSize = imageRGBAData.size(); + ASSERT_NOT_EQUAL(imageRGBADataSize, 0, + ("GenerateRouteAltitudeChart returns true but the vector with altitude image bits is empty.")); - static jfieldID const totalAscentStringField = env->GetFieldID(routeAltitudeLimitsClass, "totalAscentString", "Ljava/lang/String;"); - ASSERT(totalAscentStringField, ()); - env->SetObjectField(routeAltitudeLimits, totalAscentStringField, totalAscentString.get()); + size_t const pxlCount = width * height; + if (maps::kAltitudeChartBPP * pxlCount != imageRGBADataSize) + { + LOG(LWARNING, ("Wrong size of vector with altitude image bits. Expected size:", pxlCount, + ". Real size:", imageRGBADataSize)); + return nullptr; + } - static jfieldID const totalDescentStringField = env->GetFieldID(routeAltitudeLimitsClass, "totalDescentString", "Ljava/lang/String;"); - ASSERT(totalDescentStringField, ()); - env->SetObjectField(routeAltitudeLimits, totalDescentStringField, totalDescentString.get()); + jintArray imageRGBADataArray = env->NewIntArray(static_cast(pxlCount)); + ASSERT(imageRGBADataArray, ()); + jint * arrayElements = env->GetIntArrayElements(imageRGBADataArray, 0); + ASSERT(arrayElements, ()); - static jfieldID const isMetricUnitsField = env->GetFieldID(routeAltitudeLimitsClass, "isMetricUnits", "Z"); - ASSERT(isMetricUnitsField, ()); - env->SetBooleanField(routeAltitudeLimits, isMetricUnitsField, units == Units::Metric); + for (size_t i = 0; i < pxlCount; ++i) + { + size_t const shiftInBytes = i * maps::kAltitudeChartBPP; + // Type of |imageRGBAData| elements is uint8_t. But uint8_t is promoted to unsinged int in code below before + // shifting. So there's no data lost in code below. + arrayElements[i] = (imageRGBAData[shiftInBytes + 3] << 24) /* alpha */ + | (imageRGBAData[shiftInBytes] << 16) /* red */ + | (imageRGBAData[shiftInBytes + 1] << 8) /* green */ + | (imageRGBAData[shiftInBytes + 2]); /* blue */ + } + env->ReleaseIntArrayElements(imageRGBADataArray, arrayElements, 0); - size_t const imageRGBADataSize = imageRGBAData.size(); - ASSERT_NOT_EQUAL(imageRGBADataSize, 0, ("GenerateRouteAltitudeChart returns true but the vector with altitude image bits is empty.")); + return imageRGBADataArray; + } - size_t const pxlCount = width * height; - if (maps::kAltitudeChartBPP * pxlCount != imageRGBADataSize) + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeShowCountry(JNIEnv * env, jclass, jstring countryId, + jboolean zoomToDownloadButton) { - LOG(LWARNING, ("Wrong size of vector with altitude image bits. Expected size:", pxlCount, ". Real size:", imageRGBADataSize)); - return nullptr; + g_framework->ShowNode(jni::ToNativeString(env, countryId), (bool)zoomToDownloadButton); } - jintArray imageRGBADataArray = env->NewIntArray(static_cast(pxlCount)); - ASSERT(imageRGBADataArray, ()); - jint * arrayElements = env->GetIntArrayElements(imageRGBADataArray, 0); - ASSERT(arrayElements, ()); - - for (size_t i = 0; i < pxlCount; ++i) + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeSetRoutingListener(JNIEnv * env, jclass, jobject listener) { - size_t const shiftInBytes = i * maps::kAltitudeChartBPP; - // Type of |imageRGBAData| elements is uint8_t. But uint8_t is promoted to unsinged int in code below before shifting. - // So there's no data lost in code below. - arrayElements[i] = (imageRGBAData[shiftInBytes + 3] << 24) /* alpha */ - | (imageRGBAData[shiftInBytes] << 16) /* red */ - | (imageRGBAData[shiftInBytes + 1] << 8) /* green */ - | (imageRGBAData[shiftInBytes + 2]); /* blue */ + CHECK(g_framework, ("Framework isn't created yet!")); + frm()->GetRoutingManager().SetRouteBuildingListener( + [rf = jni::make_global_ref(listener)](routing::RouterResultCode e, storage::CountriesSet const & countries) + { CallRoutingListener(rf, static_cast(e), countries); }); } - env->ReleaseIntArrayElements(imageRGBADataArray, arrayElements, 0); - - return imageRGBADataArray; -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeShowCountry(JNIEnv * env, jclass, jstring countryId, jboolean zoomToDownloadButton) -{ - g_framework->ShowNode(jni::ToNativeString(env, countryId), (bool) zoomToDownloadButton); -} -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeSetRoutingListener(JNIEnv * env, jclass, jobject listener) -{ - CHECK(g_framework, ("Framework isn't created yet!")); - frm()->GetRoutingManager().SetRouteBuildingListener( - [rf = jni::make_global_ref(listener)](routing::RouterResultCode e, storage::CountriesSet const & countries) { - CallRoutingListener(rf, static_cast(e), countries); - }); -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeSetRouteProgressListener(JNIEnv * env, jclass, jobject listener) -{ - CHECK(g_framework, ("Framework isn't created yet!")); - frm()->GetRoutingManager().SetRouteProgressListener( - bind(&CallRouteProgressListener, jni::make_global_ref(listener), _1)); -} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeSetRouteProgressListener(JNIEnv * env, jclass, + jobject listener) + { + CHECK(g_framework, ("Framework isn't created yet!")); + frm()->GetRoutingManager().SetRouteProgressListener( + bind(&CallRouteProgressListener, jni::make_global_ref(listener), _1)); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeSetRoutingRecommendationListener(JNIEnv * env, jclass, - jobject listener) -{ - CHECK(g_framework, ("Framework isn't created yet!")); - frm()->GetRoutingManager().SetRouteRecommendationListener( - bind(&CallRouteRecommendationListener, jni::make_global_ref(listener), _1)); -} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeSetRoutingRecommendationListener(JNIEnv * env, jclass, + jobject listener) + { + CHECK(g_framework, ("Framework isn't created yet!")); + frm()->GetRoutingManager().SetRouteRecommendationListener( + bind(&CallRouteRecommendationListener, jni::make_global_ref(listener), _1)); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeSetRoutingLoadPointsListener( - JNIEnv *, jclass, jobject listener) -{ - CHECK(g_framework, ("Framework isn't created yet!")); - if (listener != nullptr) - g_loadRouteHandler = bind(&CallSetRoutingLoadPointsListener, jni::make_global_ref(listener), _1); - else - g_loadRouteHandler = nullptr; -} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeSetRoutingLoadPointsListener(JNIEnv *, jclass, + jobject listener) + { + CHECK(g_framework, ("Framework isn't created yet!")); + if (listener != nullptr) + g_loadRouteHandler = bind(&CallSetRoutingLoadPointsListener, jni::make_global_ref(listener), _1); + else + g_loadRouteHandler = nullptr; + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeDeactivatePopup(JNIEnv * env, jclass) -{ - return g_framework->DeactivatePopup(); -} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeDeactivatePopup(JNIEnv * env, jclass) + { + return g_framework->DeactivatePopup(); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeSetMapStyle(JNIEnv * env, jclass, jint mapStyle) -{ - MapStyle const val = static_cast(mapStyle); - if (val != g_framework->GetMapStyle()) - g_framework->SetMapStyle(val); -} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeSetMapStyle(JNIEnv * env, jclass, jint mapStyle) + { + MapStyle const val = static_cast(mapStyle); + if (val != g_framework->GetMapStyle()) + g_framework->SetMapStyle(val); + } -JNIEXPORT jint JNICALL -Java_app_organicmaps_Framework_nativeGetMapStyle(JNIEnv * env, jclass) -{ - return g_framework->GetMapStyle(); -} + JNIEXPORT jint JNICALL Java_app_organicmaps_Framework_nativeGetMapStyle(JNIEnv * env, jclass) + { + return g_framework->GetMapStyle(); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeMarkMapStyle(JNIEnv * env, jclass, jint mapStyle) -{ - MapStyle const val = static_cast(mapStyle); - if (val != g_framework->GetMapStyle()) - g_framework->MarkMapStyle(val); -} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeMarkMapStyle(JNIEnv * env, jclass, jint mapStyle) + { + MapStyle const val = static_cast(mapStyle); + if (val != g_framework->GetMapStyle()) + g_framework->MarkMapStyle(val); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeSetRouter(JNIEnv * env, jclass, jint routerType) -{ - using Type = routing::RouterType; - Type type = Type::Vehicle; - switch (routerType) + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeSetRouter(JNIEnv * env, jclass, jint routerType) { + using Type = routing::RouterType; + Type type = Type::Vehicle; + switch (routerType) + { case 0: break; case 1: type = Type::Pedestrian; break; case 2: type = Type::Bicycle; break; case 3: type = Type::Transit; break; case 4: type = Type::Ruler; break; default: assert(false); break; + } + g_framework->GetRoutingManager().SetRouter(type); } - g_framework->GetRoutingManager().SetRouter(type); -} -JNIEXPORT jint JNICALL -Java_app_organicmaps_Framework_nativeGetRouter(JNIEnv * env, jclass) -{ - return static_cast(g_framework->GetRoutingManager().GetRouter()); -} + JNIEXPORT jint JNICALL Java_app_organicmaps_Framework_nativeGetRouter(JNIEnv * env, jclass) + { + return static_cast(g_framework->GetRoutingManager().GetRouter()); + } -JNIEXPORT jint JNICALL -Java_app_organicmaps_Framework_nativeGetLastUsedRouter(JNIEnv * env, jclass) -{ - return static_cast(g_framework->GetRoutingManager().GetLastUsedRouter()); -} + JNIEXPORT jint JNICALL Java_app_organicmaps_Framework_nativeGetLastUsedRouter(JNIEnv * env, jclass) + { + return static_cast(g_framework->GetRoutingManager().GetLastUsedRouter()); + } -JNIEXPORT jint JNICALL -Java_app_organicmaps_Framework_nativeGetBestRouter(JNIEnv * env, jclass, - jdouble srcLat, jdouble srcLon, - jdouble dstLat, jdouble dstLon) -{ - return static_cast(frm()->GetRoutingManager().GetBestRouter( - mercator::FromLatLon(srcLat, srcLon), mercator::FromLatLon(dstLat, dstLon))); -} + JNIEXPORT jint JNICALL Java_app_organicmaps_Framework_nativeGetBestRouter(JNIEnv * env, jclass, jdouble srcLat, + jdouble srcLon, jdouble dstLat, + jdouble dstLon) + { + return static_cast(frm()->GetRoutingManager().GetBestRouter(mercator::FromLatLon(srcLat, srcLon), + mercator::FromLatLon(dstLat, dstLon))); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeAddRoutePoint(JNIEnv * env, jclass, jstring title, - jstring subtitle, jint markType, - jint intermediateIndex, - jboolean isMyPosition, - jdouble lat, jdouble lon) -{ - RouteMarkData data; - data.m_title = jni::ToNativeString(env, title); - data.m_subTitle = jni::ToNativeString(env, subtitle); - data.m_pointType = static_cast(markType); - data.m_intermediateIndex = static_cast(intermediateIndex); - data.m_isMyPosition = static_cast(isMyPosition); - data.m_position = m2::PointD(mercator::FromLatLon(lat, lon)); - - frm()->GetRoutingManager().AddRoutePoint(std::move(data)); -} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeAddRoutePoint(JNIEnv * env, jclass, jstring title, + jstring subtitle, jint markType, + jint intermediateIndex, + jboolean isMyPosition, jdouble lat, + jdouble lon) + { + RouteMarkData data; + data.m_title = jni::ToNativeString(env, title); + data.m_subTitle = jni::ToNativeString(env, subtitle); + data.m_pointType = static_cast(markType); + data.m_intermediateIndex = static_cast(intermediateIndex); + data.m_isMyPosition = static_cast(isMyPosition); + data.m_position = m2::PointD(mercator::FromLatLon(lat, lon)); + + frm()->GetRoutingManager().AddRoutePoint(std::move(data)); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeRemoveRoutePoint(JNIEnv * env, jclass, - jint markType, jint intermediateIndex) -{ - frm()->GetRoutingManager().RemoveRoutePoint(static_cast(markType), - static_cast(intermediateIndex)); -} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeRemoveRoutePoint(JNIEnv * env, jclass, jint markType, + jint intermediateIndex) + { + frm()->GetRoutingManager().RemoveRoutePoint(static_cast(markType), + static_cast(intermediateIndex)); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeRemoveIntermediateRoutePoints(JNIEnv * env, jclass) -{ - frm()->GetRoutingManager().RemoveIntermediateRoutePoints(); -} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeRemoveIntermediateRoutePoints(JNIEnv * env, jclass) + { + frm()->GetRoutingManager().RemoveIntermediateRoutePoints(); + } -JNIEXPORT jboolean JNICALL -Java_app_organicmaps_Framework_nativeCouldAddIntermediatePoint(JNIEnv * env, jclass) -{ - return frm()->GetRoutingManager().CouldAddIntermediatePoint(); -} + JNIEXPORT jboolean JNICALL Java_app_organicmaps_Framework_nativeCouldAddIntermediatePoint(JNIEnv * env, jclass) + { + return frm()->GetRoutingManager().CouldAddIntermediatePoint(); + } -JNIEXPORT jobjectArray JNICALL -Java_app_organicmaps_Framework_nativeGetRoutePoints(JNIEnv * env, jclass) -{ - auto const points = frm()->GetRoutingManager().GetRoutePoints(); - - static jclass const pointClazz = jni::GetGlobalClassRef(env, - "app/organicmaps/routing/RouteMarkData"); - // Java signature : RouteMarkData(String title, String subtitle, - // @RoutePointInfo.RouteMarkType int pointType, - // int intermediateIndex, boolean isVisible, boolean isMyPosition, - // boolean isPassed, double lat, double lon) - static jmethodID const pointConstructor = jni::GetConstructorID(env, pointClazz, - "(Ljava/lang/String;Ljava/lang/String;IIZZZDD)V"); - return jni::ToJavaArray(env, pointClazz, points, [&](JNIEnv * jEnv, RouteMarkData const & data) - { - jni::TScopedLocalRef const title(env, jni::ToJavaString(env, data.m_title)); - jni::TScopedLocalRef const subtitle(env, jni::ToJavaString(env, data.m_subTitle)); - return env->NewObject(pointClazz, pointConstructor, - title.get(), subtitle.get(), - static_cast(data.m_pointType), - static_cast(data.m_intermediateIndex), - static_cast(data.m_isVisible), - static_cast(data.m_isMyPosition), - static_cast(data.m_isPassed), - mercator::YToLat(data.m_position.y), - mercator::XToLon(data.m_position.x)); - }); -} + JNIEXPORT jobjectArray JNICALL Java_app_organicmaps_Framework_nativeGetRoutePoints(JNIEnv * env, jclass) + { + auto const points = frm()->GetRoutingManager().GetRoutePoints(); + + static jclass const pointClazz = jni::GetGlobalClassRef(env, "app/organicmaps/routing/RouteMarkData"); + // Java signature : RouteMarkData(String title, String subtitle, + // @RoutePointInfo.RouteMarkType int pointType, + // int intermediateIndex, boolean isVisible, boolean isMyPosition, + // boolean isPassed, double lat, double lon) + static jmethodID const pointConstructor = + jni::GetConstructorID(env, pointClazz, "(Ljava/lang/String;Ljava/lang/String;IIZZZDD)V"); + return jni::ToJavaArray(env, pointClazz, points, + [&](JNIEnv * jEnv, RouteMarkData const & data) + { + jni::TScopedLocalRef const title(env, jni::ToJavaString(env, data.m_title)); + jni::TScopedLocalRef const subtitle(env, jni::ToJavaString(env, data.m_subTitle)); + return env->NewObject( + pointClazz, pointConstructor, title.get(), subtitle.get(), + static_cast(data.m_pointType), static_cast(data.m_intermediateIndex), + static_cast(data.m_isVisible), static_cast(data.m_isMyPosition), + static_cast(data.m_isPassed), mercator::YToLat(data.m_position.y), + mercator::XToLon(data.m_position.x)); + }); + } -JNIEXPORT jobject JNICALL -Java_app_organicmaps_Framework_nativeGetTransitRouteInfo(JNIEnv * env, jclass) -{ - auto const routeInfo = frm()->GetRoutingManager().GetTransitRouteInfo(); - - static jclass const transitStepClass = jni::GetGlobalClassRef(env, - "app/organicmaps/routing/TransitStepInfo"); - // Java signature : TransitStepInfo(@TransitType int type, @Nullable String distance, @Nullable String distanceUnits, - // int timeInSec, @Nullable String number, int color, int intermediateIndex) - static jmethodID const transitStepConstructor = jni::GetConstructorID(env, transitStepClass, - "(ILjava/lang/String;Ljava/lang/String;ILjava/lang/String;II)V"); - - jni::TScopedLocalRef const steps(env, jni::ToJavaArray(env, transitStepClass, - routeInfo.m_steps, - [&](JNIEnv * jEnv, TransitStepInfo const & stepInfo) - { - jni::TScopedLocalRef const distance(env, jni::ToJavaString(env, stepInfo.m_distanceStr)); - jni::TScopedLocalRef const distanceUnits(env, jni::ToJavaString(env, stepInfo.m_distanceUnitsSuffix)); - jni::TScopedLocalRef const number(env, jni::ToJavaString(env, stepInfo.m_number)); - return env->NewObject(transitStepClass, transitStepConstructor, - static_cast(stepInfo.m_type), - distance.get(), - distanceUnits.get(), - static_cast(stepInfo.m_timeInSec), - number.get(), - static_cast(stepInfo.m_colorARGB), - static_cast(stepInfo.m_intermediateIndex)); - })); - - static jclass const transitRouteInfoClass = jni::GetGlobalClassRef(env, - "app/organicmaps/routing/TransitRouteInfo"); - // Java signature : TransitRouteInfo(@NonNull String totalDistance, @NonNull String totalDistanceUnits, int totalTimeInSec, - // @NonNull String totalPedestrianDistance, @NonNull String totalPedestrianDistanceUnits, - // int totalPedestrianTimeInSec, @NonNull TransitStepInfo[] steps) - static jmethodID const transitRouteInfoConstructor = jni::GetConstructorID(env, transitRouteInfoClass, - "(Ljava/lang/String;Ljava/lang/String;I" - "Ljava/lang/String;Ljava/lang/String;I" - "[Lapp/organicmaps/routing/TransitStepInfo;)V"); - jni::TScopedLocalRef const distance(env, jni::ToJavaString(env, routeInfo.m_totalDistanceStr)); - jni::TScopedLocalRef const distanceUnits(env, jni::ToJavaString(env, routeInfo.m_totalDistanceUnitsSuffix)); - jni::TScopedLocalRef const distancePedestrian(env, jni::ToJavaString(env, routeInfo.m_totalPedestrianDistanceStr)); - jni::TScopedLocalRef const distancePedestrianUnits(env, jni::ToJavaString(env, routeInfo.m_totalPedestrianUnitsSuffix)); - return env->NewObject(transitRouteInfoClass, transitRouteInfoConstructor, - distance.get(), distanceUnits.get(), static_cast(routeInfo.m_totalTimeInSec), - distancePedestrian.get(), distancePedestrianUnits.get(), static_cast(routeInfo.m_totalPedestrianTimeInSec), - steps.get()); -} + JNIEXPORT jobject JNICALL Java_app_organicmaps_Framework_nativeGetTransitRouteInfo(JNIEnv * env, jclass) + { + auto const routeInfo = frm()->GetRoutingManager().GetTransitRouteInfo(); + + static jclass const transitStepClass = jni::GetGlobalClassRef(env, "app/organicmaps/routing/TransitStepInfo"); + // Java signature : TransitStepInfo(@TransitType int type, @Nullable String distance, @Nullable String + // distanceUnits, + // int timeInSec, @Nullable String number, int color, int intermediateIndex) + static jmethodID const transitStepConstructor = + jni::GetConstructorID(env, transitStepClass, "(ILjava/lang/String;Ljava/lang/String;ILjava/lang/String;II)V"); + + jni::TScopedLocalRef const steps( + env, jni::ToJavaArray( + env, transitStepClass, routeInfo.m_steps, + [&](JNIEnv * jEnv, TransitStepInfo const & stepInfo) + { + jni::TScopedLocalRef const distance(env, jni::ToJavaString(env, stepInfo.m_distanceStr)); + jni::TScopedLocalRef const distanceUnits(env, + jni::ToJavaString(env, stepInfo.m_distanceUnitsSuffix)); + jni::TScopedLocalRef const number(env, jni::ToJavaString(env, stepInfo.m_number)); + return env->NewObject(transitStepClass, transitStepConstructor, static_cast(stepInfo.m_type), + distance.get(), distanceUnits.get(), static_cast(stepInfo.m_timeInSec), + number.get(), static_cast(stepInfo.m_colorARGB), + static_cast(stepInfo.m_intermediateIndex)); + })); + + static jclass const transitRouteInfoClass = jni::GetGlobalClassRef(env, "app/organicmaps/routing/TransitRouteInfo"); + // Java signature : TransitRouteInfo(@NonNull String totalDistance, @NonNull String totalDistanceUnits, int + // totalTimeInSec, + // @NonNull String totalPedestrianDistance, @NonNull String + // totalPedestrianDistanceUnits, int totalPedestrianTimeInSec, @NonNull + // TransitStepInfo[] steps) + static jmethodID const transitRouteInfoConstructor = + jni::GetConstructorID(env, transitRouteInfoClass, + "(Ljava/lang/String;Ljava/lang/String;I" + "Ljava/lang/String;Ljava/lang/String;I" + "[Lapp/organicmaps/routing/TransitStepInfo;)V"); + jni::TScopedLocalRef const distance(env, jni::ToJavaString(env, routeInfo.m_totalDistanceStr)); + jni::TScopedLocalRef const distanceUnits(env, jni::ToJavaString(env, routeInfo.m_totalDistanceUnitsSuffix)); + jni::TScopedLocalRef const distancePedestrian(env, jni::ToJavaString(env, routeInfo.m_totalPedestrianDistanceStr)); + jni::TScopedLocalRef const distancePedestrianUnits(env, + jni::ToJavaString(env, routeInfo.m_totalPedestrianUnitsSuffix)); + return env->NewObject(transitRouteInfoClass, transitRouteInfoConstructor, distance.get(), distanceUnits.get(), + static_cast(routeInfo.m_totalTimeInSec), distancePedestrian.get(), + distancePedestrianUnits.get(), static_cast(routeInfo.m_totalPedestrianTimeInSec), + steps.get()); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeReloadWorldMaps(JNIEnv * env, jclass) -{ - g_framework->ReloadWorldMaps(); -} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeReloadWorldMaps(JNIEnv * env, jclass) + { + g_framework->ReloadWorldMaps(); + } -JNIEXPORT jboolean JNICALL -Java_app_organicmaps_Framework_nativeIsDayTime(JNIEnv * env, jclass, jlong utcTimeSeconds, jdouble lat, jdouble lon) -{ - DayTimeType const dt = GetDayTime(static_cast(utcTimeSeconds), lat, lon); - return (dt == DayTimeType::Day || dt == DayTimeType::PolarDay); -} + JNIEXPORT jboolean JNICALL Java_app_organicmaps_Framework_nativeIsDayTime(JNIEnv * env, jclass, jlong utcTimeSeconds, + jdouble lat, jdouble lon) + { + DayTimeType const dt = GetDayTime(static_cast(utcTimeSeconds), lat, lon); + return (dt == DayTimeType::Day || dt == DayTimeType::PolarDay); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeSet3dMode(JNIEnv * env, jclass, jboolean allow, jboolean allowBuildings) -{ - bool const allow3d = static_cast(allow); - bool const allow3dBuildings = static_cast(allowBuildings); + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeSet3dMode(JNIEnv * env, jclass, jboolean allow, + jboolean allowBuildings) + { + bool const allow3d = static_cast(allow); + bool const allow3dBuildings = static_cast(allowBuildings); - g_framework->Save3dMode(allow3d, allow3dBuildings); - g_framework->Set3dMode(allow3d, allow3dBuildings); -} + g_framework->Save3dMode(allow3d, allow3dBuildings); + g_framework->Set3dMode(allow3d, allow3dBuildings); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeGet3dMode(JNIEnv * env, jclass, jobject result) -{ - bool enabled; - bool buildings; - g_framework->Get3dMode(enabled, buildings); + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeGet3dMode(JNIEnv * env, jclass, jobject result) + { + bool enabled; + bool buildings; + g_framework->Get3dMode(enabled, buildings); - static jclass const resultClass = env->GetObjectClass(result); + static jclass const resultClass = env->GetObjectClass(result); - static jfieldID const enabledField = env->GetFieldID(resultClass, "enabled", "Z"); - env->SetBooleanField(result, enabledField, enabled); + static jfieldID const enabledField = env->GetFieldID(resultClass, "enabled", "Z"); + env->SetBooleanField(result, enabledField, enabled); - static jfieldID const buildingsField = env->GetFieldID(resultClass, "buildings", "Z"); - env->SetBooleanField(result, buildingsField, buildings); -} + static jfieldID const buildingsField = env->GetFieldID(resultClass, "buildings", "Z"); + env->SetBooleanField(result, buildingsField, buildings); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeSetAutoZoomEnabled(JNIEnv * env, jclass, jboolean enabled) -{ - bool const autoZoomEnabled = static_cast(enabled); - frm()->SaveAutoZoom(autoZoomEnabled); - frm()->AllowAutoZoom(autoZoomEnabled); -} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeSetAutoZoomEnabled(JNIEnv * env, jclass, jboolean enabled) + { + bool const autoZoomEnabled = static_cast(enabled); + frm()->SaveAutoZoom(autoZoomEnabled); + frm()->AllowAutoZoom(autoZoomEnabled); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeSetTransitSchemeEnabled(JNIEnv * env, jclass, jboolean enabled) -{ - frm()->GetTransitManager().EnableTransitSchemeMode(static_cast(enabled)); -} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeSetTransitSchemeEnabled(JNIEnv * env, jclass, + jboolean enabled) + { + frm()->GetTransitManager().EnableTransitSchemeMode(static_cast(enabled)); + } -JNIEXPORT jboolean JNICALL -Java_app_organicmaps_Framework_nativeIsTransitSchemeEnabled(JNIEnv * env, jclass) -{ - return static_cast(frm()->LoadTransitSchemeEnabled()); -} + JNIEXPORT jboolean JNICALL Java_app_organicmaps_Framework_nativeIsTransitSchemeEnabled(JNIEnv * env, jclass) + { + return static_cast(frm()->LoadTransitSchemeEnabled()); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeSetIsolinesLayerEnabled(JNIEnv * env, jclass, jboolean enabled) -{ - auto const isolinesEnabled = static_cast(enabled); - frm()->GetIsolinesManager().SetEnabled(isolinesEnabled); - frm()->SaveIsolinesEnabled(isolinesEnabled); -} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeSetIsolinesLayerEnabled(JNIEnv * env, jclass, + jboolean enabled) + { + auto const isolinesEnabled = static_cast(enabled); + frm()->GetIsolinesManager().SetEnabled(isolinesEnabled); + frm()->SaveIsolinesEnabled(isolinesEnabled); + } -JNIEXPORT jboolean JNICALL -Java_app_organicmaps_Framework_nativeIsIsolinesLayerEnabled(JNIEnv * env, jclass) -{ - return static_cast(frm()->LoadIsolinesEnabled()); -} + JNIEXPORT jboolean JNICALL Java_app_organicmaps_Framework_nativeIsIsolinesLayerEnabled(JNIEnv * env, jclass) + { + return static_cast(frm()->LoadIsolinesEnabled()); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeSetOutdoorsLayerEnabled(JNIEnv * env, jclass, jboolean enabled) -{ - frm()->SaveOutdoorsEnabled(enabled); -} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeSetOutdoorsLayerEnabled(JNIEnv * env, jclass, + jboolean enabled) + { + frm()->SaveOutdoorsEnabled(enabled); + } -JNIEXPORT jboolean JNICALL -Java_app_organicmaps_Framework_nativeIsOutdoorsLayerEnabled(JNIEnv * env, jclass) -{ - return static_cast(frm()->LoadOutdoorsEnabled()); -} + JNIEXPORT jboolean JNICALL Java_app_organicmaps_Framework_nativeIsOutdoorsLayerEnabled(JNIEnv * env, jclass) + { + return static_cast(frm()->LoadOutdoorsEnabled()); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeSaveSettingSchemeEnabled(JNIEnv * env, jclass, jboolean enabled) -{ - frm()->SaveTransitSchemeEnabled(static_cast(enabled)); -} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeSaveSettingSchemeEnabled(JNIEnv * env, jclass, + jboolean enabled) + { + frm()->SaveTransitSchemeEnabled(static_cast(enabled)); + } -JNIEXPORT jboolean JNICALL -Java_app_organicmaps_Framework_nativeGetAutoZoomEnabled(JNIEnv *, jclass) -{ - return frm()->LoadAutoZoom(); -} + JNIEXPORT jboolean JNICALL Java_app_organicmaps_Framework_nativeGetAutoZoomEnabled(JNIEnv *, jclass) + { + return frm()->LoadAutoZoom(); + } -// static void nativeZoomToPoint(double lat, double lon, int zoom, boolean animate); -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeZoomToPoint(JNIEnv * env, jclass, jdouble lat, jdouble lon, jint zoom, jboolean animate) -{ - g_framework->Scale(m2::PointD(mercator::FromLatLon(lat, lon)), zoom, animate); -} + // static void nativeZoomToPoint(double lat, double lon, int zoom, boolean animate); + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeZoomToPoint(JNIEnv * env, jclass, jdouble lat, + jdouble lon, jint zoom, jboolean animate) + { + g_framework->Scale(m2::PointD(mercator::FromLatLon(lat, lon)), zoom, animate); + } -JNIEXPORT jobject JNICALL -Java_app_organicmaps_Framework_nativeDeleteBookmarkFromMapObject(JNIEnv * env, jclass) -{ - if (!frm()->HasPlacePageInfo()) - return nullptr; + JNIEXPORT jobject JNICALL Java_app_organicmaps_Framework_nativeDeleteBookmarkFromMapObject(JNIEnv * env, jclass) + { + if (!frm()->HasPlacePageInfo()) + return nullptr; - place_page::Info const & info = g_framework->GetPlacePageInfo(); - auto const bookmarkId = info.GetBookmarkId(); - frm()->GetBookmarkManager().GetEditSession().DeleteBookmark(bookmarkId); + place_page::Info const & info = g_framework->GetPlacePageInfo(); + auto const bookmarkId = info.GetBookmarkId(); + frm()->GetBookmarkManager().GetEditSession().DeleteBookmark(bookmarkId); - auto buildInfo = info.GetBuildInfo(); - buildInfo.m_match = place_page::BuildInfo::Match::FeatureOnly; - buildInfo.m_userMarkId = kml::kInvalidMarkId; - buildInfo.m_source = place_page::BuildInfo::Source::Other; - frm()->UpdatePlacePageInfoForCurrentSelection(buildInfo); + auto buildInfo = info.GetBuildInfo(); + buildInfo.m_match = place_page::BuildInfo::Match::FeatureOnly; + buildInfo.m_userMarkId = kml::kInvalidMarkId; + buildInfo.m_source = place_page::BuildInfo::Source::Other; + frm()->UpdatePlacePageInfoForCurrentSelection(buildInfo); - return usermark_helper::CreateMapObject(env, g_framework->GetPlacePageInfo()); -} + return usermark_helper::CreateMapObject(env, g_framework->GetPlacePageInfo()); + } -JNIEXPORT jstring JNICALL -Java_app_organicmaps_Framework_nativeGetPoiContactUrl(JNIEnv *env, jclass, jint id) -{ - auto const metaID = static_cast(id); - string_view const value = g_framework->GetPlacePageInfo().GetMetadata(metaID); - if (osm::isSocialContactTag(metaID)) - return jni::ToJavaString(env, osm::socialContactToURL(metaID, value)); - return jni::ToJavaString(env, value); -} + JNIEXPORT jstring JNICALL Java_app_organicmaps_Framework_nativeGetPoiContactUrl(JNIEnv * env, jclass, jint id) + { + auto const metaID = static_cast(id); + string_view const value = g_framework->GetPlacePageInfo().GetMetadata(metaID); + if (osm::isSocialContactTag(metaID)) + return jni::ToJavaString(env, osm::socialContactToURL(metaID, value)); + return jni::ToJavaString(env, value); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeSetChoosePositionMode(JNIEnv *, jclass, jint mode, jboolean isBusiness, - jboolean applyPosition) -{ - auto const pos = applyPosition && frm()->HasPlacePageInfo() - ? g_framework->GetPlacePageInfo().GetMercator() - : m2::PointD(); - g_framework->SetChoosePositionMode(static_cast(mode), isBusiness, applyPosition, pos); -} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeSetChoosePositionMode(JNIEnv *, jclass, jint mode, + jboolean isBusiness, + jboolean applyPosition) + { + auto const pos = + applyPosition && frm()->HasPlacePageInfo() ? g_framework->GetPlacePageInfo().GetMercator() : m2::PointD(); + g_framework->SetChoosePositionMode(static_cast(mode), isBusiness, applyPosition, pos); + } -JNIEXPORT jint JNICALL -Java_app_organicmaps_Framework_nativeGetChoosePositionMode(JNIEnv *, jclass) -{ - return static_cast(g_framework->GetChoosePositionMode()); -} + JNIEXPORT jint JNICALL Java_app_organicmaps_Framework_nativeGetChoosePositionMode(JNIEnv *, jclass) + { + return static_cast(g_framework->GetChoosePositionMode()); + } -JNIEXPORT jboolean JNICALL -Java_app_organicmaps_Framework_nativeIsDownloadedMapAtScreenCenter(JNIEnv *, jclass) -{ - ::Framework * fr = frm(); - return storage::IsPointCoveredByDownloadedMaps(fr->GetViewportCenter(), fr->GetStorage(), fr->GetCountryInfoGetter()); -} + JNIEXPORT jboolean JNICALL Java_app_organicmaps_Framework_nativeIsDownloadedMapAtScreenCenter(JNIEnv *, jclass) + { + ::Framework * fr = frm(); + return storage::IsPointCoveredByDownloadedMaps(fr->GetViewportCenter(), fr->GetStorage(), + fr->GetCountryInfoGetter()); + } -JNIEXPORT jstring JNICALL -Java_app_organicmaps_Framework_nativeGetActiveObjectFormattedCuisine(JNIEnv * env, jclass) -{ - ::Framework * frm = g_framework->NativeFramework(); - if (!frm->HasPlacePageInfo()) - return {}; + JNIEXPORT jstring JNICALL Java_app_organicmaps_Framework_nativeGetActiveObjectFormattedCuisine(JNIEnv * env, jclass) + { + ::Framework * frm = g_framework->NativeFramework(); + if (!frm->HasPlacePageInfo()) + return {}; - return jni::ToJavaString(env, g_framework->GetPlacePageInfo().FormatCuisines()); -} + return jni::ToJavaString(env, g_framework->GetPlacePageInfo().FormatCuisines()); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeSetVisibleRect(JNIEnv * env, jclass, jint left, jint top, jint right, jint bottom) -{ - frm()->SetVisibleViewport(m2::RectD(left, top, right, bottom)); -} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeSetVisibleRect(JNIEnv * env, jclass, jint left, jint top, + jint right, jint bottom) + { + frm()->SetVisibleViewport(m2::RectD(left, top, right, bottom)); + } -JNIEXPORT jboolean JNICALL -Java_app_organicmaps_Framework_nativeIsRouteFinished(JNIEnv * env, jclass) -{ - return frm()->GetRoutingManager().IsRouteFinished(); -} + JNIEXPORT jboolean JNICALL Java_app_organicmaps_Framework_nativeIsRouteFinished(JNIEnv * env, jclass) + { + return frm()->GetRoutingManager().IsRouteFinished(); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeRunFirstLaunchAnimation(JNIEnv * env, jclass) -{ - frm()->RunFirstLaunchAnimation(); -} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeRunFirstLaunchAnimation(JNIEnv * env, jclass) + { + frm()->RunFirstLaunchAnimation(); + } -JNIEXPORT jint JNICALL -Java_app_organicmaps_Framework_nativeOpenRoutePointsTransaction(JNIEnv * env, jclass) -{ - return frm()->GetRoutingManager().OpenRoutePointsTransaction(); -} + JNIEXPORT jint JNICALL Java_app_organicmaps_Framework_nativeOpenRoutePointsTransaction(JNIEnv * env, jclass) + { + return frm()->GetRoutingManager().OpenRoutePointsTransaction(); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeApplyRoutePointsTransaction(JNIEnv * env, jclass, - jint transactionId) -{ - frm()->GetRoutingManager().ApplyRoutePointsTransaction(transactionId); -} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeApplyRoutePointsTransaction(JNIEnv * env, jclass, + jint transactionId) + { + frm()->GetRoutingManager().ApplyRoutePointsTransaction(transactionId); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeCancelRoutePointsTransaction(JNIEnv * env, jclass, - jint transactionId) -{ - frm()->GetRoutingManager().CancelRoutePointsTransaction(transactionId); -} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeCancelRoutePointsTransaction(JNIEnv * env, jclass, + jint transactionId) + { + frm()->GetRoutingManager().CancelRoutePointsTransaction(transactionId); + } -JNIEXPORT jint JNICALL -Java_app_organicmaps_Framework_nativeInvalidRoutePointsTransactionId(JNIEnv * env, jclass) -{ - return frm()->GetRoutingManager().InvalidRoutePointsTransactionId(); -} + JNIEXPORT jint JNICALL Java_app_organicmaps_Framework_nativeInvalidRoutePointsTransactionId(JNIEnv * env, jclass) + { + return frm()->GetRoutingManager().InvalidRoutePointsTransactionId(); + } -JNIEXPORT jboolean JNICALL -Java_app_organicmaps_Framework_nativeHasSavedRoutePoints(JNIEnv *, jclass) -{ - return frm()->GetRoutingManager().HasSavedRoutePoints(); -} + JNIEXPORT jboolean JNICALL Java_app_organicmaps_Framework_nativeHasSavedRoutePoints(JNIEnv *, jclass) + { + return frm()->GetRoutingManager().HasSavedRoutePoints(); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeLoadRoutePoints(JNIEnv *, jclass) -{ - frm()->GetRoutingManager().LoadRoutePoints(g_loadRouteHandler); -} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeLoadRoutePoints(JNIEnv *, jclass) + { + frm()->GetRoutingManager().LoadRoutePoints(g_loadRouteHandler); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeSaveRoutePoints(JNIEnv *, jclass) -{ - frm()->GetRoutingManager().SaveRoutePoints(); -} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeSaveRoutePoints(JNIEnv *, jclass) + { + frm()->GetRoutingManager().SaveRoutePoints(); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeDeleteSavedRoutePoints(JNIEnv *, jclass) -{ - frm()->GetRoutingManager().DeleteSavedRoutePoints(); -} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeDeleteSavedRoutePoints(JNIEnv *, jclass) + { + frm()->GetRoutingManager().DeleteSavedRoutePoints(); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeShowFeature(JNIEnv * env, jclass, jobject featureId) -{ - auto const f = g_framework->BuildFeatureId(env, featureId); + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeShowFeature(JNIEnv * env, jclass, jobject featureId) + { + auto const f = g_framework->BuildFeatureId(env, featureId); - if (f.IsValid()) - frm()->ShowFeature(f); -} + if (f.IsValid()) + frm()->ShowFeature(f); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeMakeCrash(JNIEnv *env, jclass type) -{ - CHECK(false, ("Diagnostic native crash!")); -} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeMakeCrash(JNIEnv * env, jclass type) + { + CHECK(false, ("Diagnostic native crash!")); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeSetPowerManagerFacility(JNIEnv *, jclass, - jint facilityType, jboolean state) -{ - frm()->GetPowerManager().SetFacility(static_cast(facilityType), - static_cast(state)); -} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeSetPowerManagerFacility(JNIEnv *, jclass, + jint facilityType, jboolean state) + { + frm()->GetPowerManager().SetFacility(static_cast(facilityType), + static_cast(state)); + } -JNIEXPORT jint JNICALL -Java_app_organicmaps_Framework_nativeGetPowerManagerScheme(JNIEnv *, jclass) -{ - return static_cast(frm()->GetPowerManager().GetScheme()); -} + JNIEXPORT jint JNICALL Java_app_organicmaps_Framework_nativeGetPowerManagerScheme(JNIEnv *, jclass) + { + return static_cast(frm()->GetPowerManager().GetScheme()); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeSetPowerManagerScheme(JNIEnv *, jclass, jint schemeType) -{ - frm()->GetPowerManager().SetScheme(static_cast(schemeType)); -} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeSetPowerManagerScheme(JNIEnv *, jclass, jint schemeType) + { + frm()->GetPowerManager().SetScheme(static_cast(schemeType)); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeSetViewportCenter(JNIEnv *, jclass, jdouble lat, jdouble lon, jint zoom) -{ - // isAnim = true because of previous nativeSetChoosePositionMode animations. - frm()->SetViewportCenter(mercator::FromLatLon(lat, lon), static_cast(zoom), true /* isAnim */); -} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeSetViewportCenter(JNIEnv *, jclass, jdouble lat, + jdouble lon, jint zoom) + { + // isAnim = true because of previous nativeSetChoosePositionMode animations. + frm()->SetViewportCenter(mercator::FromLatLon(lat, lon), static_cast(zoom), true /* isAnim */); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeStopLocationFollow(JNIEnv *, jclass) -{ - frm()->StopLocationFollow(); -} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeStopLocationFollow(JNIEnv *, jclass) + { + frm()->StopLocationFollow(); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeSetSearchViewport(JNIEnv *, jclass, jdouble lat, - jdouble lon, jint zoom) -{ - auto const center = mercator::FromLatLon(static_cast(lat), - static_cast(lon)); - auto const rect = df::GetRectForDrawScale(static_cast(zoom), center); - frm()->GetSearchAPI().OnViewportChanged(rect); -} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeSetSearchViewport(JNIEnv *, jclass, jdouble lat, + jdouble lon, jint zoom) + { + auto const center = mercator::FromLatLon(static_cast(lat), static_cast(lon)); + auto const rect = df::GetRectForDrawScale(static_cast(zoom), center); + frm()->GetSearchAPI().OnViewportChanged(rect); + } -JNIEXPORT jboolean JNICALL -Java_app_organicmaps_Framework_nativeHasPlacePageInfo(JNIEnv *, jclass) -{ - return static_cast(frm()->HasPlacePageInfo()); -} + JNIEXPORT jboolean JNICALL Java_app_organicmaps_Framework_nativeHasPlacePageInfo(JNIEnv *, jclass) + { + return static_cast(frm()->HasPlacePageInfo()); + } -JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeMemoryWarning(JNIEnv *, jclass) -{ - return frm()->MemoryWarning(); -} + JNIEXPORT void JNICALL Java_app_organicmaps_Framework_nativeMemoryWarning(JNIEnv *, jclass) + { + return frm()->MemoryWarning(); + } -JNIEXPORT jstring JNICALL -Java_app_organicmaps_Framework_nativeGetKayakHotelLink(JNIEnv * env, jclass, jstring countryIsoCode, jstring uri, - jlong firstDaySec, jlong lastDaySec, jboolean isReferral) -{ - string const url = osm::GetKayakHotelURLFromURI(jni::ToNativeString(env, countryIsoCode), - jni::ToNativeString(env, uri), - static_cast(firstDaySec), - static_cast(lastDaySec), - isReferral); - return url.empty() ? nullptr : jni::ToJavaString(env, url); -} + JNIEXPORT jstring JNICALL Java_app_organicmaps_Framework_nativeGetKayakHotelLink(JNIEnv * env, jclass, + jstring countryIsoCode, jstring uri, + jlong firstDaySec, jlong lastDaySec, + jboolean isReferral) + { + string const url = + osm::GetKayakHotelURLFromURI(jni::ToNativeString(env, countryIsoCode), jni::ToNativeString(env, uri), + static_cast(firstDaySec), static_cast(lastDaySec), isReferral); + return url.empty() ? nullptr : jni::ToJavaString(env, url); + } } // extern "C" diff --git a/android/app/src/main/cpp/app/organicmaps/Framework.hpp b/android/app/src/main/cpp/app/organicmaps/Framework.hpp index b88fabac5f3..e49fb566542 100644 --- a/android/app/src/main/cpp/app/organicmaps/Framework.hpp +++ b/android/app/src/main/cpp/app/organicmaps/Framework.hpp @@ -142,7 +142,7 @@ namespace android void Scroll(double distanceX, double distanceY); void Touch(int action, Finger const & f1, Finger const & f2, uint8_t maskedPointer); - + void SendDeviceToken(std::string const & token); bool Search(search::EverywhereSearchParams const & params); std::string GetLastSearchQuery() { return m_searchQuery; } void ClearLastSearchQuery() { m_searchQuery.clear(); } diff --git a/android/app/src/main/cpp/app/organicmaps/Notification.cpp b/android/app/src/main/cpp/app/organicmaps/Notification.cpp new file mode 100644 index 00000000000..ab4180dfd17 --- /dev/null +++ b/android/app/src/main/cpp/app/organicmaps/Notification.cpp @@ -0,0 +1,11 @@ +#include "app/organicmaps/core/jni_helper.hpp" +#include +// +//extern "C" +//JNIEXPORT void JNICALL +//Java_app_organicmaps_PushNotificationService_nativeSendTokenToCpp(JNIEnv *env, jobject thiz, +// jstring token) { +// // TODO: implement nativeSendTokenToCpp()std::string tokenCpp = jni::ToNativeString(env, token); +// //framework::SendTokenToCpp(tokenCpp); +// g_framework->SendTokenToCpp(tokenCpp); +//} diff --git a/android/app/src/main/ic_launcher-playstore.png b/android/app/src/main/ic_launcher-playstore.png new file mode 100644 index 00000000000..0eb96de4ed3 Binary files /dev/null and b/android/app/src/main/ic_launcher-playstore.png differ diff --git a/android/app/src/main/java/app/organicmaps/Alerts.java b/android/app/src/main/java/app/organicmaps/Alerts.java new file mode 100644 index 00000000000..5e319140133 --- /dev/null +++ b/android/app/src/main/java/app/organicmaps/Alerts.java @@ -0,0 +1,37 @@ +package app.organicmaps; + +import android.content.Intent; +import android.os.Bundle; + +import androidx.fragment.app.Fragment; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import app.organicmaps.base.BaseMwmFragment; +import app.organicmaps.util.Constants; + +/** + * A simple {@link Fragment} subclass. + * create an instance of this fragment. + */ +public class Alerts extends BaseMwmFragment { + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + View root = inflater.inflate(R.layout.fragment_alerts, container, false); + new WebContainerDelegate(root, Constants.Url.DRIMS_PUBLIC_ALERTS) + { + @Override + protected void doStartActivity(Intent intent) + { + startActivity(intent); + } + }; + + return root; + } +} \ No newline at end of file diff --git a/android/app/src/main/java/app/organicmaps/AlertsActivity.java b/android/app/src/main/java/app/organicmaps/AlertsActivity.java new file mode 100644 index 00000000000..5ef099044ce --- /dev/null +++ b/android/app/src/main/java/app/organicmaps/AlertsActivity.java @@ -0,0 +1,23 @@ +package app.organicmaps; + +import android.content.Intent; +import android.os.Bundle; + +import androidx.activity.EdgeToEdge; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.graphics.Insets; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowInsetsCompat; +import androidx.fragment.app.Fragment; + +import app.organicmaps.base.BaseMwmFragmentActivity; +import app.organicmaps.help.HelpFragment; +import app.organicmaps.util.Constants; + +public class AlertsActivity extends BaseMwmFragmentActivity { + @Override + protected Class getFragmentClass() + { + return Alerts.class; + } +} \ No newline at end of file diff --git a/android/app/src/main/java/app/organicmaps/LiveFeeds.java b/android/app/src/main/java/app/organicmaps/LiveFeeds.java new file mode 100644 index 00000000000..3283e0bc123 --- /dev/null +++ b/android/app/src/main/java/app/organicmaps/LiveFeeds.java @@ -0,0 +1,37 @@ +package app.organicmaps; + +import android.content.Intent; +import android.os.Bundle; + +import androidx.fragment.app.Fragment; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import app.organicmaps.base.BaseMwmFragment; +import app.organicmaps.util.Constants; + +/** + * A simple {@link Fragment} subclass. + * create an instance of this fragment. + */ +public class LiveFeeds extends BaseMwmFragment { + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + View root = inflater.inflate(R.layout.fragment_live_feeds, container, false); + new WebContainerDelegate(root, Constants.Url.DRIMS_LIVE) + { + @Override + protected void doStartActivity(Intent intent) + { + startActivity(intent); + } + }; + + return root; + } +} \ No newline at end of file diff --git a/android/app/src/main/java/app/organicmaps/LiveFeedsWebview.java b/android/app/src/main/java/app/organicmaps/LiveFeedsWebview.java new file mode 100644 index 00000000000..c345aa9ac96 --- /dev/null +++ b/android/app/src/main/java/app/organicmaps/LiveFeedsWebview.java @@ -0,0 +1,24 @@ +package app.organicmaps; + +import android.os.Bundle; + +import androidx.activity.EdgeToEdge; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.graphics.Insets; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowInsetsCompat; + +public class LiveFeedsWebview extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + EdgeToEdge.enable(this); + setContentView(R.layout.activity_live_feeds_webview); + ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> { + Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()); + v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom); + return insets; + }); + } +} \ No newline at end of file diff --git a/android/app/src/main/java/app/organicmaps/MapFragment.java b/android/app/src/main/java/app/organicmaps/MapFragment.java index 958aa564f2f..1d9b9e86a17 100644 --- a/android/app/src/main/java/app/organicmaps/MapFragment.java +++ b/android/app/src/main/java/app/organicmaps/MapFragment.java @@ -19,7 +19,10 @@ import app.organicmaps.display.DisplayType; import app.organicmaps.util.log.Logger; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.google.firebase.messaging.FirebaseMessaging; public class MapFragment extends BaseMwmFragment implements View.OnTouchListener, SurfaceHolder.Callback { @@ -107,6 +110,20 @@ public void onCreate(Bundle b) Bundle args = getArguments(); if (args != null) launchByDeepLink = args.getBoolean(Map.ARG_LAUNCH_BY_DEEP_LINK); + + + FirebaseMessaging.getInstance().getToken() + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (!task.isSuccessful()) { + return; + } + String token = task.getResult(); + PushNotificationService.nativeSendTokenToCpp(token); + + } + }); mMap.onCreate(launchByDeepLink); } diff --git a/android/app/src/main/java/app/organicmaps/MwmActivity.java b/android/app/src/main/java/app/organicmaps/MwmActivity.java index 9c9bdfcc105..fe9d155e789 100644 --- a/android/app/src/main/java/app/organicmaps/MwmActivity.java +++ b/android/app/src/main/java/app/organicmaps/MwmActivity.java @@ -167,6 +167,7 @@ public class MwmActivity extends BaseMwmFragmentActivity private NavigationController mNavigationController; + private MainMenu mMainMenu; private PanelAnimator mPanelAnimator; @@ -387,6 +388,11 @@ private void showHelp() startActivity(intent); } + private void showAlerts(){ + Intent intent = new Intent(this, AlertsActivity.class); + startActivity(intent); + } + private void showSearch(String query) { closeSearchToolbar(false, true); @@ -774,6 +780,7 @@ public void onMapButtonClick(MapButtonsController.MapButtons button) showBottomSheet(MAIN_MENU_ID); } case help -> showHelp(); + case alerts -> showAlerts(); } } @@ -2169,8 +2176,8 @@ public ArrayList getMenuBottomSheetItems(String id) this::onDownloadMapsOptionSelected )); mDonatesUrl = Config.getDonateUrl(getApplicationContext()); - if (!TextUtils.isEmpty(mDonatesUrl)) - items.add(new MenuBottomSheetItem(R.string.donate, R.drawable.ic_donate, this::onDonateOptionSelected)); + // if (!TextUtils.isEmpty(mDonatesUrl)) + // items.add(new MenuBottomSheetItem(R.string.donate, R.drawable.ic_donate, this::onDonateOptionSelected)); items.add(new MenuBottomSheetItem(R.string.settings, R.drawable.ic_settings, this::onSettingsOptionSelected)); items.add(new MenuBottomSheetItem(R.string.share_my_location, R.drawable.ic_share, this::onShareLocationOptionSelected)); return items; diff --git a/android/app/src/main/java/app/organicmaps/PushNotificationService.java b/android/app/src/main/java/app/organicmaps/PushNotificationService.java new file mode 100644 index 00000000000..01a04d04783 --- /dev/null +++ b/android/app/src/main/java/app/organicmaps/PushNotificationService.java @@ -0,0 +1,32 @@ +package app.organicmaps; + +import android.util.Log; + +import androidx.annotation.NonNull; + +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; +import com.google.firebase.messaging.*; + +public class PushNotificationService extends FirebaseMessagingService { + + public PushNotificationService() { + super(); + Log.d("Firebase","SERVICE INTIALIZED"); + } + + @Override + public void onMessageReceived(RemoteMessage remoteMessage) { + super.onMessageReceived(remoteMessage); + Log.d("Firebase","ON MESSAGE RECEIVED CALLED" + remoteMessage.toString()); + + } + @Override + public void onNewToken(@NonNull String token) { + Log.d(this.getClass().getSimpleName(),"Refreshed token: " + token); + // Pass the token to native code + nativeSendTokenToCpp(token); + } + + public static native void nativeSendTokenToCpp(String token); +} \ No newline at end of file diff --git a/android/app/src/main/java/app/organicmaps/SplashActivity.java b/android/app/src/main/java/app/organicmaps/SplashActivity.java index f46babb9063..a620d0a810e 100644 --- a/android/app/src/main/java/app/organicmaps/SplashActivity.java +++ b/android/app/src/main/java/app/organicmaps/SplashActivity.java @@ -2,11 +2,15 @@ import static android.Manifest.permission.ACCESS_COARSE_LOCATION; import static android.Manifest.permission.ACCESS_FINE_LOCATION; +import static android.Manifest.permission.POST_NOTIFICATIONS; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; +import android.os.Build; import android.os.Bundle; +import android.util.Log; import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; @@ -15,6 +19,7 @@ import androidx.annotation.Nullable; import androidx.annotation.StringRes; import androidx.appcompat.app.AppCompatActivity; +import androidx.core.content.ContextCompat; import app.organicmaps.display.DisplayManager; import app.organicmaps.location.LocationHelper; @@ -40,6 +45,35 @@ public class SplashActivity extends AppCompatActivity @NonNull private ActivityResultLauncher mPermissionRequest; + // Declare the launcher at the top of your Activity/Fragment: + private final ActivityResultLauncher requestPermissionLauncher = + registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> { + if (isGranted) { + // FCM SDK (and your app) can post notifications. + } else { + // TODO: Inform user that that your app will not show notifications. + } + }); + + private void askNotificationPermission() { + // This is only necessary for API level >= 33 (TIRAMISU) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + if (ContextCompat.checkSelfPermission(this, POST_NOTIFICATIONS) == + PackageManager.PERMISSION_GRANTED) { + Log.d(TAG, "PERMISSION_GRANTED"); + // FCM SDK (and your app) can post notifications. + } else if (shouldShowRequestPermissionRationale(POST_NOTIFICATIONS)) { + // TODO: display an educational UI explaining to the user the features that will be enabled + // by them granting the POST_NOTIFICATION permission. This UI should provide the user + // "OK" and "No thanks" buttons. If the user selects "OK," directly request the permission. + // If the user selects "No thanks," allow the user to continue without notifications. + } else { + // Directly ask for the permission + requestPermissionLauncher.launch(POST_NOTIFICATIONS); + } + } + } + @NonNull private final Runnable mInitCoreDelayedTask = this::init; @@ -61,6 +95,7 @@ else if (ThemeUtils.isNightTheme(context, theme)) setContentView(R.layout.activity_splash); mPermissionRequest = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), result -> Config.setLocationRequested()); + this.askNotificationPermission(); if (DisplayManager.from(this).isCarDisplayUsed()) { diff --git a/android/app/src/main/java/app/organicmaps/help/HelpFragment.java b/android/app/src/main/java/app/organicmaps/help/HelpFragment.java index c6c128537e3..acfb0c76c53 100644 --- a/android/app/src/main/java/app/organicmaps/help/HelpFragment.java +++ b/android/app/src/main/java/app/organicmaps/help/HelpFragment.java @@ -52,40 +52,40 @@ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, osmPresentationView.setText(getString(R.string.osm_presentation, dataVersion)); setupItem(R.id.news, true, root); - setupItem(R.id.web, true, root); - setupItem(R.id.email, true, root); - setupItem(R.id.github, true, root); - setupItem(R.id.telegram, false, root); - setupItem(R.id.instagram, false, root); - setupItem(R.id.facebook, false, root); - setupItem(R.id.twitter, true, root); - setupItem(R.id.matrix, true, root); - setupItem(R.id.mastodon, false, root); - setupItem(R.id.openstreetmap, true, root); - setupItem(R.id.faq, true, root); - setupItem(R.id.report, isLandscape, root); - - final TextView supportUsView = root.findViewById(R.id.support_us); - if (BuildConfig.FLAVOR.equals("google") && !TextUtils.isEmpty(mDonateUrl)) - supportUsView.setVisibility(View.GONE); - else - setupItem(R.id.support_us, true, root); - - final TextView donateView = root.findViewById(R.id.donate); - if (TextUtils.isEmpty(mDonateUrl)) - donateView.setVisibility(View.GONE); - else - { - if (Config.isNY()) - donateView.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_christmas_tree, 0, - R.drawable.ic_christmas_tree, 0); - setupItem(R.id.donate, isLandscape, root); - } - - if (BuildConfig.REVIEW_URL.isEmpty()) - root.findViewById(R.id.rate).setVisibility(View.GONE); - else - setupItem(R.id.rate, true, root); +// setupItem(R.id.web, true, root); +// setupItem(R.id.email, true, root); +// setupItem(R.id.github, true, root); +// setupItem(R.id.telegram, false, root); +// setupItem(R.id.instagram, false, root); +// setupItem(R.id.facebook, false, root); +// setupItem(R.id.twitter, true, root); +// setupItem(R.id.matrix, true, root); +// setupItem(R.id.mastodon, false, root); +// setupItem(R.id.openstreetmap, true, root); +// setupItem(R.id.faq, true, root); +// setupItem(R.id.report, isLandscape, root); + +// final TextView supportUsView = root.findViewById(R.id.support_us); +// if (BuildConfig.FLAVOR.equals("google") && !TextUtils.isEmpty(mDonateUrl)) +// supportUsView.setVisibility(View.GONE); +// else +// setupItem(R.id.support_us, true, root); +// +// final TextView donateView = root.findViewById(R.id.donate); +// if (TextUtils.isEmpty(mDonateUrl)) +// donateView.setVisibility(View.GONE); +// else +// { +// if (Config.isNY()) +// donateView.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_christmas_tree, 0, +// R.drawable.ic_christmas_tree, 0); +// setupItem(R.id.donate, isLandscape, root); +// } +// +// if (BuildConfig.REVIEW_URL.isEmpty()) +// root.findViewById(R.id.rate).setVisibility(View.GONE); +// else +// setupItem(R.id.rate, true, root); setupItem(R.id.copyright, false, root); View termOfUseView = root.findViewById(R.id.term_of_use_link); diff --git a/android/app/src/main/java/app/organicmaps/maplayer/MapButtonsController.java b/android/app/src/main/java/app/organicmaps/maplayer/MapButtonsController.java index 94cbbc6f9c6..651e5a931a4 100644 --- a/android/app/src/main/java/app/organicmaps/maplayer/MapButtonsController.java +++ b/android/app/src/main/java/app/organicmaps/maplayer/MapButtonsController.java @@ -64,8 +64,7 @@ public class MapButtonsController extends Fragment @Nullable @Override - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) - { + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { final FragmentActivity activity = requireActivity(); mMapButtonClickListener = (MwmActivity) activity; mPlacePageViewModel = new ViewModelProvider(activity).get(PlacePageViewModel.class); @@ -83,22 +82,23 @@ else if (layoutMode == LayoutMode.planning) mBottomButtonsFrame = mFrame.findViewById(R.id.map_buttons_bottom); final FloatingActionButton helpButton = mFrame.findViewById(R.id.help_button); - if (helpButton != null) - { - if (Config.isNY() && !TextUtils.isEmpty(Config.getDonateUrl(requireContext()))) - helpButton.setImageResource(R.drawable.ic_christmas_tree); - else - helpButton.setImageResource(R.drawable.logo); + if (helpButton != null) { // Keep this button colorful in normal theme. if (!ThemeUtils.isNightTheme(requireContext())) helpButton.getDrawable().setTintList(null); } + final FloatingActionButton alertsButton = mFrame.findViewById(R.id.alerts_button); + if (alertsButton != null) { + // i want to navigate to the alerts page and there is no callback from menu buttons; + alertsButton.setOnClickListener((v) -> mMapButtonClickListener.onMapButtonClick(MapButtons.menu)); + } + final View zoomFrame = mFrame.findViewById(R.id.zoom_buttons_container); mFrame.findViewById(R.id.nav_zoom_in) - .setOnClickListener((v) -> mMapButtonClickListener.onMapButtonClick(MapButtons.zoomIn)); + .setOnClickListener((v) -> mMapButtonClickListener.onMapButtonClick(MapButtons.zoomIn)); mFrame.findViewById(R.id.nav_zoom_out) - .setOnClickListener((v) -> mMapButtonClickListener.onMapButtonClick(MapButtons.zoomOut)); + .setOnClickListener((v) -> mMapButtonClickListener.onMapButtonClick(MapButtons.zoomOut)); final View bookmarksButton = mFrame.findViewById(R.id.btn_bookmarks); bookmarksButton.setOnClickListener((v) -> mMapButtonClickListener.onMapButtonClick(MapButtons.bookmarks)); final View myPosition = mFrame.findViewById(R.id.my_position); @@ -106,25 +106,28 @@ else if (layoutMode == LayoutMode.planning) // Some buttons do not exist in navigation mode mToggleMapLayerButton = mFrame.findViewById(R.id.layers_button); - if (mToggleMapLayerButton != null) - { + if (mToggleMapLayerButton != null) { mToggleMapLayerButton.setOnClickListener(view -> mMapButtonClickListener.onMapButtonClick(MapButtons.toggleMapLayer)); mToggleMapLayerButton.setVisibility(View.VISIBLE); } final View menuButton = mFrame.findViewById(R.id.menu_button); - if (menuButton != null) - { + if (menuButton != null) { menuButton.setOnClickListener((v) -> mMapButtonClickListener.onMapButtonClick(MapButtons.menu)); // This hack is needed to show the badge on the initial startup. For some reason, updateMenuBadge does not work from onResume() there. menuButton.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override - public void onGlobalLayout() - { + public void onGlobalLayout() { updateMenuBadge(); menuButton.getViewTreeObserver().removeOnGlobalLayoutListener(this); } }); } + + final View alertButton = mFrame.findViewById(R.id.alerts_button); + if (alertButton != null) { + alertButton.setOnClickListener((v) -> mMapButtonClickListener.onMapButtonClick(MapButtons.alerts)); + } + if (helpButton != null) helpButton.setOnClickListener((v) -> mMapButtonClickListener.onMapButtonClick(MapButtons.help)); @@ -350,7 +353,8 @@ public enum MapButtons search, bookmarks, menu, - help + help, + alerts } public interface MapButtonClickListener diff --git a/android/app/src/main/java/app/organicmaps/util/Constants.java b/android/app/src/main/java/app/organicmaps/util/Constants.java index e26115ab004..4ac69141053 100644 --- a/android/app/src/main/java/app/organicmaps/util/Constants.java +++ b/android/app/src/main/java/app/organicmaps/util/Constants.java @@ -33,6 +33,10 @@ public static class Url public static final String OSM_REGISTER = "https://www.openstreetmap.org/user/new"; public static final String OSM_RECOVER_PASSWORD = "https://www.openstreetmap.org/user/forgot-password"; + public static final String DRIMS_PUBLIC_ALERTS = "https://drimsplatform.com/alerts"; + public static final String DRIMS_LIVE = "https://drimsplatform.com/home"; + public static final String DRIMS_LOGIN = "https://drimsplatform.com"; + private Url() {} } diff --git a/android/app/src/main/res/drawable/asset_1_3.xml b/android/app/src/main/res/drawable/asset_1_3.xml new file mode 100644 index 00000000000..44abf2e6e90 --- /dev/null +++ b/android/app/src/main/res/drawable/asset_1_3.xml @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/res/layout-land/about.xml b/android/app/src/main/res/layout-land/about.xml index 56017f1543e..2236a6182e2 100644 --- a/android/app/src/main/res/layout-land/about.xml +++ b/android/app/src/main/res/layout-land/about.xml @@ -57,7 +57,7 @@ android:layout_width="@dimen/about_logo" android:layout_height="@dimen/about_logo" android:contentDescription="@string/app_name" - app:srcCompat="@drawable/logo" + app:srcCompat="@drawable/asset_1_3" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/linearLayout2" app:layout_constraintHorizontal_bias="0.5" diff --git a/android/app/src/main/res/layout-land/map_buttons_bottom.xml b/android/app/src/main/res/layout-land/map_buttons_bottom.xml index 2d3d0995295..0d17b4f9408 100644 --- a/android/app/src/main/res/layout-land/map_buttons_bottom.xml +++ b/android/app/src/main/res/layout-land/map_buttons_bottom.xml @@ -22,13 +22,21 @@ app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/btn_bookmarks" app:layout_constraintStart_toEndOf="@+id/help_button" /> + + + android:contentDescription="DRIMS" + app:srcCompat="@drawable/asset_1_3" /> - - - - - - - - - + android:text="DRIMS"/> - - - - - - - - - - - - - + + - - - - - + + - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - @@ -135,13 +120,15 @@ - + - + + + diff --git a/iphone/Maps/UI/Help/AboutController/AboutController.swift b/iphone/Maps/UI/Help/AboutController/AboutController.swift index 59fd59ccf64..27cb98b42dd 100644 --- a/iphone/Maps/UI/Help/AboutController/AboutController.swift +++ b/iphone/Maps/UI/Help/AboutController/AboutController.swift @@ -26,14 +26,14 @@ final class AboutController: MWMViewController { private let logoImageView = UIImageView() private let headerTitleLabel = UILabel() private let additionalInfoStackView = UIStackView() - private let donationView = DonationView() - private let osmView = OSMView() + // private let donationView = DonationView() + // private let osmView = OSMView() private let infoTableView = UITableView(frame: .zero, style: .plain) private var infoTableViewHeightAnchor: NSLayoutConstraint? - private let socialMediaHeaderLabel = UILabel() - private let socialMediaCollectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout()) - private lazy var socialMediaCollectionViewHeighConstraint = socialMediaCollectionView.heightAnchor.constraint(equalToConstant: .zero) - private let termsOfUseAndPrivacyPolicyView = ButtonsStackView() + // private let socialMediaHeaderLabel = UILabel() + // private let socialMediaCollectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout()) + // private lazy var socialMediaCollectionViewHeighConstraint = socialMediaCollectionView.heightAnchor.constraint(equalToConstant: .zero) + // private let termsOfUseAndPrivacyPolicyView = ButtonsStackView() private var infoTableViewData = [AboutInfoTableViewCellModel]() private var socialMediaCollectionViewData = [SocialMediaCollectionViewCellModel]() private var onDidAppearCompletionHandler: (() -> Void)? @@ -58,7 +58,7 @@ final class AboutController: MWMViewController { override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - updateCollection() + // updateCollection() } override func viewDidAppear(_ animated: Bool) { @@ -71,7 +71,7 @@ final class AboutController: MWMViewController { override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) - updateCollection() + // updateCollection() } } @@ -80,7 +80,7 @@ private extension AboutController { func setupViews() { func setupTitle() { let titleView = UILabel() - titleView.text = Self.formattedAppVersion() + titleView.text = formattedAppVersion() titleView.textColor = .white titleView.font = UIFont.systemFont(ofSize: 17, weight: .semibold) titleView.isUserInteractionEnabled = true @@ -112,32 +112,32 @@ private extension AboutController { headerTitleLabel.setStyleAndApply("semibold18:blackPrimaryText") headerTitleLabel.text = L("about_headline") headerTitleLabel.textAlignment = .center - headerTitleLabel.numberOfLines = 1 + headerTitleLabel.numberOfLines = 2 headerTitleLabel.allowsDefaultTighteningForTruncation = true headerTitleLabel.adjustsFontSizeToFitWidth = true - headerTitleLabel.minimumScaleFactor = 0.5 + headerTitleLabel.minimumScaleFactor = 2 } func setupAdditionalInfo() { additionalInfoStackView.axis = .vertical additionalInfoStackView.spacing = 15 - [AboutInfo.noTracking, .noWifi, .community].forEach({ additionalInfoStackView.addArrangedSubview(InfoView(image: nil, title: $0.title)) }) + [AboutInfo.noWifi].forEach({ additionalInfoStackView.addArrangedSubview(InfoView(image: nil, title: $0.title)) }) } - func setupDonation() { - donationView.donateButtonDidTapHandler = { [weak self] in - guard let self else { return } - self.openUrl(self.isDonateEnabled() ? Settings.donateUrl() : L("translated_om_site_url") + "support-us/") - } - } + // func setupDonation() { + // donationView.donateButtonDidTapHandler = { [weak self] in + // guard let self else { return } + // self.openUrl(self.isDonateEnabled() ? Settings.donateUrl() : L("translated_om_site_url") + "support-us/") + // } + // } - func setupOSM() { - osmView.setMapDate(Self.formattedMapsDataVersion()) - osmView.didTapHandler = { [weak self] in - self?.openUrl("https://www.openstreetmap.org/") - } - } + // func setupOSM() { + // osmView.setMapDate(formattedMapsDataVersion()) + // osmView.didTapHandler = { [weak self] in + // self?.openUrl("https://www.openstreetmap.org/") + // } + // } func setupInfoTable() { infoTableView.setStyleAndApply("ClearBackground") @@ -150,32 +150,32 @@ private extension AboutController { infoTableView.register(cell: InfoTableViewCell.self) } - func setupSocialMediaCollection() { - socialMediaHeaderLabel.setStyleAndApply("regular16:blackPrimaryText") - socialMediaHeaderLabel.text = L("follow_us") - socialMediaHeaderLabel.numberOfLines = 1 - socialMediaHeaderLabel.allowsDefaultTighteningForTruncation = true - socialMediaHeaderLabel.adjustsFontSizeToFitWidth = true - socialMediaHeaderLabel.minimumScaleFactor = 0.5 - - socialMediaCollectionView.backgroundColor = .clear - socialMediaCollectionView.isScrollEnabled = false - socialMediaCollectionView.dataSource = self - socialMediaCollectionView.delegate = self - socialMediaCollectionView.register(cell: SocialMediaCollectionViewCell.self) - } - - func setupTermsAndPrivacy() { - termsOfUseAndPrivacyPolicyView.addButton(title: L("privacy_policy"), didTapHandler: { [weak self] in - self?.openUrl(L("translated_om_site_url") + "privacy/") - }) - termsOfUseAndPrivacyPolicyView.addButton(title: L("terms_of_use"), didTapHandler: { [weak self] in - self?.openUrl(L("translated_om_site_url") + "terms/") - }) - termsOfUseAndPrivacyPolicyView.addButton(title: L("copyright"), didTapHandler: { [weak self] in - self?.showCopyright() - }) - } + // func setupSocialMediaCollection() { + // socialMediaHeaderLabel.setStyleAndApply("regular16:blackPrimaryText") + // socialMediaHeaderLabel.text = L("follow_us") + // socialMediaHeaderLabel.numberOfLines = 1 + // socialMediaHeaderLabel.allowsDefaultTighteningForTruncation = true + // socialMediaHeaderLabel.adjustsFontSizeToFitWidth = true + // socialMediaHeaderLabel.minimumScaleFactor = 0.5 + + // socialMediaCollectionView.backgroundColor = .clear + // socialMediaCollectionView.isScrollEnabled = false + // socialMediaCollectionView.dataSource = self + // socialMediaCollectionView.delegate = self + // socialMediaCollectionView.register(cell: SocialMediaCollectionViewCell.self) + // } + + // func setupTermsAndPrivacy() { + // termsOfUseAndPrivacyPolicyView.addButton(title: L("privacy_policy"), didTapHandler: { [weak self] in + // self?.openUrl(L("translated_om_site_url") + "privacy/") + // }) + // termsOfUseAndPrivacyPolicyView.addButton(title: L("terms_of_use"), didTapHandler: { [weak self] in + // self?.openUrl(L("translated_om_site_url") + "terms/") + // }) + // termsOfUseAndPrivacyPolicyView.addButton(title: L("copyright"), didTapHandler: { [weak self] in + // self?.showCopyright() + // }) + // } view.setStyleAndApply("PressBackground") @@ -184,11 +184,11 @@ private extension AboutController { setupLogo() setupHeaderTitle() setupAdditionalInfo() - setupDonation() - setupOSM() + // setupDonation() + // setupOSM() setupInfoTable() - setupSocialMediaCollection() - setupTermsAndPrivacy() + // setupSocialMediaCollection() + // setupTermsAndPrivacy() infoTableViewData = buildInfoTableViewData() socialMediaCollectionViewData = buildSocialMediaCollectionViewData() @@ -200,14 +200,14 @@ private extension AboutController { stackView.addArrangedSubview(logoImageView) stackView.addArrangedSubview(headerTitleLabel) stackView.addArrangedSubviewWithSeparator(additionalInfoStackView) - if isDonateEnabled() { - stackView.addArrangedSubviewWithSeparator(donationView) - } - stackView.addArrangedSubviewWithSeparator(osmView) + // if isDonateEnabled() { + // stackView.addArrangedSubviewWithSeparator(donationView) + // } + // stackView.addArrangedSubviewWithSeparator(osmView) stackView.addArrangedSubviewWithSeparator(infoTableView) - stackView.addArrangedSubviewWithSeparator(socialMediaHeaderLabel) - stackView.addArrangedSubview(socialMediaCollectionView) - stackView.addArrangedSubviewWithSeparator(termsOfUseAndPrivacyPolicyView) + // stackView.addArrangedSubviewWithSeparator(socialMediaHeaderLabel) + // stackView.addArrangedSubview(socialMediaCollectionView) + // stackView.addArrangedSubviewWithSeparator(termsOfUseAndPrivacyPolicyView) } func layoutViews() { @@ -215,10 +215,10 @@ private extension AboutController { stackView.translatesAutoresizingMaskIntoConstraints = false logoImageView.translatesAutoresizingMaskIntoConstraints = false additionalInfoStackView.translatesAutoresizingMaskIntoConstraints = false - donationView.translatesAutoresizingMaskIntoConstraints = false + // donationView.translatesAutoresizingMaskIntoConstraints = false infoTableView.translatesAutoresizingMaskIntoConstraints = false - socialMediaCollectionView.translatesAutoresizingMaskIntoConstraints = false - termsOfUseAndPrivacyPolicyView.translatesAutoresizingMaskIntoConstraints = false + // socialMediaCollectionView.translatesAutoresizingMaskIntoConstraints = false + // termsOfUseAndPrivacyPolicyView.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ scrollView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor), @@ -237,60 +237,47 @@ private extension AboutController { additionalInfoStackView.widthAnchor.constraint(equalTo: stackView.widthAnchor), - osmView.widthAnchor.constraint(equalTo: stackView.widthAnchor), + // osmView.widthAnchor.constraint(equalTo: stackView.widthAnchor), infoTableView.widthAnchor.constraint(equalTo: stackView.widthAnchor), infoTableView.heightAnchor.constraint(equalToConstant: Constants.infoTableViewCellHeight * CGFloat(infoTableViewData.count)), - socialMediaHeaderLabel.leadingAnchor.constraint(equalTo: socialMediaCollectionView.leadingAnchor), + // socialMediaHeaderLabel.leadingAnchor.constraint(equalTo: socialMediaCollectionView.leadingAnchor), - socialMediaCollectionView.widthAnchor.constraint(equalTo: stackView.widthAnchor), - socialMediaCollectionView.contentLayoutGuide.widthAnchor.constraint(equalTo: stackView.widthAnchor), - socialMediaCollectionViewHeighConstraint, + // socialMediaCollectionView.widthAnchor.constraint(equalTo: stackView.widthAnchor), + // socialMediaCollectionView.contentLayoutGuide.widthAnchor.constraint(equalTo: stackView.widthAnchor), + // socialMediaCollectionViewHeighConstraint, - termsOfUseAndPrivacyPolicyView.widthAnchor.constraint(equalTo: stackView.widthAnchor), + // termsOfUseAndPrivacyPolicyView.widthAnchor.constraint(equalTo: stackView.widthAnchor), ]) - donationView.widthAnchor.constraint(equalTo: stackView.widthAnchor).isActive = isDonateEnabled() + // donationView.widthAnchor.constraint(equalTo: stackView.widthAnchor).isActive = isDonateEnabled() view.layoutIfNeeded() - updateCollection() + // updateCollection() } - func updateCollection() { - socialMediaCollectionView.collectionViewLayout.invalidateLayout() - // On devices with the iOS 12 the actual collectionView layout update not always occurs during the current layout update cycle. - // So constraints update should be performed on the next layout update cycle. - DispatchQueue.main.async { - self.socialMediaCollectionViewHeighConstraint.constant = self.socialMediaCollectionView.collectionViewLayout.collectionViewContentSize.height - } - } + // func updateCollection() { + // socialMediaCollectionView.collectionViewLayout.invalidateLayout() + // // On devices with the iOS 12 the actual collectionView layout update not always occurs during the current layout update cycle. + // // So constraints update should be performed on the next layout update cycle. + // DispatchQueue.main.async { + // self.socialMediaCollectionViewHeighConstraint.constant = self.socialMediaCollectionView.collectionViewLayout.collectionViewContentSize.height + // } + // } func isDonateEnabled() -> Bool { return Settings.donateUrl() != nil } func buildInfoTableViewData() -> [AboutInfoTableViewCellModel] { - let infoContent: [AboutInfo] = [.faq, .reportMapDataProblem, .reportABug, .news, .volunteer, .rateTheApp] + let infoContent: [AboutInfo] = [.faq] let data = infoContent.map { [weak self] aboutInfo in return AboutInfoTableViewCellModel(title: aboutInfo.title, image: aboutInfo.image, didTapHandler: { switch aboutInfo { case .faq: self?.navigationController?.pushViewController(FaqController(), animated: true) - case .reportABug: - guard let link = aboutInfo.link else { fatalError("The recipient link should be provided to report a bug.") } - UIApplication.shared.showLoadingOverlay { - let logFileURL = Logger.getLogFileURL() - UIApplication.shared.hideLoadingOverlay { - guard let self else { return } - self.sendEmailWith(header: "Organic Maps Bugreport", toRecipients: [link], attachmentFileURL: logFileURL) - } - } - case .reportMapDataProblem, .volunteer, .news: - self?.openUrl(aboutInfo.link) - case .rateTheApp: - UIApplication.shared.rateApp() - default: - break + case .noWifi: + return } }) } @@ -322,7 +309,7 @@ private extension AboutController { } // Returns a human-readable maps data version. - static func formattedMapsDataVersion() -> String { + func formattedMapsDataVersion() -> String { // First, convert version code like 220131 to a date. let df = DateFormatter() df.locale = Locale(identifier:"en_US_POSIX") @@ -336,7 +323,7 @@ private extension AboutController { return df.string(from:mapsDate) } - static func formattedAppVersion() -> String { + func formattedAppVersion() -> String { let appInfo = AppInfo.shared(); // Use strong left-to-right unicode direction characters for the app version. return String(format: L("version"), "\u{2066}\(appInfo.bundleVersion)-\(appInfo.buildNumber)\u{2069}") @@ -361,11 +348,11 @@ private extension AboutController { // MARK: - Actions private extension AboutController { @objc func appVersionButtonTapped() { - copyToClipboard(Self.formattedAppVersion()) + copyToClipboard(formattedAppVersion()) } @objc func osmMapsDataButtonTapped() { - copyToClipboard(Self.formattedMapsDataVersion()) + copyToClipboard(formattedMapsDataVersion()) } } diff --git a/iphone/Maps/UI/Help/AboutController/Models/AboutInfo.swift b/iphone/Maps/UI/Help/AboutController/Models/AboutInfo.swift index 85a415cfe72..9c9d34d456f 100644 --- a/iphone/Maps/UI/Help/AboutController/Models/AboutInfo.swift +++ b/iphone/Maps/UI/Help/AboutController/Models/AboutInfo.swift @@ -1,35 +1,14 @@ enum AboutInfo { case faq - case reportABug - case reportMapDataProblem - case volunteer - case news - case rateTheApp - case noTracking case noWifi - case community var title: String { switch self { case .faq: return L("faq") - case .reportABug: - return L("report_a_bug") - case .reportMapDataProblem: - return L("report_incorrect_map_bug") - case .volunteer: - return L("volunteer") - case .news: - return L("news") - case .rateTheApp: - return L("rate_the_app") - case .noTracking: - return L("about_proposition_1") case .noWifi: return L("about_proposition_2") - case .community: - return L("about_proposition_3") } } @@ -37,17 +16,7 @@ enum AboutInfo { switch self { case .faq: return UIImage(named: "ic_about_faq")! - case .reportABug: - return UIImage(named: "ic_about_report_bug")! - case .reportMapDataProblem: - return UIImage(named: "ic_about_report_osm")! - case .volunteer: - return UIImage(named: "ic_about_volunteer")! - case .news: - return UIImage(named: "ic_about_news")! - case .rateTheApp: - return UIImage(named: "ic_about_rate_app")! - case .noTracking, .noWifi, .community: + case .noWifi: // Dots are used for these cases return nil } @@ -55,17 +24,9 @@ enum AboutInfo { var link: String? { switch self { - case .faq, .rateTheApp, .noTracking, .noWifi, .community: + case .faq, .noWifi: // These cases don't provide redirection to the web return nil - case .reportABug: - return "ios@organicmaps.app" - case .reportMapDataProblem: - return "https://www.openstreetmap.org/fixthemap" - case .volunteer: - return L("translated_om_site_url") + "support-us/" - case .news: - return L("translated_om_site_url") + "news/" } } } diff --git a/iphone/Maps/UI/LiveFeedsViewController.swift b/iphone/Maps/UI/LiveFeedsViewController.swift new file mode 100644 index 00000000000..4e9b63e019a --- /dev/null +++ b/iphone/Maps/UI/LiveFeedsViewController.swift @@ -0,0 +1,21 @@ +final class LiveFeedsViewController: MWMViewController { + override func loadView() { + super.loadView() + + // TODO: FAQ? + self.title = L("Live Feeds") + + let webViewController = WebViewController.init(url:URL(string:"https://drimsplatform.com/home")!, title: "Live")! + webViewController.openInSafari = true + addChild(webViewController) + let aboutView = webViewController.view! + view.addSubview(aboutView) + aboutView.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + aboutView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + aboutView.trailingAnchor.constraint(equalTo: view.trailingAnchor), + aboutView.topAnchor.constraint(equalTo: view.topAnchor), + aboutView.bottomAnchor.constraint(equalTo: view.bottomAnchor) + ]) + } +} diff --git a/iphone/Maps/UI/LoginViewController.swift b/iphone/Maps/UI/LoginViewController.swift new file mode 100644 index 00000000000..3b3f5b10d27 --- /dev/null +++ b/iphone/Maps/UI/LoginViewController.swift @@ -0,0 +1,21 @@ +final class LoginViewController: MWMViewController { + override func loadView() { + super.loadView() + + // TODO: FAQ? + self.title = L("Login") + + let webViewController = WebViewController.init(url:URL(string:"https://drimsplatform.com/")!, title: "Login")! + webViewController.openInSafari = true + addChild(webViewController) + let aboutView = webViewController.view! + view.addSubview(aboutView) + aboutView.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + aboutView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + aboutView.trailingAnchor.constraint(equalTo: view.trailingAnchor), + aboutView.topAnchor.constraint(equalTo: view.topAnchor), + aboutView.bottomAnchor.constraint(equalTo: view.bottomAnchor) + ]) + } +} diff --git a/iphone/Maps/UI/Settings/MWMSettingsViewController.mm b/iphone/Maps/UI/Settings/MWMSettingsViewController.mm index 83efc3cd222..192f76273b5 100644 --- a/iphone/Maps/UI/Settings/MWMSettingsViewController.mm +++ b/iphone/Maps/UI/Settings/MWMSettingsViewController.mm @@ -196,7 +196,7 @@ - (void)configCommonSection { [strongSelf.iCloudSynchronizationCell updateWithError:error]; }]; - [self.enableLoggingCell configWithDelegate:self title:L(@"enable_logging") isOn:MWMSettings.isFileLoggingEnabled]; + // [self.enableLoggingCell configWithDelegate:self title:L(@"enable_logging") isOn:MWMSettings.isFileLoggingEnabled]; [self updateLogFileSize]; } @@ -391,7 +391,8 @@ - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInte - (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section { switch (section) { case 1: - return L(@"enable_logging_warning_message"); + // return L(@"enable_logging_warning_message"); + return nil; default: return nil; } diff --git a/iphone/Maps/UI/Storyboard/Login.storyboard b/iphone/Maps/UI/Storyboard/Login.storyboard new file mode 100644 index 00000000000..d6ce1c50b9a --- /dev/null +++ b/iphone/Maps/UI/Storyboard/Login.storyboard @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iphone/Maps/UI/Storyboard/Settings.storyboard b/iphone/Maps/UI/Storyboard/Settings.storyboard index dc2993590b4..8feade0f1a2 100644 --- a/iphone/Maps/UI/Storyboard/Settings.storyboard +++ b/iphone/Maps/UI/Storyboard/Settings.storyboard @@ -458,7 +458,7 @@ - + @@ -921,7 +921,15 @@ - + + + + + + + + + diff --git a/iphone/Maps/UI/Storyboard/Storyboard.swift b/iphone/Maps/UI/Storyboard/Storyboard.swift index 07b3a5daaad..6b2c064beac 100644 --- a/iphone/Maps/UI/Storyboard/Storyboard.swift +++ b/iphone/Maps/UI/Storyboard/Storyboard.swift @@ -11,6 +11,7 @@ enum Storyboard: Int { case drivingOptions case carPlay case placePage + case login } extension UIStoryboard { @@ -28,6 +29,7 @@ extension UIStoryboard { case .drivingOptions: name = "DrivingOptions" case .carPlay: name = "CarPlayStoryboard" case .placePage: name = "PlacePage" + case .login: name = "Login" } return UIStoryboard(name: name, bundle: nil) } diff --git a/iphone/metadata/ar-SA/description.txt b/iphone/metadata/ar-SA/description.txt index 6d3c81b6670..240de4f7a03 100644 --- a/iphone/metadata/ar-SA/description.txt +++ b/iphone/metadata/ar-SA/description.txt @@ -17,7 +17,6 @@ Organic Maps is free from trackers and other bad stuff: • No ads • No tracking -• No data collection • No phoning home • No annoying registration • No mandatory tutorials diff --git a/iphone/metadata/da/description.txt b/iphone/metadata/da/description.txt index 6d3c81b6670..240de4f7a03 100644 --- a/iphone/metadata/da/description.txt +++ b/iphone/metadata/da/description.txt @@ -17,7 +17,6 @@ Organic Maps is free from trackers and other bad stuff: • No ads • No tracking -• No data collection • No phoning home • No annoying registration • No mandatory tutorials diff --git a/iphone/metadata/el/description.txt b/iphone/metadata/el/description.txt index 6d3c81b6670..240de4f7a03 100644 --- a/iphone/metadata/el/description.txt +++ b/iphone/metadata/el/description.txt @@ -17,7 +17,6 @@ Organic Maps is free from trackers and other bad stuff: • No ads • No tracking -• No data collection • No phoning home • No annoying registration • No mandatory tutorials diff --git a/iphone/metadata/en-AU/description.txt b/iphone/metadata/en-AU/description.txt index 6d3c81b6670..240de4f7a03 100644 --- a/iphone/metadata/en-AU/description.txt +++ b/iphone/metadata/en-AU/description.txt @@ -17,7 +17,6 @@ Organic Maps is free from trackers and other bad stuff: • No ads • No tracking -• No data collection • No phoning home • No annoying registration • No mandatory tutorials diff --git a/iphone/metadata/en-CA/description.txt b/iphone/metadata/en-CA/description.txt index 6d3c81b6670..7f0fa96a7c1 100644 --- a/iphone/metadata/en-CA/description.txt +++ b/iphone/metadata/en-CA/description.txt @@ -17,7 +17,7 @@ Organic Maps is free from trackers and other bad stuff: • No ads • No tracking -• No data collection + • No phoning home • No annoying registration • No mandatory tutorials diff --git a/iphone/metadata/en-GB/description.txt b/iphone/metadata/en-GB/description.txt index 6d3c81b6670..7f0fa96a7c1 100644 --- a/iphone/metadata/en-GB/description.txt +++ b/iphone/metadata/en-GB/description.txt @@ -17,7 +17,7 @@ Organic Maps is free from trackers and other bad stuff: • No ads • No tracking -• No data collection + • No phoning home • No annoying registration • No mandatory tutorials diff --git a/iphone/metadata/en-US/description.txt b/iphone/metadata/en-US/description.txt index 6d3c81b6670..7f0fa96a7c1 100644 --- a/iphone/metadata/en-US/description.txt +++ b/iphone/metadata/en-US/description.txt @@ -17,7 +17,7 @@ Organic Maps is free from trackers and other bad stuff: • No ads • No tracking -• No data collection + • No phoning home • No annoying registration • No mandatory tutorials diff --git a/iphone/metadata/es-MX/description.txt b/iphone/metadata/es-MX/description.txt index 6d3c81b6670..7f0fa96a7c1 100644 --- a/iphone/metadata/es-MX/description.txt +++ b/iphone/metadata/es-MX/description.txt @@ -17,7 +17,7 @@ Organic Maps is free from trackers and other bad stuff: • No ads • No tracking -• No data collection + • No phoning home • No annoying registration • No mandatory tutorials diff --git a/iphone/metadata/fi/description.txt b/iphone/metadata/fi/description.txt index 6d3c81b6670..7f0fa96a7c1 100644 --- a/iphone/metadata/fi/description.txt +++ b/iphone/metadata/fi/description.txt @@ -17,7 +17,7 @@ Organic Maps is free from trackers and other bad stuff: • No ads • No tracking -• No data collection + • No phoning home • No annoying registration • No mandatory tutorials diff --git a/iphone/metadata/fr-CA/description.txt b/iphone/metadata/fr-CA/description.txt index 6d3c81b6670..240de4f7a03 100644 --- a/iphone/metadata/fr-CA/description.txt +++ b/iphone/metadata/fr-CA/description.txt @@ -17,7 +17,6 @@ Organic Maps is free from trackers and other bad stuff: • No ads • No tracking -• No data collection • No phoning home • No annoying registration • No mandatory tutorials diff --git a/iphone/metadata/he/description.txt b/iphone/metadata/he/description.txt index 6d3c81b6670..7f0fa96a7c1 100644 --- a/iphone/metadata/he/description.txt +++ b/iphone/metadata/he/description.txt @@ -17,7 +17,7 @@ Organic Maps is free from trackers and other bad stuff: • No ads • No tracking -• No data collection + • No phoning home • No annoying registration • No mandatory tutorials diff --git a/iphone/metadata/hr/description.txt b/iphone/metadata/hr/description.txt index 6d3c81b6670..7f0fa96a7c1 100644 --- a/iphone/metadata/hr/description.txt +++ b/iphone/metadata/hr/description.txt @@ -17,7 +17,7 @@ Organic Maps is free from trackers and other bad stuff: • No ads • No tracking -• No data collection + • No phoning home • No annoying registration • No mandatory tutorials diff --git a/iphone/metadata/ja/description.txt b/iphone/metadata/ja/description.txt index 6d3c81b6670..7f0fa96a7c1 100644 --- a/iphone/metadata/ja/description.txt +++ b/iphone/metadata/ja/description.txt @@ -17,7 +17,7 @@ Organic Maps is free from trackers and other bad stuff: • No ads • No tracking -• No data collection + • No phoning home • No annoying registration • No mandatory tutorials diff --git a/iphone/metadata/ko/description.txt b/iphone/metadata/ko/description.txt index 6d3c81b6670..7f0fa96a7c1 100644 --- a/iphone/metadata/ko/description.txt +++ b/iphone/metadata/ko/description.txt @@ -17,7 +17,7 @@ Organic Maps is free from trackers and other bad stuff: • No ads • No tracking -• No data collection + • No phoning home • No annoying registration • No mandatory tutorials diff --git a/iphone/metadata/ms/description.txt b/iphone/metadata/ms/description.txt index 6d3c81b6670..7f0fa96a7c1 100644 --- a/iphone/metadata/ms/description.txt +++ b/iphone/metadata/ms/description.txt @@ -17,7 +17,7 @@ Organic Maps is free from trackers and other bad stuff: • No ads • No tracking -• No data collection + • No phoning home • No annoying registration • No mandatory tutorials diff --git a/iphone/metadata/nl-NL/description.txt b/iphone/metadata/nl-NL/description.txt index 6d3c81b6670..7f0fa96a7c1 100644 --- a/iphone/metadata/nl-NL/description.txt +++ b/iphone/metadata/nl-NL/description.txt @@ -17,7 +17,7 @@ Organic Maps is free from trackers and other bad stuff: • No ads • No tracking -• No data collection + • No phoning home • No annoying registration • No mandatory tutorials diff --git a/iphone/metadata/no/description.txt b/iphone/metadata/no/description.txt index 6d3c81b6670..7f0fa96a7c1 100644 --- a/iphone/metadata/no/description.txt +++ b/iphone/metadata/no/description.txt @@ -17,7 +17,7 @@ Organic Maps is free from trackers and other bad stuff: • No ads • No tracking -• No data collection + • No phoning home • No annoying registration • No mandatory tutorials diff --git a/iphone/metadata/ro/description.txt b/iphone/metadata/ro/description.txt index 6d3c81b6670..7f0fa96a7c1 100644 --- a/iphone/metadata/ro/description.txt +++ b/iphone/metadata/ro/description.txt @@ -17,7 +17,7 @@ Organic Maps is free from trackers and other bad stuff: • No ads • No tracking -• No data collection + • No phoning home • No annoying registration • No mandatory tutorials diff --git a/iphone/metadata/sk/description.txt b/iphone/metadata/sk/description.txt index 6d3c81b6670..7f0fa96a7c1 100644 --- a/iphone/metadata/sk/description.txt +++ b/iphone/metadata/sk/description.txt @@ -17,7 +17,7 @@ Organic Maps is free from trackers and other bad stuff: • No ads • No tracking -• No data collection + • No phoning home • No annoying registration • No mandatory tutorials diff --git a/iphone/metadata/th/description.txt b/iphone/metadata/th/description.txt index 6d3c81b6670..7f0fa96a7c1 100644 --- a/iphone/metadata/th/description.txt +++ b/iphone/metadata/th/description.txt @@ -17,7 +17,7 @@ Organic Maps is free from trackers and other bad stuff: • No ads • No tracking -• No data collection + • No phoning home • No annoying registration • No mandatory tutorials diff --git a/iphone/metadata/vi/description.txt b/iphone/metadata/vi/description.txt index 6d3c81b6670..7f0fa96a7c1 100644 --- a/iphone/metadata/vi/description.txt +++ b/iphone/metadata/vi/description.txt @@ -17,7 +17,7 @@ Organic Maps is free from trackers and other bad stuff: • No ads • No tracking -• No data collection + • No phoning home • No annoying registration • No mandatory tutorials diff --git a/map/framework.cpp b/map/framework.cpp index afb6366989c..d221640f4a3 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -71,6 +71,10 @@ #include "defines.hpp" #include +#include +#include +#include +#include #include "framework.hpp" @@ -93,6 +97,7 @@ Framework::FixedPosition::FixedPosition() namespace { + char const kMapStyleKey[] = "MapStyleKeyV1"; char const kAllow3dKey[] = "Allow3d"; char const kAllow3dBuildingsKey[] = "Buildings3d"; @@ -110,7 +115,6 @@ char const kShowDebugInfo[] = "DebugInfo"; auto constexpr kLargeFontsScaleFactor = 1.6; size_t constexpr kMaxTrafficCacheSizeBytes = 64 /* Mb */ * 1024 * 1024; auto constexpr kBuildingCentroidThreshold = 10.0; - // TODO! // To adjust GpsTrackFilter was added secret command "?gpstrackaccuracy:xxx;" // where xxx is a new value for horizontal accuracy. @@ -137,6 +141,12 @@ bool ParseSetGpsTrackMinAccuracyCommand(string const & query) pair Framework::RegisterMap(LocalCountryFile const & file) { + auto storedtoken = GetFcmToken(); + LOG(LINFO, ("Stored token:", storedtoken)); + if (!storedtoken.empty()) + { + HandleDeviceToken(storedtoken); + } auto res = m_featuresFetcher.RegisterMap(file); if (res.second == MwmSet::RegResult::Success) { @@ -181,6 +191,7 @@ void Framework::OnLocationUpdate(GpsInfo const & info) #endif m_routingManager.OnLocationUpdate(rInfo); + SendDeviceTokenWithLocation(rInfo); } void Framework::OnCompassUpdate(CompassInfo const & info) @@ -410,17 +421,37 @@ osm::EditableMapObject Framework::CreateGeoFeatureByMwmId(MwmSet::MwmId const & return emo; } + +std::string getCurrentTimestamp() +{ + // Get current time as time_point + auto now = std::chrono::system_clock::now(); + // Convert to time_t for conversion to tm structure + auto now_c = std::chrono::system_clock::to_time_t(now); + // Convert to tm structure for formatting + std::tm now_tm = *std::localtime(&now_c); + + // Use stringstream to format date + std::stringstream ss; + // Format: YYYY-MM-DDTHH:MM:SS, compatible with JavaScript Date string + ss << std::put_time(&now_tm, "%Y-%m-%dT%H:%M:%S"); + + return ss.str(); +} + std::string createUrl(m2::RectD rect) { - // TODO: Get base url from config/enviroment - std::string baseUrl = "http://localhost:3000/api/geo-elements/published-transform-element-in-view-port?"; + auto timestamp = Framework::getLastTimeStamp(); + LOG(LINFO, ("Last timestamp:", timestamp, getCurrentTimestamp())); + + std::string baseUrl = "https://drimsplatform.com/api/api/geo-elements/published-transform-element-in-view-port?"; std::string southWestLng = "southWest[lng]=" + std::to_string(rect.minX()); std::string southWestLat = "&southWest[lat]=" + std::to_string(rect.minY()); std::string northEastLng = "&northEast[lng]=" + std::to_string(rect.maxX()); std::string northEastLat = "&northEast[lat]=" + std::to_string(rect.maxY()); std::string types = "&types[]=geoCircle&types[]=geoPath&types[]=geoRegion&types[]=geoMarker"; - - return baseUrl + southWestLng + southWestLat + northEastLng + northEastLat + types; + std::string timestampParam = "×tamp=" + timestamp; + return baseUrl + southWestLng + southWestLat + northEastLng + northEastLat + types + timestampParam; } void Framework::CreateTestMapObjectIfNeeded(MwmSet::MwmId mwmId) @@ -445,7 +476,6 @@ void Framework::CreateTestMapObjectIfNeeded(MwmSet::MwmId mwmId) if (element.type == "geoMarker") { - // TODO: Add feature type from API uint32_t featurType = classif().GetTypeByPathSafe({"amenity", "cafe"}); LOG(LINFO, ("Feature Type ID:", featurType)); m2::PointD const point = m2::PointD(mercator::FromLatLon(element.position.lat, element.position.lng)); @@ -460,6 +490,8 @@ void Framework::CreateTestMapObjectIfNeeded(MwmSet::MwmId mwmId) if (result == osm::Editor::SaveResult::SavedSuccessfully) { LOG(LINFO, ("Test map object created successfully")); + // Move this to collective success after multiple element types are added. + storeLastTimeStamp(getCurrentTimestamp()); } else { @@ -2786,6 +2818,7 @@ void SetHostingBuildingAddress(FeatureID const & hostingBuildingFid, DataSource } } } // namespace +string m_deviceToken; bool Framework::CanEditMap() const { return !GetStorage().IsDownloadInProgress(); } @@ -3163,3 +3196,56 @@ void Framework::OnPowerSchemeChanged(power_management::Scheme const actualScheme if (actualScheme == power_management::Scheme::EconomyMaximum && GetTrafficManager().IsEnabled()) GetTrafficManager().SetEnabled(false); } + +string BuildPostRequest(std::initializer_list> const & params) +{ + string result; + for (auto it = params.begin(); it != params.end(); ++it) + { + if (it != params.begin()) + result += "&"; + result += it->first + "=" + url::UrlEncode(it->second); + } + return result; +} + +void Framework::HandleDeviceToken(std::string const & deviceToken) +{ + LOG(LINFO, ("Received device token:", deviceToken)); + + // Store the token + m_deviceToken = deviceToken; +} +void Framework::SendDeviceTokenWithLocation(GpsInfo const & info) +{ + if (m_deviceToken.empty()) + return; + + if (!info.IsValid()) + { + LOG(LINFO, ("Failed to get current position, will try again later")); + return; + } + + // Send the device token and current lat,lng to the server + std::string serverUrl = "https://drimsplatform.com/api/api/device"; + platform::HttpClient request(serverUrl); + auto params = BuildPostRequest({ + {"deviceId", m_deviceToken}, + {"lat", std::to_string(info.m_latitude)}, + {"lng", std::to_string(info.m_longitude)}, + }); + request.SetBodyData(std::move(params), "application/x-www-form-urlencoded"); + LOG(LINFO, ("Sending device token to server:", info.m_latitude, info.m_longitude)); + request.SetHttpMethod("POST"); + if (request.RunHttpRequest() && (request.ErrorCode() == 200 || request.ErrorCode() == 304 || + request.ErrorCode() == 201 || request.ErrorCode() == 204)) + { + LOG(LINFO, ("Device token sent successfully")); + m_deviceToken.clear(); // Clear the token after successful send + } + else + { + LOG(LINFO, ("Failed to send device token", request.ServerResponse(), request.ErrorCode())); + } +} \ No newline at end of file diff --git a/map/framework.hpp b/map/framework.hpp index e4c9aece296..9685c9dd72e 100644 --- a/map/framework.hpp +++ b/map/framework.hpp @@ -230,7 +230,22 @@ class Framework : public PositionProvider, std::string const & name, uint32_t featureType, uint32_t index) const; void CreateTestMapObjectIfNeeded(MwmSet::MwmId id); + void HandleDeviceToken(std::string const & deviceToken); + static void storeLastTimeStamp(std::string const & timestamp) + { + GetPlatform().GetSecureStorage().Save("lastTimeStamp", timestamp); + } + + static std::string getLastTimeStamp() + { + std::string timestamp; + GetPlatform().GetSecureStorage().Load("lastTimeStamp", timestamp); + return timestamp; + } + void SendDeviceTokenWithLocation(location::GpsInfo const & info); + + void TrySendDeviceTokenWithLocation(); df::DrapeApi & GetDrapeApi() { return m_drapeApi; } /// \returns true if there're unsaved changes in map with |countryId| and false otherwise. @@ -395,6 +410,17 @@ class Framework : public PositionProvider, void SwitchMyPositionNextMode(); /// Should be set before Drape initialization. Guarantees that fn is called in main thread context. void SetMyPositionModeListener(location::TMyPositionModeChanged && fn); + void StoreFcmToken(std::string const & token) + { + GetPlatform().GetSecureStorage().Save("fcmToken", token); + LOG(LINFO, ("FCM token saved")); + }; + std::string GetFcmToken() + { + std::string token; + GetPlatform().GetSecureStorage().Load("fcmToken", token); + return token; + }; location::EMyPositionMode GetMyPositionMode() const; diff --git a/packaging/app.organicmaps.desktop.metainfo.xml b/packaging/app.organicmaps.desktop.metainfo.xml index 60f75941588..791bdfba97f 100644 --- a/packaging/app.organicmaps.desktop.metainfo.xml +++ b/packaging/app.organicmaps.desktop.metainfo.xml @@ -24,8 +24,8 @@ Organic Maps is a free Android & iOS offline maps app for travelers, tourists, hikers, drivers and cyclists. It uses crowd-sourced OpenStreetMap data and is developed with love by - MapsWithMe (MapsMe) founders and our community. - No ads, no tracking, no data collection, no crapware. + MapsWithMe ( MapsMe) founders and our community. + No ads, no tracking, no crapware. Your donations and positive reviews motivate and inspire us, thanks ❤️!

## Features

@@ -61,7 +61,6 @@