diff options
Diffstat (limited to 'platform/android/src')
64 files changed, 1213 insertions, 536 deletions
diff --git a/platform/android/src/android_renderer_backend.cpp b/platform/android/src/android_renderer_backend.cpp index 9e49915650..ae35acc5da 100755 --- a/platform/android/src/android_renderer_backend.cpp +++ b/platform/android/src/android_renderer_backend.cpp @@ -21,7 +21,7 @@ void AndroidRendererBackend::bind() { /** * From mbgl::RendererBackend. */ -gl::ProcAddress AndroidRendererBackend::initializeExtension(const char* name) { +gl::ProcAddress AndroidRendererBackend::getExtensionFunctionPointer(const char* name) { assert(BackendScope::exists()); return eglGetProcAddress(name); } diff --git a/platform/android/src/android_renderer_backend.hpp b/platform/android/src/android_renderer_backend.hpp index c5c552459f..d2c100dcc1 100755 --- a/platform/android/src/android_renderer_backend.hpp +++ b/platform/android/src/android_renderer_backend.hpp @@ -24,7 +24,7 @@ public: protected: // mbgl::RendererBackend // - gl::ProcAddress initializeExtension(const char*) override; + gl::ProcAddress getExtensionFunctionPointer(const char*) override; void activate() override {}; void deactivate() override {}; diff --git a/platform/android/src/android_renderer_frontend.cpp b/platform/android/src/android_renderer_frontend.cpp index afdb08a10e..2a03d9de9e 100644 --- a/platform/android/src/android_renderer_frontend.cpp +++ b/platform/android/src/android_renderer_frontend.cpp @@ -77,8 +77,8 @@ void AndroidRendererFrontend::update(std::shared_ptr<UpdateParameters> params) { mapRenderer.requestRender(); } -void AndroidRendererFrontend::onLowMemory() { - mapRenderer.actor().invoke(&Renderer::onLowMemory); +void AndroidRendererFrontend::reduceMemoryUse() { + mapRenderer.actor().invoke(&Renderer::reduceMemoryUse); } std::vector<Feature> AndroidRendererFrontend::querySourceFeatures(const std::string& sourceID, diff --git a/platform/android/src/android_renderer_frontend.hpp b/platform/android/src/android_renderer_frontend.hpp index 178870c452..b61904e388 100644 --- a/platform/android/src/android_renderer_frontend.hpp +++ b/platform/android/src/android_renderer_frontend.hpp @@ -39,7 +39,7 @@ public: AnnotationIDs queryShapeAnnotations(const ScreenBox& box) const; // Memory - void onLowMemory(); + void reduceMemoryUse(); private: MapRenderer& mapRenderer; diff --git a/platform/android/src/example_custom_layer.cpp b/platform/android/src/example_custom_layer.cpp index 1ed68d0835..6d0bd4de4b 100644 --- a/platform/android/src/example_custom_layer.cpp +++ b/platform/android/src/example_custom_layer.cpp @@ -96,7 +96,7 @@ void nativeContextLost(void */*context*/) { mbgl::Log::Info(mbgl::Event::General, "nativeContextLost"); } -void nativeDenitialize(void *context) { +void nativeDeinitialize(void *context) { mbgl::Log::Info(mbgl::Event::General, "nativeDeinitialize"); delete reinterpret_cast<ExampleCustomLayer*>(context); } @@ -132,7 +132,7 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { env->SetStaticLongField(customLayerClass, env->GetStaticFieldID(customLayerClass, "DeinitializeFunction", "J"), - reinterpret_cast<jlong>(nativeDenitialize)); + reinterpret_cast<jlong>(nativeDeinitialize)); return JNI_VERSION_1_6; } diff --git a/platform/android/src/geojson/conversion/geometry.hpp b/platform/android/src/geojson/conversion/geometry.hpp index 2ca63e2c11..5d2aab4c2d 100644 --- a/platform/android/src/geojson/conversion/geometry.hpp +++ b/platform/android/src/geojson/conversion/geometry.hpp @@ -21,88 +21,91 @@ public: jni::JNIEnv& env; /** - * Point (double[]) + * static Point fromLngLat(double longitude,double latitude) */ jni::jobject* operator()(const mapbox::geometry::point<T> &geometry) const { - static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/services/commons/geojson/Point")).release(); - static jni::jmethodID* fromCoordinates = &jni::GetStaticMethodID(env, *javaClass, "fromCoordinates", "([D)Lcom/mapbox/services/commons/geojson/Point;"); + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/geojson/Point")).release(); + static jni::jmethodID* fromLngLat = &jni::GetStaticMethodID(env, *javaClass, "fromLngLat", "(DD)Lcom/mapbox/geojson/Point;"); - // Create Point - jni::LocalObject<jni::jarray<jni::jdouble>> position = jni::NewLocalObject(env, toGeoJsonPosition(env, geometry.x, geometry.y)); - return reinterpret_cast<jni::jobject*>(jni::CallStaticMethod<jni::jobject*>(env, *javaClass, *fromCoordinates, position.get())); + return reinterpret_cast<jni::jobject*>(jni::CallStaticMethod<jni::jobject*>(env, *javaClass, *fromLngLat, geometry.x, geometry.y)); } /** - * LineString (double[][]) + * static LineString fromLngLats(List<Point> points) */ jni::jobject* operator()(const mapbox::geometry::line_string<T> &geometry) const { - static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/services/commons/geojson/LineString")).release(); - static jni::jmethodID* fromCoordinates = &jni::GetStaticMethodID(env, *javaClass, "fromCoordinates", "([[D)Lcom/mapbox/services/commons/geojson/LineString;"); + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/geojson/LineString")).release(); + static jni::jmethodID* fromLngLats = &jni::GetStaticMethodID(env, *javaClass, "fromLngLats", "(Ljava/util/List;)Lcom/mapbox/geojson/LineString;"); // Create - jni::LocalObject<jni::jarray<jni::jobject>> coordinates = jni::NewLocalObject(env, toGeoJsonCoordinates(env, geometry)); - return reinterpret_cast<jni::jobject*>(jni::CallStaticMethod<jni::jobject*>(env, *javaClass, *fromCoordinates, coordinates.get())); + jni::LocalObject<jni::jobject> listOfPoints = jni::NewLocalObject(env, toGeoJsonListOfPoints(env, geometry)); + return reinterpret_cast<jni::jobject*>(jni::CallStaticMethod<jni::jobject*>(env, *javaClass, *fromLngLats, listOfPoints.get())); } /** - * MultiPoint (double[][]) + * static MultiPoint fromLngLats(List<Point> points) */ jni::jobject* operator()(const mapbox::geometry::multi_point<T> &geometry) const { - static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/services/commons/geojson/MultiPoint")).release(); - static jni::jmethodID* fromCoordinates = &jni::GetStaticMethodID(env, *javaClass, "fromCoordinates", "([[D)Lcom/mapbox/services/commons/geojson/MultiPoint;"); + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/geojson/MultiPoint")).release(); + static jni::jmethodID* fromLngLats = &jni::GetStaticMethodID(env, *javaClass, "fromLngLats", "(Ljava/util/List;)Lcom/mapbox/geojson/MultiPoint;"); // Create - jni::LocalObject<jni::jarray<jni::jobject>> coordinates = jni::NewLocalObject(env, toGeoJsonCoordinates(env, geometry)); - return reinterpret_cast<jni::jobject*>(jni::CallStaticMethod<jni::jobject*>(env, *javaClass, *fromCoordinates, coordinates.get())); + jni::LocalObject<jni::jobject> coordinates = jni::NewLocalObject(env, toGeoJsonListOfPoints(env, geometry)); + return reinterpret_cast<jni::jobject*>(jni::CallStaticMethod<jni::jobject*>(env, *javaClass, *fromLngLats, coordinates.get())); } /** - * Polygon (double[][][]) + * static Polygon fromLngLats(List<List<Point>> coordinates) */ jni::jobject* operator()(const mapbox::geometry::polygon<T> &geometry) const { - static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/services/commons/geojson/Polygon")).release(); - static jni::jmethodID* fromCoordinates = &jni::GetStaticMethodID(env, *javaClass, "fromCoordinates", "([[[D)Lcom/mapbox/services/commons/geojson/Polygon;"); + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/geojson/Polygon")).release(); + static jni::jmethodID* fromLngLats = &jni::GetStaticMethodID(env, *javaClass, "fromLngLats", "(Ljava/util/List;)Lcom/mapbox/geojson/Polygon;"); // Create - jni::LocalObject<jni::jarray<jni::jobject>> shape = jni::NewLocalObject(env, toShape<>(env, geometry)); - return reinterpret_cast<jni::jobject*>(jni::CallStaticMethod<jni::jobject*>(env, *javaClass, *fromCoordinates, shape.get())); + jni::LocalObject<jni::jobject> shape = jni::NewLocalObject(env, toShape<>(env, geometry)); + return reinterpret_cast<jni::jobject*>(jni::CallStaticMethod<jni::jobject*>(env, *javaClass, *fromLngLats, shape.get())); } /** - * MultiLineString (double[][][]) + * static MultiLineString fromLngLats(List<List<Point>> points) */ jni::jobject* operator()(const mapbox::geometry::multi_line_string<T> &geometry) const { - static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/services/commons/geojson/MultiLineString")).release(); - static jni::jmethodID* fromCoordinates = &jni::GetStaticMethodID(env, *javaClass, "fromCoordinates", "([[[D)Lcom/mapbox/services/commons/geojson/MultiLineString;"); + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/geojson/MultiLineString")).release(); + static jni::jmethodID* fromLngLats = &jni::GetStaticMethodID(env, *javaClass, "fromLngLats", "(Ljava/util/List;)Lcom/mapbox/geojson/MultiLineString;"); // Create - jni::LocalObject<jni::jarray<jni::jobject>> shape = jni::NewLocalObject(env, toShape<>(env, geometry)); - return reinterpret_cast<jni::jobject*>(jni::CallStaticMethod<jni::jobject*>(env, *javaClass, *fromCoordinates, shape.get())); + jni::LocalObject<jni::jobject> shape = jni::NewLocalObject(env, toShape<>(env, geometry)); + return reinterpret_cast<jni::jobject*>(jni::CallStaticMethod<jni::jobject*>(env, *javaClass, *fromLngLats, shape.get())); } /** * MultiPolygon (double[][][][]) -> [[[D + Object array == [[[[D + * + * static MultiPolygon fromLngLats(List<List<List<Point>>> points) */ jni::jobject* operator()(const mapbox::geometry::multi_polygon<T> &geometry) const { - static jni::jclass* listClass = jni::NewGlobalRef(env, &jni::FindClass(env, "[[[D")).release(); - jni::LocalObject<jni::jarray<jni::jobject>> jarray = jni::NewLocalObject(env, &jni::NewObjectArray(env, geometry.size(), *listClass)); + // ArrayList + static jni::jclass* arrayListClass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/util/ArrayList")).release(); + static jni::jmethodID* constructor = &jni::GetMethodID(env, *arrayListClass, "<init>", "(I)V"); + static jni::jmethodID* add = &jni::GetMethodID(env, *arrayListClass, "add", "(ILjava/lang/Object;)V"); + jni::jobject* arrayList = &jni::NewObject(env, *arrayListClass, *constructor, geometry.size()); for(size_t i = 0; i < geometry.size(); i = i + 1) { - jni::LocalObject<jni::jarray<jni::jobject>> shape = jni::NewLocalObject(env, toShape<>(env, geometry.at(i))); - jni::SetObjectArrayElement(env, *jarray, i, shape.get()); + jni::LocalObject<jni::jobject> shape = jni::NewLocalObject(env, toShape<>(env, geometry.at(i))); + jni::CallMethod<void>(env, arrayList, *add, i, shape.get()); } // Create the MultiPolygon - static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/services/commons/geojson/MultiPolygon")).release(); - static jni::jmethodID* fromGeometries = &jni::GetStaticMethodID(env, *javaClass, "fromCoordinates", "([[[[D)Lcom/mapbox/services/commons/geojson/MultiPolygon;"); - return reinterpret_cast<jni::jobject*>(jni::CallStaticMethod<jni::jobject*>(env, *javaClass, *fromGeometries, jarray.get())); + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/geojson/MultiPolygon")).release(); + static jni::jmethodID* fromGeometries = &jni::GetStaticMethodID(env, *javaClass, "fromLngLats", "(Ljava/util/List;)Lcom/mapbox/geojson/MultiPolygon;"); + return reinterpret_cast<jni::jobject*>(jni::CallStaticMethod<jni::jobject*>(env, *javaClass, *fromGeometries, arrayList)); } /** * GeometryCollection */ jni::jobject* operator()(const mapbox::geometry::geometry_collection<T> &collection) const { - static jni::jclass* geometryClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/services/commons/geojson/Geometry")).release(); + static jni::jclass* geometryClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/geojson/Geometry")).release(); jni::LocalObject<jni::jarray<jni::jobject>> jarray = jni::NewLocalObject(env, &jni::NewObjectArray(env, collection.size(), *geometryClass)); for(size_t i = 0; i < collection.size(); i = i + 1) { @@ -112,8 +115,8 @@ public: } // Turn into array list and create the GeometryCollection - static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/services/commons/geojson/GeometryCollection")).release(); - static jni::jmethodID* fromGeometries = &jni::GetStaticMethodID(env, *javaClass, "fromGeometries", "(Ljava/util/List;)Lcom/mapbox/services/commons/geojson/GeometryCollection;"); + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/geojson/GeometryCollection")).release(); + static jni::jmethodID* fromGeometries = &jni::GetStaticMethodID(env, *javaClass, "fromGeometries", "(Ljava/util/List;)Lcom/mapbox/geojson/GeometryCollection;"); jni::LocalObject<jni::jobject> list = jni::NewLocalObject(env, toArrayList<>(env, *jarray)); return reinterpret_cast<jni::jobject*>(jni::CallStaticMethod<jni::jobject*>(env, *javaClass, *fromGeometries, list.get())); @@ -122,47 +125,50 @@ public: private: /** - * x, y -> jarray<jdouble> ([x,y]) - */ - static jni::jarray<jni::jdouble>* toGeoJsonPosition(JNIEnv& env, double x, double y) { - jni::jarray<jni::jdouble>& jarray = jni::NewArray<jni::jdouble>(env, 2); - jni::jdouble array[] = {x, y}; - jni::SetArrayRegion(env, jarray, 0, 2, array); - return &jarray; - } + * vector<point<T>> -> List<Point> + */ + static jni::jobject* toGeoJsonListOfPoints(JNIEnv& env, std::vector<mapbox::geometry::point<T>> points) { - /** - * vector<point<T>> -> jarray<jobject> (double[][]) -> [D + Object array == [[D - */ - static jni::jarray<jni::jobject>* toGeoJsonCoordinates(JNIEnv& env, std::vector<mapbox::geometry::point<T>> points) { - static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "[D")).release(); - jni::jarray<jni::jobject>& jarray = jni::NewObjectArray(env, points.size(), *javaClass); + // ArrayList + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/util/ArrayList")).release(); + static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "(I)V"); + static jni::jmethodID* add = &jni::GetMethodID(env, *javaClass, "add", "(ILjava/lang/Object;)V"); + jni::jobject* arrayList = &jni::NewObject(env, *javaClass, *constructor, points.size()); + + + // Point + static jni::jclass* pointJavaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/geojson/Point")).release(); + static jni::jmethodID* fromLngLat = &jni::GetStaticMethodID(env, *pointJavaClass, "fromLngLat", "(DD)Lcom/mapbox/geojson/Point;"); for(size_t i = 0; i < points.size(); i = i + 1) { mapbox::geometry::point<T> point = points.at(i); - jni::LocalObject<jni::jarray<jni::jdouble>> position = jni::NewLocalObject(env, toGeoJsonPosition(env, point.x, point.y)); - jni::SetObjectArrayElement(env, jarray, i, position.get()); + jni::LocalObject<jni::jobject> pointObject = + jni::NewLocalObject(env, jni::CallStaticMethod<jni::jobject*>(env, *pointJavaClass, *fromLngLat, point.x, point.y)); + jni::CallMethod<void>(env, arrayList, *add, i, pointObject.get()); } - return &jarray; + return arrayList; } /** - * polygon<T> - * multi_line_string<T> - * -> jarray<jobject> (double[][][]) -> [[D + Object array == [[[D + * geometry -> List<List<Point>> */ template <class SHAPE> - static jni::jarray<jni::jobject>* toShape(JNIEnv& env, SHAPE value) { - static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "[[D")).release(); - jni::jarray<jni::jobject>& jarray = jni::NewObjectArray(env, value.size(), *javaClass); + static jni::jobject* toShape(JNIEnv& env, SHAPE value) { + + // ArrayList + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/util/ArrayList")).release(); + static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "(I)V"); + static jni::jmethodID* add = &jni::GetMethodID(env, *javaClass, "add", "(ILjava/lang/Object;)V"); + jni::jobject* arrayList = &jni::NewObject(env, *javaClass, *constructor, value.size()); + for(size_t i = 0; i < value.size(); i = i + 1) { - jni::LocalObject<jni::jarray<jni::jobject>> coordinates = jni::NewLocalObject(env, toGeoJsonCoordinates(env, value.at(i))); - jni::SetObjectArrayElement(env, jarray, i, coordinates.get()); + jni::LocalObject<jni::jobject> listOfPoints = jni::NewLocalObject(env, toGeoJsonListOfPoints(env, value.at(i))); + jni::CallMethod<void>(env, arrayList, *add, i, listOfPoints.get()); } - return &jarray; + return arrayList; } }; diff --git a/platform/android/src/geojson/feature.cpp b/platform/android/src/geojson/feature.cpp index a6b387cd15..d8a4e829e2 100644 --- a/platform/android/src/geojson/feature.cpp +++ b/platform/android/src/geojson/feature.cpp @@ -8,11 +8,11 @@ namespace geojson { mbgl::Feature Feature::convert(jni::JNIEnv& env, jni::Object<Feature> jFeature) { // Convert - auto jGeometry = getGeometry(env, jFeature); - auto jProperties = Feature::getProperties(env, jFeature); + auto jGeometry = geometry(env, jFeature); + auto jProperties = Feature::properties(env, jFeature); std::experimental::optional<mapbox::geometry::identifier> id; - auto jId = Feature::getId(env, jFeature); + auto jId = Feature::id(env, jFeature); if (jId) { id = { jni::Make<std::string>(env, jId) }; } @@ -31,18 +31,18 @@ mbgl::Feature Feature::convert(jni::JNIEnv& env, jni::Object<Feature> jFeature) return feature; } -jni::Object<Geometry> Feature::getGeometry(jni::JNIEnv& env, jni::Object<Feature> jFeature) { - static auto method = Feature::javaClass.GetMethod<jni::Object<Geometry> ()>(env, "getGeometry"); +jni::Object<Geometry> Feature::geometry(jni::JNIEnv& env, jni::Object<Feature> jFeature) { + static auto method = Feature::javaClass.GetMethod<jni::Object<Geometry> ()>(env, "geometry"); return jFeature.Call(env, method); } -jni::Object<gson::JsonObject> Feature::getProperties(jni::JNIEnv& env, jni::Object<Feature> jFeature) { - static auto method = Feature::javaClass.GetMethod<jni::Object<gson::JsonObject> ()>(env, "getProperties"); +jni::Object<gson::JsonObject> Feature::properties(jni::JNIEnv& env, jni::Object<Feature> jFeature) { + static auto method = Feature::javaClass.GetMethod<jni::Object<gson::JsonObject> ()>(env, "properties"); return jFeature.Call(env, method); } -jni::String Feature::getId(jni::JNIEnv& env, jni::Object<Feature> jFeature) { - static auto method = Feature::javaClass.GetMethod<jni::String ()>(env, "getId"); +jni::String Feature::id(jni::JNIEnv& env, jni::Object<Feature> jFeature) { + static auto method = Feature::javaClass.GetMethod<jni::String ()>(env, "id"); return jFeature.Call(env, method); } diff --git a/platform/android/src/geojson/feature.hpp b/platform/android/src/geojson/feature.hpp index b5d856cc42..ab59d783e5 100644 --- a/platform/android/src/geojson/feature.hpp +++ b/platform/android/src/geojson/feature.hpp @@ -16,17 +16,17 @@ namespace geojson { class Feature : private mbgl::util::noncopyable { public: - static constexpr auto Name() { return "com/mapbox/services/commons/geojson/Feature"; }; + static constexpr auto Name() { return "com/mapbox/geojson/Feature"; }; static jni::Object<Feature> fromGeometry(jni::JNIEnv&, jni::Object<Geometry>, jni::Object<gson::JsonObject>, jni::String); static mbgl::Feature convert(jni::JNIEnv&, jni::Object<Feature>); - static jni::Object<Geometry> getGeometry(jni::JNIEnv&, jni::Object<Feature>); + static jni::Object<Geometry> geometry(jni::JNIEnv&, jni::Object<Feature>); - static jni::String getId(jni::JNIEnv&, jni::Object<Feature>); + static jni::String id(jni::JNIEnv&, jni::Object<Feature>); - static jni::Object<gson::JsonObject> getProperties(jni::JNIEnv&, jni::Object<Feature>); + static jni::Object<gson::JsonObject> properties(jni::JNIEnv&, jni::Object<Feature>); static jni::Class<Feature> javaClass; diff --git a/platform/android/src/geojson/feature_collection.cpp b/platform/android/src/geojson/feature_collection.cpp index 2f156532ae..06f8f10b9a 100644 --- a/platform/android/src/geojson/feature_collection.cpp +++ b/platform/android/src/geojson/feature_collection.cpp @@ -1,3 +1,4 @@ +#include <android/log.h> #include "feature_collection.hpp" #include "feature.hpp" @@ -7,24 +8,28 @@ namespace android { namespace geojson { mbgl::FeatureCollection FeatureCollection::convert(jni::JNIEnv& env, jni::Object<FeatureCollection> jCollection) { - auto jFeatureList = FeatureCollection::getFeatures(env, jCollection); - auto jFeatures = java::util::List::toArray<Feature>(env, jFeatureList); - auto size = size_t(jFeatures.Length(env)); - auto collection = mbgl::FeatureCollection(); - collection.reserve(size); - for (size_t i = 0; i < size; i++) { - auto jFeature = jFeatures.Get(env, i); - collection.push_back(Feature::convert(env, jFeature)); - jni::DeleteLocalRef(env, jFeature); - } + if (jCollection) { + auto jFeatureList = FeatureCollection::features(env, jCollection); + auto jFeatures = java::util::List::toArray<Feature>(env, jFeatureList); + auto size = size_t(jFeatures.Length(env)); + collection.reserve(size); + for (size_t i = 0; i < size; i++) { + auto jFeature = jFeatures.Get(env, i); + collection.push_back(Feature::convert(env, jFeature)); + jni::DeleteLocalRef(env, jFeature); + } + + jni::DeleteLocalRef(env, jFeatures); + jni::DeleteLocalRef(env, jFeatureList); + } return collection; } -jni::Object<java::util::List> FeatureCollection::getFeatures(jni::JNIEnv& env, jni::Object<FeatureCollection> jCollection) { - static auto method = FeatureCollection::javaClass.GetMethod<jni::Object<java::util::List> ()>(env, "getFeatures"); +jni::Object<java::util::List> FeatureCollection::features(jni::JNIEnv& env, jni::Object<FeatureCollection> jCollection) { + static auto method = FeatureCollection::javaClass.GetMethod<jni::Object<java::util::List> ()>(env, "features"); return jCollection.Call(env, method); } diff --git a/platform/android/src/geojson/feature_collection.hpp b/platform/android/src/geojson/feature_collection.hpp index 8e9717e82b..259ffab370 100644 --- a/platform/android/src/geojson/feature_collection.hpp +++ b/platform/android/src/geojson/feature_collection.hpp @@ -13,11 +13,11 @@ namespace geojson { class FeatureCollection : private mbgl::util::noncopyable { public: - static constexpr auto Name() { return "com/mapbox/services/commons/geojson/FeatureCollection"; }; + static constexpr auto Name() { return "com/mapbox/geojson/FeatureCollection"; }; static mbgl::FeatureCollection convert(jni::JNIEnv&, jni::Object<FeatureCollection>); - static jni::Object<java::util::List> getFeatures(jni::JNIEnv&, jni::Object<FeatureCollection>); + static jni::Object<java::util::List> features(jni::JNIEnv&, jni::Object<FeatureCollection>); static jni::Class<FeatureCollection> javaClass; diff --git a/platform/android/src/geojson/geometry.cpp b/platform/android/src/geojson/geometry.cpp index 33bb4ee3db..ca19d8fb03 100644 --- a/platform/android/src/geojson/geometry.cpp +++ b/platform/android/src/geojson/geometry.cpp @@ -33,7 +33,7 @@ mapbox::geojson::geometry Geometry::convert(jni::JNIEnv &env, jni::Object<Geomet } std::string Geometry::getType(jni::JNIEnv &env, jni::Object<Geometry> jGeometry) { - static auto method = Geometry::javaClass.GetMethod<jni::String ()>(env, "getType"); + static auto method = Geometry::javaClass.GetMethod<jni::String ()>(env, "type"); auto jType = jGeometry.Call(env, method); auto type = jni::Make<std::string>(env, jType); jni::DeleteLocalRef(env, jType); diff --git a/platform/android/src/geojson/geometry.hpp b/platform/android/src/geojson/geometry.hpp index bdcff6bb3e..b7f8909f6f 100644 --- a/platform/android/src/geojson/geometry.hpp +++ b/platform/android/src/geojson/geometry.hpp @@ -11,7 +11,7 @@ namespace geojson { class Geometry : private mbgl::util::noncopyable { public: - static constexpr auto Name() { return "com/mapbox/services/commons/geojson/Geometry"; }; + static constexpr auto Name() { return "com/mapbox/geojson/Geometry"; }; static mapbox::geojson::geometry convert(jni::JNIEnv&, jni::Object<Geometry>); diff --git a/platform/android/src/geojson/line_string.cpp b/platform/android/src/geojson/line_string.cpp index d0719f2538..8eebd53550 100644 --- a/platform/android/src/geojson/line_string.cpp +++ b/platform/android/src/geojson/line_string.cpp @@ -1,6 +1,6 @@ #include "line_string.hpp" -#include "position.hpp" +#include "point.hpp" namespace mbgl { namespace android { @@ -10,35 +10,36 @@ mapbox::geojson::line_string LineString::convert(jni::JNIEnv &env, jni::Object<L mapbox::geojson::line_string lineString; if (jLineString) { - auto jPositionList = LineString::getCoordinates(env, jLineString); - lineString = LineString::convert(env, jPositionList); - jni::DeleteLocalRef(env, jPositionList); + auto jPointList = LineString::coordinates(env, jLineString); + lineString = LineString::convert(env, jPointList); + jni::DeleteLocalRef(env, jPointList); } return lineString; } -mapbox::geojson::line_string LineString::convert(jni::JNIEnv &env, jni::Object<java::util::List/*<Position>*/> jPositionList) { +mapbox::geojson::line_string LineString::convert(jni::JNIEnv &env, jni::Object<java::util::List/*<Point>*/> jPointList) { mapbox::geojson::line_string lineString; - if (jPositionList) { - auto jPositionArray = java::util::List::toArray<Position>(env, jPositionList); + if (jPointList) { + auto jPointArray = java::util::List::toArray<Point>(env, jPointList); + auto size = jPointArray.Length(env); + lineString.reserve(size); - auto size = jPositionArray.Length(env); for (std::size_t i = 0; i < size; i++) { - auto jPosition = jPositionArray.Get(env, i); - lineString.push_back(Position::convert(env, jPosition)); - jni::DeleteLocalRef(env, jPosition); + auto jPoint = jPointArray.Get(env, i); + lineString.push_back(Point::convert(env, jPoint)); + jni::DeleteLocalRef(env, jPoint); } - jni::DeleteLocalRef(env, jPositionArray); + jni::DeleteLocalRef(env, jPointArray); } return lineString; } -jni::Object<java::util::List> LineString::getCoordinates(jni::JNIEnv &env, jni::Object<LineString> jLineString) { - static auto method = LineString::javaClass.GetMethod<jni::Object<java::util::List> ()>(env, "getCoordinates"); +jni::Object<java::util::List> LineString::coordinates(jni::JNIEnv &env, jni::Object<LineString> jLineString) { + static auto method = LineString::javaClass.GetMethod<jni::Object<java::util::List> ()>(env, "coordinates"); return jLineString.Call(env, method); } diff --git a/platform/android/src/geojson/line_string.hpp b/platform/android/src/geojson/line_string.hpp index d3be68d0a5..86033c2e6a 100644 --- a/platform/android/src/geojson/line_string.hpp +++ b/platform/android/src/geojson/line_string.hpp @@ -14,15 +14,15 @@ namespace geojson { class LineString : private mbgl::util::noncopyable { public: - static constexpr auto Name() { return "com/mapbox/services/commons/geojson/LineString"; }; + static constexpr auto Name() { return "com/mapbox/geojson/LineString"; }; static constexpr auto Type() { return "LineString"; }; static mapbox::geojson::line_string convert(jni::JNIEnv&, jni::Object<LineString>); - static mapbox::geojson::line_string convert(jni::JNIEnv&, jni::Object<java::util::List/*<Position>*/>); + static mapbox::geojson::line_string convert(jni::JNIEnv&, jni::Object<java::util::List/*<Point>*/>); - static jni::Object<java::util::List> getCoordinates(jni::JNIEnv&, jni::Object<LineString>); + static jni::Object<java::util::List> coordinates(jni::JNIEnv&, jni::Object<LineString>); static jni::Class<LineString> javaClass; diff --git a/platform/android/src/geojson/multi_line_string.cpp b/platform/android/src/geojson/multi_line_string.cpp index b676144bf5..c748d4786f 100644 --- a/platform/android/src/geojson/multi_line_string.cpp +++ b/platform/android/src/geojson/multi_line_string.cpp @@ -10,27 +10,27 @@ mapbox::geojson::multi_line_string MultiLineString::convert(jni::JNIEnv &env, jn mapbox::geojson::multi_line_string multiLineString; if (jMultiLineString) { - auto jPositionListsList = MultiLineString::getCoordinates(env, jMultiLineString); - multiLineString = MultiLineString::convert(env, jPositionListsList); - jni::DeleteLocalRef(env, jPositionListsList); + auto jPointListsList = MultiLineString::coordinates(env, jMultiLineString); + multiLineString = MultiLineString::convert(env, jPointListsList); + jni::DeleteLocalRef(env, jPointListsList); } return multiLineString; } -mapbox::geojson::multi_line_string MultiLineString::convert(jni::JNIEnv &env, jni::Object<java::util::List/*<java::util::List<Position>>*/> jPositionListsList) { +mapbox::geojson::multi_line_string MultiLineString::convert(jni::JNIEnv &env, jni::Object<java::util::List/*<java::util::List<Point>>*/> jPointListsList) { mapbox::geojson::multi_line_string multiLineString; - if (jPositionListsList) { - auto jPositionListsArray = java::util::List::toArray<java::util::List>(env, jPositionListsList); + if (jPointListsList) { + auto jPositionListsArray = java::util::List::toArray<java::util::List>(env, jPointListsList); auto size = jPositionListsArray.Length(env); multiLineString.reserve(size); for (std::size_t i = 0; i < size; i++) { - auto jPositionList = jPositionListsArray.Get(env, i); - multiLineString.push_back(LineString::convert(env, jPositionList)); - jni::DeleteLocalRef(env, jPositionList); + auto jPointsList = jPositionListsArray.Get(env, i); + multiLineString.push_back(LineString::convert(env, jPointsList)); + jni::DeleteLocalRef(env, jPointsList); } jni::DeleteLocalRef(env, jPositionListsArray); @@ -39,8 +39,8 @@ mapbox::geojson::multi_line_string MultiLineString::convert(jni::JNIEnv &env, jn return multiLineString; } -jni::Object<java::util::List> MultiLineString::getCoordinates(jni::JNIEnv &env, jni::Object<MultiLineString> jLineString) { - static auto method = MultiLineString::javaClass.GetMethod<jni::Object<java::util::List> ()>(env, "getCoordinates"); +jni::Object<java::util::List> MultiLineString::coordinates(jni::JNIEnv &env, jni::Object<MultiLineString> jLineString) { + static auto method = MultiLineString::javaClass.GetMethod<jni::Object<java::util::List> ()>(env, "coordinates"); return jLineString.Call(env, method); } diff --git a/platform/android/src/geojson/multi_line_string.hpp b/platform/android/src/geojson/multi_line_string.hpp index af33fe72d6..358a6b5dda 100644 --- a/platform/android/src/geojson/multi_line_string.hpp +++ b/platform/android/src/geojson/multi_line_string.hpp @@ -13,15 +13,15 @@ namespace geojson { class MultiLineString : private mbgl::util::noncopyable { public: - static constexpr auto Name() { return "com/mapbox/services/commons/geojson/MultiLineString"; }; + static constexpr auto Name() { return "com/mapbox/geojson/MultiLineString"; }; static constexpr auto Type() { return "MultiLineString"; }; static mapbox::geojson::multi_line_string convert(jni::JNIEnv&, jni::Object<MultiLineString>); - static mapbox::geojson::multi_line_string convert(jni::JNIEnv&, jni::Object<java::util::List/*<java::util::List<Position>>*/>); + static mapbox::geojson::multi_line_string convert(jni::JNIEnv&, jni::Object<java::util::List/*<java::util::List<Point>>*/>); - static jni::Object<java::util::List> getCoordinates(jni::JNIEnv&, jni::Object<MultiLineString>); + static jni::Object<java::util::List> coordinates(jni::JNIEnv&, jni::Object<MultiLineString>); static jni::Class<MultiLineString> javaClass; diff --git a/platform/android/src/geojson/multi_point.cpp b/platform/android/src/geojson/multi_point.cpp index f3acdb1ea6..4f9ff596b2 100644 --- a/platform/android/src/geojson/multi_point.cpp +++ b/platform/android/src/geojson/multi_point.cpp @@ -12,16 +12,16 @@ mapbox::geojson::multi_point MultiPoint::convert(jni::JNIEnv &env, jni::Object<M mapbox::geojson::multi_point multiPoint; if (jMultiPoint) { - auto jPositionListsList = MultiPoint::getCoordinates(env, jMultiPoint); - multiPoint = convertExplicit<mapbox::geojson::multi_point>(LineString::convert(env, jPositionListsList)); - jni::DeleteLocalRef(env, jPositionListsList); + auto jPointListsList = MultiPoint::coordinates(env, jMultiPoint); + multiPoint = convertExplicit<mapbox::geojson::multi_point>(LineString::convert(env, jPointListsList)); + jni::DeleteLocalRef(env, jPointListsList); } return multiPoint; } -jni::Object<java::util::List> MultiPoint::getCoordinates(jni::JNIEnv &env, jni::Object<MultiPoint> jMultiPoint) { - static auto method = MultiPoint::javaClass.GetMethod<jni::Object<java::util::List> ()>(env, "getCoordinates"); +jni::Object<java::util::List> MultiPoint::coordinates(jni::JNIEnv &env, jni::Object<MultiPoint> jMultiPoint) { + static auto method = MultiPoint::javaClass.GetMethod<jni::Object<java::util::List> ()>(env, "coordinates"); return jMultiPoint.Call(env, method); } diff --git a/platform/android/src/geojson/multi_point.hpp b/platform/android/src/geojson/multi_point.hpp index 7a698287eb..e893e879af 100644 --- a/platform/android/src/geojson/multi_point.hpp +++ b/platform/android/src/geojson/multi_point.hpp @@ -13,13 +13,13 @@ namespace geojson { class MultiPoint : private mbgl::util::noncopyable { public: - static constexpr auto Name() { return "com/mapbox/services/commons/geojson/MultiPoint"; }; + static constexpr auto Name() { return "com/mapbox/geojson/MultiPoint"; }; static constexpr auto Type() { return "MultiPoint"; }; static mapbox::geojson::multi_point convert(jni::JNIEnv&, jni::Object<MultiPoint>); - static jni::Object<java::util::List> getCoordinates(jni::JNIEnv&, jni::Object<MultiPoint>); + static jni::Object<java::util::List> coordinates(jni::JNIEnv&, jni::Object<MultiPoint>); static jni::Class<MultiPoint> javaClass; diff --git a/platform/android/src/geojson/multi_polygon.cpp b/platform/android/src/geojson/multi_polygon.cpp index a55884a110..aadba8c8a6 100644 --- a/platform/android/src/geojson/multi_polygon.cpp +++ b/platform/android/src/geojson/multi_polygon.cpp @@ -10,27 +10,27 @@ mapbox::geojson::multi_polygon MultiPolygon::convert(jni::JNIEnv &env, jni::Obje mapbox::geojson::multi_polygon multiPolygon; if (jMultiPolygon) { - auto jPositionListsListList = MultiPolygon::getCoordinates(env, jMultiPolygon); - auto jPositionListsListArray = java::util::List::toArray<java::util::List>(env, jPositionListsListList); + auto jPointListsListList = MultiPolygon::coordinates(env, jMultiPolygon); + auto jPointListsListArray = java::util::List::toArray<java::util::List>(env, jPointListsListList); - auto size = jPositionListsListArray.Length(env); + auto size = jPointListsListArray.Length(env); multiPolygon.reserve(size); for (size_t i = 0; i < size; i++) { - auto jPositionListsList = jPositionListsListArray.Get(env, i); + auto jPositionListsList = jPointListsListArray.Get(env, i); multiPolygon.push_back(Polygon::convert(env, jPositionListsList)); jni::DeleteLocalRef(env, jPositionListsList); } - jni::DeleteLocalRef(env, jPositionListsListList); - jni::DeleteLocalRef(env, jPositionListsListArray); + jni::DeleteLocalRef(env, jPointListsListArray); + jni::DeleteLocalRef(env, jPointListsListList); } return multiPolygon; } -jni::Object<java::util::List> MultiPolygon::getCoordinates(jni::JNIEnv &env, jni::Object<MultiPolygon> jPolygon) { - static auto method = MultiPolygon::javaClass.GetMethod<jni::Object<java::util::List> ()>(env, "getCoordinates"); +jni::Object<java::util::List> MultiPolygon::coordinates(jni::JNIEnv &env, jni::Object<MultiPolygon> jPolygon) { + static auto method = MultiPolygon::javaClass.GetMethod<jni::Object<java::util::List> ()>(env, "coordinates"); return jPolygon.Call(env, method); } diff --git a/platform/android/src/geojson/multi_polygon.hpp b/platform/android/src/geojson/multi_polygon.hpp index 1f144cffd2..6e1dfacfc8 100644 --- a/platform/android/src/geojson/multi_polygon.hpp +++ b/platform/android/src/geojson/multi_polygon.hpp @@ -13,13 +13,13 @@ namespace geojson { class MultiPolygon : private mbgl::util::noncopyable { public: - static constexpr auto Name() { return "com/mapbox/services/commons/geojson/MultiPolygon"; }; + static constexpr auto Name() { return "com/mapbox/geojson/MultiPolygon"; }; static constexpr auto Type() { return "MultiPolygon"; }; static mapbox::geojson::multi_polygon convert(jni::JNIEnv&, jni::Object<MultiPolygon>); - static jni::Object<java::util::List> getCoordinates(jni::JNIEnv&, jni::Object<MultiPolygon>); + static jni::Object<java::util::List> coordinates(jni::JNIEnv&, jni::Object<MultiPolygon>); static jni::Class<MultiPolygon> javaClass; diff --git a/platform/android/src/geojson/point.cpp b/platform/android/src/geojson/point.cpp index 3d19a119d7..d064547145 100644 --- a/platform/android/src/geojson/point.cpp +++ b/platform/android/src/geojson/point.cpp @@ -1,19 +1,49 @@ +#include <android/log.h> #include "point.hpp" +#include "../java/util.hpp" +#include "../java_types.hpp" +#include "../style/value.hpp" namespace mbgl { namespace android { namespace geojson { mapbox::geojson::point Point::convert(jni::JNIEnv &env, jni::Object<Point> jPoint) { - auto jPosition = Point::getPosition(env, jPoint); - auto point = Position::convert(env, jPosition); - jni::DeleteLocalRef(env, jPosition); + mapbox::geojson::point point; + + if (jPoint) { + auto jDoubleList = Point::coordinates(env, jPoint); + point = Point::convert(env, jDoubleList); + jni::DeleteLocalRef(env, jDoubleList); + } + + return point; +} + +mapbox::geojson::point Point::convert(jni::JNIEnv &env, jni::Object<java::util::List/*<Double>*/> jDoubleList) { + mapbox::geojson::point point; + + if (jDoubleList) { + auto jDoubleArray = java::util::List::toArray<jobject>(env, jDoubleList); + + auto lonObject = jDoubleArray.Get(env, 0); + auto latObject = jDoubleArray.Get(env, 1); + + point.x = jni::CallMethod<jni::jdouble>(env, lonObject, + *java::Number::doubleValueMethodId); + point.y = jni::CallMethod<jni::jdouble>(env, latObject, + *java::Number::doubleValueMethodId); + + jni::DeleteLocalRef(env, lonObject); + jni::DeleteLocalRef(env, latObject); + jni::DeleteLocalRef(env, jDoubleArray); + } return point; } -jni::Object<Position> Point::getPosition(JNIEnv& env, jni::Object<Point> jPoint) { - static auto method = Point::javaClass.GetMethod<jni::Object<Position> ()>(env, "getCoordinates"); - return jPoint.Call(env, method); +jni::Object<java::util::List> Point::coordinates(jni::JNIEnv &env, jni::Object<Point> jPoint) { + static auto method = Point::javaClass.GetMethod<jni::Object<java::util::List> ()>(env, "coordinates"); + return jPoint.Call(env, method); } void Point::registerNative(jni::JNIEnv &env) { diff --git a/platform/android/src/geojson/point.hpp b/platform/android/src/geojson/point.hpp index 64ac0af9cc..c6412299bf 100644 --- a/platform/android/src/geojson/point.hpp +++ b/platform/android/src/geojson/point.hpp @@ -3,23 +3,25 @@ #include <mbgl/util/geojson.hpp> #include <mbgl/util/noncopyable.hpp> -#include "position.hpp" - #include <jni/jni.hpp> +#include "../java/util.hpp" + namespace mbgl { namespace android { namespace geojson { class Point : private mbgl::util::noncopyable { public: - static constexpr auto Name() { return "com/mapbox/services/commons/geojson/Point"; }; + static constexpr auto Name() { return "com/mapbox/geojson/Point"; }; static constexpr auto Type() { return "Point"; }; static mapbox::geojson::point convert(jni::JNIEnv&, jni::Object<Point>); - static jni::Object<Position> getPosition(JNIEnv&, jni::Object<Point>); + static mapbox::geojson::point convert(jni::JNIEnv&, jni::Object<java::util::List/*<Double>*/>); + + static jni::Object<java::util::List> coordinates(JNIEnv&, jni::Object<Point>); static jni::Class<Point> javaClass; diff --git a/platform/android/src/geojson/polygon.cpp b/platform/android/src/geojson/polygon.cpp index ef00f9df3f..30ba996640 100644 --- a/platform/android/src/geojson/polygon.cpp +++ b/platform/android/src/geojson/polygon.cpp @@ -12,7 +12,7 @@ mapbox::geojson::polygon Polygon::convert(jni::JNIEnv &env, jni::Object<Polygon> mapbox::geojson::polygon polygon; if (jPolygon) { - auto jPositionListsList = Polygon::getCoordinates(env, jPolygon); + auto jPositionListsList = Polygon::coordinates(env, jPolygon); polygon = Polygon::convert(env, jPositionListsList); jni::DeleteLocalRef(env, jPositionListsList); } @@ -20,11 +20,11 @@ mapbox::geojson::polygon Polygon::convert(jni::JNIEnv &env, jni::Object<Polygon> return polygon; } -mapbox::geojson::polygon Polygon::convert(jni::JNIEnv &env, jni::Object<java::util::List/*<java::util::List<Position>>*/> jPositionListsList) { +mapbox::geojson::polygon Polygon::convert(jni::JNIEnv &env, jni::Object<java::util::List/*<java::util::List<Point>>*/> jPointListsList) { mapbox::geojson::polygon polygon; - if (jPositionListsList) { - auto multiLine = MultiLineString::convert(env, jPositionListsList); + if (jPointListsList) { + auto multiLine = MultiLineString::convert(env, jPointListsList); polygon.reserve(multiLine.size()); for (auto&& line : multiLine) { polygon.emplace_back(convertExplicit<mapbox::geojson::linear_ring>(std::move(line))); @@ -35,8 +35,8 @@ mapbox::geojson::polygon Polygon::convert(jni::JNIEnv &env, jni::Object<java::ut } -jni::Object<java::util::List> Polygon::getCoordinates(jni::JNIEnv &env, jni::Object<Polygon> jPolygon) { - static auto method = Polygon::javaClass.GetMethod<jni::Object<java::util::List> ()>(env, "getCoordinates"); +jni::Object<java::util::List> Polygon::coordinates(jni::JNIEnv &env, jni::Object<Polygon> jPolygon) { + static auto method = Polygon::javaClass.GetMethod<jni::Object<java::util::List> ()>(env, "coordinates"); return jPolygon.Call(env, method); } diff --git a/platform/android/src/geojson/polygon.hpp b/platform/android/src/geojson/polygon.hpp index e5362cedf1..a8b2b93827 100644 --- a/platform/android/src/geojson/polygon.hpp +++ b/platform/android/src/geojson/polygon.hpp @@ -13,15 +13,15 @@ namespace geojson { class Polygon : private mbgl::util::noncopyable { public: - static constexpr auto Name() { return "com/mapbox/services/commons/geojson/Polygon"; }; + static constexpr auto Name() { return "com/mapbox/geojson/Polygon"; }; static constexpr auto Type() { return "Polygon"; }; static mapbox::geojson::polygon convert(jni::JNIEnv &, jni::Object<Polygon>); - static mapbox::geojson::polygon convert(jni::JNIEnv&, jni::Object<java::util::List/*<java::util::List<Position>>*/>); + static mapbox::geojson::polygon convert(jni::JNIEnv&, jni::Object<java::util::List/*<java::util::List<Point>>*/>); - static jni::Object<java::util::List> getCoordinates(jni::JNIEnv&, jni::Object<Polygon>); + static jni::Object<java::util::List> coordinates(jni::JNIEnv&, jni::Object<Polygon>); static jni::Class<Polygon> javaClass; diff --git a/platform/android/src/geojson/position.cpp b/platform/android/src/geojson/position.cpp deleted file mode 100644 index c0e6da3887..0000000000 --- a/platform/android/src/geojson/position.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "position.hpp" - -namespace mbgl { -namespace android { -namespace geojson { - -mapbox::geojson::point Position::convert(jni::JNIEnv &env, jni::Object<Position> jPosition) { - static auto method = Position::javaClass.GetMethod<jni::Array<jdouble> ()>(env, "getCoordinates"); - // Array with 0: longitude, 1: latitude (and optionally 2: altitude) - auto coordinates = jPosition.Call(env, method); - jdouble lngLat[2]; - coordinates.GetRegion(env, 0, lngLat); - mapbox::geojson::point point(lngLat[0], lngLat[1]); - jni::DeleteLocalRef(env, coordinates); - return point; -} - -void Position::registerNative(jni::JNIEnv &env) { - // Lookup the class - javaClass = *jni::Class<Position>::Find(env).NewGlobalRef(env).release(); -} - -jni::Class<Position> Position::javaClass; - -} // namespace geojson -} // namespace android -} // namespace mbgl
\ No newline at end of file diff --git a/platform/android/src/geojson/position.hpp b/platform/android/src/geojson/position.hpp deleted file mode 100644 index 7017a8172a..0000000000 --- a/platform/android/src/geojson/position.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include <mbgl/util/geojson.hpp> -#include <mbgl/util/noncopyable.hpp> - -#include <jni/jni.hpp> - -namespace mbgl { -namespace android { -namespace geojson { - -class Position : private mbgl::util::noncopyable { -public: - static constexpr auto Name() { return "com/mapbox/services/commons/models/Position"; }; - - static constexpr auto Type() { return "Position"; }; - - static mapbox::geojson::point convert(jni::JNIEnv&, jni::Object<Position>); - - static jni::Class<Position> javaClass; - - static void registerNative(jni::JNIEnv&); -}; - -} // namespace geojson -} // namespace android -} // namespace mbgl
\ No newline at end of file diff --git a/platform/android/src/jni.cpp b/platform/android/src/jni.cpp index e75a9c6985..c2fd1c95ad 100755 --- a/platform/android/src/jni.cpp +++ b/platform/android/src/jni.cpp @@ -20,7 +20,6 @@ #include "geojson/multi_polygon.hpp" #include "geojson/point.hpp" #include "geojson/polygon.hpp" -#include "geojson/position.hpp" #include "geometry/lat_lng.hpp" #include "geometry/lat_lng_bounds.hpp" #include "geometry/lat_lng_quad.hpp" @@ -47,7 +46,7 @@ #include "style/functions/interval_stops.hpp" #include "style/functions/stop.hpp" #include "style/layers/layers.hpp" -#include "style/sources/sources.hpp" +#include "style/sources/source.hpp" #include "style/light.hpp" #include "snapshotter/map_snapshotter.hpp" #include "snapshotter/map_snapshot.hpp" @@ -128,7 +127,6 @@ void registerNatives(JavaVM *vm) { geojson::MultiPolygon::registerNative(env); geojson::Point::registerNative(env); geojson::Polygon::registerNative(env); - geojson::Position::registerNative(env); // Geometry LatLng::registerNative(env); @@ -162,7 +160,7 @@ void registerNatives(JavaVM *vm) { // Style TransitionOptions::registerNative(env); registerNativeLayers(env); - registerNativeSources(env); + Source::registerNative(env); Light::registerNative(env); Position::registerNative(env); Stop::registerNative(env); diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp index 04cbb21927..67fc132204 100755 --- a/platform/android/src/native_map_view.cpp +++ b/platform/android/src/native_map_view.cpp @@ -450,7 +450,7 @@ jni::Array<jni::jlong> NativeMapView::addMarkers(jni::JNIEnv& env, jni::Array<jn } void NativeMapView::onLowMemory(JNIEnv&) { - rendererFrontend->onLowMemory(); + rendererFrontend->reduceMemoryUse(); } using DebugOptions = mbgl::MapDebugOptions; @@ -856,9 +856,7 @@ jni::Array<jni::Object<Source>> NativeMapView::getSources(JNIEnv& env) { jni::Array<jni::Object<Source>> jSources = jni::Array<jni::Object<Source>>::New(env, sources.size(), Source::javaClass); int index = 0; for (auto source : sources) { - auto jSource = jni::Object<Source>(createJavaSourcePeer(env, *rendererFrontend, *source)); - jSources.Set(env, index, jSource); - jni::DeleteLocalRef(env, jSource); + jSources.Set(env, index, Source::peerForCoreSource(env, *source, *rendererFrontend)); index++; } @@ -874,38 +872,25 @@ jni::Object<Source> NativeMapView::getSource(JNIEnv& env, jni::String sourceId) } // Create and return the source's native peer - return jni::Object<Source>(createJavaSourcePeer(env, *rendererFrontend, *coreSource)); + return Source::peerForCoreSource(env, *coreSource, *rendererFrontend); } -void NativeMapView::addSource(JNIEnv& env, jni::jlong sourcePtr) { +void NativeMapView::addSource(JNIEnv& env, jni::Object<Source> obj, jlong sourcePtr) { assert(sourcePtr != 0); Source *source = reinterpret_cast<Source *>(sourcePtr); try { - source->addToMap(*map); - source->setRendererFrontend(*rendererFrontend); + source->addToMap(env, obj, *map, *rendererFrontend); } catch (const std::runtime_error& error) { jni::ThrowNew(env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/sources/CannotAddSourceException"), error.what()); } } -jni::Object<Source> NativeMapView::removeSourceById(JNIEnv& env, jni::String id) { - std::unique_ptr<mbgl::style::Source> coreSource = map->getStyle().removeSource(jni::Make<std::string>(env, id)); - if (coreSource) { - return jni::Object<Source>(createJavaSourcePeer(env, *rendererFrontend, *coreSource)); - } else { - return jni::Object<Source>(); - } -} - -void NativeMapView::removeSource(JNIEnv&, jlong sourcePtr) { +void NativeMapView::removeSource(JNIEnv& env, jni::Object<Source> obj, jlong sourcePtr) { assert(sourcePtr != 0); mbgl::android::Source *source = reinterpret_cast<mbgl::android::Source *>(sourcePtr); - std::unique_ptr<mbgl::style::Source> coreSource = map->getStyle().removeSource(source->get().getID()); - if (coreSource) { - source->setSource(std::move(coreSource)); - } + source->removeFromMap(env, obj, *map); } void NativeMapView::addImage(JNIEnv& env, jni::String name, jni::jint w, jni::jint h, jni::jfloat scale, jni::Array<jbyte> pixels) { @@ -1048,7 +1033,6 @@ void NativeMapView::registerNative(jni::JNIEnv& env) { METHOD(&NativeMapView::getSources, "nativeGetSources"), METHOD(&NativeMapView::getSource, "nativeGetSource"), METHOD(&NativeMapView::addSource, "nativeAddSource"), - METHOD(&NativeMapView::removeSourceById, "nativeRemoveSourceById"), METHOD(&NativeMapView::removeSource, "nativeRemoveSource"), METHOD(&NativeMapView::addImage, "nativeAddImage"), METHOD(&NativeMapView::addImages, "nativeAddImages"), diff --git a/platform/android/src/native_map_view.hpp b/platform/android/src/native_map_view.hpp index d7e3b17b99..507d77ac5f 100755 --- a/platform/android/src/native_map_view.hpp +++ b/platform/android/src/native_map_view.hpp @@ -19,7 +19,7 @@ #include "geometry/lat_lng.hpp" #include "geometry/projected_meters.hpp" #include "style/layers/layers.hpp" -#include "style/sources/sources.hpp" +#include "style/sources/source.hpp" #include "geometry/lat_lng_bounds.hpp" #include "map/camera_position.hpp" #include "map/image.hpp" @@ -230,11 +230,11 @@ public: jni::Object<Source> getSource(JNIEnv&, jni::String); - void addSource(JNIEnv&, jni::jlong); + void addSource(JNIEnv&, jni::Object<Source>, jlong nativePtr); jni::Object<Source> removeSourceById(JNIEnv&, jni::String); - void removeSource(JNIEnv&, jlong); + void removeSource(JNIEnv&, jni::Object<Source>, jlong nativePtr); void addImage(JNIEnv&, jni::String, jni::jint, jni::jint, jni::jfloat, jni::Array<jbyte>); diff --git a/platform/android/src/run_loop.cpp b/platform/android/src/run_loop.cpp index 1d284a9e72..34366d836a 100644 --- a/platform/android/src/run_loop.cpp +++ b/platform/android/src/run_loop.cpp @@ -216,11 +216,8 @@ LOOP_HANDLE RunLoop::getLoopHandle() { return Get()->impl.get(); } -void RunLoop::push(std::shared_ptr<WorkTask> task) { - withMutex([&] { - queue.push(std::move(task)); - impl->wake(); - }); +void RunLoop::wake() { + impl->wake(); } void RunLoop::run() { diff --git a/platform/android/src/style/android_conversion.hpp b/platform/android/src/style/android_conversion.hpp index 082fe411e2..510a9f8444 100644 --- a/platform/android/src/style/android_conversion.hpp +++ b/platform/android/src/style/android_conversion.hpp @@ -4,8 +4,9 @@ #include <mbgl/util/feature.hpp> #include <mbgl/util/logging.hpp> -#include <mbgl/style/conversion.hpp> #include <mbgl/util/optional.hpp> +#include <mbgl/style/conversion.hpp> +#include <mbgl/style/conversion/geojson.hpp> #include <jni/jni.hpp> @@ -13,89 +14,105 @@ namespace mbgl { namespace style { namespace conversion { -inline bool isUndefined(const mbgl::android::Value& value) { - return value.isNull(); -} +template <> +class ConversionTraits<mbgl::android::Value> { +public: + static bool isUndefined(const mbgl::android::Value& value) { + return value.isNull(); + } -inline bool isArray(const mbgl::android::Value& value) { - return value.isArray(); -} + static bool isArray(const mbgl::android::Value& value) { + return value.isArray(); + } -inline bool isObject(const mbgl::android::Value& value) { - return value.isObject(); -} + static bool isObject(const mbgl::android::Value& value) { + return value.isObject(); + } -inline std::size_t arrayLength(const mbgl::android::Value& value) { - return value.getLength();; -} + static std::size_t arrayLength(const mbgl::android::Value& value) { + return value.getLength();; + } -inline mbgl::android::Value arrayMember(const mbgl::android::Value& value, std::size_t i) { - return value.get(i); -} + static mbgl::android::Value arrayMember(const mbgl::android::Value& value, std::size_t i) { + return value.get(i); + } -inline optional<mbgl::android::Value> objectMember(const mbgl::android::Value& value, const char* key) { - mbgl::android::Value member = value.get(key); + static optional<mbgl::android::Value> objectMember(const mbgl::android::Value& value, const char* key) { + mbgl::android::Value member = value.get(key); + if (!member.isNull()) { + return member; + } else { + return {}; + } + } - if (!member.isNull()) { - return member; - } else { + template <class Fn> + static optional<Error> eachMember(const mbgl::android::Value&, Fn&&) { + // TODO + mbgl::Log::Warning(mbgl::Event::Android, "eachMember not implemented"); return {}; } -} -template <class Fn> -optional<Error> eachMember(const mbgl::android::Value&, Fn&&) { - // TODO - mbgl::Log::Warning(mbgl::Event::Android, "eachMember not implemented"); - return {}; -} + static optional<bool> toBool(const mbgl::android::Value& value) { + if (value.isBool()) { + return value.toBool(); + } else { + return {}; + } + } -inline optional<bool> toBool(const mbgl::android::Value& value) { - if (value.isBool()) { - return value.toBool(); - } else { - return {}; + static optional<float> toNumber(const mbgl::android::Value& value) { + if (value.isNumber()) { + auto num = value.toFloat(); + return num; + } else { + return {}; + } } -} -inline optional<float> toNumber(const mbgl::android::Value& value) { - if (value.isNumber()) { - auto num = value.toFloat(); - return num; - } else { - return {}; + static optional<double> toDouble(const mbgl::android::Value& value) { + if (value.isNumber()) { + return value.toDouble(); + } else { + return {}; + } } -} -inline optional<double> toDouble(const mbgl::android::Value& value) { - if (value.isNumber()) { - return value.toDouble(); - } else { - return {}; + static optional<std::string> toString(const mbgl::android::Value& value) { + if (value.isString()) { + return value.toString(); + } else { + return {}; + } } -} -inline optional<std::string> toString(const mbgl::android::Value& value) { - if (value.isString()) { - return value.toString(); - } else { - return {}; + static optional<Value> toValue(const mbgl::android::Value& value) { + if (value.isNull()) { + return {}; + } else if (value.isBool()) { + return { value.toBool() }; + } else if (value.isString()) { + return { value.toString() }; + } else if (value.isNumber()) { + auto doubleVal = value.toDouble(); + return { doubleVal - (int) doubleVal > 0.0 ? doubleVal : value.toLong() }; + } else { + return {}; + } } -} -inline optional<Value> toValue(const mbgl::android::Value& value) { - if (value.isNull()) { - return {}; - } else if (value.isBool()) { - return { value.toBool() }; - } else if (value.isString()) { - return { value.toString() }; - } else if (value.isNumber()) { - auto doubleVal = value.toDouble(); - return { doubleVal - (int) doubleVal > 0.0 ? doubleVal : value.toLong() }; - } else { - return {}; + static optional<GeoJSON> toGeoJSON(const mbgl::android::Value &value, Error &error) { + if (value.isNull() || !value.isString()) { + error = { "no json data found" }; + return {}; + } + return parseGeoJSON(value.toString(), error); } +}; + +template <class T, class...Args> +optional<T> convert(mbgl::android::Value&& value, Error& error, Args&&...args) { + return convert<T>(Convertible(std::move(value)), error, std::forward<Args>(args)...); } } // namespace conversion diff --git a/platform/android/src/style/conversion/filter.hpp b/platform/android/src/style/conversion/filter.hpp index 1f0abcf3a4..c154e88e7c 100644 --- a/platform/android/src/style/conversion/filter.hpp +++ b/platform/android/src/style/conversion/filter.hpp @@ -16,9 +16,8 @@ namespace conversion { inline optional<mbgl::style::Filter> toFilter(jni::JNIEnv& env, jni::Array<jni::Object<>> jfilter) { mbgl::optional<mbgl::style::Filter> filter; if (jfilter) { - Value filterValue(env, jfilter); mbgl::style::conversion::Error error; - auto converted = mbgl::style::conversion::convert<mbgl::style::Filter>(filterValue, 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); } diff --git a/platform/android/src/style/conversion/geojson.hpp b/platform/android/src/style/conversion/geojson.hpp deleted file mode 100644 index 748fe7361e..0000000000 --- a/platform/android/src/style/conversion/geojson.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<GeoJSON> Converter<GeoJSON>::operator()(const mbgl::android::Value& value, Error& error) const { - if(value.isNull() || !value.isString()) { - error = { "no json data found" }; - return {}; - } - - return convert<GeoJSON>(value.toString(), error); -} - -} // namespace conversion -} // namespace style -} // namespace mbgl diff --git a/platform/android/src/style/conversion/types.hpp b/platform/android/src/style/conversion/types.hpp index 375d1a33aa..8a75b870b3 100644 --- a/platform/android/src/style/conversion/types.hpp +++ b/platform/android/src/style/conversion/types.hpp @@ -93,6 +93,13 @@ struct Converter<jni::jobject*, mbgl::style::CirclePitchScaleType> { }; 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)); diff --git a/platform/android/src/style/conversion/types_string_values.hpp b/platform/android/src/style/conversion/types_string_values.hpp index a19ca33a2f..7e4fd4a7f7 100644 --- a/platform/android/src/style/conversion/types_string_values.hpp +++ b/platform/android/src/style/conversion/types_string_values.hpp @@ -206,6 +206,20 @@ namespace conversion { } } + // 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) { diff --git a/platform/android/src/style/conversion/url_or_tileset.hpp b/platform/android/src/style/conversion/url_or_tileset.hpp index 00ef913d41..92c1182a63 100644 --- a/platform/android/src/style/conversion/url_or_tileset.hpp +++ b/platform/android/src/style/conversion/url_or_tileset.hpp @@ -17,18 +17,19 @@ 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(const Value& value) { +inline variant<std::string, Tileset> convertURLOrTileset(mbgl::android::Value&& value) { using namespace mbgl::style::conversion; - if (isObject(value)) { + const Convertible convertible(std::move(value)); + if (isObject(convertible)) { Error error; - optional<Tileset> tileset = convert<Tileset>(value, error); + optional<Tileset> tileset = convert<Tileset>(convertible, error); if (!tileset) { throw std::logic_error(error.message); } return { *tileset }; } else { - return { *toString(value) }; + return { *toString(convertible) }; } } diff --git a/platform/android/src/style/layers/heatmap_layer.cpp b/platform/android/src/style/layers/heatmap_layer.cpp new file mode 100644 index 0000000000..609499ec93 --- /dev/null +++ b/platform/android/src/style/layers/heatmap_layer.cpp @@ -0,0 +1,134 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#include "heatmap_layer.hpp" + +#include <string> + +#include "../conversion/property_value.hpp" +#include "../conversion/transition_options.hpp" + +namespace mbgl { +namespace android { + + /** + * Creates an owning peer object (for layers not attached to the map) from the JVM side + */ + HeatmapLayer::HeatmapLayer(jni::JNIEnv& env, jni::String layerId, jni::String sourceId) + : Layer(env, std::make_unique<mbgl::style::HeatmapLayer>(jni::Make<std::string>(env, layerId), jni::Make<std::string>(env, sourceId))) { + } + + /** + * Creates a non-owning peer object (for layers currently attached to the map) + */ + HeatmapLayer::HeatmapLayer(mbgl::Map& map, mbgl::style::HeatmapLayer& coreLayer) + : Layer(map, coreLayer) { + } + + /** + * Creates an owning peer object (for layers not attached to the map) + */ + HeatmapLayer::HeatmapLayer(mbgl::Map& map, std::unique_ptr<mbgl::style::HeatmapLayer> coreLayer) + : Layer(map, std::move(coreLayer)) { + } + + HeatmapLayer::~HeatmapLayer() = default; + + // Property getters + + jni::Object<jni::ObjectTag> HeatmapLayer::getHeatmapRadius(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::HeatmapLayer>()->HeatmapLayer::getHeatmapRadius()); + return jni::Object<jni::ObjectTag>(*converted); + } + + jni::Object<TransitionOptions> HeatmapLayer::getHeatmapRadiusTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = layer.as<mbgl::style::HeatmapLayer>()->HeatmapLayer::getHeatmapRadiusTransition(); + return *convert<jni::Object<TransitionOptions>>(env, options); + } + + void HeatmapLayer::setHeatmapRadiusTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + layer.as<mbgl::style::HeatmapLayer>()->HeatmapLayer::setHeatmapRadiusTransition(options); + } + + jni::Object<jni::ObjectTag> HeatmapLayer::getHeatmapWeight(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::HeatmapLayer>()->HeatmapLayer::getHeatmapWeight()); + return jni::Object<jni::ObjectTag>(*converted); + } + + jni::Object<jni::ObjectTag> HeatmapLayer::getHeatmapIntensity(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::HeatmapLayer>()->HeatmapLayer::getHeatmapIntensity()); + return jni::Object<jni::ObjectTag>(*converted); + } + + jni::Object<TransitionOptions> HeatmapLayer::getHeatmapIntensityTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = layer.as<mbgl::style::HeatmapLayer>()->HeatmapLayer::getHeatmapIntensityTransition(); + return *convert<jni::Object<TransitionOptions>>(env, options); + } + + void HeatmapLayer::setHeatmapIntensityTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + layer.as<mbgl::style::HeatmapLayer>()->HeatmapLayer::setHeatmapIntensityTransition(options); + } + + jni::Object<jni::ObjectTag> HeatmapLayer::getHeatmapOpacity(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::HeatmapLayer>()->HeatmapLayer::getHeatmapOpacity()); + return jni::Object<jni::ObjectTag>(*converted); + } + + jni::Object<TransitionOptions> HeatmapLayer::getHeatmapOpacityTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = layer.as<mbgl::style::HeatmapLayer>()->HeatmapLayer::getHeatmapOpacityTransition(); + return *convert<jni::Object<TransitionOptions>>(env, options); + } + + void HeatmapLayer::setHeatmapOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + layer.as<mbgl::style::HeatmapLayer>()->HeatmapLayer::setHeatmapOpacityTransition(options); + } + + + jni::Class<HeatmapLayer> HeatmapLayer::javaClass; + + jni::jobject* HeatmapLayer::createJavaPeer(jni::JNIEnv& env) { + static auto constructor = HeatmapLayer::javaClass.template GetConstructor<jni::jlong>(env); + return HeatmapLayer::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this)); + } + + void HeatmapLayer::registerNative(jni::JNIEnv& env) { + // Lookup the class + HeatmapLayer::javaClass = *jni::Class<HeatmapLayer>::Find(env).NewGlobalRef(env).release(); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name) + + // Register the peer + jni::RegisterNativePeer<HeatmapLayer>( + env, HeatmapLayer::javaClass, "nativePtr", + std::make_unique<HeatmapLayer, JNIEnv&, jni::String, jni::String>, + "initialize", + "finalize", + METHOD(&HeatmapLayer::getHeatmapRadiusTransition, "nativeGetHeatmapRadiusTransition"), + METHOD(&HeatmapLayer::setHeatmapRadiusTransition, "nativeSetHeatmapRadiusTransition"), + METHOD(&HeatmapLayer::getHeatmapRadius, "nativeGetHeatmapRadius"), + METHOD(&HeatmapLayer::getHeatmapWeight, "nativeGetHeatmapWeight"), + METHOD(&HeatmapLayer::getHeatmapIntensityTransition, "nativeGetHeatmapIntensityTransition"), + METHOD(&HeatmapLayer::setHeatmapIntensityTransition, "nativeSetHeatmapIntensityTransition"), + METHOD(&HeatmapLayer::getHeatmapIntensity, "nativeGetHeatmapIntensity"), + METHOD(&HeatmapLayer::getHeatmapOpacityTransition, "nativeGetHeatmapOpacityTransition"), + METHOD(&HeatmapLayer::setHeatmapOpacityTransition, "nativeSetHeatmapOpacityTransition"), + METHOD(&HeatmapLayer::getHeatmapOpacity, "nativeGetHeatmapOpacity")); + } + +} // namespace android +} // namespace mbgl diff --git a/platform/android/src/style/layers/heatmap_layer.hpp b/platform/android/src/style/layers/heatmap_layer.hpp new file mode 100644 index 0000000000..85f9f0292e --- /dev/null +++ b/platform/android/src/style/layers/heatmap_layer.hpp @@ -0,0 +1,50 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#pragma once + +#include "layer.hpp" +#include "../transition_options.hpp" +#include <mbgl/style/layers/heatmap_layer.hpp> +#include <jni/jni.hpp> + +namespace mbgl { +namespace android { + +class HeatmapLayer : public Layer { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/HeatmapLayer"; }; + + static jni::Class<HeatmapLayer> javaClass; + + static void registerNative(jni::JNIEnv&); + + HeatmapLayer(jni::JNIEnv&, jni::String, jni::String); + + HeatmapLayer(mbgl::Map&, mbgl::style::HeatmapLayer&); + + HeatmapLayer(mbgl::Map&, std::unique_ptr<mbgl::style::HeatmapLayer>); + + ~HeatmapLayer(); + + // Properties + + jni::Object<jni::ObjectTag> getHeatmapRadius(jni::JNIEnv&); + void setHeatmapRadiusTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Object<TransitionOptions> getHeatmapRadiusTransition(jni::JNIEnv&); + + jni::Object<jni::ObjectTag> getHeatmapWeight(jni::JNIEnv&); + + jni::Object<jni::ObjectTag> getHeatmapIntensity(jni::JNIEnv&); + void setHeatmapIntensityTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Object<TransitionOptions> getHeatmapIntensityTransition(jni::JNIEnv&); + + jni::Object<jni::ObjectTag> getHeatmapOpacity(jni::JNIEnv&); + void setHeatmapOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Object<TransitionOptions> getHeatmapOpacityTransition(jni::JNIEnv&); + jni::jobject* createJavaPeer(jni::JNIEnv&); + +}; // class HeatmapLayer + +} // namespace android +} // namespace mbgl diff --git a/platform/android/src/style/layers/hillshade_layer.cpp b/platform/android/src/style/layers/hillshade_layer.cpp new file mode 100644 index 0000000000..d98e3ee074 --- /dev/null +++ b/platform/android/src/style/layers/hillshade_layer.cpp @@ -0,0 +1,163 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#include "hillshade_layer.hpp" + +#include <string> + +#include "../conversion/property_value.hpp" +#include "../conversion/transition_options.hpp" + +namespace mbgl { +namespace android { + + /** + * Creates an owning peer object (for layers not attached to the map) from the JVM side + */ + HillshadeLayer::HillshadeLayer(jni::JNIEnv& env, jni::String layerId, jni::String sourceId) + : Layer(env, std::make_unique<mbgl::style::HillshadeLayer>(jni::Make<std::string>(env, layerId), jni::Make<std::string>(env, sourceId))) { + } + + /** + * Creates a non-owning peer object (for layers currently attached to the map) + */ + HillshadeLayer::HillshadeLayer(mbgl::Map& map, mbgl::style::HillshadeLayer& coreLayer) + : Layer(map, coreLayer) { + } + + /** + * Creates an owning peer object (for layers not attached to the map) + */ + HillshadeLayer::HillshadeLayer(mbgl::Map& map, std::unique_ptr<mbgl::style::HillshadeLayer> coreLayer) + : Layer(map, std::move(coreLayer)) { + } + + HillshadeLayer::~HillshadeLayer() = default; + + // Property getters + + jni::Object<jni::ObjectTag> HillshadeLayer::getHillshadeIlluminationDirection(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::HillshadeLayer>()->HillshadeLayer::getHillshadeIlluminationDirection()); + return jni::Object<jni::ObjectTag>(*converted); + } + + jni::Object<jni::ObjectTag> HillshadeLayer::getHillshadeIlluminationAnchor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::HillshadeLayer>()->HillshadeLayer::getHillshadeIlluminationAnchor()); + return jni::Object<jni::ObjectTag>(*converted); + } + + jni::Object<jni::ObjectTag> HillshadeLayer::getHillshadeExaggeration(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::HillshadeLayer>()->HillshadeLayer::getHillshadeExaggeration()); + return jni::Object<jni::ObjectTag>(*converted); + } + + jni::Object<TransitionOptions> HillshadeLayer::getHillshadeExaggerationTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = layer.as<mbgl::style::HillshadeLayer>()->HillshadeLayer::getHillshadeExaggerationTransition(); + return *convert<jni::Object<TransitionOptions>>(env, options); + } + + void HillshadeLayer::setHillshadeExaggerationTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + layer.as<mbgl::style::HillshadeLayer>()->HillshadeLayer::setHillshadeExaggerationTransition(options); + } + + jni::Object<jni::ObjectTag> HillshadeLayer::getHillshadeShadowColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::HillshadeLayer>()->HillshadeLayer::getHillshadeShadowColor()); + return jni::Object<jni::ObjectTag>(*converted); + } + + jni::Object<TransitionOptions> HillshadeLayer::getHillshadeShadowColorTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = layer.as<mbgl::style::HillshadeLayer>()->HillshadeLayer::getHillshadeShadowColorTransition(); + return *convert<jni::Object<TransitionOptions>>(env, options); + } + + void HillshadeLayer::setHillshadeShadowColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + layer.as<mbgl::style::HillshadeLayer>()->HillshadeLayer::setHillshadeShadowColorTransition(options); + } + + jni::Object<jni::ObjectTag> HillshadeLayer::getHillshadeHighlightColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::HillshadeLayer>()->HillshadeLayer::getHillshadeHighlightColor()); + return jni::Object<jni::ObjectTag>(*converted); + } + + jni::Object<TransitionOptions> HillshadeLayer::getHillshadeHighlightColorTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = layer.as<mbgl::style::HillshadeLayer>()->HillshadeLayer::getHillshadeHighlightColorTransition(); + return *convert<jni::Object<TransitionOptions>>(env, options); + } + + void HillshadeLayer::setHillshadeHighlightColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + layer.as<mbgl::style::HillshadeLayer>()->HillshadeLayer::setHillshadeHighlightColorTransition(options); + } + + jni::Object<jni::ObjectTag> HillshadeLayer::getHillshadeAccentColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::HillshadeLayer>()->HillshadeLayer::getHillshadeAccentColor()); + return jni::Object<jni::ObjectTag>(*converted); + } + + jni::Object<TransitionOptions> HillshadeLayer::getHillshadeAccentColorTransition(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + mbgl::style::TransitionOptions options = layer.as<mbgl::style::HillshadeLayer>()->HillshadeLayer::getHillshadeAccentColorTransition(); + return *convert<jni::Object<TransitionOptions>>(env, options); + } + + void HillshadeLayer::setHillshadeAccentColorTransition(jni::JNIEnv&, jlong duration, jlong delay) { + mbgl::style::TransitionOptions options; + options.duration.emplace(mbgl::Milliseconds(duration)); + options.delay.emplace(mbgl::Milliseconds(delay)); + layer.as<mbgl::style::HillshadeLayer>()->HillshadeLayer::setHillshadeAccentColorTransition(options); + } + + + jni::Class<HillshadeLayer> HillshadeLayer::javaClass; + + jni::jobject* HillshadeLayer::createJavaPeer(jni::JNIEnv& env) { + static auto constructor = HillshadeLayer::javaClass.template GetConstructor<jni::jlong>(env); + return HillshadeLayer::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this)); + } + + void HillshadeLayer::registerNative(jni::JNIEnv& env) { + // Lookup the class + HillshadeLayer::javaClass = *jni::Class<HillshadeLayer>::Find(env).NewGlobalRef(env).release(); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name) + + // Register the peer + jni::RegisterNativePeer<HillshadeLayer>( + env, HillshadeLayer::javaClass, "nativePtr", + std::make_unique<HillshadeLayer, JNIEnv&, jni::String, jni::String>, + "initialize", + "finalize", + METHOD(&HillshadeLayer::getHillshadeIlluminationDirection, "nativeGetHillshadeIlluminationDirection"), + METHOD(&HillshadeLayer::getHillshadeIlluminationAnchor, "nativeGetHillshadeIlluminationAnchor"), + METHOD(&HillshadeLayer::getHillshadeExaggerationTransition, "nativeGetHillshadeExaggerationTransition"), + METHOD(&HillshadeLayer::setHillshadeExaggerationTransition, "nativeSetHillshadeExaggerationTransition"), + METHOD(&HillshadeLayer::getHillshadeExaggeration, "nativeGetHillshadeExaggeration"), + METHOD(&HillshadeLayer::getHillshadeShadowColorTransition, "nativeGetHillshadeShadowColorTransition"), + METHOD(&HillshadeLayer::setHillshadeShadowColorTransition, "nativeSetHillshadeShadowColorTransition"), + METHOD(&HillshadeLayer::getHillshadeShadowColor, "nativeGetHillshadeShadowColor"), + METHOD(&HillshadeLayer::getHillshadeHighlightColorTransition, "nativeGetHillshadeHighlightColorTransition"), + METHOD(&HillshadeLayer::setHillshadeHighlightColorTransition, "nativeSetHillshadeHighlightColorTransition"), + METHOD(&HillshadeLayer::getHillshadeHighlightColor, "nativeGetHillshadeHighlightColor"), + METHOD(&HillshadeLayer::getHillshadeAccentColorTransition, "nativeGetHillshadeAccentColorTransition"), + METHOD(&HillshadeLayer::setHillshadeAccentColorTransition, "nativeSetHillshadeAccentColorTransition"), + METHOD(&HillshadeLayer::getHillshadeAccentColor, "nativeGetHillshadeAccentColor")); + } + +} // namespace android +} // namespace mbgl diff --git a/platform/android/src/style/layers/hillshade_layer.hpp b/platform/android/src/style/layers/hillshade_layer.hpp new file mode 100644 index 0000000000..4b68251775 --- /dev/null +++ b/platform/android/src/style/layers/hillshade_layer.hpp @@ -0,0 +1,56 @@ +// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. + +#pragma once + +#include "layer.hpp" +#include "../transition_options.hpp" +#include <mbgl/style/layers/hillshade_layer.hpp> +#include <jni/jni.hpp> + +namespace mbgl { +namespace android { + +class HillshadeLayer : public Layer { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/HillshadeLayer"; }; + + static jni::Class<HillshadeLayer> javaClass; + + static void registerNative(jni::JNIEnv&); + + HillshadeLayer(jni::JNIEnv&, jni::String, jni::String); + + HillshadeLayer(mbgl::Map&, mbgl::style::HillshadeLayer&); + + HillshadeLayer(mbgl::Map&, std::unique_ptr<mbgl::style::HillshadeLayer>); + + ~HillshadeLayer(); + + // Properties + + jni::Object<jni::ObjectTag> getHillshadeIlluminationDirection(jni::JNIEnv&); + + jni::Object<jni::ObjectTag> getHillshadeIlluminationAnchor(jni::JNIEnv&); + + jni::Object<jni::ObjectTag> getHillshadeExaggeration(jni::JNIEnv&); + void setHillshadeExaggerationTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Object<TransitionOptions> getHillshadeExaggerationTransition(jni::JNIEnv&); + + jni::Object<jni::ObjectTag> getHillshadeShadowColor(jni::JNIEnv&); + void setHillshadeShadowColorTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Object<TransitionOptions> getHillshadeShadowColorTransition(jni::JNIEnv&); + + jni::Object<jni::ObjectTag> getHillshadeHighlightColor(jni::JNIEnv&); + void setHillshadeHighlightColorTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Object<TransitionOptions> getHillshadeHighlightColorTransition(jni::JNIEnv&); + + jni::Object<jni::ObjectTag> getHillshadeAccentColor(jni::JNIEnv&); + void setHillshadeAccentColorTransition(jni::JNIEnv&, jlong duration, jlong delay); + jni::Object<TransitionOptions> getHillshadeAccentColorTransition(jni::JNIEnv&); + jni::jobject* createJavaPeer(jni::JNIEnv&); + +}; // class HillshadeLayer + +} // namespace android +} // namespace mbgl diff --git a/platform/android/src/style/layers/layer.cpp b/platform/android/src/style/layers/layer.cpp index 02a1f0be82..29530879a5 100644 --- a/platform/android/src/style/layers/layer.cpp +++ b/platform/android/src/style/layers/layer.cpp @@ -4,11 +4,22 @@ #include <jni/jni.hpp> #include <mbgl/style/style.hpp> +#include <mbgl/style/filter.hpp> #include <mbgl/style/transition_options.hpp> +#include <mbgl/style/layers/background_layer.hpp> +#include <mbgl/style/layers/circle_layer.hpp> +#include <mbgl/style/layers/fill_layer.hpp> +#include <mbgl/style/layers/fill_extrusion_layer.hpp> +#include <mbgl/style/layers/heatmap_layer.hpp> +#include <mbgl/style/layers/hillshade_layer.hpp> +#include <mbgl/style/layers/line_layer.hpp> +#include <mbgl/style/layers/raster_layer.hpp> +#include <mbgl/style/layers/symbol_layer.hpp> #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> @@ -78,10 +89,8 @@ namespace android { } void Layer::setLayoutProperty(jni::JNIEnv& env, jni::String jname, jni::Object<> jvalue) { - Value value(env, jvalue); - // Convert and set property - optional<mbgl::style::conversion::Error> error = mbgl::style::conversion::setLayoutProperty(layer, jni::Make<std::string>(env, jname), value); + optional<mbgl::style::conversion::Error> error = mbgl::style::conversion::setLayoutProperty(layer, 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; @@ -89,10 +98,8 @@ namespace android { } void Layer::setPaintProperty(jni::JNIEnv& env, jni::String jname, jni::Object<> jvalue) { - Value value(env, jvalue); - // Convert and set property - optional<mbgl::style::conversion::Error> error = mbgl::style::conversion::setPaintProperty(layer, jni::Make<std::string>(env, jname), value); + optional<mbgl::style::conversion::Error> error = mbgl::style::conversion::setPaintProperty(layer, 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; @@ -105,6 +112,7 @@ namespace android { void operator()(style::BackgroundLayer&) { Log::Warning(mbgl::Event::JNI, "BackgroundLayer doesn't support filters"); } void operator()(style::CustomLayer&) { Log::Warning(mbgl::Event::JNI, "CustomLayer doesn't support filters"); } void operator()(style::RasterLayer&) { Log::Warning(mbgl::Event::JNI, "RasterLayer doesn't support filters"); } + void operator()(style::HillshadeLayer&) { Log::Warning(mbgl::Event::JNI, "HillshadeLayer doesn't support filters"); } template <class LayerType> void operator()(LayerType& layer) { @@ -116,10 +124,8 @@ namespace android { using namespace mbgl::style; using namespace mbgl::style::conversion; - Value wrapped(env, jfilter); - Error error; - optional<Filter> converted = convert<Filter>(wrapped, error); + optional<Filter> converted = convert<Filter>(Value(env, jfilter), error); if (!converted) { mbgl::Log::Error(mbgl::Event::JNI, "Error setting filter: " + error.message); return; @@ -134,6 +140,7 @@ namespace android { void operator()(style::BackgroundLayer&) { Log::Warning(mbgl::Event::JNI, "BackgroundLayer doesn't support source layer"); } void operator()(style::CustomLayer&) { Log::Warning(mbgl::Event::JNI, "CustomLayer doesn't support source layer"); } void operator()(style::RasterLayer&) { Log::Warning(mbgl::Event::JNI, "RasterLayer doesn't support source layer"); } + void operator()(style::HillshadeLayer&) { Log::Warning(mbgl::Event::JNI, "HillshadeLayer doesn't support source layer"); } template <class LayerType> void operator()(LayerType& layer) { @@ -154,6 +161,7 @@ namespace android { std::string operator()(style::BackgroundLayer&) { return noop("BackgroundLayer"); } std::string operator()(style::CustomLayer&) { return noop("CustomLayer"); } std::string operator()(style::RasterLayer&) { return noop("RasterLayer"); } + std::string operator()(style::HillshadeLayer&) { return noop("HillshadeLayer"); } template <class LayerType> std::string operator()(LayerType& layer) { diff --git a/platform/android/src/style/layers/layers.cpp b/platform/android/src/style/layers/layers.cpp index 9803b6f841..5df689b45d 100644 --- a/platform/android/src/style/layers/layers.cpp +++ b/platform/android/src/style/layers/layers.cpp @@ -5,6 +5,8 @@ #include <mbgl/style/layers/circle_layer.hpp> #include <mbgl/style/layers/fill_extrusion_layer.hpp> #include <mbgl/style/layers/fill_layer.hpp> +#include <mbgl/style/layers/heatmap_layer.hpp> +#include <mbgl/style/layers/hillshade_layer.hpp> #include <mbgl/style/layers/line_layer.hpp> #include <mbgl/style/layers/raster_layer.hpp> #include <mbgl/style/layers/symbol_layer.hpp> @@ -15,6 +17,8 @@ #include "custom_layer.hpp" #include "fill_extrusion_layer.hpp" #include "fill_layer.hpp" +#include "heatmap_layer.hpp" +#include "hillshade_layer.hpp" #include "line_layer.hpp" #include "raster_layer.hpp" #include "symbol_layer.hpp" @@ -30,6 +34,8 @@ template <> struct PeerType<style::BackgroundLayer> { using Type = android::Back template <> struct PeerType<style::CircleLayer> { using Type = android::CircleLayer; }; template <> struct PeerType<style::FillExtrusionLayer> { using Type = android::FillExtrusionLayer; }; template <> struct PeerType<style::FillLayer> { using Type = android::FillLayer; }; +template <> struct PeerType<style::HeatmapLayer> { using Type = android::HeatmapLayer; }; +template <> struct PeerType<style::HillshadeLayer> { using Type = android::HillshadeLayer; }; template <> struct PeerType<style::LineLayer> { using Type = android::LineLayer; }; template <> struct PeerType<style::RasterLayer> { using Type = android::RasterLayer; }; template <> struct PeerType<style::SymbolLayer> { using Type = android::SymbolLayer; }; @@ -92,6 +98,8 @@ void registerNativeLayers(jni::JNIEnv& env) { CustomLayer::registerNative(env); FillExtrusionLayer::registerNative(env); FillLayer::registerNative(env); + HeatmapLayer::registerNative(env); + HillshadeLayer::registerNative(env); LineLayer::registerNative(env); RasterLayer::registerNative(env); SymbolLayer::registerNative(env); diff --git a/platform/android/src/style/layers/raster_layer.cpp b/platform/android/src/style/layers/raster_layer.cpp index 98923d5129..6d36298bb1 100644 --- a/platform/android/src/style/layers/raster_layer.cpp +++ b/platform/android/src/style/layers/raster_layer.cpp @@ -155,19 +155,6 @@ namespace android { return jni::Object<jni::ObjectTag>(*converted); } - jni::Object<TransitionOptions> RasterLayer::getRasterFadeDurationTransition(jni::JNIEnv& env) { - using namespace mbgl::android::conversion; - mbgl::style::TransitionOptions options = layer.as<mbgl::style::RasterLayer>()->RasterLayer::getRasterFadeDurationTransition(); - return *convert<jni::Object<TransitionOptions>>(env, options); - } - - void RasterLayer::setRasterFadeDurationTransition(jni::JNIEnv&, jlong duration, jlong delay) { - mbgl::style::TransitionOptions options; - options.duration.emplace(mbgl::Milliseconds(duration)); - options.delay.emplace(mbgl::Milliseconds(delay)); - layer.as<mbgl::style::RasterLayer>()->RasterLayer::setRasterFadeDurationTransition(options); - } - jni::Class<RasterLayer> RasterLayer::javaClass; @@ -206,8 +193,6 @@ namespace android { METHOD(&RasterLayer::getRasterContrastTransition, "nativeGetRasterContrastTransition"), METHOD(&RasterLayer::setRasterContrastTransition, "nativeSetRasterContrastTransition"), METHOD(&RasterLayer::getRasterContrast, "nativeGetRasterContrast"), - METHOD(&RasterLayer::getRasterFadeDurationTransition, "nativeGetRasterFadeDurationTransition"), - METHOD(&RasterLayer::setRasterFadeDurationTransition, "nativeSetRasterFadeDurationTransition"), METHOD(&RasterLayer::getRasterFadeDuration, "nativeGetRasterFadeDuration")); } diff --git a/platform/android/src/style/layers/raster_layer.hpp b/platform/android/src/style/layers/raster_layer.hpp index 3b119ee0d2..ed6fc3e1b2 100644 --- a/platform/android/src/style/layers/raster_layer.hpp +++ b/platform/android/src/style/layers/raster_layer.hpp @@ -54,8 +54,6 @@ public: jni::Object<TransitionOptions> getRasterContrastTransition(jni::JNIEnv&); jni::Object<jni::ObjectTag> getRasterFadeDuration(jni::JNIEnv&); - void setRasterFadeDurationTransition(jni::JNIEnv&, jlong duration, jlong delay); - jni::Object<TransitionOptions> getRasterFadeDurationTransition(jni::JNIEnv&); jni::jobject* createJavaPeer(jni::JNIEnv&); }; // class RasterLayer diff --git a/platform/android/src/style/sources/custom_geometry_source.cpp b/platform/android/src/style/sources/custom_geometry_source.cpp new file mode 100644 index 0000000000..b38405a3b1 --- /dev/null +++ b/platform/android/src/style/sources/custom_geometry_source.cpp @@ -0,0 +1,143 @@ +#include "custom_geometry_source.hpp" + +#include <mbgl/renderer/query.hpp> + +// Java -> C++ conversion +#include "../android_conversion.hpp" +#include "../conversion/filter.hpp" + +// C++ -> Java conversion +#include "../../conversion/conversion.hpp" +#include "../../conversion/collection.hpp" +#include "../../geojson/conversion/feature.hpp" +#include <mbgl/style/conversion/custom_geometry_source_options.hpp> + +#include <string> + +namespace mbgl { +namespace android { + + // This conversion is expected not to fail because it's used only in contexts where + // the value was originally a CustomGeometrySourceOptions object on the Java side. If it fails + // to convert, it's a bug in our serialization or Java-side static typing. + static style::CustomGeometrySource::Options convertCustomGeometrySourceOptions(jni::JNIEnv& env, + jni::Object<> options, + style::TileFunction fetchFn, + style::TileFunction cancelFn) { + using namespace mbgl::style::conversion; + if (!options) { + return style::CustomGeometrySource::Options(); + } + Error error; + optional<style::CustomGeometrySource::Options> result = convert<style::CustomGeometrySource::Options>(Value(env, options), error); + if (!result) { + throw std::logic_error(error.message); + } + result->fetchTileFunction = fetchFn; + result->cancelTileFunction = cancelFn; + return *result; + } + + CustomGeometrySource::CustomGeometrySource(jni::JNIEnv& env, + jni::String sourceId, + jni::Object<> options) + : Source(env, std::make_unique<mbgl::style::CustomGeometrySource>( + jni::Make<std::string>(env, sourceId), + convertCustomGeometrySourceOptions(env, options, + std::bind(&CustomGeometrySource::fetchTile, this, std::placeholders::_1), + std::bind(&CustomGeometrySource::cancelTile, this, std::placeholders::_1)))) { + } + + CustomGeometrySource::CustomGeometrySource(jni::JNIEnv& env, + mbgl::style::Source& coreSource, + AndroidRendererFrontend& frontend) + : Source(env, coreSource, createJavaPeer(env), frontend) { + } + + CustomGeometrySource::~CustomGeometrySource() = default; + + void CustomGeometrySource::fetchTile (const mbgl::CanonicalTileID& tileID) { + android::UniqueEnv _env = android::AttachEnv(); + + static auto fetchTile = javaClass.GetMethod<void (jni::jint, jni::jint, jni::jint)>(*_env, "fetchTile"); + + assert(javaPeer); + + auto peer = jni::Cast(*_env, *javaPeer, javaClass); + peer.Call(*_env, fetchTile, (int)tileID.z, (int)tileID.x, (int)tileID.y); + }; + + void CustomGeometrySource::cancelTile(const mbgl::CanonicalTileID& tileID) { + android::UniqueEnv _env = android::AttachEnv(); + + static auto cancelTile = javaClass.GetMethod<void (jni::jint, jni::jint, jni::jint)>(*_env, "cancelTile"); + + assert(javaPeer); + + auto peer = jni::Cast(*_env, *javaPeer, javaClass); + peer.Call(*_env, cancelTile, (int)tileID.z, (int)tileID.x, (int)tileID.y); + }; + + void CustomGeometrySource::setTileData(jni::JNIEnv& env, + jni::jint z, + jni::jint x, + jni::jint y, + jni::Object<geojson::FeatureCollection> jFeatures) { + using namespace mbgl::android::geojson; + + // Convert the jni object + auto geometry = geojson::FeatureCollection::convert(env, jFeatures); + + // Update the core source + source.as<mbgl::style::CustomGeometrySource>()->CustomGeometrySource::setTileData(CanonicalTileID(z, x, y), GeoJSON(geometry)); + } + + void CustomGeometrySource::invalidateTile(jni::JNIEnv&, jni::jint z, jni::jint x, jni::jint y) { + source.as<mbgl::style::CustomGeometrySource>()->CustomGeometrySource::invalidateTile(CanonicalTileID(z, x, y)); + } + + void CustomGeometrySource::invalidateBounds(jni::JNIEnv& env, jni::Object<LatLngBounds> jBounds) { + auto bounds = LatLngBounds::getLatLngBounds(env, jBounds); + source.as<mbgl::style::CustomGeometrySource>()->CustomGeometrySource::invalidateRegion(bounds); + } + + jni::Array<jni::Object<geojson::Feature>> CustomGeometrySource::querySourceFeatures(jni::JNIEnv& env, + jni::Array<jni::Object<>> jfilter) { + using namespace mbgl::android::conversion; + using namespace mbgl::android::geojson; + + std::vector<mbgl::Feature> features; + if (rendererFrontend) { + features = rendererFrontend->querySourceFeatures(source.getID(), { {}, toFilter(env, jfilter) }); + } + return *convert<jni::Array<jni::Object<Feature>>, std::vector<mbgl::Feature>>(env, features); + } + + jni::Class<CustomGeometrySource> CustomGeometrySource::javaClass; + + jni::Object<Source> CustomGeometrySource::createJavaPeer(jni::JNIEnv& env) { + static auto constructor = CustomGeometrySource::javaClass.template GetConstructor<jni::jlong>(env); + return jni::Object<Source>(CustomGeometrySource::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this)).Get()); + } + + void CustomGeometrySource::registerNative(jni::JNIEnv& env) { + // Lookup the class + CustomGeometrySource::javaClass = *jni::Class<CustomGeometrySource>::Find(env).NewGlobalRef(env).release(); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name) + + // Register the peer + jni::RegisterNativePeer<CustomGeometrySource>( + env, CustomGeometrySource::javaClass, "nativePtr", + std::make_unique<CustomGeometrySource, JNIEnv&, jni::String, jni::Object<>>, + "initialize", + "finalize", + METHOD(&CustomGeometrySource::querySourceFeatures, "querySourceFeatures"), + METHOD(&CustomGeometrySource::setTileData, "nativeSetTileData"), + METHOD(&CustomGeometrySource::invalidateTile, "nativeInvalidateTile"), + METHOD(&CustomGeometrySource::invalidateBounds, "nativeInvalidateBounds") + ); + } + +} // namespace android +} // namespace mbgl diff --git a/platform/android/src/style/sources/custom_geometry_source.hpp b/platform/android/src/style/sources/custom_geometry_source.hpp new file mode 100644 index 0000000000..1dc1c07b4f --- /dev/null +++ b/platform/android/src/style/sources/custom_geometry_source.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include "source.hpp" +#include <mbgl/style/sources/custom_geometry_source.hpp> +#include <mbgl/util/geojson.hpp> +#include <mbgl/tile/tile_id.hpp> +#include "../../geojson/geometry.hpp" +#include "../../geojson/feature.hpp" +#include "../../geojson/feature_collection.hpp" +#include "../../geometry/lat_lng_bounds.hpp" +#include <jni/jni.hpp> + +namespace mbgl { +namespace android { + +class CustomGeometrySource : public Source { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/sources/CustomGeometrySource"; }; + + static jni::Class<CustomGeometrySource> javaClass; + + static void registerNative(jni::JNIEnv&); + + CustomGeometrySource(jni::JNIEnv&, jni::String, jni::Object<>); + + CustomGeometrySource(jni::JNIEnv&, mbgl::style::Source&, AndroidRendererFrontend&); + + ~CustomGeometrySource(); + + void fetchTile(const mbgl::CanonicalTileID& tileID); + void cancelTile(const mbgl::CanonicalTileID& tileID); + 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); + void invalidateBounds(jni::JNIEnv& env, jni::Object<LatLngBounds> bounds); + + jni::Array<jni::Object<geojson::Feature>> querySourceFeatures(jni::JNIEnv&, + jni::Array<jni::Object<>> ); + +private: + jni::Object<Source> createJavaPeer(jni::JNIEnv&); + +}; // class CustomGeometrySource + +} // namespace android +} // namespace mbgl diff --git a/platform/android/src/style/sources/geojson_source.cpp b/platform/android/src/style/sources/geojson_source.cpp index 90ef851eba..6d9ab9e22c 100644 --- a/platform/android/src/style/sources/geojson_source.cpp +++ b/platform/android/src/style/sources/geojson_source.cpp @@ -5,15 +5,15 @@ // Java -> C++ conversion #include "../android_conversion.hpp" #include "../conversion/filter.hpp" -#include "../conversion/geojson.hpp" +#include <mbgl/style/conversion.hpp> +#include <mbgl/style/conversion/geojson.hpp> +#include <mbgl/style/conversion/geojson_options.hpp> // C++ -> Java conversion #include "../../conversion/conversion.hpp" #include "../../conversion/collection.hpp" #include "../../geojson/conversion/feature.hpp" #include "../conversion/url_or_tileset.hpp" -#include <mbgl/style/conversion.hpp> -#include <mbgl/style/conversion/geojson_options.hpp> #include <string> @@ -29,7 +29,7 @@ namespace android { return style::GeoJSONOptions(); } Error error; - optional<style::GeoJSONOptions> result = convert<style::GeoJSONOptions>(Value(env, options), error); + optional<style::GeoJSONOptions> result = convert<style::GeoJSONOptions>(mbgl::android::Value(env, options), error); if (!result) { throw std::logic_error(error.message); } @@ -43,8 +43,10 @@ namespace android { ) { } - GeoJSONSource::GeoJSONSource(mbgl::style::GeoJSONSource& coreSource) - : Source(coreSource) { + GeoJSONSource::GeoJSONSource(jni::JNIEnv& env, + mbgl::style::Source& coreSource, + AndroidRendererFrontend& frontend) + : Source(env, coreSource, createJavaPeer(env), frontend) { } GeoJSONSource::~GeoJSONSource() = default; @@ -54,7 +56,7 @@ namespace android { // Convert the jni object Error error; - optional<GeoJSON> converted = convert<GeoJSON>(Value(env, json), 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; @@ -118,9 +120,9 @@ namespace android { jni::Class<GeoJSONSource> GeoJSONSource::javaClass; - jni::jobject* GeoJSONSource::createJavaPeer(jni::JNIEnv& env) { + jni::Object<Source> GeoJSONSource::createJavaPeer(jni::JNIEnv& env) { static auto constructor = GeoJSONSource::javaClass.template GetConstructor<jni::jlong>(env); - return GeoJSONSource::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this)); + return jni::Object<Source>(GeoJSONSource::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this)).Get()); } void GeoJSONSource::registerNative(jni::JNIEnv& env) { diff --git a/platform/android/src/style/sources/geojson_source.hpp b/platform/android/src/style/sources/geojson_source.hpp index 52dd632bfa..c46519b04a 100644 --- a/platform/android/src/style/sources/geojson_source.hpp +++ b/platform/android/src/style/sources/geojson_source.hpp @@ -21,7 +21,7 @@ public: GeoJSONSource(jni::JNIEnv&, jni::String, jni::Object<>); - GeoJSONSource(mbgl::style::GeoJSONSource&); + GeoJSONSource(jni::JNIEnv&, mbgl::style::Source&, AndroidRendererFrontend&); ~GeoJSONSource(); @@ -40,7 +40,8 @@ public: jni::String getURL(jni::JNIEnv&); - jni::jobject* createJavaPeer(jni::JNIEnv&); +private: + jni::Object<Source> createJavaPeer(jni::JNIEnv&); }; // class GeoJSONSource diff --git a/platform/android/src/style/sources/image_source.cpp b/platform/android/src/style/sources/image_source.cpp index d46b367c53..0cd6995969 100644 --- a/platform/android/src/style/sources/image_source.cpp +++ b/platform/android/src/style/sources/image_source.cpp @@ -23,8 +23,10 @@ namespace android { ) { } - ImageSource::ImageSource(mbgl::style::ImageSource& coreSource) - : Source(coreSource) { + ImageSource::ImageSource(jni::JNIEnv& env, + mbgl::style::Source& coreSource, + AndroidRendererFrontend& frontend) + : Source(env, coreSource, createJavaPeer(env), frontend) { } ImageSource::~ImageSource() = default; @@ -45,9 +47,9 @@ namespace android { jni::Class<ImageSource> ImageSource::javaClass; - jni::jobject* ImageSource::createJavaPeer(jni::JNIEnv& env) { + jni::Object<Source> ImageSource::createJavaPeer(jni::JNIEnv& env) { static auto constructor = ImageSource::javaClass.template GetConstructor<jni::jlong>(env); - return ImageSource::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this)); + return jni::Object<Source>(ImageSource::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this)).Get()); } void ImageSource::registerNative(jni::JNIEnv& env) { diff --git a/platform/android/src/style/sources/image_source.hpp b/platform/android/src/style/sources/image_source.hpp index 9787a7294f..f0af28d357 100644 --- a/platform/android/src/style/sources/image_source.hpp +++ b/platform/android/src/style/sources/image_source.hpp @@ -21,7 +21,7 @@ public: ImageSource(jni::JNIEnv&, jni::String, jni::Object<LatLngQuad>); - ImageSource(mbgl::style::ImageSource&); + ImageSource(jni::JNIEnv&, mbgl::style::Source&, AndroidRendererFrontend&); ~ImageSource(); @@ -30,7 +30,8 @@ public: void setImage(jni::JNIEnv&, jni::Object<Bitmap>); - jni::jobject* createJavaPeer(jni::JNIEnv&); +private: + jni::Object<Source> createJavaPeer(jni::JNIEnv&); }; // class ImageSource diff --git a/platform/android/src/style/sources/raster_dem_source.cpp b/platform/android/src/style/sources/raster_dem_source.cpp new file mode 100644 index 0000000000..75e0159d7c --- /dev/null +++ b/platform/android/src/style/sources/raster_dem_source.cpp @@ -0,0 +1,63 @@ +#include "raster_dem_source.hpp" + +#include "../android_conversion.hpp" +#include "../value.hpp" +#include "../conversion/url_or_tileset.hpp" +#include "source.hpp" + +#include <mbgl/util/variant.hpp> + +#include <string> + +namespace mbgl { +namespace android { + + RasterDEMSource::RasterDEMSource(jni::JNIEnv& env, jni::String sourceId, jni::Object<> urlOrTileSet, jni::jint tileSize) + : Source( + env, + std::make_unique<mbgl::style::RasterDEMSource>( + jni::Make<std::string>(env, sourceId), + convertURLOrTileset(Value(env, urlOrTileSet)), + tileSize + ) + ) { + } + + RasterDEMSource::RasterDEMSource(jni::JNIEnv& env, + mbgl::style::Source& coreSource, + AndroidRendererFrontend& frontend) + : Source(env, coreSource, createJavaPeer(env), frontend) { + } + + RasterDEMSource::~RasterDEMSource() = default; + + jni::String RasterDEMSource::getURL(jni::JNIEnv& env) { + optional<std::string> url = source.as<mbgl::style::RasterDEMSource>()->RasterDEMSource::getURL(); + return url ? jni::Make<jni::String>(env, *url) : jni::String(); + } + + jni::Class<RasterDEMSource> RasterDEMSource::javaClass; + + jni::Object<Source> RasterDEMSource::createJavaPeer(jni::JNIEnv& env) { + static auto constructor = RasterDEMSource::javaClass.template GetConstructor<jni::jlong>(env); + return jni::Object<Source>(RasterDEMSource::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this)).Get()); + } + + void RasterDEMSource::registerNative(jni::JNIEnv& env) { + // Lookup the class + RasterDEMSource::javaClass = *jni::Class<RasterDEMSource>::Find(env).NewGlobalRef(env).release(); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name) + + // Register the peer + jni::RegisterNativePeer<RasterDEMSource>( + env, RasterDEMSource::javaClass, "nativePtr", + std::make_unique<RasterDEMSource, JNIEnv&, jni::String, jni::Object<>, jni::jint>, + "initialize", + "finalize", + METHOD(&RasterDEMSource::getURL, "nativeGetUrl") + ); + } + +} // namespace android +} // namespace mbgl diff --git a/platform/android/src/style/sources/raster_dem_source.hpp b/platform/android/src/style/sources/raster_dem_source.hpp new file mode 100644 index 0000000000..56924c1f8d --- /dev/null +++ b/platform/android/src/style/sources/raster_dem_source.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include "source.hpp" +#include <mbgl/style/sources/raster_dem_source.hpp> +#include <jni/jni.hpp> + +namespace mbgl { +namespace android { + +class RasterDEMSource : public Source { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/sources/RasterDemSource"; }; + + static jni::Class<RasterDEMSource> javaClass; + + static void registerNative(jni::JNIEnv&); + + RasterDEMSource(jni::JNIEnv&, jni::String, jni::Object<>, jni::jint); + + RasterDEMSource(jni::JNIEnv&, mbgl::style::Source&, AndroidRendererFrontend&); + + ~RasterDEMSource(); + + jni::String getURL(jni::JNIEnv&); + +private: + jni::Object<Source> createJavaPeer(jni::JNIEnv&); + +}; // class RasterDEMSource + +} // namespace android +} // namespace mbgl diff --git a/platform/android/src/style/sources/raster_source.cpp b/platform/android/src/style/sources/raster_source.cpp index d45342a1ad..33223a5b69 100644 --- a/platform/android/src/style/sources/raster_source.cpp +++ b/platform/android/src/style/sources/raster_source.cpp @@ -22,8 +22,10 @@ namespace android { ) { } - RasterSource::RasterSource(mbgl::style::RasterSource& coreSource) - : Source(coreSource) { + RasterSource::RasterSource(jni::JNIEnv& env, + mbgl::style::Source& coreSource, + AndroidRendererFrontend& frontend) + : Source(env, coreSource, createJavaPeer(env), frontend) { } RasterSource::~RasterSource() = default; @@ -35,9 +37,9 @@ namespace android { jni::Class<RasterSource> RasterSource::javaClass; - jni::jobject* RasterSource::createJavaPeer(jni::JNIEnv& env) { + jni::Object<Source> RasterSource::createJavaPeer(jni::JNIEnv& env) { static auto constructor = RasterSource::javaClass.template GetConstructor<jni::jlong>(env); - return RasterSource::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this)); + return jni::Object<Source>(RasterSource::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this)).Get()); } void RasterSource::registerNative(jni::JNIEnv& env) { diff --git a/platform/android/src/style/sources/raster_source.hpp b/platform/android/src/style/sources/raster_source.hpp index 84c49d7381..a1da22f40d 100644 --- a/platform/android/src/style/sources/raster_source.hpp +++ b/platform/android/src/style/sources/raster_source.hpp @@ -18,13 +18,14 @@ public: RasterSource(jni::JNIEnv&, jni::String, jni::Object<>, jni::jint); - RasterSource(mbgl::style::RasterSource&); + RasterSource(jni::JNIEnv&, mbgl::style::Source&, AndroidRendererFrontend&); ~RasterSource(); jni::String getURL(jni::JNIEnv&); - jni::jobject* createJavaPeer(jni::JNIEnv&); +private: + jni::Object<Source> createJavaPeer(jni::JNIEnv&); }; // class RasterSource diff --git a/platform/android/src/style/sources/source.cpp b/platform/android/src/style/sources/source.cpp index 447b13019d..413530a5ec 100644 --- a/platform/android/src/style/sources/source.cpp +++ b/platform/android/src/style/sources/source.cpp @@ -15,29 +15,71 @@ #include <string> +// Core Sources +#include <mbgl/style/sources/geojson_source.hpp> +#include <mbgl/style/sources/image_source.hpp> +#include <mbgl/style/sources/raster_source.hpp> +#include <mbgl/style/sources/vector_source.hpp> + +// Android Source peers +#include "geojson_source.hpp" +#include "image_source.hpp" +#include "raster_source.hpp" +#include "unknown_source.hpp" +#include "vector_source.hpp" +#include "custom_geometry_source.hpp" +#include "raster_dem_source.hpp" + namespace mbgl { namespace android { - /** - * Invoked when the construction is initiated from the jvm through a subclass - */ - Source::Source(jni::JNIEnv&, std::unique_ptr<mbgl::style::Source> coreSource) - : ownedSource(std::move(coreSource)) - , source(*ownedSource) { + static std::unique_ptr<Source> createSourcePeer(jni::JNIEnv& env, mbgl::style::Source& coreSource, AndroidRendererFrontend& frontend) { + if (coreSource.is<mbgl::style::VectorSource>()) { + return std::make_unique<VectorSource>(env, *coreSource.as<mbgl::style::VectorSource>(), frontend); + } else if (coreSource.is<mbgl::style::RasterSource>()) { + return std::make_unique<RasterSource>(env, *coreSource.as<mbgl::style::RasterSource>(), frontend); + } else if (coreSource.is<mbgl::style::GeoJSONSource>()) { + return std::make_unique<GeoJSONSource>(env, *coreSource.as<mbgl::style::GeoJSONSource>(), frontend); + } else if (coreSource.is<mbgl::style::ImageSource>()) { + return std::make_unique<ImageSource>(env, *coreSource.as<mbgl::style::ImageSource>(), frontend); + } else { + return std::make_unique<UnknownSource>(env, coreSource, frontend); + } } - Source::Source(mbgl::style::Source& coreSource) - : source(coreSource) { + jni::Object<Source> Source::peerForCoreSource(jni::JNIEnv& env, mbgl::style::Source& coreSource, AndroidRendererFrontend& frontend) { + if (!coreSource.peer.has_value()) { + coreSource.peer = createSourcePeer(env, coreSource, frontend); + } + return *mbgl::util::any_cast<std::unique_ptr<Source>>(&coreSource.peer)->get()->javaPeer; } - Source::~Source() = default; + Source::Source(jni::JNIEnv& env, mbgl::style::Source& coreSource, jni::Object<Source> obj, AndroidRendererFrontend& frontend) + : source(coreSource) + , javaPeer(obj.NewGlobalRef(env)) + , rendererFrontend(&frontend) { + } - style::Source& Source::get() { - return source; + Source::Source(jni::JNIEnv&, std::unique_ptr<mbgl::style::Source> coreSource) + : ownedSource(std::move(coreSource)) + , source(*ownedSource) { } - void Source::setSource(std::unique_ptr<style::Source> coreSource) { - this->ownedSource = std::move(coreSource); + Source::~Source() { + // Before being added to a map, the Java peer owns this C++ peer and cleans + // up after itself correctly through the jni native peer bindings. + // After being added to the map, the ownership is flipped and the C++ peer has a strong reference + // to it's Java peer, preventing the Java peer from being GC'ed. + // In this case, the core source initiates the destruction, which requires releasing the Java peer, + // while also resetting it's nativePtr to 0 to prevent the subsequent GC of the Java peer from + // re-entering this dtor. + if (ownedSource.get() == nullptr && javaPeer.get() != nullptr) { + // Manually clear the java peer + android::UniqueEnv env = android::AttachEnv(); + static auto nativePtrField = javaClass.GetField<jlong>(*env, "nativePtr"); + javaPeer->Set(*env, nativePtrField, (jlong) 0); + javaPeer.reset(); + } } jni::String Source::getId(jni::JNIEnv& env) { @@ -49,23 +91,48 @@ namespace android { return attribution ? jni::Make<jni::String>(env, attribution.value()) : jni::Make<jni::String>(env,""); } - void Source::addToMap(mbgl::Map& _map) { + void Source::addToMap(JNIEnv& env, jni::Object<Source> obj, mbgl::Map& map, AndroidRendererFrontend& frontend) { // Check to see if we own the source first if (!ownedSource) { throw std::runtime_error("Cannot add source twice"); } - // Add source to map - _map.getStyle().addSource(releaseCoreSource()); - } + // Add source to map and release ownership + map.getStyle().addSource(std::move(ownedSource)); + + // Add peer to core source + source.peer = std::unique_ptr<Source>(this); + + // Add strong reference to java source + javaPeer = obj.NewGlobalRef(env); - void Source::setRendererFrontend(AndroidRendererFrontend& frontend_) { - rendererFrontend = &frontend_; + rendererFrontend = &frontend; } - std::unique_ptr<mbgl::style::Source> Source::releaseCoreSource() { - assert(ownedSource != nullptr); - return std::move(ownedSource); + void 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"); + } + + // Remove the source from the map and take ownership + ownedSource = map.getStyle().removeSource(source.getID()); + + // The source may not be removed if any layers still reference it + 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.reset(); + + // Release the strong reference to the java peer + assert(javaPeer); + javaPeer.release(); + + rendererFrontend = nullptr; } jni::Class<Source> Source::javaClass; @@ -82,6 +149,14 @@ namespace android { METHOD(&Source::getAttribution, "nativeGetAttribution") ); + // Register subclasses + GeoJSONSource::registerNative(env); + ImageSource::registerNative(env); + RasterSource::registerNative(env); + UnknownSource::registerNative(env); + VectorSource::registerNative(env); + CustomGeometrySource::registerNative(env); + RasterDEMSource::registerNative(env); } } // namespace android diff --git a/platform/android/src/style/sources/source.hpp b/platform/android/src/style/sources/source.hpp index 383017b66f..718f60b381 100644 --- a/platform/android/src/style/sources/source.hpp +++ b/platform/android/src/style/sources/source.hpp @@ -21,48 +21,40 @@ public: static void registerNative(jni::JNIEnv&); + static jni::Object<Source> peerForCoreSource(jni::JNIEnv&, mbgl::style::Source&, AndroidRendererFrontend&); + /* - * Called when a Java object is created on the c++ side + * Called when a Java object is created for a core source that belongs to a map. */ - Source(mbgl::style::Source&); + Source(jni::JNIEnv&, mbgl::style::Source&, jni::Object<Source>, AndroidRendererFrontend&); /* - * Called when a Java object was created from the jvm side + * Called when a Java object is created for a new core source that does not belong to a map. */ Source(jni::JNIEnv&, std::unique_ptr<mbgl::style::Source>); virtual ~Source(); - /** - * Set core source (ie return ownership after remove) - */ - void setSource(std::unique_ptr<style::Source>); - - style::Source& get(); - - void addToMap(mbgl::Map&); + void addToMap(JNIEnv&, jni::Object<Source>, mbgl::Map&, AndroidRendererFrontend&); - void setRendererFrontend(AndroidRendererFrontend&); - - virtual jni::jobject* createJavaPeer(jni::JNIEnv&) = 0; + void removeFromMap(JNIEnv&, jni::Object<Source>, mbgl::Map&); jni::String getId(jni::JNIEnv&); jni::String getAttribution(jni::JNIEnv&); protected: - // Release the owned view and return it - std::unique_ptr<mbgl::style::Source> releaseCoreSource(); - - // Set on newly created sources until added to the map + // Set on newly created sources until added to the map. std::unique_ptr<mbgl::style::Source> ownedSource; - // Raw pointer that is valid until the source is removed from the map + // Raw pointer that is valid at all times. mbgl::style::Source& source; - // RendererFrontend pointer is valid only when - // added to the map - AndroidRendererFrontend* rendererFrontend; + // Set when the source is added to a map. + jni::UniqueObject<Source> javaPeer; + + // RendererFrontend pointer is valid only when added to the map. + AndroidRendererFrontend* rendererFrontend { nullptr }; }; } // namespace android diff --git a/platform/android/src/style/sources/sources.cpp b/platform/android/src/style/sources/sources.cpp deleted file mode 100644 index 9ab3ca8e84..0000000000 --- a/platform/android/src/style/sources/sources.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include "sources.hpp" - -#include <mbgl/style/source.hpp> -#include <mbgl/style/sources/geojson_source.hpp> -#include <mbgl/style/sources/image_source.hpp> -#include <mbgl/style/sources/raster_source.hpp> -#include <mbgl/style/sources/vector_source.hpp> - -#include "source.hpp" -#include "geojson_source.hpp" -#include "image_source.hpp" -#include "raster_source.hpp" -#include "unknown_source.hpp" -#include "vector_source.hpp" - -namespace { - - using namespace mbgl::android; - - Source* initializeSourcePeer(mbgl::style::Source& coreSource) { - Source* source; - if (coreSource.is<mbgl::style::VectorSource>()) { - source = new VectorSource(*coreSource.as<mbgl::style::VectorSource>()); - } else if (coreSource.is<mbgl::style::RasterSource>()) { - source = new RasterSource(*coreSource.as<mbgl::style::RasterSource>()); - } else if (coreSource.is<mbgl::style::GeoJSONSource>()) { - source = new GeoJSONSource(*coreSource.as<mbgl::style::GeoJSONSource>()); - } else if (coreSource.is<mbgl::style::ImageSource>()) { - source = new ImageSource(*coreSource.as<mbgl::style::ImageSource>()); - } else { - source = new UnknownSource(coreSource); - } - - return source; - } -} // namespace - -namespace mbgl { -namespace android { - - -jni::jobject* createJavaSourcePeer(jni::JNIEnv& env, AndroidRendererFrontend& frontend, mbgl::style::Source& coreSource) { - std::unique_ptr<Source> peerSource = std::unique_ptr<Source>(initializeSourcePeer(coreSource)); - peerSource->setRendererFrontend(frontend); - jni::jobject* result = peerSource->createJavaPeer(env); - peerSource.release(); - return result; -} - -void registerNativeSources(jni::JNIEnv& env) { - Source::registerNative(env); - GeoJSONSource::registerNative(env); - ImageSource::registerNative(env); - RasterSource::registerNative(env); - UnknownSource::registerNative(env); - VectorSource::registerNative(env); -} - -} -} diff --git a/platform/android/src/style/sources/sources.hpp b/platform/android/src/style/sources/sources.hpp deleted file mode 100644 index c7b36818b2..0000000000 --- a/platform/android/src/style/sources/sources.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include <mbgl/style/source.hpp> - -#include "source.hpp" -#include "../../android_renderer_frontend.hpp" - -#include <jni/jni.hpp> - -namespace mbgl { -namespace android { - - jni::jobject* createJavaSourcePeer(jni::JNIEnv&, AndroidRendererFrontend&, mbgl::style::Source&); - - void registerNativeSources(jni::JNIEnv&); - -} // namespace android -} // namespace mbgl diff --git a/platform/android/src/style/sources/unknown_source.cpp b/platform/android/src/style/sources/unknown_source.cpp index 79f27bdfbf..4b5510c1db 100644 --- a/platform/android/src/style/sources/unknown_source.cpp +++ b/platform/android/src/style/sources/unknown_source.cpp @@ -12,15 +12,17 @@ namespace { namespace mbgl { namespace android { - UnknownSource::UnknownSource(mbgl::style::Source& coreSource) - : Source(coreSource) { + UnknownSource::UnknownSource(jni::JNIEnv& env, + mbgl::style::Source& coreSource, + AndroidRendererFrontend& frontend) + : Source(env, coreSource, createJavaPeer(env), frontend) { } jni::Class<UnknownSource> UnknownSource::javaClass; - jni::jobject* UnknownSource::createJavaPeer(jni::JNIEnv& env) { + jni::Object<Source> UnknownSource::createJavaPeer(jni::JNIEnv& env) { static auto constructor = UnknownSource::javaClass.template GetConstructor<jni::jlong>(env); - return UnknownSource::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this)); + return jni::Object<Source>(UnknownSource::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this)).Get()); } void UnknownSource::registerNative(jni::JNIEnv& env) { diff --git a/platform/android/src/style/sources/unknown_source.hpp b/platform/android/src/style/sources/unknown_source.hpp index 4a003c9a7f..414d420c61 100644 --- a/platform/android/src/style/sources/unknown_source.hpp +++ b/platform/android/src/style/sources/unknown_source.hpp @@ -16,11 +16,12 @@ public: static void registerNative(jni::JNIEnv&); - UnknownSource(mbgl::style::Source&); + UnknownSource(jni::JNIEnv&, mbgl::style::Source&, AndroidRendererFrontend&); ~UnknownSource() = default; - jni::jobject* createJavaPeer(jni::JNIEnv&); +private: + jni::Object<Source> createJavaPeer(jni::JNIEnv&); }; // class UnknownSource diff --git a/platform/android/src/style/sources/vector_source.cpp b/platform/android/src/style/sources/vector_source.cpp index 7fe45441bd..9a9548d283 100644 --- a/platform/android/src/style/sources/vector_source.cpp +++ b/platform/android/src/style/sources/vector_source.cpp @@ -30,8 +30,10 @@ namespace android { ) { } - VectorSource::VectorSource(mbgl::style::VectorSource& coreSource) - : Source(coreSource) { + VectorSource::VectorSource(jni::JNIEnv& env, + mbgl::style::Source& coreSource, + AndroidRendererFrontend& frontend) + : Source(env, coreSource, createJavaPeer(env), frontend) { } VectorSource::~VectorSource() = default; @@ -56,9 +58,9 @@ namespace android { jni::Class<VectorSource> VectorSource::javaClass; - jni::jobject* VectorSource::createJavaPeer(jni::JNIEnv& env) { + jni::Object<Source> VectorSource::createJavaPeer(jni::JNIEnv& env) { static auto constructor = VectorSource::javaClass.template GetConstructor<jni::jlong>(env); - return VectorSource::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this)); + return jni::Object<Source>(VectorSource::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this)).Get()); } void VectorSource::registerNative(jni::JNIEnv& env) { diff --git a/platform/android/src/style/sources/vector_source.hpp b/platform/android/src/style/sources/vector_source.hpp index 509fe068d1..16049f5c77 100644 --- a/platform/android/src/style/sources/vector_source.hpp +++ b/platform/android/src/style/sources/vector_source.hpp @@ -19,7 +19,7 @@ public: VectorSource(jni::JNIEnv&, jni::String, jni::Object<>); - VectorSource(mbgl::style::VectorSource&); + VectorSource(jni::JNIEnv&, mbgl::style::Source&, AndroidRendererFrontend&); ~VectorSource(); @@ -28,7 +28,8 @@ public: jni::String getURL(jni::JNIEnv&); - jni::jobject* createJavaPeer(jni::JNIEnv&); +private: + jni::Object<Source> createJavaPeer(jni::JNIEnv&); }; // class VectorSource diff --git a/platform/android/src/style/value.cpp b/platform/android/src/style/value.cpp index e1cd81d7fd..70bdea6677 100644 --- a/platform/android/src/style/value.cpp +++ b/platform/android/src/style/value.cpp @@ -24,8 +24,6 @@ namespace android { Value::Value(jni::JNIEnv& _env, jni::jobject* _value) : env(_env), value(_value, ObjectDeleter(env)) {} - Value::~Value() = default; - bool Value::isNull() const { return value == nullptr; } diff --git a/platform/android/src/style/value.hpp b/platform/android/src/style/value.hpp index 7464bae832..2057b93454 100644 --- a/platform/android/src/style/value.hpp +++ b/platform/android/src/style/value.hpp @@ -9,9 +9,13 @@ namespace android { class Value { public: - Value(jni::JNIEnv&, jni::jobject*); - virtual ~Value(); + + Value(Value&&) = default; + Value& operator=(Value&&) = default; + + Value(const Value&) = delete; + Value& operator=(const Value&) = delete; bool isNull() const; bool isArray() const; |