From 9cd42201a88da0593e9e39352e0b794d8fd64616 Mon Sep 17 00:00:00 2001 From: "r.kuznetsov" Date: Thu, 22 Mar 2018 16:09:23 +0300 Subject: [PATCH] Added functions for KML import and conversion --- .../maps/bookmarks/data/BookmarkManager.cpp | 29 ++++++ .../maps/bookmarks/data/BookmarkManager.java | 30 ++++++ map/bookmark_manager.cpp | 96 ++++++++++++++++++- map/bookmark_manager.hpp | 9 ++ 4 files changed, 161 insertions(+), 3 deletions(-) diff --git a/android/jni/com/mapswithme/maps/bookmarks/data/BookmarkManager.cpp b/android/jni/com/mapswithme/maps/bookmarks/data/BookmarkManager.cpp index 641c736ae1..9dfa4f0fe5 100644 --- a/android/jni/com/mapswithme/maps/bookmarks/data/BookmarkManager.cpp +++ b/android/jni/com/mapswithme/maps/bookmarks/data/BookmarkManager.cpp @@ -18,6 +18,7 @@ jfieldID g_bookmarkManagerInstanceField; jmethodID g_onBookmarksLoadingStartedMethod; jmethodID g_onBookmarksLoadingFinishedMethod; jmethodID g_onBookmarksFileLoadedMethod; +jmethodID g_onFinishKmlConversionMethod; void PrepareClassRefs(JNIEnv * env) { @@ -38,6 +39,8 @@ void PrepareClassRefs(JNIEnv * env) g_onBookmarksFileLoadedMethod = jni::GetMethodID(env, bookmarkManagerInstance, "onBookmarksFileLoaded", "(ZLjava/lang/String;Z)V"); + g_onFinishKmlConversionMethod = + jni::GetMethodID(env, bookmarkManagerInstance, "onFinishKmlConversion", "(Z)V"); } void OnAsyncLoadingStarted(JNIEnv * env) @@ -79,6 +82,15 @@ void OnAsyncLoadingFileError(JNIEnv * env, std::string const & fileName, bool is false /* success */, jFileName.get(), isTemporaryFile); jni::HandleJavaException(env); } + +void OnFinishKmlConversion(JNIEnv * env, bool success) +{ + ASSERT(g_bookmarkManagerClass != nullptr, ()); + jobject bookmarkManagerInstance = env->GetStaticObjectField(g_bookmarkManagerClass, + g_bookmarkManagerInstanceField); + env->CallVoidMethod(bookmarkManagerInstance, g_onFinishKmlConversionMethod, success); + jni::HandleJavaException(env); +} } // namespace extern "C" @@ -385,4 +397,21 @@ Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeSetAllCategoriesVi { frm()->GetBookmarkManager().SetAllCategoriesVisibility(static_cast(visible)); } + +JNIEXPORT jint JNICALL +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeGetKmlFilesCountForConversion( + JNIEnv * env, jobject thiz) +{ + return static_cast(frm()->GetBookmarkManager().GetKmlFilesCountForConversion()); +} + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeConvertAllKmlFiles( + JNIEnv * env, jobject thiz) +{ + frm()->GetBookmarkManager().ConvertAllKmlFiles([env](bool success) + { + OnFinishKmlConversion(env, success); + }); +} } // extern "C" diff --git a/android/src/com/mapswithme/maps/bookmarks/data/BookmarkManager.java b/android/src/com/mapswithme/maps/bookmarks/data/BookmarkManager.java index e5ce751188..c08206198a 100644 --- a/android/src/com/mapswithme/maps/bookmarks/data/BookmarkManager.java +++ b/android/src/com/mapswithme/maps/bookmarks/data/BookmarkManager.java @@ -21,6 +21,9 @@ public enum BookmarkManager @NonNull private List mListeners = new ArrayList<>(); + @NonNull + private List mConversionListeners = new ArrayList<>(); + static { ICONS.add(new Icon("placemark-red", "placemark-red", R.drawable.ic_bookmark_marker_red_off, R.drawable.ic_bookmark_marker_red_on)); @@ -68,6 +71,16 @@ public enum BookmarkManager mListeners.remove(listener); } + public void addListener(@NonNull KmlConversionListener listener) + { + mConversionListeners.add(listener); + } + + public void removeListener(@NonNull KmlConversionListener listener) + { + mConversionListeners.remove(listener); + } + // Called from JNI. @MainThread public void onBookmarksLoadingStarted() @@ -101,6 +114,14 @@ public enum BookmarkManager listener.onBookmarksFileLoaded(success); } + // Called from JNI. + @MainThread + public void onFinishKmlConversion(boolean success) + { + for (KmlConversionListener listener : mConversionListeners) + listener.onFinishKmlConversion(success); + } + public boolean isVisible(long catId) { return nativeIsVisible(catId); @@ -339,10 +360,19 @@ public enum BookmarkManager private static native void nativeSetAllCategoriesVisibility(boolean visible); + private static native int nativeGetKmlFilesCountForConversion(); + + private static native void nativeConvertAllKmlFiles(); + public interface BookmarksLoadingListener { void onBookmarksLoadingStarted(); void onBookmarksLoadingFinished(); void onBookmarksFileLoaded(boolean success); } + + public interface KmlConversionListener + { + void onFinishKmlConversion(boolean success); + } } diff --git a/map/bookmark_manager.cpp b/map/bookmark_manager.cpp index 21e4775e77..57bdb1a809 100644 --- a/map/bookmark_manager.cpp +++ b/map/bookmark_manager.cpp @@ -264,12 +264,17 @@ void OnMigrationFailure(std::string && failedStage) alohalytics::Stats::Instance().LogEvent("Bookmarks_migration_failure", details); } -void MigrateIfNeeded() +bool IsMigrationCompleted() { bool isCompleted; if (!settings::Get(kSettingsParam, isCompleted)) - isCompleted = false; - if (isCompleted) + return false; + return isCompleted; +} + +void MigrateIfNeeded() +{ + if (IsMigrationCompleted()) return; GetPlatform().RunTask(Platform::Thread::File, []() @@ -1561,6 +1566,91 @@ BookmarkManager::SharingResult BookmarkManager::GetFileForSharing(df::MarkGroupI return SharingResult(tmpFilePath); } +size_t BookmarkManager::GetKmlFilesCountForConversion() const +{ + // The conversion available only after successful migration. + if (!migration::IsMigrationCompleted()) + return 0; + + Platform::FilesList files; + Platform::GetFilesByExt(GetPlatform().SettingsDir(), + BOOKMARKS_FILE_EXTENSION, files); + return files.size(); +} + +void BookmarkManager::ConvertAllKmlFiles(ConversionHandler && handler) const +{ + // The conversion available only after successful migration. + if (!migration::IsMigrationCompleted()) + return; + + GetPlatform().RunTask(Platform::Thread::File, [handler = std::move(handler)]() + { + auto const oldDir = GetPlatform().SettingsDir(); + Platform::FilesList files; + Platform::GetFilesByExt(oldDir, BOOKMARKS_FILE_EXTENSION, files); + for (auto & f : files) + f = my::JoinFoldersToPath(oldDir, f); + + auto const newDir = GetBookmarksDirectory(); + if (!GetPlatform().IsFileExistsByFullPath(newDir) && !GetPlatform().MkDirChecked(newDir)) + { + handler(false /* success */); + return; + } + + std::vector> fileData; + fileData.reserve(files.size()); + for (auto const & f : files) + { + std::string fileName = f; + my::GetNameFromFullPath(fileName); + my::GetNameWithoutExt(fileName); + auto kmbPath = my::JoinPath(newDir, fileName + kBookmarksExt); + size_t counter = 1; + while (Platform::IsFileExistsByFullPath(kmbPath)) + kmbPath = my::JoinPath(newDir, fileName + strings::to_string(counter++) + kBookmarksExt); + + kml::FileData kmlData; + try + { + kml::DeserializerKml des(kmlData); + FileReader reader(f); + des.Deserialize(reader); + } + catch (FileReader::Exception const & exc) + { + LOG(LDEBUG, ("KML text deserialization failure: ", exc.what(), "file", f)); + handler(false /* success */); + return; + } + + try + { + kml::binary::SerializerKml ser(kmlData); + FileWriter writer(kmbPath); + ser.Serialize(writer); + } + catch (FileWriter::Exception const & exc) + { + my::DeleteFileX(kmbPath); + LOG(LDEBUG, ("KML binary serialization failure: ", exc.what(), "file", f)); + handler(false /* success */); + return; + } + + fileData.emplace_back(kmbPath, std::move(kmlData)); + } + + for (auto const & f : files) + my::DeleteFileX(f); + + //TODO(@darina): add fileData to m_categories. + + handler(true /* success */); + }); +} + df::GroupIDSet BookmarkManager::MarksChangesTracker::GetAllGroupIds() const { auto const & groupIds = m_bmManager.GetBmGroupsIdList(); diff --git a/map/bookmark_manager.hpp b/map/bookmark_manager.hpp index 4dd533a9b7..ae8b1bb0f7 100644 --- a/map/bookmark_manager.hpp +++ b/map/bookmark_manager.hpp @@ -9,6 +9,8 @@ #include "geometry/any_rect2d.hpp" #include "geometry/screenbase.hpp" +#include "platform/safe_callback.hpp" + #include "base/macros.hpp" #include "base/strings_bundle.hpp" #include "base/thread_checker.hpp" @@ -231,6 +233,13 @@ public: bool AreAllCategoriesInvisible() const; void SetAllCategoriesVisibility(bool visible); + // Return number of files for the conversion to the binary format. + size_t GetKmlFilesCountForConversion() const; + + // Convert all found kml files to the binary format. + using ConversionHandler = platform::SafeCallback; + void ConvertAllKmlFiles(ConversionHandler && handler) const; + /// These functions are public for unit tests only. You shouldn't call them from client code. void SaveToKML(df::MarkGroupID groupId, std::ostream & s); void CreateCategories(KMLDataCollection && dataCollection, bool autoSave = true);