diff options
author | Wilhelm Berg <wb@BergWerk-GIS.at> | 2018-08-22 16:56:32 +0200 |
---|---|---|
committer | Wilhelm Berg <wb@BergWerk-GIS.at> | 2018-08-22 16:56:32 +0200 |
commit | 797f622a26b34db5a30e7f1728d87c6700a2ec1e (patch) | |
tree | 75ea93979db2baf3eb2234c6fbb3d1a9c5b70329 /platform/android/src | |
parent | 86fc3f525e42d042f239876b93525ff411ad7182 (diff) | |
parent | 520df7f02049cdbbb9e68041e755d6c3a8d5b21f (diff) | |
download | qtlocation-mapboxgl-797f622a26b34db5a30e7f1728d87c6700a2ec1e.tar.gz |
Merge branch 'master' of github.com:mapbox/mapbox-gl-native into bwg-vs2017
Diffstat (limited to 'platform/android/src')
41 files changed, 769 insertions, 1007 deletions
diff --git a/platform/android/src/android_renderer_frontend.cpp b/platform/android/src/android_renderer_frontend.cpp index 2a03d9de9e..8b4a25a4d9 100644 --- a/platform/android/src/android_renderer_frontend.cpp +++ b/platform/android/src/android_renderer_frontend.cpp @@ -4,6 +4,7 @@ #include <mbgl/renderer/renderer.hpp> #include <mbgl/renderer/renderer_observer.hpp> #include <mbgl/storage/file_source.hpp> +#include <mbgl/util/async_task.hpp> #include <mbgl/util/thread.hpp> #include <mbgl/util/run_loop.hpp> @@ -56,7 +57,11 @@ private: AndroidRendererFrontend::AndroidRendererFrontend(MapRenderer& mapRenderer_) : mapRenderer(mapRenderer_) - , mapRunLoop(util::RunLoop::Get()) { + , mapRunLoop(util::RunLoop::Get()) + , updateAsyncTask(std::make_unique<util::AsyncTask>([this]() { + mapRenderer.update(std::move(updateParams)); + mapRenderer.requestRender(); + })) { } AndroidRendererFrontend::~AndroidRendererFrontend() = default; @@ -73,8 +78,8 @@ void AndroidRendererFrontend::setObserver(RendererObserver& observer) { } void AndroidRendererFrontend::update(std::shared_ptr<UpdateParameters> params) { - mapRenderer.update(std::move(params)); - mapRenderer.requestRender(); + updateParams = std::move(params); + updateAsyncTask->send(); } void AndroidRendererFrontend::reduceMemoryUse() { diff --git a/platform/android/src/android_renderer_frontend.hpp b/platform/android/src/android_renderer_frontend.hpp index b61904e388..9bd64e4819 100644 --- a/platform/android/src/android_renderer_frontend.hpp +++ b/platform/android/src/android_renderer_frontend.hpp @@ -18,6 +18,12 @@ namespace mbgl { class RenderedQueryOptions; class SourceQueryOptions; +namespace util { + +class AsyncTask; + +} // namespace util + namespace android { class AndroidRendererFrontend : public RendererFrontend { @@ -44,6 +50,8 @@ public: private: MapRenderer& mapRenderer; util::RunLoop* mapRunLoop; + std::unique_ptr<util::AsyncTask> updateAsyncTask; + std::shared_ptr<UpdateParameters> updateParams; }; } // namespace android diff --git a/platform/android/src/conversion/collection.cpp b/platform/android/src/conversion/collection.cpp new file mode 100644 index 0000000000..27b614e8cd --- /dev/null +++ b/platform/android/src/conversion/collection.cpp @@ -0,0 +1,24 @@ +#include "collection.hpp" +#include "constant.hpp" + +namespace mbgl { +namespace android { +namespace conversion { + +std::vector<std::string> toVector(JNIEnv& env, jni::Array<jni::String> array) { + std::size_t len = array.Length(env); + std::vector<std::string> vector; + vector.reserve(len); + + for (std::size_t i = 0; i < len; i++) { + jni::String jstr = array.Get(env, i); + vector.push_back(*convert<std::string, jni::String>(env, jstr)); + jni::DeleteLocalRef(env, jstr); + } + + return vector; +} + +} +} +} diff --git a/platform/android/src/conversion/collection.hpp b/platform/android/src/conversion/collection.hpp index 2b953e73f4..bb8941c984 100644 --- a/platform/android/src/conversion/collection.hpp +++ b/platform/android/src/conversion/collection.hpp @@ -1,9 +1,7 @@ #pragma once #include "conversion.hpp" -#include "constant.hpp" -#include <mbgl/util/optional.hpp> #include <jni/jni.hpp> #include <vector> @@ -12,46 +10,7 @@ namespace mbgl { namespace android { namespace conversion { -/** - * Convert jarray -> ArrayList - */ -template <class T> -inline jni::jobject* toArrayList(JNIEnv& env, jni::jarray<T>& array) { - static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/util/Arrays")).release(); - static jni::jmethodID* asList = &jni::GetStaticMethodID(env, *javaClass, "asList", "([Ljava/lang/Object;)Ljava/util/List;"); - return reinterpret_cast<jni::jobject*>(jni::CallStaticMethod<jni::jobject*>(env, *javaClass, *asList, array)); -} - -// Java -> C++ - - -inline std::vector<std::string> toVector(JNIEnv& env, jni::jarray<jni::jobject>& array) { - std::vector<std::string> vector; - std::size_t len = jni::GetArrayLength(env, array); - vector.reserve(len); - - for (std::size_t i = 0; i < len; i++) { - jni::jstring* jstr = reinterpret_cast<jni::jstring*>(jni::GetObjectArrayElement(env, array, i)); - vector.push_back(*convert<std::string, jni::String>(env, jni::String(jstr))); - jni::DeleteLocalRef(env, jstr); - } - - return vector; -} - -inline std::vector<std::string> toVector(JNIEnv& env, jni::Array<jni::String> array) { - std::size_t len = array.Length(env); - std::vector<std::string> vector; - vector.reserve(len); - - for (std::size_t i = 0; i < len; i++) { - jni::String jstr = array.Get(env, i); - vector.push_back(*convert<std::string, jni::String>(env, jstr)); - jni::DeleteLocalRef(env, jstr); - } - - return vector; -} +std::vector<std::string> toVector(JNIEnv& env, jni::Array<jni::String> array); } } diff --git a/platform/android/src/conversion/color.cpp b/platform/android/src/conversion/color.cpp new file mode 100644 index 0000000000..ce85943e61 --- /dev/null +++ b/platform/android/src/conversion/color.cpp @@ -0,0 +1,17 @@ +#include "color.hpp" + +namespace mbgl { +namespace android { +namespace conversion { + +Result<mbgl::Color> Converter<mbgl::Color, int>::operator()(jni::JNIEnv&, const int& color) const { + float r = (color >> 16) & 0xFF; + float g = (color >> 8) & 0xFF; + float b = (color) & 0xFF; + float a = (color >> 24) & 0xFF; + return { mbgl::Color( r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f ) }; +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/platform/android/src/conversion/color.hpp b/platform/android/src/conversion/color.hpp index 40aa68d4a9..2b4144b933 100644 --- a/platform/android/src/conversion/color.hpp +++ b/platform/android/src/conversion/color.hpp @@ -10,13 +10,7 @@ namespace conversion { template <> struct Converter<mbgl::Color, int> { - Result<mbgl::Color> operator()(jni::JNIEnv&, const int& color) const { - float r = (color >> 16) & 0xFF; - float g = (color >> 8) & 0xFF; - float b = (color) & 0xFF; - float a = (color >> 24) & 0xFF; - return { mbgl::Color( r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f ) }; - } + Result<mbgl::Color> operator()(jni::JNIEnv&, const int& color) const; }; } // namespace conversion diff --git a/platform/android/src/conversion/constant.cpp b/platform/android/src/conversion/constant.cpp new file mode 100644 index 0000000000..16e8b32943 --- /dev/null +++ b/platform/android/src/conversion/constant.cpp @@ -0,0 +1,70 @@ +#include "constant.hpp" + +#include <sstream> + +namespace mbgl { +namespace android { +namespace conversion { + +Result<jni::jobject*> Converter<jni::jobject*, bool>::operator()(jni::JNIEnv& env, const bool& value) const { + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/Boolean")).release(); + static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "(Z)V"); + return {&jni::NewObject(env, *javaClass, *constructor, (jboolean) value)}; +} + +Result<jni::jobject*> Converter<jni::jobject*, float>::operator()(jni::JNIEnv& env, const float& value) const { + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/Float")).release(); + static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "(F)V"); + return {&jni::NewObject(env, *javaClass, *constructor, (jfloat) value)}; +} + +Result<jni::jobject*> Converter<jni::jobject*, double>::operator()(jni::JNIEnv& env, const double& value) const { + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/Double")).release(); + static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "(D)V"); + return {&jni::NewObject(env, *javaClass, *constructor, (jfloat) value)}; +} + +Result<jni::jobject*> Converter<jni::jobject*, std::string>::operator()(jni::JNIEnv& env, const std::string& value) const { + return {jni::Make<jni::String>(env, value).Get()}; +} + +Result<jni::jobject*> Converter<jni::jobject*, Color>::operator()(jni::JNIEnv& env, const Color& value) const { + std::stringstream sstream; + sstream << "rgba(" << value.r << ", " << value.g << ", " << value.b << ", " << value.a << ")"; + std::string result = sstream.str(); + return convert<jni::jobject*, std::string>(env, result); +} + +Result<jni::jobject*> Converter<jni::jobject*, std::vector<std::string>>::operator()(jni::JNIEnv& env, const std::vector<std::string>& value) const { + static jni::jclass* stringCass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/String")).release(); + jni::jarray<jni::jobject>& jarray = jni::NewObjectArray(env, value.size(), *stringCass); + + for(size_t i = 0; i < value.size(); i = i + 1) { + Result<jni::jobject*> converted = convert<jni::jobject*, std::string>(env, value.at(i)); + jni::SetObjectArrayElement(env, jarray, i, *converted); + } + + return &jarray; +} + +Result<jni::jobject*> Converter<jni::jobject*, std::vector<float>>::operator()(jni::JNIEnv& env, const std::vector<float>& value) const { + static jni::jclass* floatClass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/Float")).release(); + jni::jarray<jni::jobject>& jarray = jni::NewObjectArray(env, value.size(), *floatClass); + + for(size_t i = 0; i < value.size(); i = i + 1) { + Result<jni::jobject*> converted = convert<jni::jobject*, float>(env, value.at(i)); + jni::SetObjectArrayElement(env, jarray, i, *converted); + } + + return &jarray; +} + +// Java -> C++ + +Result<std::string> Converter<std::string, jni::String>::operator()(jni::JNIEnv& env, const jni::String& value) const { + return { jni::Make<std::string>(env, value) }; +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/platform/android/src/conversion/constant.hpp b/platform/android/src/conversion/constant.hpp index f1c72eb5dd..0e665cf56a 100644 --- a/platform/android/src/conversion/constant.hpp +++ b/platform/android/src/conversion/constant.hpp @@ -2,14 +2,14 @@ #include "conversion.hpp" -#include <mbgl/util/optional.hpp> #include <mbgl/util/color.hpp> +#include <mbgl/util/enum.hpp> + #include <jni/jni.hpp> #include <string> #include <array> #include <vector> -#include <sstream> namespace mbgl { namespace android { @@ -17,51 +17,17 @@ namespace conversion { template <> struct Converter<jni::jobject*, bool> { - Result<jni::jobject*> operator()(jni::JNIEnv& env, const bool& value) const { - static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/Boolean")).release(); - static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "(Z)V"); - return {&jni::NewObject(env, *javaClass, *constructor, (jboolean) value)}; - } -}; - -template <> -struct Converter<jni::jboolean, bool> { - Result<jni::jboolean> operator()(jni::JNIEnv&, const bool& value) const { - return {(jni::jboolean) value}; - } + Result<jni::jobject*> operator()(jni::JNIEnv& env, const bool& value) const; }; template <> struct Converter<jni::jobject*, float> { - Result<jni::jobject*> operator()(jni::JNIEnv& env, const float& value) const { - static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/Float")).release(); - static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "(F)V"); - return {&jni::NewObject(env, *javaClass, *constructor, (jfloat) value)}; - } -}; - -template <> -struct Converter<jni::jfloat, float> { - Result<jni::jfloat> operator()(jni::JNIEnv&, const float& value) const { - return {(jni::jfloat) value}; - } + Result<jni::jobject*> operator()(jni::JNIEnv& env, const float& value) const; }; - template <> struct Converter<jni::jobject*, double> { - Result<jni::jobject*> operator()(jni::JNIEnv& env, const double& value) const { - static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/Double")).release(); - static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "(D)V"); - return {&jni::NewObject(env, *javaClass, *constructor, (jfloat) value)}; - } -}; - -template <> -struct Converter<jni::jdouble, float> { - Result<jni::jdouble> operator()(jni::JNIEnv&, const double& value) const { - return {(jni::jdouble) value}; - } + Result<jni::jobject*> operator()(jni::JNIEnv& env, const double& value) const; }; /** @@ -81,26 +47,12 @@ struct Converter<jni::jobject*, T, typename std::enable_if<std::is_integral<T>:: template <> struct Converter<jni::jobject*, std::string> { - Result<jni::jobject*> operator()(jni::JNIEnv& env, const std::string& value) const { - return {jni::Make<jni::String>(env, value).Get()}; - } -}; - -template <> -struct Converter<jni::jstring*, std::string> { - Result<jni::jstring*> operator()(jni::JNIEnv& env, const std::string& value) const { - return {jni::Make<jni::String>(env, value).Get()}; - } + Result<jni::jobject*> operator()(jni::JNIEnv& env, const std::string& value) const; }; template <> struct Converter<jni::jobject*, Color> { - Result<jni::jobject*> operator()(jni::JNIEnv& env, const Color& value) const { - std::stringstream sstream; - sstream << "rgba(" << value.r << ", " << value.g << ", " << value.b << ", " << value.a << ")"; - std::string result = sstream.str(); - return convert<jni::jobject*, std::string>(env, result); - } + Result<jni::jobject*> operator()(jni::JNIEnv& env, const Color& value) const; }; template <std::size_t N> @@ -116,31 +68,18 @@ struct Converter<jni::jobject*, std::array<float, N>> { template <> struct Converter<jni::jobject*, std::vector<std::string>> { - Result<jni::jobject*> operator()(jni::JNIEnv& env, const std::vector<std::string>& value) const { - static jni::jclass* stringCass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/String")).release(); - jni::jarray<jni::jobject>& jarray = jni::NewObjectArray(env, value.size(), *stringCass); - - for(size_t i = 0; i < value.size(); i = i + 1) { - Result<jni::jobject*> converted = convert<jni::jobject*, std::string>(env, value.at(i)); - jni::SetObjectArrayElement(env, jarray, i, *converted); - } - - return &jarray; - } + Result<jni::jobject*> operator()(jni::JNIEnv& env, const std::vector<std::string>& value) const; }; template <> struct Converter<jni::jobject*, std::vector<float>> { - Result<jni::jobject*> operator()(jni::JNIEnv& env, const std::vector<float>& value) const { - static jni::jclass* floatClass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/Float")).release(); - jni::jarray<jni::jobject>& jarray = jni::NewObjectArray(env, value.size(), *floatClass); - - for(size_t i = 0; i < value.size(); i = i + 1) { - Result<jni::jobject*> converted = convert<jni::jobject*, float>(env, value.at(i)); - jni::SetObjectArrayElement(env, jarray, i, *converted); - } + Result<jni::jobject*> operator()(jni::JNIEnv& env, const std::vector<float>& value) const; +}; - return &jarray; +template <class T> +struct Converter<jni::jobject*, T, typename std::enable_if_t<std::is_enum<T>::value>> { + Result<jni::jobject*> operator()(jni::JNIEnv& env, const T& value) const { + return convert<jni::jobject*, std::string>(env, Enum<T>::toString(value)); } }; @@ -148,9 +87,7 @@ struct Converter<jni::jobject*, std::vector<float>> { template <> struct Converter<std::string, jni::String> { - Result<std::string> operator()(jni::JNIEnv& env, const jni::String& value) const { - return { jni::Make<std::string>(env, value) }; - } + Result<std::string> operator()(jni::JNIEnv& env, const jni::String& value) const; }; } // namespace conversion diff --git a/platform/android/src/geojson/conversion/feature.cpp b/platform/android/src/geojson/conversion/feature.cpp new file mode 100644 index 0000000000..3cb6d37b17 --- /dev/null +++ b/platform/android/src/geojson/conversion/feature.cpp @@ -0,0 +1,191 @@ +#include "feature.hpp" + +#include "../../conversion/constant.hpp" +#include "../../conversion/conversion.hpp" +#include "../../jni/local_object.hpp" + +namespace mbgl { +namespace android { +namespace conversion { + +/** + * Turn feature identifier into std::string + */ +class FeatureIdVisitor { +public: + + template<class T> + std::string operator()(const T& i) const { + return std::to_string(i); + } + + std::string operator()(const std::string& i) const { + return i; + } + + std::string operator()(const std::nullptr_t&) const { + return ""; + } + +}; + +/** + * Turn properties into Java GSON JsonObject's + */ +class PropertyValueEvaluator { +public: + jni::JNIEnv& env; + + /** + * null + */ + jni::jobject* operator()(const mapbox::geometry::null_value_t &) const { + return (jni::jobject*) nullptr; + } + + /** + * Boolean primitive + */ + jni::jobject* operator()(const bool& value) const { + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonPrimitive")).release(); + static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "(Ljava/lang/Boolean;)V"); + + // Create JsonPrimitive + jni::LocalObject<jni::jobject> converted = jni::NewLocalObject(env, *convert<jni::jobject*, bool>(env, value)); + jni::jobject* object = &jni::NewObject(env, *javaClass, *constructor, *converted); + + return object; + } + + /** + * String primitive + */ + jni::jobject* operator()(const std::string& value) const { + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonPrimitive")).release(); + static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "(Ljava/lang/String;)V"); + + // Create JsonPrimitive + jni::LocalObject<jni::jobject> converted = jni::NewLocalObject(env, *convert<jni::jobject*, std::string>(env, value)); + jni::jobject* object = &jni::NewObject(env, *javaClass, *constructor, converted.get()); + + return object; + } + + /** + * Number primitives + */ + template <class Number> + jni::jobject* operator()(const Number& value) const { + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonPrimitive")).release(); + static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "(Ljava/lang/Number;)V"); + + // Create JsonPrimitive + jni::LocalObject<jni::jobject> converted = jni::NewLocalObject(env, *convert<jni::jobject*, Number>(env, value)); + jni::jobject* object = &jni::NewObject(env, *javaClass, *constructor, converted.get()); + + return object; + } + + + /** + * Json Array + */ + jni::jobject* operator()(const std::vector<mbgl::Value> &values) const { + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonArray")).release(); + static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "()V");; + static jni::jmethodID* add = &jni::GetMethodID(env, *javaClass, "add", "(Lcom/google/gson/JsonElement;)V"); + + // Create json array + jni::jobject* jarray = &jni::NewObject(env, *javaClass, *constructor); + + // Add values + for (const auto &v : values) { + jni::LocalObject<jni::jobject> converted = jni::NewLocalObject(env, mbgl::Value::visit(v, *this)); + jni::CallMethod<void>(env, jarray, *add, converted.get()); + } + + return jarray; + } + + /** + * Json Object + */ + jni::jobject* operator()(const std::unordered_map<std::string, mbgl::Value> &value) const { + // TODO: clean up duplication here + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonObject")).release(); + static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "()V");; + static jni::jmethodID* add = &jni::GetMethodID(env, *javaClass, "add", "(Ljava/lang/String;Lcom/google/gson/JsonElement;)V"); + + // Create json object + jni::jobject* jsonObject = &jni::NewObject(env, *javaClass, *constructor); + + // Add items + for (auto &item : value) { + jni::LocalObject<jni::jobject> converted = jni::NewLocalObject(env, mbgl::Value::visit(item.second, *this)); + jni::LocalObject<jni::jobject> key = jni::NewLocalObject(env, *convert<jni::jobject*, std::string>(env, item.first)); + jni::CallMethod<void>(env, jsonObject, *add, key.get(), converted.get()); + } + + return jsonObject; + } +}; + +Result<jni::jobject*> Converter<jni::jobject*, std::unordered_map<std::string, mbgl::Value>>::operator()(jni::JNIEnv& env, const std::unordered_map<std::string, mbgl::Value>& value) const { + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonObject")).release(); + static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "()V");; + static jni::jmethodID* add = &jni::GetMethodID(env, *javaClass, "add", "(Ljava/lang/String;Lcom/google/gson/JsonElement;)V"); + + // Create json object + jni::jobject* jsonObject = &jni::NewObject(env, *javaClass, *constructor); + + // Add items + PropertyValueEvaluator evaluator {env}; + for (auto &item : value) { + jni::LocalObject<jni::jobject> converted = jni::NewLocalObject(env, mbgl::Value::visit(item.second, evaluator)); + jni::LocalObject<jni::jobject> key = jni::NewLocalObject(env, *convert<jni::jobject*, std::string>(env, item.first)); + jni::CallMethod<void>(env, jsonObject, *add, key.get(), converted.get()); + } + + return {jsonObject}; +} + +Result<jni::Object<android::geojson::Feature>> Converter<jni::Object<android::geojson::Feature>, mbgl::Feature>::operator()(jni::JNIEnv& env, const mbgl::Feature& value) const { + + // Convert Id + FeatureIdVisitor idEvaluator; + std::string id = (value.id) ? mapbox::geometry::identifier::visit(value.id.value(), idEvaluator) : ""; + auto jid = jni::Make<jni::String>(env, id); + + // Convert properties + auto properties = jni::Object<gson::JsonObject>(*convert<jni::jobject*>(env, value.properties)); + + // Convert geometry + auto geometry = android::geojson::Geometry::New(env, value.geometry); + + // Create feature + auto feature = android::geojson::Feature::fromGeometry(env, geometry, properties, jid); + + //Cleanup + jni::DeleteLocalRef(env, jid); + jni::DeleteLocalRef(env, geometry); + jni::DeleteLocalRef(env, properties); + + return feature; +} + +Result<jni::Array<jni::Object<android::geojson::Feature>>> Converter<jni::Array<jni::Object<android::geojson::Feature>>, std::vector<mbgl::Feature>>::operator()(jni::JNIEnv& env, const std::vector<mbgl::Feature>& value) const { + using namespace mbgl::android::geojson; + auto features = jni::Array<jni::Object<Feature>>::New(env, value.size(), Feature::javaClass); + + for(size_t i = 0; i < value.size(); i = i + 1) { + auto converted = *convert<jni::Object<android::geojson::Feature>, mbgl::Feature>(env, value.at(i)); + features.Set(env, i, converted); + jni::DeleteLocalRef(env, converted); + } + + return {features}; +} + +} // namespace conversion +} // namespace android +} // namespace mbgl diff --git a/platform/android/src/geojson/conversion/feature.hpp b/platform/android/src/geojson/conversion/feature.hpp index 8fc62a2789..031449cd23 100644 --- a/platform/android/src/geojson/conversion/feature.hpp +++ b/platform/android/src/geojson/conversion/feature.hpp @@ -1,215 +1,31 @@ #pragma once -#include "../../conversion/constant.hpp" #include "../../conversion/conversion.hpp" -#include "geometry.hpp" -#include "../../gson/json_object.hpp" +#include "../feature.hpp" #include <mbgl/util/feature.hpp> -#include <mapbox/variant.hpp> -#include <mapbox/geometry.hpp> - #include <jni/jni.hpp> -#include "../../jni/local_object.hpp" -#include "../feature.hpp" -#include <string> -#include <array> #include <vector> -#include <sstream> - -#include <mbgl/util/logging.hpp> +#include <unordered_map> namespace mbgl { namespace android { namespace conversion { -/** - * Turn feature identifier into std::string - */ -class FeatureIdVisitor { -public: - - template<class T> - std::string operator()(const T& i) const { - return std::to_string(i); - } - - std::string operator()(const std::string& i) const { - return i; - } - - std::string operator()(const std::nullptr_t&) const { - return ""; - } - -}; - -/** - * Turn properties into Java GSON JsonObject's - */ -class PropertyValueEvaluator { -public: - jni::JNIEnv& env; - - /** - * null - */ - jni::jobject* operator()(const mapbox::geometry::null_value_t &) const { - return (jni::jobject*) nullptr; - } - - /** - * Boolean primitive - */ - jni::jobject* operator()(const bool& value) const { - static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonPrimitive")).release(); - static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "(Ljava/lang/Boolean;)V"); - - // Create JsonPrimitive - jni::LocalObject<jni::jobject> converted = jni::NewLocalObject(env, *convert<jni::jobject*, bool>(env, value)); - jni::jobject* object = &jni::NewObject(env, *javaClass, *constructor, *converted); - - return object; - } - - /** - * String primitive - */ - jni::jobject* operator()(const std::string& value) const { - static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonPrimitive")).release(); - static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "(Ljava/lang/String;)V"); - - // Create JsonPrimitive - jni::LocalObject<jni::jobject> converted = jni::NewLocalObject(env, *convert<jni::jobject*, std::string>(env, value)); - jni::jobject* object = &jni::NewObject(env, *javaClass, *constructor, converted.get()); - - return object; - } - - /** - * Number primitives - */ - template <class Number> - jni::jobject* operator()(const Number& value) const { - static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonPrimitive")).release(); - static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "(Ljava/lang/Number;)V"); - - // Create JsonPrimitive - jni::LocalObject<jni::jobject> converted = jni::NewLocalObject(env, *convert<jni::jobject*, Number>(env, value)); - jni::jobject* object = &jni::NewObject(env, *javaClass, *constructor, converted.get()); - - return object; - } - - - /** - * Json Array - */ - jni::jobject* operator()(const std::vector<mbgl::Value> &values) const { - static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonArray")).release(); - static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "()V");; - static jni::jmethodID* add = &jni::GetMethodID(env, *javaClass, "add", "(Lcom/google/gson/JsonElement;)V"); - - // Create json array - jni::jobject* jarray = &jni::NewObject(env, *javaClass, *constructor); - - // Add values - for (const auto &v : values) { - jni::LocalObject<jni::jobject> converted = jni::NewLocalObject(env, mbgl::Value::visit(v, *this)); - jni::CallMethod<void>(env, jarray, *add, converted.get()); - } - - return jarray; - } - - /** - * Json Object - */ - jni::jobject* operator()(const std::unordered_map<std::string, mbgl::Value> &value) const { - // TODO: clean up duplication here - static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonObject")).release(); - static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "()V");; - static jni::jmethodID* add = &jni::GetMethodID(env, *javaClass, "add", "(Ljava/lang/String;Lcom/google/gson/JsonElement;)V"); - - // Create json object - jni::jobject* jsonObject = &jni::NewObject(env, *javaClass, *constructor); - - // Add items - for (auto &item : value) { - jni::LocalObject<jni::jobject> converted = jni::NewLocalObject(env, mbgl::Value::visit(item.second, *this)); - jni::LocalObject<jni::jobject> key = jni::NewLocalObject(env, *convert<jni::jobject*, std::string>(env, item.first)); - jni::CallMethod<void>(env, jsonObject, *add, key.get(), converted.get()); - } - - return jsonObject; - } -}; - template <> struct Converter<jni::jobject*, std::unordered_map<std::string, mbgl::Value>> { - Result<jni::jobject*> operator()(jni::JNIEnv& env, const std::unordered_map<std::string, mbgl::Value>& value) const { - static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonObject")).release(); - static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "()V");; - static jni::jmethodID* add = &jni::GetMethodID(env, *javaClass, "add", "(Ljava/lang/String;Lcom/google/gson/JsonElement;)V"); - - // Create json object - jni::jobject* jsonObject = &jni::NewObject(env, *javaClass, *constructor); - - // Add items - PropertyValueEvaluator evaluator {env}; - for (auto &item : value) { - jni::LocalObject<jni::jobject> converted = jni::NewLocalObject(env, mbgl::Value::visit(item.second, evaluator)); - jni::LocalObject<jni::jobject> key = jni::NewLocalObject(env, *convert<jni::jobject*, std::string>(env, item.first)); - jni::CallMethod<void>(env, jsonObject, *add, key.get(), converted.get()); - } - - return {jsonObject}; - } + Result<jni::jobject*> operator()(jni::JNIEnv& env, const std::unordered_map<std::string, mbgl::Value>& value) const; }; - template <> struct Converter<jni::Object<android::geojson::Feature>, mbgl::Feature> { - Result<jni::Object<android::geojson::Feature>> operator()(jni::JNIEnv& env, const mbgl::Feature& value) const { - - // Convert Id - FeatureIdVisitor idEvaluator; - std::string id = (value.id) ? mapbox::geometry::identifier::visit(value.id.value(), idEvaluator) : ""; - auto jid = jni::Make<jni::String>(env, id); - - // Convert properties - auto properties = jni::Object<gson::JsonObject>(*convert<jni::jobject*>(env, value.properties)); - - // Convert geometry - auto geometry = *convert<jni::Object<android::geojson::Geometry>>(env, value.geometry); - - // Create feature - auto feature = android::geojson::Feature::fromGeometry(env, geometry, properties, jid); - - //Cleanup - jni::DeleteLocalRef(env, jid); - jni::DeleteLocalRef(env, geometry); - jni::DeleteLocalRef(env, properties); - - return feature; - } + Result<jni::Object<android::geojson::Feature>> operator()(jni::JNIEnv& env, const mbgl::Feature& value) const; }; template <> struct Converter<jni::Array<jni::Object<android::geojson::Feature>>, std::vector<mbgl::Feature>> { - Result<jni::Array<jni::Object<android::geojson::Feature>>> operator()(jni::JNIEnv& env, const std::vector<mbgl::Feature>& value) const { - using namespace mbgl::android::geojson; - auto features = jni::Array<jni::Object<Feature>>::New(env, value.size(), Feature::javaClass); - - for(size_t i = 0; i < value.size(); i = i + 1) { - auto converted = *convert<jni::Object<android::geojson::Feature>, mbgl::Feature>(env, value.at(i)); - features.Set(env, i, converted); - jni::DeleteLocalRef(env, converted); - } - - return {features}; - } + Result<jni::Array<jni::Object<android::geojson::Feature>>> operator()(jni::JNIEnv& env, const std::vector<mbgl::Feature>& value) const; }; } // namespace conversion diff --git a/platform/android/src/geojson/conversion/geometry.hpp b/platform/android/src/geojson/conversion/geometry.hpp deleted file mode 100644 index 242a68df02..0000000000 --- a/platform/android/src/geojson/conversion/geometry.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include <mapbox/geometry.hpp> -#include "../geometry.hpp" -#include <jni/jni.hpp> - -namespace mbgl { -namespace android { -namespace conversion { - -/** - * mapbox::geometry::geometry<T> -> Java GeoJson Geometry - */ -template <class T> -struct Converter<jni::Object<android::geojson::Geometry>, mapbox::geometry::geometry<T>> { - Result<jni::Object<android::geojson::Geometry>> operator()(jni::JNIEnv& env, const mapbox::geometry::geometry<T>& value) const { - return { android::geojson::Geometry::New(env, value) }; - } -}; - - -} // conversion -} // android -} // mbgl diff --git a/platform/android/src/jni.cpp b/platform/android/src/jni.cpp index beb2c14eb3..18b966e261 100755 --- a/platform/android/src/jni.cpp +++ b/platform/android/src/jni.cpp @@ -180,6 +180,7 @@ void registerNatives(JavaVM *vm) { OfflineRegion::registerNative(env); OfflineRegionDefinition::registerNative(env); OfflineTilePyramidRegionDefinition::registerNative(env); + OfflineGeometryRegionDefinition::registerNative(env); OfflineRegionError::registerNative(env); OfflineRegionStatus::registerNative(env); diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp index 44b04fc538..8c76332b39 100755 --- a/platform/android/src/native_map_view.cpp +++ b/platform/android/src/native_map_view.cpp @@ -30,8 +30,8 @@ // Java -> C++ conversion #include "style/android_conversion.hpp" -#include <mbgl/style/conversion.hpp> #include <mbgl/style/conversion/filter.hpp> +#include <mbgl/style/conversion_impl.hpp> // C++ -> Java conversion #include "conversion/conversion.hpp" @@ -892,7 +892,9 @@ void NativeMapView::removeSource(JNIEnv& env, jni::Object<Source> obj, jlong sou assert(sourcePtr != 0); mbgl::android::Source *source = reinterpret_cast<mbgl::android::Source *>(sourcePtr); - source->removeFromMap(env, obj, *map); + if (source->removeFromMap(env, obj, *map)) { + source->releaseJavaPeer(); + } } void NativeMapView::addImage(JNIEnv& env, jni::String name, jni::Object<Bitmap> bitmap, jni::jfloat scale, jni::jboolean sdf) { diff --git a/platform/android/src/offline/offline_manager.cpp b/platform/android/src/offline/offline_manager.cpp index 4960ae2845..e96ed7e4d2 100644 --- a/platform/android/src/offline/offline_manager.cpp +++ b/platform/android/src/offline/offline_manager.cpp @@ -26,15 +26,18 @@ void OfflineManager::listOfflineRegions(jni::JNIEnv& env_, jni::Object<FileSourc //Keep a shared ptr to a global reference of the callback and file source so they are not GC'd in the meanwhile callback = std::shared_ptr<jni::jobject>(callback_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter()), jFileSource = std::shared_ptr<jni::jobject>(jFileSource_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter()) - ](std::exception_ptr error, mbgl::optional<std::vector<mbgl::OfflineRegion>> regions) mutable { + ](mbgl::expected<mbgl::OfflineRegions, std::exception_ptr> regions) mutable { // Reattach, the callback comes from a different thread android::UniqueEnv env = android::AttachEnv(); - if (error) { - OfflineManager::ListOfflineRegionsCallback::onError(*env, jni::Object<ListOfflineRegionsCallback>(*callback), error); - } else if (regions) { - OfflineManager::ListOfflineRegionsCallback::onList(*env, jni::Object<FileSource>(*jFileSource), jni::Object<ListOfflineRegionsCallback>(*callback), std::move(regions)); + if (regions) { + OfflineManager::ListOfflineRegionsCallback::onList( + *env, jni::Object<FileSource>(*jFileSource), + jni::Object<ListOfflineRegionsCallback>(*callback), std::move(*regions)); + } else { + OfflineManager::ListOfflineRegionsCallback::onError( + *env, jni::Object<ListOfflineRegionsCallback>(*callback), regions.error()); } }); } @@ -45,9 +48,7 @@ void OfflineManager::createOfflineRegion(jni::JNIEnv& env_, jni::Array<jni::jbyte> metadata_, jni::Object<CreateOfflineRegionCallback> callback_) { // Convert - - // XXX hardcoded cast for now as we only support OfflineTilePyramidRegionDefinition - auto definition = OfflineTilePyramidRegionDefinition::getDefinition(env_, jni::Object<OfflineTilePyramidRegionDefinition>(*definition_)); + auto definition = OfflineRegionDefinition::getDefinition(env_, definition_); mbgl::OfflineRegionMetadata metadata; if (metadata_) { @@ -59,19 +60,19 @@ void OfflineManager::createOfflineRegion(jni::JNIEnv& env_, //Keep a shared ptr to a global reference of the callback and file source so they are not GC'd in the meanwhile callback = std::shared_ptr<jni::jobject>(callback_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter()), jFileSource = std::shared_ptr<jni::jobject>(jFileSource_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter()) - ](std::exception_ptr error, mbgl::optional<mbgl::OfflineRegion> region) mutable { + ](mbgl::expected<mbgl::OfflineRegion, std::exception_ptr> region) mutable { // Reattach, the callback comes from a different thread android::UniqueEnv env = android::AttachEnv(); - if (error) { - OfflineManager::CreateOfflineRegionCallback::onError(*env, jni::Object<CreateOfflineRegionCallback>(*callback), error); - } else if (region) { + if (region) { OfflineManager::CreateOfflineRegionCallback::onCreate( *env, jni::Object<FileSource>(*jFileSource), - jni::Object<CreateOfflineRegionCallback>(*callback), std::move(region) + jni::Object<CreateOfflineRegionCallback>(*callback), std::move(*region) ); + } else { + OfflineManager::CreateOfflineRegionCallback::onError(*env, jni::Object<CreateOfflineRegionCallback>(*callback), region.error()); } }); } @@ -149,7 +150,7 @@ void OfflineManager::CreateOfflineRegionCallback::onCreate(jni::JNIEnv& env, jni::Object<FileSource> jFileSource, jni::Object<OfflineManager::CreateOfflineRegionCallback> callback, mbgl::optional<mbgl::OfflineRegion> region) { - //Convert the region to java peer object + // Convert the region to java peer object auto jregion = OfflineRegion::New(env, jFileSource, std::move(*region)); // Trigger callback diff --git a/platform/android/src/offline/offline_region.cpp b/platform/android/src/offline/offline_region.cpp index 27de76fb00..5ed37eda73 100644 --- a/platform/android/src/offline/offline_region.cpp +++ b/platform/android/src/offline/offline_region.cpp @@ -107,14 +107,14 @@ void OfflineRegion::getOfflineRegionStatus(jni::JNIEnv& env_, jni::Object<Offlin fileSource.getOfflineRegionStatus(*region, [ //Ensure the object is not gc'd in the meanwhile callback = std::shared_ptr<jni::jobject>(callback_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter()) - ](std::exception_ptr error, mbgl::optional<mbgl::OfflineRegionStatus> status) mutable { + ](mbgl::expected<mbgl::OfflineRegionStatus, std::exception_ptr> status) mutable { // Reattach, the callback comes from a different thread android::UniqueEnv env = android::AttachEnv(); - if (error) { - OfflineRegionStatusCallback::onError(*env, jni::Object<OfflineRegionStatusCallback>(*callback), error); - } else if (status) { - OfflineRegionStatusCallback::onStatus(*env, jni::Object<OfflineRegionStatusCallback>(*callback), std::move(status)); + if (status) { + OfflineRegionStatusCallback::onStatus(*env, jni::Object<OfflineRegionStatusCallback>(*callback), std::move(*status)); + } else { + OfflineRegionStatusCallback::onError(*env, jni::Object<OfflineRegionStatusCallback>(*callback), status.error()); } }); } @@ -144,14 +144,14 @@ void OfflineRegion::updateOfflineRegionMetadata(jni::JNIEnv& env_, jni::Array<jn fileSource.updateOfflineMetadata(region->getID(), metadata, [ //Ensure the object is not gc'd in the meanwhile callback = std::shared_ptr<jni::jobject>(callback_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter()) - ](std::exception_ptr error, mbgl::optional<mbgl::OfflineRegionMetadata> data) mutable { + ](mbgl::expected<mbgl::OfflineRegionMetadata, std::exception_ptr> data) mutable { // Reattach, the callback comes from a different thread android::UniqueEnv env = android::AttachEnv(); - if (error) { - OfflineRegionUpdateMetadataCallback::onError(*env, jni::Object<OfflineRegionUpdateMetadataCallback>(*callback), error); - } else if (data) { - OfflineRegionUpdateMetadataCallback::onUpdate(*env, jni::Object<OfflineRegionUpdateMetadataCallback>(*callback), std::move(data)); + if (data) { + OfflineRegionUpdateMetadataCallback::onUpdate(*env, jni::Object<OfflineRegionUpdateMetadataCallback>(*callback), std::move(*data)); + } else { + OfflineRegionUpdateMetadataCallback::onError(*env, jni::Object<OfflineRegionUpdateMetadataCallback>(*callback), data.error()); } }); } @@ -159,7 +159,14 @@ void OfflineRegion::updateOfflineRegionMetadata(jni::JNIEnv& env_, jni::Array<jn jni::Object<OfflineRegion> OfflineRegion::New(jni::JNIEnv& env, jni::Object<FileSource> jFileSource, mbgl::OfflineRegion region) { // Definition - auto definition = jni::Object<OfflineRegionDefinition>(*OfflineTilePyramidRegionDefinition::New(env, region.getDefinition())); + auto definition = region.getDefinition().match( + [&](const mbgl::OfflineTilePyramidRegionDefinition def) { + return jni::Object<OfflineRegionDefinition>( + *OfflineTilePyramidRegionDefinition::New(env, def)); + }, [&](const mbgl::OfflineGeometryRegionDefinition def) { + return jni::Object<OfflineRegionDefinition>( + *OfflineGeometryRegionDefinition::New(env, def)); + }); // Metadata auto metadata = OfflineRegion::metadata(env, region.getMetadata()); diff --git a/platform/android/src/offline/offline_region_definition.cpp b/platform/android/src/offline/offline_region_definition.cpp index 66a9bdf99d..a856672902 100644 --- a/platform/android/src/offline/offline_region_definition.cpp +++ b/platform/android/src/offline/offline_region_definition.cpp @@ -1,6 +1,9 @@ #include "offline_region_definition.hpp" #include "../geometry/lat_lng_bounds.hpp" +#include "../geojson/geometry.hpp" + +#include <exception> namespace mbgl { namespace android { @@ -13,9 +16,21 @@ void OfflineRegionDefinition::registerNative(jni::JNIEnv& env) { javaClass = *jni::Class<OfflineRegionDefinition>::Find(env).NewGlobalRef(env).release(); } +mbgl::OfflineRegionDefinition OfflineRegionDefinition::getDefinition(JNIEnv& env, + jni::Object<OfflineRegionDefinition> jDefinition) { + + if (jDefinition.IsInstanceOf(env, OfflineTilePyramidRegionDefinition::javaClass)) { + return OfflineTilePyramidRegionDefinition::getDefinition(env, jni::Object<OfflineTilePyramidRegionDefinition>(*jDefinition)); + } else if (jDefinition.IsInstanceOf(env, OfflineGeometryRegionDefinition::javaClass)) { + return OfflineGeometryRegionDefinition::getDefinition(env, jni::Object<OfflineGeometryRegionDefinition>(*jDefinition)); + } + + throw std::runtime_error("Unknown offline region definition java class"); +} + // OfflineTilePyramidRegionDefinition // -jni::Object<OfflineTilePyramidRegionDefinition> OfflineTilePyramidRegionDefinition::New(jni::JNIEnv& env, mbgl::OfflineTilePyramidRegionDefinition definition) { +jni::Object<OfflineTilePyramidRegionDefinition> OfflineTilePyramidRegionDefinition::New(jni::JNIEnv& env, const mbgl::OfflineTilePyramidRegionDefinition& definition) { //Convert objects auto styleURL = jni::Make<jni::String>(env, definition.styleURL); @@ -65,5 +80,56 @@ void OfflineTilePyramidRegionDefinition::registerNative(jni::JNIEnv& env) { javaClass = *jni::Class<OfflineTilePyramidRegionDefinition>::Find(env).NewGlobalRef(env).release(); } +// OfflineGeometryRegionDefinition // + +jni::Object<OfflineGeometryRegionDefinition> OfflineGeometryRegionDefinition::New(jni::JNIEnv& env, const mbgl::OfflineGeometryRegionDefinition& definition) { + //Convert objects + auto styleURL = jni::Make<jni::String>(env, definition.styleURL); + auto geometry = geojson::Geometry::New(env, definition.geometry); + + static auto constructor = javaClass.GetConstructor<jni::String, jni::Object<geojson::Geometry>, jni::jdouble, jni::jdouble, jni::jfloat>(env); + auto jdefinition = javaClass.New(env, constructor, styleURL, geometry, definition.minZoom, definition.maxZoom, definition.pixelRatio); + + //Delete References + jni::DeleteLocalRef(env, styleURL); + jni::DeleteLocalRef(env, geometry); + + return jdefinition; +} + +mbgl::OfflineGeometryRegionDefinition OfflineGeometryRegionDefinition::getDefinition(jni::JNIEnv& env, jni::Object<OfflineGeometryRegionDefinition> jDefinition) { + // Field references + static auto styleURLF = javaClass.GetField<jni::String>(env, "styleURL"); + static auto geometryF = javaClass.GetField<jni::Object<geojson::Geometry>>(env, "geometry"); + static auto minZoomF = javaClass.GetField<jni::jdouble>(env, "minZoom"); + static auto maxZoomF = javaClass.GetField<jni::jdouble>(env, "maxZoom"); + static auto pixelRatioF = javaClass.GetField<jni::jfloat>(env, "pixelRatio"); + + // Get objects + auto jStyleURL = jDefinition.Get(env, styleURLF); + auto jGeometry = jDefinition.Get(env, geometryF); + + // Create definition + mbgl::OfflineGeometryRegionDefinition definition( + jni::Make<std::string>(env, jStyleURL), + geojson::Geometry::convert(env, jGeometry), + jDefinition.Get(env, minZoomF), + jDefinition.Get(env, maxZoomF), + jDefinition.Get(env, pixelRatioF) + ); + + // Delete references + jni::DeleteLocalRef(env, jStyleURL); + jni::DeleteLocalRef(env, jGeometry); + + return definition; +} + +jni::Class<OfflineGeometryRegionDefinition> OfflineGeometryRegionDefinition::javaClass; + +void OfflineGeometryRegionDefinition::registerNative(jni::JNIEnv& env) { + javaClass = *jni::Class<OfflineGeometryRegionDefinition>::Find(env).NewGlobalRef(env).release(); +} + } // namespace android } // namespace mbgl diff --git a/platform/android/src/offline/offline_region_definition.hpp b/platform/android/src/offline/offline_region_definition.hpp index 2ca82a4d96..a9dfb54634 100644 --- a/platform/android/src/offline/offline_region_definition.hpp +++ b/platform/android/src/offline/offline_region_definition.hpp @@ -14,13 +14,14 @@ public: static void registerNative(jni::JNIEnv&); + static mbgl::OfflineRegionDefinition getDefinition(JNIEnv& env, jni::Object<OfflineRegionDefinition> jDefinition); }; class OfflineTilePyramidRegionDefinition: public OfflineRegionDefinition { public: static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition"; }; - static jni::Object<OfflineTilePyramidRegionDefinition> New(jni::JNIEnv&, mbgl::OfflineTilePyramidRegionDefinition); + static jni::Object<OfflineTilePyramidRegionDefinition> New(jni::JNIEnv&, const mbgl::OfflineTilePyramidRegionDefinition&); static mbgl::OfflineTilePyramidRegionDefinition getDefinition(jni::JNIEnv&, jni::Object<OfflineTilePyramidRegionDefinition>); @@ -30,5 +31,19 @@ public: }; +class OfflineGeometryRegionDefinition: public OfflineRegionDefinition { +public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineGeometryRegionDefinition"; }; + + static jni::Object<OfflineGeometryRegionDefinition> New(jni::JNIEnv&, const mbgl::OfflineGeometryRegionDefinition&); + + static mbgl::OfflineGeometryRegionDefinition getDefinition(jni::JNIEnv&, jni::Object<OfflineGeometryRegionDefinition>); + + static jni::Class<OfflineGeometryRegionDefinition> javaClass; + + static void registerNative(jni::JNIEnv&); + +}; + } // namespace android } // namespace mbgl diff --git a/platform/android/src/style/android_conversion.hpp b/platform/android/src/style/android_conversion.hpp index 510a9f8444..8559720b2f 100644 --- a/platform/android/src/style/android_conversion.hpp +++ b/platform/android/src/style/android_conversion.hpp @@ -5,8 +5,8 @@ #include <mbgl/util/feature.hpp> #include <mbgl/util/logging.hpp> #include <mbgl/util/optional.hpp> -#include <mbgl/style/conversion.hpp> #include <mbgl/style/conversion/geojson.hpp> +#include <mbgl/style/conversion_impl.hpp> #include <jni/jni.hpp> diff --git a/platform/android/src/style/conversion/filter.cpp b/platform/android/src/style/conversion/filter.cpp new file mode 100644 index 0000000000..4eac0cf82b --- /dev/null +++ b/platform/android/src/style/conversion/filter.cpp @@ -0,0 +1,26 @@ +#include "filter.hpp" +#include "../android_conversion.hpp" + +#include <mbgl/style/conversion.hpp> +#include <mbgl/style/conversion/filter.hpp> + +namespace mbgl { +namespace android { +namespace conversion { + +optional<mbgl::style::Filter> toFilter(jni::JNIEnv& env, jni::Array<jni::Object<>> jfilter) { + mbgl::optional<mbgl::style::Filter> filter; + if (jfilter) { + mbgl::style::conversion::Error error; + auto converted = mbgl::style::conversion::convert<mbgl::style::Filter>(Value(env, jfilter), error); + if (!converted) { + mbgl::Log::Error(mbgl::Event::JNI, "Error converting filter: " + error.message); + } + filter = std::move(*converted); + } + return filter; +} + +} // namespace conversion +} // namespace android +} // namespace mbgl
\ No newline at end of file diff --git a/platform/android/src/style/conversion/filter.hpp b/platform/android/src/style/conversion/filter.hpp index c154e88e7c..df482de8f3 100644 --- a/platform/android/src/style/conversion/filter.hpp +++ b/platform/android/src/style/conversion/filter.hpp @@ -1,30 +1,15 @@ #pragma once -#include "../android_conversion.hpp" -#include <mbgl/style/conversion.hpp> -#include <mbgl/style/conversion/filter.hpp> +#include <mbgl/style/filter.hpp> +#include <mbgl/util/optional.hpp> #include <jni/jni.hpp> -#include <tuple> -#include <map> - namespace mbgl { namespace android { namespace conversion { -inline optional<mbgl::style::Filter> toFilter(jni::JNIEnv& env, jni::Array<jni::Object<>> jfilter) { - mbgl::optional<mbgl::style::Filter> filter; - if (jfilter) { - mbgl::style::conversion::Error error; - auto converted = mbgl::style::conversion::convert<mbgl::style::Filter>(Value(env, jfilter), error); - if (!converted) { - mbgl::Log::Error(mbgl::Event::JNI, "Error converting filter: " + error.message); - } - filter = std::move(*converted); - } - return filter; -} +optional<mbgl::style::Filter> toFilter(jni::JNIEnv&, jni::Array<jni::Object<>>); } // namespace conversion } // namespace android diff --git a/platform/android/src/style/conversion/latlngquad.hpp b/platform/android/src/style/conversion/latlngquad.hpp deleted file mode 100644 index 9d1a83e164..0000000000 --- a/platform/android/src/style/conversion/latlngquad.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include <mapbox/geojson.hpp> -#include <mbgl/style/conversion.hpp> -#include <mbgl/style/conversion/geojson.hpp> -#include <jni/jni.hpp> - -namespace mbgl { -namespace style { -namespace conversion { - -template <> -optional<std::array<LatLng, 4>> Converter<std::array<LatLng, 4>>::operator()(const mbgl::android::Value& value, Error& error) const { - if (value.isNull() || !value.isArray()) { - error = { "value cannot be converted to LatLng array" }; - return {}; - } - - return convert<GeoJSON>(value.toString(), error); -} - -} // namespace conversion -} // namespace style -} // namespace mbgl diff --git a/platform/android/src/style/conversion/position.cpp b/platform/android/src/style/conversion/position.cpp new file mode 100644 index 0000000000..9b3925914e --- /dev/null +++ b/platform/android/src/style/conversion/position.cpp @@ -0,0 +1,24 @@ +#include "position.hpp" + +namespace mbgl { +namespace android { +namespace conversion { + +Result<jni::Object<Position>> Converter<jni::Object<Position>, mbgl::style::Position>::operator()(jni::JNIEnv &env, const mbgl::style::Position &value) const { + std::array<float, 3> cartPosition = value.getSpherical(); + return Position::fromPosition(env, cartPosition[0], cartPosition[1], cartPosition[2]); +} + +Result<mbgl::style::Position> Converter<mbgl::style::Position, jni::Object<Position>>::operator()(jni::JNIEnv &env, const jni::Object<Position> &value) const { + float radialCoordinate = Position::getRadialCoordinate(env, value); + float azimuthalAngle = Position::getAzimuthalAngle(env, value); + float polarAngle = Position::getPolarAngle(env, value); + std::array<float, 3> cartPosition {{radialCoordinate, azimuthalAngle, polarAngle}}; + mbgl::style::Position position{}; + position.set(cartPosition); + return position; +} + +} +} +} diff --git a/platform/android/src/style/conversion/position.hpp b/platform/android/src/style/conversion/position.hpp index f32a892c0c..2ef4bf4395 100644 --- a/platform/android/src/style/conversion/position.hpp +++ b/platform/android/src/style/conversion/position.hpp @@ -1,37 +1,25 @@ #pragma once #include "../../conversion/conversion.hpp" +#include "../position.hpp" -#include <jni/jni.hpp> #include <mbgl/style/position.hpp> -#include "../../jni/local_object.hpp" -#include "../position.hpp" +#include <jni/jni.hpp> namespace mbgl { namespace android { namespace conversion { -template<> +template <> struct Converter<jni::Object<Position>, mbgl::style::Position> { - Result<jni::Object<Position>> operator()(jni::JNIEnv &env, const mbgl::style::Position &value) const { - std::array<float, 3> cartPosition = value.getSpherical(); - return Position::fromPosition(env, cartPosition[0], cartPosition[1], cartPosition[2]); - } + Result<jni::Object<Position>> operator()(jni::JNIEnv &env, const mbgl::style::Position &value) const; }; -template<> +template <> struct Converter<mbgl::style::Position, jni::Object<Position>> { - Result<mbgl::style::Position> operator()(jni::JNIEnv &env, const jni::Object<Position> &value) const { - float radialCoordinate = Position::getRadialCoordinate(env, value); - float azimuthalAngle = Position::getAzimuthalAngle(env, value); - float polarAngle = Position::getPolarAngle(env, value); - std::array<float, 3> cartPosition {{radialCoordinate, azimuthalAngle, polarAngle}}; - mbgl::style::Position position{}; - position.set(cartPosition); - return position; - } + Result<mbgl::style::Position> operator()(jni::JNIEnv &env, const jni::Object<Position> &value) const; }; } } -}
\ No newline at end of file +} diff --git a/platform/android/src/style/conversion/property_expression.hpp b/platform/android/src/style/conversion/property_expression.hpp index ae9d4ea41c..08429960cb 100644 --- a/platform/android/src/style/conversion/property_expression.hpp +++ b/platform/android/src/style/conversion/property_expression.hpp @@ -1,16 +1,11 @@ #pragma once -#include <mbgl/style/property_value.hpp> #include "../../conversion/conversion.hpp" -#include "../../conversion/constant.hpp" -#include "types.hpp" -#include "../../java/lang.hpp" - -#include <jni/jni.hpp> #include "../../gson/json_element.hpp" -#include <tuple> -#include <map> +#include <mbgl/style/property_expression.hpp> + +#include <jni/jni.hpp> namespace mbgl { namespace android { @@ -18,11 +13,8 @@ namespace conversion { template <class T> struct Converter<jni::Object<android::gson::JsonElement>, mbgl::style::PropertyExpression<T>> { - Result<jni::Object<android::gson::JsonElement>> operator()(jni::JNIEnv& env, const mbgl::style::PropertyExpression<T>& value) const { - // Convert expressions - mbgl::Value expressionValue = value.getExpression().serialize(); - return gson::JsonElement::New(env, expressionValue); + return gson::JsonElement::New(env, value.getExpression().serialize()); } }; diff --git a/platform/android/src/style/conversion/property_value.hpp b/platform/android/src/style/conversion/property_value.hpp index 256647cddf..8150285c85 100644 --- a/platform/android/src/style/conversion/property_value.hpp +++ b/platform/android/src/style/conversion/property_value.hpp @@ -2,10 +2,10 @@ #include <mbgl/style/color_ramp_property_value.hpp> #include <mbgl/style/property_value.hpp> + #include "../../conversion/conversion.hpp" #include "../../conversion/constant.hpp" #include "property_expression.hpp" -#include "types.hpp" namespace mbgl { namespace android { @@ -17,25 +17,22 @@ namespace conversion { template <typename T> class PropertyValueEvaluator { public: - PropertyValueEvaluator(jni::JNIEnv& _env) : env(_env) {} jni::jobject* operator()(const mbgl::style::Undefined) const { return nullptr; } - jni::jobject* operator()(const T &value) const { - Result<jni::jobject*> result = convert<jni::jobject*>(env, value); - return *result; + jni::jobject* operator()(const T& value) const { + return *convert<jni::jobject*>(env, value); } - jni::jobject* operator()(const mbgl::style::PropertyExpression<T> &value) const { - return *convert<jni::Object<android::gson::JsonElement>, mbgl::style::PropertyExpression<T>>(env, value); + jni::jobject* operator()(const mbgl::style::PropertyExpression<T>& value) const { + return *convert<jni::Object<android::gson::JsonElement>>(env, value); } private: jni::JNIEnv& env; - }; /** @@ -43,7 +40,6 @@ private: */ template <class T> struct Converter<jni::jobject*, mbgl::style::PropertyValue<T>> { - Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::PropertyValue<T>& value) const { PropertyValueEvaluator<T> evaluator(env); return value.evaluate(evaluator); @@ -55,8 +51,7 @@ struct Converter<jni::jobject*, mbgl::style::PropertyValue<T>> { */ template <> struct Converter<jni::jobject*, mbgl::style::ColorRampPropertyValue> { - - Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::ColorRampPropertyValue value) const { + Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::ColorRampPropertyValue& value) const { PropertyValueEvaluator<mbgl::style::ColorRampPropertyValue> evaluator(env); return *convert<jni::jobject*>(env, value.evaluate(evaluator)); } diff --git a/platform/android/src/style/conversion/transition_options.cpp b/platform/android/src/style/conversion/transition_options.cpp new file mode 100644 index 0000000000..313333ad17 --- /dev/null +++ b/platform/android/src/style/conversion/transition_options.cpp @@ -0,0 +1,16 @@ +#include "transition_options.hpp" + +namespace mbgl { +namespace android { +namespace conversion { + +Result<jni::Object<TransitionOptions>> Converter<jni::Object<TransitionOptions>, mbgl::style::TransitionOptions>::operator()(jni::JNIEnv& env, const mbgl::style::TransitionOptions& value) const { + return TransitionOptions::fromTransitionOptions(env, + std::chrono::duration_cast<std::chrono::milliseconds>(value.duration.value_or(mbgl::Duration::zero())).count(), + std::chrono::duration_cast<std::chrono::milliseconds>(value.delay.value_or(mbgl::Duration::zero())).count() + ); +} + +} +} +} diff --git a/platform/android/src/style/conversion/transition_options.hpp b/platform/android/src/style/conversion/transition_options.hpp index ae65a32194..6630456d37 100644 --- a/platform/android/src/style/conversion/transition_options.hpp +++ b/platform/android/src/style/conversion/transition_options.hpp @@ -1,11 +1,11 @@ #pragma once #include "../../conversion/conversion.hpp" +#include "../transition_options.hpp" -#include <jni/jni.hpp> #include <mbgl/style/transition_options.hpp> -#include "../../jni/local_object.hpp" -#include "../transition_options.hpp" + +#include <jni/jni.hpp> namespace mbgl { namespace android { @@ -13,18 +13,9 @@ namespace conversion { template<> struct Converter<jni::Object<TransitionOptions>, mbgl::style::TransitionOptions> { - Result<jni::Object<TransitionOptions>> operator()(jni::JNIEnv &env, const mbgl::style::TransitionOptions &value) const { - - // Convert duration - jlong duration = std::chrono::duration_cast<std::chrono::milliseconds>(value.duration.value_or(mbgl::Duration::zero())).count(); - // Convert delay - jlong delay = std::chrono::duration_cast<std::chrono::milliseconds>(value.delay.value_or(mbgl::Duration::zero())).count(); - - // Create transition options - return TransitionOptions::fromTransitionOptions(env, duration, delay); - } + Result<jni::Object<TransitionOptions>> operator()(jni::JNIEnv&, const mbgl::style::TransitionOptions&) const; }; } } -}
\ No newline at end of file +} diff --git a/platform/android/src/style/conversion/types.hpp b/platform/android/src/style/conversion/types.hpp deleted file mode 100644 index e87782fad0..0000000000 --- a/platform/android/src/style/conversion/types.hpp +++ /dev/null @@ -1,119 +0,0 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. -#pragma once - -#include "types_string_values.hpp" -#include "../../conversion/conversion.hpp" -#include "../../conversion/constant.hpp" - -#include <mbgl/style/types.hpp> -#include <mbgl/util/optional.hpp> -#include <jni/jni.hpp> - -#include <string> - -namespace mbgl { -namespace android { -namespace conversion { - -template <> -struct Converter<jni::jobject*, mbgl::style::VisibilityType> { - Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::VisibilityType& value) const { - return convert<jni::jobject*, std::string>(env, toString(value)); - } -}; - -template <> -struct Converter<jni::jobject*, mbgl::style::LineCapType> { - Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::LineCapType& value) const { - return convert<jni::jobject*, std::string>(env, toString(value)); - } -}; - -template <> -struct Converter<jni::jobject*, mbgl::style::LineJoinType> { - Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::LineJoinType& value) const { - return convert<jni::jobject*, std::string>(env, toString(value)); - } -}; - -template <> -struct Converter<jni::jobject*, mbgl::style::SymbolPlacementType> { - Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::SymbolPlacementType& value) const { - return convert<jni::jobject*, std::string>(env, toString(value)); - } -}; - -template <> -struct Converter<jni::jobject*, mbgl::style::AlignmentType> { - Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::AlignmentType& value) const { - return convert<jni::jobject*, std::string>(env, toString(value)); - } -}; - -template <> -struct Converter<jni::jobject*, mbgl::style::IconTextFitType> { - Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::IconTextFitType& value) const { - return convert<jni::jobject*, std::string>(env, toString(value)); - } -}; - -template <> -struct Converter<jni::jobject*, mbgl::style::SymbolAnchorType> { - Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::SymbolAnchorType& value) const { - return convert<jni::jobject*, std::string>(env, toString(value)); - } -}; - -template <> -struct Converter<jni::jobject*, mbgl::style::TextJustifyType> { - Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::TextJustifyType& value) const { - return convert<jni::jobject*, std::string>(env, toString(value)); - } -}; - -template <> -struct Converter<jni::jobject*, mbgl::style::TextTransformType> { - Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::TextTransformType& value) const { - return convert<jni::jobject*, std::string>(env, toString(value)); - } -}; - -template <> -struct Converter<jni::jobject*, mbgl::style::TranslateAnchorType> { - Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::TranslateAnchorType& value) const { - return convert<jni::jobject*, std::string>(env, toString(value)); - } -}; - -template <> -struct Converter<jni::jobject*, mbgl::style::CirclePitchScaleType> { - Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::CirclePitchScaleType& value) const { - return convert<jni::jobject*, std::string>(env, toString(value)); - } -}; - -template <> -struct Converter<jni::jobject*, mbgl::style::RasterResamplingType> { - Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::RasterResamplingType& value) const { - return convert<jni::jobject*, std::string>(env, toString(value)); - } -}; - -template <> -struct Converter<jni::jobject*, mbgl::style::HillshadeIlluminationAnchorType> { - Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::HillshadeIlluminationAnchorType& value) const { - return convert<jni::jobject*, std::string>(env, toString(value)); - } -}; - -template <> -struct Converter<jni::jobject*, mbgl::style::LightAnchorType> { - Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::LightAnchorType& value) const { - return convert<jni::jobject*, std::string>(env, toString(value)); - } -}; - - -} // namespace conversion -} // namespace android -} // namespace mbgl diff --git a/platform/android/src/style/conversion/types.hpp.ejs b/platform/android/src/style/conversion/types.hpp.ejs deleted file mode 100644 index 3cd4764015..0000000000 --- a/platform/android/src/style/conversion/types.hpp.ejs +++ /dev/null @@ -1,40 +0,0 @@ -<% - const properties = locals.properties; --%> -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. -#pragma once - -#include "types_string_values.hpp" -#include "../../conversion/conversion.hpp" -#include "../../conversion/constant.hpp" - -#include <mbgl/style/types.hpp> -#include <mbgl/util/optional.hpp> -#include <jni/jni.hpp> - -#include <string> - -namespace mbgl { -namespace android { -namespace conversion { - -template <> -struct Converter<jni::jobject*, mbgl::style::VisibilityType> { - Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::VisibilityType& value) const { - return convert<jni::jobject*, std::string>(env, toString(value)); - } -}; - -<% for (const property of properties) { -%> -template <> -struct Converter<jni::jobject*, mbgl::style::<%- propertyNativeType(property) %>> { - Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::<%- propertyNativeType(property) %>& value) const { - return convert<jni::jobject*, std::string>(env, toString(value)); - } -}; - -<% } -%> - -} // namespace conversion -} // namespace android -} // namespace mbgl diff --git a/platform/android/src/style/conversion/types_string_values.hpp b/platform/android/src/style/conversion/types_string_values.hpp deleted file mode 100644 index 9f6696d181..0000000000 --- a/platform/android/src/style/conversion/types_string_values.hpp +++ /dev/null @@ -1,257 +0,0 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. -#pragma once - -#include <mbgl/style/types.hpp> - -#include <string> -#include <stdexcept> - -namespace mbgl { -namespace android { -namespace conversion { - - // visibility - inline std::string toString(mbgl::style::VisibilityType value) { - switch (value) { - case mbgl::style::VisibilityType::Visible: - return "visible"; - break; - case mbgl::style::VisibilityType::None: - return "none"; - break; - default: - throw std::runtime_error("Not implemented"); - } - } - - // line-cap - inline std::string toString(mbgl::style::LineCapType value) { - switch (value) { - case mbgl::style::LineCapType::Butt: - return "butt"; - break; - case mbgl::style::LineCapType::Round: - return "round"; - break; - case mbgl::style::LineCapType::Square: - return "square"; - break; - default: - throw std::runtime_error("Not implemented"); - } - } - - // line-join - inline std::string toString(mbgl::style::LineJoinType value) { - switch (value) { - case mbgl::style::LineJoinType::Bevel: - return "bevel"; - break; - case mbgl::style::LineJoinType::Round: - return "round"; - break; - case mbgl::style::LineJoinType::Miter: - return "miter"; - break; - default: - throw std::runtime_error("Not implemented"); - } - } - - // symbol-placement - inline std::string toString(mbgl::style::SymbolPlacementType value) { - switch (value) { - case mbgl::style::SymbolPlacementType::Point: - return "point"; - break; - case mbgl::style::SymbolPlacementType::Line: - return "line"; - break; - case mbgl::style::SymbolPlacementType::LineCenter: - return "line-center"; - break; - default: - throw std::runtime_error("Not implemented"); - } - } - - // icon-rotation-alignment - inline std::string toString(mbgl::style::AlignmentType value) { - switch (value) { - case mbgl::style::AlignmentType::Map: - return "map"; - break; - case mbgl::style::AlignmentType::Viewport: - return "viewport"; - break; - case mbgl::style::AlignmentType::Auto: - return "auto"; - break; - default: - throw std::runtime_error("Not implemented"); - } - } - - // icon-text-fit - inline std::string toString(mbgl::style::IconTextFitType value) { - switch (value) { - case mbgl::style::IconTextFitType::None: - return "none"; - break; - case mbgl::style::IconTextFitType::Width: - return "width"; - break; - case mbgl::style::IconTextFitType::Height: - return "height"; - break; - case mbgl::style::IconTextFitType::Both: - return "both"; - break; - default: - throw std::runtime_error("Not implemented"); - } - } - - // icon-anchor - inline std::string toString(mbgl::style::SymbolAnchorType value) { - switch (value) { - case mbgl::style::SymbolAnchorType::Center: - return "center"; - break; - case mbgl::style::SymbolAnchorType::Left: - return "left"; - break; - case mbgl::style::SymbolAnchorType::Right: - return "right"; - break; - case mbgl::style::SymbolAnchorType::Top: - return "top"; - break; - case mbgl::style::SymbolAnchorType::Bottom: - return "bottom"; - break; - case mbgl::style::SymbolAnchorType::TopLeft: - return "top-left"; - break; - case mbgl::style::SymbolAnchorType::TopRight: - return "top-right"; - break; - case mbgl::style::SymbolAnchorType::BottomLeft: - return "bottom-left"; - break; - case mbgl::style::SymbolAnchorType::BottomRight: - return "bottom-right"; - break; - default: - throw std::runtime_error("Not implemented"); - } - } - - // text-justify - inline std::string toString(mbgl::style::TextJustifyType value) { - switch (value) { - case mbgl::style::TextJustifyType::Left: - return "left"; - break; - case mbgl::style::TextJustifyType::Center: - return "center"; - break; - case mbgl::style::TextJustifyType::Right: - return "right"; - break; - default: - throw std::runtime_error("Not implemented"); - } - } - - // text-transform - inline std::string toString(mbgl::style::TextTransformType value) { - switch (value) { - case mbgl::style::TextTransformType::None: - return "none"; - break; - case mbgl::style::TextTransformType::Uppercase: - return "uppercase"; - break; - case mbgl::style::TextTransformType::Lowercase: - return "lowercase"; - break; - default: - throw std::runtime_error("Not implemented"); - } - } - - // fill-translate-anchor - inline std::string toString(mbgl::style::TranslateAnchorType value) { - switch (value) { - case mbgl::style::TranslateAnchorType::Map: - return "map"; - break; - case mbgl::style::TranslateAnchorType::Viewport: - return "viewport"; - break; - default: - throw std::runtime_error("Not implemented"); - } - } - - // circle-pitch-scale - inline std::string toString(mbgl::style::CirclePitchScaleType value) { - switch (value) { - case mbgl::style::CirclePitchScaleType::Map: - return "map"; - break; - case mbgl::style::CirclePitchScaleType::Viewport: - return "viewport"; - break; - default: - throw std::runtime_error("Not implemented"); - } - } - - // raster-resampling - inline std::string toString(mbgl::style::RasterResamplingType value) { - switch (value) { - case mbgl::style::RasterResamplingType::Linear: - return "linear"; - break; - case mbgl::style::RasterResamplingType::Nearest: - return "nearest"; - break; - default: - throw std::runtime_error("Not implemented"); - } - } - - // hillshade-illumination-anchor - inline std::string toString(mbgl::style::HillshadeIlluminationAnchorType value) { - switch (value) { - case mbgl::style::HillshadeIlluminationAnchorType::Map: - return "map"; - break; - case mbgl::style::HillshadeIlluminationAnchorType::Viewport: - return "viewport"; - break; - default: - throw std::runtime_error("Not implemented"); - } - } - - // anchor - inline std::string toString(mbgl::style::LightAnchorType value) { - switch (value) { - case mbgl::style::LightAnchorType::Map: - return "map"; - break; - case mbgl::style::LightAnchorType::Viewport: - return "viewport"; - break; - default: - throw std::runtime_error("Not implemented"); - } - } - - -} // namespace conversion -} // namespace android -} // namespace mbgl diff --git a/platform/android/src/style/conversion/types_string_values.hpp.ejs b/platform/android/src/style/conversion/types_string_values.hpp.ejs deleted file mode 100644 index bf52919741..0000000000 --- a/platform/android/src/style/conversion/types_string_values.hpp.ejs +++ /dev/null @@ -1,48 +0,0 @@ -<% - const properties = locals.properties; --%> -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. -#pragma once - -#include <mbgl/style/types.hpp> - -#include <string> -#include <stdexcept> - -namespace mbgl { -namespace android { -namespace conversion { - - // visibility - inline std::string toString(mbgl::style::VisibilityType value) { - switch (value) { - case mbgl::style::VisibilityType::Visible: - return "visible"; - break; - case mbgl::style::VisibilityType::None: - return "none"; - break; - default: - throw std::runtime_error("Not implemented"); - } - } - -<% for (const property of properties) { -%> - // <%- property.name %> - inline std::string toString(mbgl::style::<%- propertyNativeType(property) %> value) { - switch (value) { -<% for (const value in property.values) { -%> - case mbgl::style::<%- propertyNativeType(property) %>::<%- camelize(value) %>: - return "<%- value %>"; - break; -<% } -%> - default: - throw std::runtime_error("Not implemented"); - } - } - -<% } -%> - -} // namespace conversion -} // namespace android -} // namespace mbgl diff --git a/platform/android/src/style/conversion/url_or_tileset.cpp b/platform/android/src/style/conversion/url_or_tileset.cpp new file mode 100644 index 0000000000..2ec5856751 --- /dev/null +++ b/platform/android/src/style/conversion/url_or_tileset.cpp @@ -0,0 +1,30 @@ +#include "url_or_tileset.hpp" +#include "../android_conversion.hpp" + +#include <mbgl/style/conversion.hpp> +#include <mbgl/style/conversion/tileset.hpp> + +namespace mbgl { +namespace android { + +// This conversion is expected not to fail because it's used only in contexts where +// the value was originally a String or TileSet object on the Java side. If it fails +// to convert, it's a bug in our serialization or Java-side static typing. +variant<std::string, Tileset> convertURLOrTileset(mbgl::android::Value&& value) { + using namespace mbgl::style::conversion; + + const Convertible convertible(std::move(value)); + if (isObject(convertible)) { + Error error; + optional<Tileset> tileset = convert<Tileset>(convertible, error); + if (!tileset) { + throw std::logic_error(error.message); + } + return { *tileset }; + } else { + return { *toString(convertible) }; + } +} + +} +} diff --git a/platform/android/src/style/conversion/url_or_tileset.hpp b/platform/android/src/style/conversion/url_or_tileset.hpp index 92c1182a63..f42a9b9a2a 100644 --- a/platform/android/src/style/conversion/url_or_tileset.hpp +++ b/platform/android/src/style/conversion/url_or_tileset.hpp @@ -1,37 +1,16 @@ #pragma once -#include <mbgl/util/optional.hpp> #include <mbgl/util/variant.hpp> - #include <mbgl/util/tileset.hpp> -#include <mbgl/style/conversion.hpp> -#include <mbgl/style/conversion/tileset.hpp> - -#include <jni/jni.hpp> #include <string> +#include "../value.hpp" + namespace mbgl { namespace android { -// This conversion is expected not to fail because it's used only in contexts where -// the value was originally a String or TileSet object on the Java side. If it fails -// to convert, it's a bug in our serialization or Java-side static typing. -inline variant<std::string, Tileset> convertURLOrTileset(mbgl::android::Value&& value) { - using namespace mbgl::style::conversion; - - const Convertible convertible(std::move(value)); - if (isObject(convertible)) { - Error error; - optional<Tileset> tileset = convert<Tileset>(convertible, error); - if (!tileset) { - throw std::logic_error(error.message); - } - return { *tileset }; - } else { - return { *toString(convertible) }; - } -} +variant<std::string, Tileset> convertURLOrTileset(mbgl::android::Value&& value); } } diff --git a/platform/android/src/style/layers/layer.cpp b/platform/android/src/style/layers/layer.cpp index c7a6bcd3a3..6c08893411 100644 --- a/platform/android/src/style/layers/layer.cpp +++ b/platform/android/src/style/layers/layer.cpp @@ -18,10 +18,10 @@ #include <mbgl/util/logging.hpp> // Java -> C++ conversion -#include <mbgl/style/conversion.hpp> #include <mbgl/style/conversion/filter.hpp> #include <mbgl/style/conversion/layer.hpp> #include <mbgl/style/conversion/source.hpp> +#include <mbgl/style/conversion_impl.hpp> // C++ -> Java conversion #include "../conversion/property_value.hpp" @@ -91,7 +91,7 @@ namespace android { void Layer::setLayoutProperty(jni::JNIEnv& env, jni::String jname, jni::Object<> jvalue) { // Convert and set property - optional<mbgl::style::conversion::Error> error = mbgl::style::conversion::setLayoutProperty(layer, jni::Make<std::string>(env, jname), Value(env, jvalue)); + optional<mbgl::style::conversion::Error> error = layer.setLayoutProperty(jni::Make<std::string>(env, jname), Value(env, jvalue)); if (error) { mbgl::Log::Error(mbgl::Event::JNI, "Error setting property: " + jni::Make<std::string>(env, jname) + " " + error->message); return; @@ -100,7 +100,7 @@ namespace android { void Layer::setPaintProperty(jni::JNIEnv& env, jni::String jname, jni::Object<> jvalue) { // Convert and set property - optional<mbgl::style::conversion::Error> error = mbgl::style::conversion::setPaintProperty(layer, jni::Make<std::string>(env, jname), Value(env, jvalue)); + optional<mbgl::style::conversion::Error> error = layer.setPaintProperty(jni::Make<std::string>(env, jname), Value(env, jvalue)); if (error) { mbgl::Log::Error(mbgl::Event::JNI, "Error setting property: " + jni::Make<std::string>(env, jname) + " " + error->message); return; diff --git a/platform/android/src/style/sources/custom_geometry_source.cpp b/platform/android/src/style/sources/custom_geometry_source.cpp index b38405a3b1..9c51f70ab5 100644 --- a/platform/android/src/style/sources/custom_geometry_source.cpp +++ b/platform/android/src/style/sources/custom_geometry_source.cpp @@ -54,7 +54,9 @@ namespace android { : Source(env, coreSource, createJavaPeer(env), frontend) { } - CustomGeometrySource::~CustomGeometrySource() = default; + CustomGeometrySource::~CustomGeometrySource() { + releaseThreads(); + } void CustomGeometrySource::fetchTile (const mbgl::CanonicalTileID& tileID) { android::UniqueEnv _env = android::AttachEnv(); @@ -78,6 +80,28 @@ namespace android { peer.Call(*_env, cancelTile, (int)tileID.z, (int)tileID.x, (int)tileID.y); }; + void CustomGeometrySource::startThreads() { + android::UniqueEnv _env = android::AttachEnv(); + + static auto startThreads = javaClass.GetMethod<void ()>(*_env, "startThreads"); + + assert(javaPeer); + + auto peer = jni::Cast(*_env, *javaPeer, javaClass); + peer.Call(*_env, startThreads); + } + + void CustomGeometrySource::releaseThreads() { + android::UniqueEnv _env = android::AttachEnv(); + + static auto releaseThreads = javaClass.GetMethod<void ()>(*_env, "releaseThreads"); + + assert(javaPeer); + + auto peer = jni::Cast(*_env, *javaPeer, javaClass); + peer.Call(*_env, releaseThreads); + }; + void CustomGeometrySource::setTileData(jni::JNIEnv& env, jni::jint z, jni::jint x, @@ -120,6 +144,19 @@ namespace android { return jni::Object<Source>(CustomGeometrySource::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this)).Get()); } + void CustomGeometrySource::addToMap(JNIEnv& env, jni::Object<Source> obj, mbgl::Map& map, AndroidRendererFrontend& frontend) { + Source::addToMap(env, obj, map, frontend); + startThreads(); + } + + bool CustomGeometrySource::removeFromMap(JNIEnv& env, jni::Object<Source> source, mbgl::Map& map) { + bool successfullyRemoved = Source::removeFromMap(env, source, map); + if (successfullyRemoved) { + releaseThreads(); + } + return successfullyRemoved; + } + void CustomGeometrySource::registerNative(jni::JNIEnv& env) { // Lookup the class CustomGeometrySource::javaClass = *jni::Class<CustomGeometrySource>::Find(env).NewGlobalRef(env).release(); diff --git a/platform/android/src/style/sources/custom_geometry_source.hpp b/platform/android/src/style/sources/custom_geometry_source.hpp index 1dc1c07b4f..c38926a5b9 100644 --- a/platform/android/src/style/sources/custom_geometry_source.hpp +++ b/platform/android/src/style/sources/custom_geometry_source.hpp @@ -28,8 +28,13 @@ public: ~CustomGeometrySource(); + bool removeFromMap(JNIEnv&, jni::Object<Source>, mbgl::Map&) override; + void addToMap(JNIEnv&, jni::Object<Source>, mbgl::Map&, AndroidRendererFrontend&) override; + void fetchTile(const mbgl::CanonicalTileID& tileID); void cancelTile(const mbgl::CanonicalTileID& tileID); + void startThreads(); + void releaseThreads(); void setTileData(jni::JNIEnv& env, jni::jint z, jni::jint x, jni::jint y, jni::Object<geojson::FeatureCollection> jf); void invalidateTile(jni::JNIEnv& env, jni::jint z, jni::jint x, jni::jint y); diff --git a/platform/android/src/style/sources/geojson_source.cpp b/platform/android/src/style/sources/geojson_source.cpp index 6d9ab9e22c..e526231763 100644 --- a/platform/android/src/style/sources/geojson_source.cpp +++ b/platform/android/src/style/sources/geojson_source.cpp @@ -5,9 +5,9 @@ // Java -> C++ conversion #include "../android_conversion.hpp" #include "../conversion/filter.hpp" -#include <mbgl/style/conversion.hpp> #include <mbgl/style/conversion/geojson.hpp> #include <mbgl/style/conversion/geojson_options.hpp> +#include <mbgl/style/conversion_impl.hpp> // C++ -> Java conversion #include "../../conversion/conversion.hpp" @@ -16,7 +16,13 @@ #include "../conversion/url_or_tileset.hpp" #include <string> +#include <mbgl/util/shared_thread_pool.hpp> +// GeoJSONSource uses a "coalescing" model for high frequency asynchronous data update calls, +// which in practice means, that any update that started processing is going to finish +// and the last scheduled update is going to finish as well. Any updates scheduled during processing can be canceled. +// Conversion from Java features to core ones is done on a worker thread and once finished, +// the ownership of the converted features is returned to the calling thread. namespace mbgl { namespace android { @@ -40,60 +46,39 @@ namespace android { : Source(env, std::make_unique<mbgl::style::GeoJSONSource>( jni::Make<std::string>(env, sourceId), convertGeoJSONOptions(env, options)) - ) { + ), converter(std::make_unique<Actor<FeatureConverter>>(*sharedThreadPool())) { } GeoJSONSource::GeoJSONSource(jni::JNIEnv& env, mbgl::style::Source& coreSource, AndroidRendererFrontend& frontend) - : Source(env, coreSource, createJavaPeer(env), frontend) { + : Source(env, coreSource, createJavaPeer(env), frontend) + , converter(std::make_unique<Actor<FeatureConverter>>(*sharedThreadPool())) { } GeoJSONSource::~GeoJSONSource() = default; - void GeoJSONSource::setGeoJSONString(jni::JNIEnv& env, jni::String json) { - using namespace mbgl::style::conversion; + void GeoJSONSource::setGeoJSONString(jni::JNIEnv& env, jni::String jString) { - // Convert the jni object - Error error; - optional<GeoJSON> converted = convert<GeoJSON>(mbgl::android::Value(env, json), error); - if(!converted) { - mbgl::Log::Error(mbgl::Event::JNI, "Error setting geo json: " + error.message); - return; - } + std::shared_ptr<std::string> json = std::make_shared<std::string>(jni::Make<std::string>(env, jString)); - // Update the core source - source.as<mbgl::style::GeoJSONSource>()->GeoJSONSource::setGeoJSON(*converted); + Update::Converter converterFn = [this, json](ActorRef<Callback> _callback) { + converter->self().invoke(&FeatureConverter::convertJson, json, _callback); + }; + + setAsync(converterFn); } void GeoJSONSource::setFeatureCollection(jni::JNIEnv& env, jni::Object<geojson::FeatureCollection> jFeatures) { - using namespace mbgl::android::geojson; - - // Convert the jni object - auto features = FeatureCollection::convert(env, jFeatures); - - // Update the core source - source.as<mbgl::style::GeoJSONSource>()->GeoJSONSource::setGeoJSON(GeoJSON(features)); + setCollectionAsync(env, jFeatures); } void GeoJSONSource::setFeature(jni::JNIEnv& env, jni::Object<geojson::Feature> jFeature) { - using namespace mbgl::android::geojson; - - // Convert the jni object - auto feature = Feature::convert(env, jFeature); - - // Update the core source - source.as<mbgl::style::GeoJSONSource>()->GeoJSONSource::setGeoJSON(GeoJSON(feature)); + setCollectionAsync(env, jFeature); } void GeoJSONSource::setGeometry(jni::JNIEnv& env, jni::Object<geojson::Geometry> jGeometry) { - using namespace mbgl::android::geojson; - - // Convert the jni object - auto geometry = Geometry::convert(env, jGeometry); - - // Update the core source - source.as<mbgl::style::GeoJSONSource>()->GeoJSONSource::setGeoJSON(GeoJSON(geometry)); + setCollectionAsync(env, jGeometry); } void GeoJSONSource::setURL(jni::JNIEnv& env, jni::String url) { @@ -125,6 +110,50 @@ namespace android { return jni::Object<Source>(GeoJSONSource::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this)).Get()); } + template <class JNIType> + void GeoJSONSource::setCollectionAsync(jni::JNIEnv& env, jni::Object<JNIType> jObject) { + + std::shared_ptr<jni::jobject> object = std::shared_ptr<jni::jobject>(jObject.NewGlobalRef(env).release()->Get(), GenericGlobalRefDeleter()); + + Update::Converter converterFn = [this, object](ActorRef<Callback> _callback) { + converter->self().invoke(&FeatureConverter::convertObject<JNIType>, jni::Object<JNIType>(*object), _callback); + }; + + setAsync(converterFn); + } + + void GeoJSONSource::setAsync(Update::Converter converterFn) { + awaitingUpdate = std::make_unique<Update>( + std::move(converterFn), + std::make_unique<Actor<Callback>>( + *Scheduler::GetCurrent(), + [this](GeoJSON geoJSON) { + // conversion from Java features to core ones finished + android::UniqueEnv _env = android::AttachEnv(); + + // Update the core source + source.as<mbgl::style::GeoJSONSource>()->GeoJSONSource::setGeoJSON(geoJSON); + + // if there is an awaiting update, execute it, otherwise, release resources + if (awaitingUpdate) { + update = std::move(awaitingUpdate); + update->converterFn(update->callback->self()); + } else { + update.reset(); + } + }) + ); + + // If another update is running, wait + if (update) { + return; + } + + // no updates are being processed, execute this one + update = std::move(awaitingUpdate); + update->converterFn(update->callback->self()); + } + void GeoJSONSource::registerNative(jni::JNIEnv& env) { // Lookup the class GeoJSONSource::javaClass = *jni::Class<GeoJSONSource>::Find(env).NewGlobalRef(env).release(); @@ -147,5 +176,36 @@ namespace android { ); } + void FeatureConverter::convertJson(std::shared_ptr<std::string> json, + ActorRef<Callback> callback) { + using namespace mbgl::style::conversion; + + android::UniqueEnv _env = android::AttachEnv(); + + // Convert the jni object + Error error; + optional<GeoJSON> converted = parseGeoJSON(*json, error); + if(!converted) { + mbgl::Log::Error(mbgl::Event::JNI, "Error setting geo json: " + error.message); + return; + } + + callback.invoke(&Callback::operator(), *converted); + } + + template<class JNIType> + void FeatureConverter::convertObject(jni::Object<JNIType> jObject, ActorRef<Callback> callback) { + using namespace mbgl::android::geojson; + + android::UniqueEnv _env = android::AttachEnv(); + // Convert the jni object + auto geometry = JNIType::convert(*_env, jObject); + callback.invoke(&Callback::operator(), GeoJSON(geometry)); + } + + Update::Update(Converter _converterFn, std::unique_ptr<Actor<Callback>> _callback) + : converterFn(std::move(_converterFn)) + , callback(std::move(_callback)) {} + } // namespace android } // namespace mbgl diff --git a/platform/android/src/style/sources/geojson_source.hpp b/platform/android/src/style/sources/geojson_source.hpp index c46519b04a..b9c360c67c 100644 --- a/platform/android/src/style/sources/geojson_source.hpp +++ b/platform/android/src/style/sources/geojson_source.hpp @@ -10,6 +10,24 @@ namespace mbgl { namespace android { +using Callback = std::function<void (GeoJSON)>; + +struct FeatureConverter { + void convertJson(std::shared_ptr<std::string>, ActorRef<Callback>); + + template <class JNIType> + void convertObject(jni::Object<JNIType>, ActorRef<Callback>); +}; + +struct Update { + using Converter = std::function<void (ActorRef<Callback>)>; + Converter converterFn; + + std::unique_ptr<Actor<Callback>> callback; + + Update(Converter, std::unique_ptr<Actor<Callback>>); +}; + class GeoJSONSource : public Source { public: @@ -35,13 +53,21 @@ public: void setURL(jni::JNIEnv&, jni::String); + jni::String getURL(jni::JNIEnv&); + jni::Array<jni::Object<geojson::Feature>> querySourceFeatures(jni::JNIEnv&, jni::Array<jni::Object<>> jfilter); - jni::String getURL(jni::JNIEnv&); - private: jni::Object<Source> createJavaPeer(jni::JNIEnv&); + std::unique_ptr<Update> awaitingUpdate; + std::unique_ptr<Update> update; + std::unique_ptr<Actor<FeatureConverter>> converter; + + template <class JNIType> + void setCollectionAsync(jni::JNIEnv&, jni::Object<JNIType>); + + void setAsync(Update::Converter); }; // class GeoJSONSource diff --git a/platform/android/src/style/sources/image_source.cpp b/platform/android/src/style/sources/image_source.cpp index 249387ea51..278564485d 100644 --- a/platform/android/src/style/sources/image_source.cpp +++ b/platform/android/src/style/sources/image_source.cpp @@ -5,7 +5,7 @@ // C++ -> Java conversion #include "../../conversion/conversion.hpp" -#include <mbgl/style/conversion.hpp> +#include <mbgl/style/conversion_impl.hpp> #include <mbgl/util/premultiply.hpp> #include "../../bitmap.hpp" diff --git a/platform/android/src/style/sources/source.cpp b/platform/android/src/style/sources/source.cpp index 413530a5ec..d2e2426c0b 100644 --- a/platform/android/src/style/sources/source.cpp +++ b/platform/android/src/style/sources/source.cpp @@ -7,8 +7,8 @@ #include <mbgl/util/logging.hpp> // Java -> C++ conversion -#include <mbgl/style/conversion.hpp> #include <mbgl/style/conversion/source.hpp> +#include <mbgl/style/conversion_impl.hpp> // C++ -> Java conversion #include "../conversion/property_value.hpp" @@ -51,7 +51,7 @@ namespace android { if (!coreSource.peer.has_value()) { coreSource.peer = createSourcePeer(env, coreSource, frontend); } - return *mbgl::util::any_cast<std::unique_ptr<Source>>(&coreSource.peer)->get()->javaPeer; + return *coreSource.peer.get<std::unique_ptr<Source>>()->javaPeer; } Source::Source(jni::JNIEnv& env, mbgl::style::Source& coreSource, jni::Object<Source> obj, AndroidRendererFrontend& frontend) @@ -109,7 +109,7 @@ namespace android { rendererFrontend = &frontend; } - void Source::removeFromMap(JNIEnv&, jni::Object<Source>, mbgl::Map& map) { + bool Source::removeFromMap(JNIEnv&, jni::Object<Source>, mbgl::Map& map) { // Cannot remove if not attached yet if (ownedSource) { throw std::runtime_error("Cannot remove detached source"); @@ -119,13 +119,18 @@ namespace android { ownedSource = map.getStyle().removeSource(source.getID()); // The source may not be removed if any layers still reference it + return ownedSource != nullptr; + } + + void Source::releaseJavaPeer() { + // We can't release the peer if the source was not removed from the map if (!ownedSource) { return; } // Release the peer relationships. These will be re-established when the source is added to a map assert(ownedSource->peer.has_value()); - util::any_cast<std::unique_ptr<Source>>(&(ownedSource->peer))->release(); + ownedSource->peer.get<std::unique_ptr<Source>>().release(); ownedSource->peer.reset(); // Release the strong reference to the java peer diff --git a/platform/android/src/style/sources/source.hpp b/platform/android/src/style/sources/source.hpp index 718f60b381..6b906eb9c0 100644 --- a/platform/android/src/style/sources/source.hpp +++ b/platform/android/src/style/sources/source.hpp @@ -35,9 +35,11 @@ public: virtual ~Source(); - void addToMap(JNIEnv&, jni::Object<Source>, mbgl::Map&, AndroidRendererFrontend&); + virtual void addToMap(JNIEnv&, jni::Object<Source>, mbgl::Map&, AndroidRendererFrontend&); - void removeFromMap(JNIEnv&, jni::Object<Source>, mbgl::Map&); + virtual bool removeFromMap(JNIEnv&, jni::Object<Source>, mbgl::Map&); + + void releaseJavaPeer(); jni::String getId(jni::JNIEnv&); |