diff options
Diffstat (limited to 'platform/android/src')
66 files changed, 800 insertions, 717 deletions
diff --git a/platform/android/src/bitmap.cpp b/platform/android/src/bitmap.cpp index 50088116f4..46e7253050 100644 --- a/platform/android/src/bitmap.cpp +++ b/platform/android/src/bitmap.cpp @@ -110,8 +110,7 @@ PremultipliedImage Bitmap::GetImage(jni::JNIEnv& env, jni::Object<Bitmap> bitmap } if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) { - // TODO: convert - throw std::runtime_error("bitmap decoding: bitmap format invalid"); + bitmap = Bitmap::Copy(env, bitmap); } const PixelGuard guard(env, bitmap); @@ -128,5 +127,12 @@ PremultipliedImage Bitmap::GetImage(jni::JNIEnv& env, jni::Object<Bitmap> bitmap return { Size{ info.width, info.height }, std::move(pixels) }; } +jni::Object<Bitmap> Bitmap::Copy(jni::JNIEnv& env, jni::Object<Bitmap> bitmap) { + using Signature = jni::Object<Bitmap>(jni::Object<Config>, jni::jboolean); + auto static method = _class.GetMethod<Signature>(env, "copy"); + auto config = Bitmap::Config::Create(env, Bitmap::Config::Value::ARGB_8888); + return bitmap.Call(env, method, config, (jni::jboolean) false); +} + } // namespace android } // namespace mbgl diff --git a/platform/android/src/bitmap.hpp b/platform/android/src/bitmap.hpp index f64f42ae87..c4e41db1e0 100644 --- a/platform/android/src/bitmap.hpp +++ b/platform/android/src/bitmap.hpp @@ -43,6 +43,7 @@ public: static PremultipliedImage GetImage(jni::JNIEnv&, jni::Object<Bitmap>); static jni::Object<Bitmap> CreateBitmap(jni::JNIEnv&, const PremultipliedImage&); + static jni::Object<Bitmap> Copy(jni::JNIEnv&, jni::Object<Bitmap>); private: static jni::Class<Bitmap> _class; diff --git a/platform/android/src/example_custom_layer.cpp b/platform/android/src/example_custom_layer.cpp index f7b425c40a..e805532541 100644 --- a/platform/android/src/example_custom_layer.cpp +++ b/platform/android/src/example_custom_layer.cpp @@ -112,18 +112,9 @@ void checkCompileStatus(GLuint shader) { static const GLchar * vertexShaderSource = "attribute vec2 a_pos; void main() { gl_Position = vec4(a_pos, 0, 1); }"; static const GLchar * fragmentShaderSource = "uniform highp vec4 fill_color; void main() { gl_FragColor = fill_color; }"; -class ExampleCustomLayer { +class ExampleCustomLayer: mbgl::style::CustomLayerHost { public: ~ExampleCustomLayer() { - __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "~ExampleCustomLayer"); - if (program) { - glDeleteBuffers(1, &buffer); - glDetachShader(program, vertexShader); - glDetachShader(program, fragmentShader); - glDeleteShader(vertexShader); - glDeleteShader(fragmentShader); - glDeleteProgram(program); - } } void initialize() { @@ -158,8 +149,15 @@ public: GL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(GLfloat), background, GL_STATIC_DRAW)); } - void render() { + void render(const mbgl::style::CustomLayerRenderParameters&) { __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "Render"); + glUseProgram(program); + glBindBuffer(GL_ARRAY_BUFFER, buffer); + glEnableVertexAttribArray(a_pos); + glVertexAttribPointer(a_pos, 2, GL_FLOAT, GL_FALSE, 0, NULL); + glDisable(GL_STENCIL_TEST); + glDisable(GL_DEPTH_TEST); + glUniform4fv(fill_color, 1, color); GL_CHECK_ERROR(glUseProgram(program)); GL_CHECK_ERROR(glBindBuffer(GL_ARRAY_BUFFER, buffer)); @@ -172,6 +170,23 @@ public: } + void contextLost() { + __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "ContextLost"); + program = 0; + } + + void deinitialize() { + __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "DeInitialize"); + if (program) { + glDeleteBuffers(1, &buffer); + glDetachShader(program, vertexShader); + glDetachShader(program, fragmentShader); + glDeleteShader(vertexShader); + glDeleteShader(fragmentShader); + glDeleteProgram(program); + } + } + GLuint program = 0; GLuint vertexShader = 0; GLuint fragmentShader = 0; @@ -186,7 +201,8 @@ GLfloat ExampleCustomLayer::color[] = { 0.0f, 1.0f, 0.0f, 1.0f }; jlong JNICALL nativeCreateContext(JNIEnv*, jobject) { __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "nativeCreateContext"); - return reinterpret_cast<jlong>(new ExampleCustomLayer()); + auto exampleCustomLayer = std::make_unique<ExampleCustomLayer>(); + return reinterpret_cast<jlong>(exampleCustomLayer.release()); } void JNICALL nativeSetColor(JNIEnv*, jobject, jfloat red, jfloat green, jfloat blue, jfloat alpha) { @@ -197,25 +213,6 @@ void JNICALL nativeSetColor(JNIEnv*, jobject, jfloat red, jfloat green, jfloat b ExampleCustomLayer::color[3] = alpha; } -void nativeInitialize(void *context) { - __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "nativeInitialize"); - reinterpret_cast<ExampleCustomLayer*>(context)->initialize(); -} - -void nativeRender(void *context, const mbgl::style::CustomLayerRenderParameters& /*parameters*/) { - __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "nativeRender"); - reinterpret_cast<ExampleCustomLayer*>(context)->render(); -} - -void nativeContextLost(void */*context*/) { - __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "nativeContextLost"); -} - -void nativeDeinitialize(void *context) { - __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "nativeDeinitialize"); - delete reinterpret_cast<ExampleCustomLayer*>(context); -} - extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "OnLoad"); @@ -234,22 +231,6 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { return JNI_ERR; } - env->SetStaticLongField(customLayerClass, - env->GetStaticFieldID(customLayerClass, "InitializeFunction", "J"), - reinterpret_cast<jlong>(nativeInitialize)); - - env->SetStaticLongField(customLayerClass, - env->GetStaticFieldID(customLayerClass, "RenderFunction", "J"), - reinterpret_cast<jlong>(nativeRender)); - - env->SetStaticLongField(customLayerClass, - env->GetStaticFieldID(customLayerClass, "ContextLostFunction", "J"), - reinterpret_cast<jlong>(nativeContextLost)); - - env->SetStaticLongField(customLayerClass, - env->GetStaticFieldID(customLayerClass, "DeinitializeFunction", "J"), - reinterpret_cast<jlong>(nativeDeinitialize)); - return JNI_VERSION_1_6; } diff --git a/platform/android/src/file_source.cpp b/platform/android/src/file_source.cpp index 42c03b0974..58a91f6cf0 100644 --- a/platform/android/src/file_source.cpp +++ b/platform/android/src/file_source.cpp @@ -70,14 +70,16 @@ void FileSource::resume(jni::JNIEnv&) { activationCounter.value()++; if (activationCounter == 1) { - fileSource->resume(); + fileSource->resume(); } } void FileSource::pause(jni::JNIEnv&) { - activationCounter.value()--; - if (activationCounter == 0) { - fileSource->pause(); + if (activationCounter) { + activationCounter.value()--; + if (activationCounter == 0) { + fileSource->pause(); + } } } diff --git a/platform/android/src/geojson/conversion/feature.hpp b/platform/android/src/geojson/conversion/feature.hpp index 86aa5fc03c..8fc62a2789 100644 --- a/platform/android/src/geojson/conversion/feature.hpp +++ b/platform/android/src/geojson/conversion/feature.hpp @@ -182,7 +182,7 @@ struct Converter<jni::Object<android::geojson::Feature>, mbgl::Feature> { auto properties = jni::Object<gson::JsonObject>(*convert<jni::jobject*>(env, value.properties)); // Convert geometry - auto geometry = jni::Object<android::geojson::Geometry>(*convert<jni::jobject*>(env, value.geometry)); + auto geometry = *convert<jni::Object<android::geojson::Geometry>>(env, value.geometry); // Create feature auto feature = android::geojson::Feature::fromGeometry(env, geometry, properties, jid); diff --git a/platform/android/src/geojson/conversion/geometry.hpp b/platform/android/src/geojson/conversion/geometry.hpp index 5d2aab4c2d..242a68df02 100644 --- a/platform/android/src/geojson/conversion/geometry.hpp +++ b/platform/android/src/geojson/conversion/geometry.hpp @@ -1,190 +1,24 @@ #pragma once -#include "../../conversion/constant.hpp" -#include "../../conversion/collection.hpp" - #include <mapbox/geometry.hpp> +#include "../geometry.hpp" #include <jni/jni.hpp> -#include "../../jni/local_object.hpp" namespace mbgl { namespace android { namespace conversion { /** - * Turn mapbox::geometry type into Java GeoJson Geometries - */ -template <typename T> -class GeometryEvaluator { -public: - - jni::JNIEnv& env; - - /** - * 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/geojson/Point")).release(); - static jni::jmethodID* fromLngLat = &jni::GetStaticMethodID(env, *javaClass, "fromLngLat", "(DD)Lcom/mapbox/geojson/Point;"); - - return reinterpret_cast<jni::jobject*>(jni::CallStaticMethod<jni::jobject*>(env, *javaClass, *fromLngLat, geometry.x, geometry.y)); - } - - /** - * 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/geojson/LineString")).release(); - static jni::jmethodID* fromLngLats = &jni::GetStaticMethodID(env, *javaClass, "fromLngLats", "(Ljava/util/List;)Lcom/mapbox/geojson/LineString;"); - - // Create - 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())); - } - - /** - * 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/geojson/MultiPoint")).release(); - static jni::jmethodID* fromLngLats = &jni::GetStaticMethodID(env, *javaClass, "fromLngLats", "(Ljava/util/List;)Lcom/mapbox/geojson/MultiPoint;"); - - // Create - 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())); - } - - /** - * 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/geojson/Polygon")).release(); - static jni::jmethodID* fromLngLats = &jni::GetStaticMethodID(env, *javaClass, "fromLngLats", "(Ljava/util/List;)Lcom/mapbox/geojson/Polygon;"); - - // Create - 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())); - } - - /** - * 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/geojson/MultiLineString")).release(); - static jni::jmethodID* fromLngLats = &jni::GetStaticMethodID(env, *javaClass, "fromLngLats", "(Ljava/util/List;)Lcom/mapbox/geojson/MultiLineString;"); - - // Create - 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 { - // 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::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/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/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) { - auto& geometry = collection.at(i); - jni::LocalObject<jni::jobject> converted = jni::NewLocalObject(env, mapbox::geometry::geometry<T>::visit(geometry, *this)); - jni::SetObjectArrayElement(env, *jarray, i, converted.get()); - } - - // Turn into array list and create the 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())); - } - -private: - - /** - * vector<point<T>> -> List<Point> - */ - static jni::jobject* toGeoJsonListOfPoints(JNIEnv& env, std::vector<mapbox::geometry::point<T>> points) { - - // 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::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 arrayList; - } - - /** - * geometry -> List<List<Point>> - */ - template <class SHAPE> - 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::jobject> listOfPoints = jni::NewLocalObject(env, toGeoJsonListOfPoints(env, value.at(i))); - jni::CallMethod<void>(env, arrayList, *add, i, listOfPoints.get()); - } - - return arrayList; - } -}; - -/** - * mapbox::geometry::geometry<T> -> Java GeoJson Geometry<> + * mapbox::geometry::geometry<T> -> Java GeoJson Geometry */ template <class T> -struct Converter<jni::jobject*, mapbox::geometry::geometry<T>> { - Result<jni::jobject*> operator()(jni::JNIEnv& env, const mapbox::geometry::geometry<T>& value) const { - GeometryEvaluator<double> evaluator { env } ; - jni::jobject* converted = mapbox::geometry::geometry<double>::visit(value, evaluator); - return {converted}; +struct Converter<jni::Object<android::geojson::Geometry>, mapbox::geometry::geometry<T>> { + Result<jni::Object<android::geojson::Geometry>> operator()(jni::JNIEnv& env, const mapbox::geometry::geometry<T>& value) const { + return { android::geojson::Geometry::New(env, value) }; } }; -} -} -} +} // conversion +} // android +} // mbgl diff --git a/platform/android/src/geojson/geometry.cpp b/platform/android/src/geojson/geometry.cpp index ca19d8fb03..5635b5a0f5 100644 --- a/platform/android/src/geojson/geometry.cpp +++ b/platform/android/src/geojson/geometry.cpp @@ -6,6 +6,7 @@ #include "multi_line_string.hpp" #include "polygon.hpp" #include "multi_polygon.hpp" +#include "geometry_collection.hpp" #include <string> @@ -13,7 +14,49 @@ namespace mbgl { namespace android { namespace geojson { -mapbox::geojson::geometry Geometry::convert(jni::JNIEnv &env, jni::Object<Geometry> jGeometry) { +/** + * Turn mapbox::geometry type into Java GeoJson Geometries + */ +class GeometryEvaluator { +public: + + jni::JNIEnv& env; + + jni::Object<Geometry> operator()(const mbgl::Point<double> &geometry) const { + return jni::Cast(env, Point::New(env, geometry), Geometry::javaClass); + } + + jni::Object<Geometry> operator()(const mbgl::LineString<double> &geometry) const { + return jni::Cast(env, LineString::New(env, geometry), Geometry::javaClass); + } + + jni::Object<Geometry> operator()(const mbgl::MultiLineString<double> &geometry) const { + return jni::Cast(env, MultiLineString::New(env, geometry), Geometry::javaClass); + } + + jni::Object<Geometry> operator()(const mbgl::MultiPoint<double> &geometry) const { + return jni::Cast(env, MultiPoint::New(env, geometry), Geometry::javaClass); + } + + jni::Object<Geometry> operator()(const mbgl::Polygon<double> &geometry) const { + return jni::Cast(env, Polygon::New(env, geometry), Geometry::javaClass); + } + + jni::Object<Geometry> operator()(const mbgl::MultiPolygon<double> &geometry) const { + return jni::Cast(env, MultiPolygon::New(env, geometry), Geometry::javaClass); + } + + jni::Object<Geometry> operator()(const mapbox::geometry::geometry_collection<double> &geometry) const { + return jni::Cast(env, GeometryCollection::New(env, geometry), Geometry::javaClass); + } +}; + +jni::Object<Geometry> Geometry::New(jni::JNIEnv& env, mbgl::Geometry<double> geometry) { + GeometryEvaluator evaluator { env } ; + return mbgl::Geometry<double>::visit(geometry, evaluator); +} + +mbgl::Geometry<double> Geometry::convert(jni::JNIEnv &env, jni::Object<Geometry> jGeometry) { auto type = Geometry::getType(env, jGeometry); if (type == Point::Type()) { return { Point::convert(env, jni::Object<Point>(jGeometry.Get())) }; @@ -27,6 +70,8 @@ mapbox::geojson::geometry Geometry::convert(jni::JNIEnv &env, jni::Object<Geomet return { Polygon::convert(env, jni::Object<Polygon>(jGeometry.Get())) }; } else if (type == MultiPolygon::Type()) { return { MultiPolygon::convert(env, jni::Object<MultiPolygon>(jGeometry.Get())) }; + } else if (type == GeometryCollection::Type()) { + return { GeometryCollection::convert(env, jni::Object<GeometryCollection>(jGeometry.Get())) }; } throw std::runtime_error(std::string {"Unsupported GeoJSON type: " } + type); diff --git a/platform/android/src/geojson/geometry.hpp b/platform/android/src/geojson/geometry.hpp index b7f8909f6f..a1bb886683 100644 --- a/platform/android/src/geojson/geometry.hpp +++ b/platform/android/src/geojson/geometry.hpp @@ -1,8 +1,10 @@ #pragma once -#include <mbgl/util/geojson.hpp> +#include <mbgl/util/geometry.hpp> #include <mbgl/util/noncopyable.hpp> +#include "../java/util.hpp" + #include <jni/jni.hpp> namespace mbgl { @@ -13,7 +15,9 @@ class Geometry : private mbgl::util::noncopyable { public: static constexpr auto Name() { return "com/mapbox/geojson/Geometry"; }; - static mapbox::geojson::geometry convert(jni::JNIEnv&, jni::Object<Geometry>); + static jni::Object<Geometry> New(jni::JNIEnv&, mbgl::Geometry<double>); + + static mbgl::Geometry<double> convert(jni::JNIEnv&, jni::Object<Geometry>); static std::string getType(jni::JNIEnv&, jni::Object<Geometry>); diff --git a/platform/android/src/geojson/geometry_collection.cpp b/platform/android/src/geojson/geometry_collection.cpp new file mode 100644 index 0000000000..eb3a790404 --- /dev/null +++ b/platform/android/src/geojson/geometry_collection.cpp @@ -0,0 +1,63 @@ +#include "geometry_collection.hpp" +#include "../java/util.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +jni::Object<GeometryCollection> GeometryCollection::New(jni::JNIEnv& env, const mapbox::geometry::geometry_collection<double>& collection) { + // Create an array of geometries + auto jarray = jni::Array<jni::Object<Geometry>>::New(env, collection.size(), Geometry::javaClass); + + for (size_t i = 0; i < collection.size(); i++) { + auto& geometry = collection.at(i); + auto jGeometry = Geometry::New(env, geometry); + jarray.Set(env, i, jGeometry); + jni::DeleteLocalRef(env, jGeometry); + } + + // Turn into array list + auto jList = java::util::Arrays::asList(env, jarray); + jni::DeleteLocalRef(env, jarray); + + // create the GeometryCollection + static auto method = javaClass.GetStaticMethod<jni::Object<GeometryCollection> (jni::Object<java::util::List>)>(env, "fromGeometries"); + auto jCollection = javaClass.Call(env, method, jList); + + jni::DeleteLocalRef(env, jList); + return jCollection; +} + +mapbox::geometry::geometry_collection<double> GeometryCollection::convert(jni::JNIEnv &env, jni::Object<GeometryCollection> jCollection) { + // Get geometries + static auto getGeometries = javaClass.GetMethod<jni::Object<java::util::List> ()>(env, "getGeometries"); + auto jList = jCollection.Call(env, getGeometries); + + // Turn into array + auto jarray = java::util::List::toArray<Geometry>(env, jList); + jni::DeleteLocalRef(env, jList); + + // Convert each geometry + mapbox::geometry::geometry_collection<double> collection{}; + + auto size = jarray.Length(env); + for (jni::jsize i = 0; i < size; i++) { + auto element = jarray.Get(env, i); + collection.push_back(Geometry::convert(env, element)); + jni::DeleteLocalRef(env, element); + } + + jni::DeleteLocalRef(env, jarray); + return collection; +} + +void GeometryCollection::registerNative(jni::JNIEnv &env) { + // Lookup the class + javaClass = *jni::Class<GeometryCollection>::Find(env).NewGlobalRef(env).release(); +} + +jni::Class<GeometryCollection> GeometryCollection::javaClass; + +} // namespace geojson +} // namespace android +} // namespace mbgl
\ No newline at end of file diff --git a/platform/android/src/geojson/geometry_collection.hpp b/platform/android/src/geojson/geometry_collection.hpp new file mode 100644 index 0000000000..9ed9953b0d --- /dev/null +++ b/platform/android/src/geojson/geometry_collection.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include "geometry.hpp" + +#include <jni/jni.hpp> + +namespace mbgl { +namespace android { +namespace geojson { + +class GeometryCollection : public Geometry { +public: + static constexpr auto Name() { return "com/mapbox/geojson/GeometryCollection"; }; + + static constexpr auto Type() { return "GeometryCollection"; }; + + static jni::Object<GeometryCollection> New(jni::JNIEnv&, const mapbox::geometry::geometry_collection<double>&); + + static mapbox::geometry::geometry_collection<double> convert(jni::JNIEnv&, jni::Object<GeometryCollection>); + + static jni::Class<GeometryCollection> javaClass; + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace geojson +} // namespace android +} // namespace mbgl
\ No newline at end of file diff --git a/platform/android/src/geojson/line_string.cpp b/platform/android/src/geojson/line_string.cpp index 8eebd53550..a5f1a468ce 100644 --- a/platform/android/src/geojson/line_string.cpp +++ b/platform/android/src/geojson/line_string.cpp @@ -1,11 +1,22 @@ #include "line_string.hpp" - #include "point.hpp" +#include "util.hpp" +#include "../java/util.hpp" namespace mbgl { namespace android { namespace geojson { +jni::Object<LineString> LineString::New(jni::JNIEnv& env, const mbgl::LineString<double>& lineString) { + auto jList = asPointsList(env, lineString); + + static auto method = javaClass.GetStaticMethod<jni::Object<LineString>(jni::Object<java::util::List>)>(env, "fromLngLats"); + auto jLineString = javaClass.Call(env, method, jList); + + jni::DeleteLocalRef(env, jList); + return jLineString; +} + mapbox::geojson::line_string LineString::convert(jni::JNIEnv &env, jni::Object<LineString> jLineString) { mapbox::geojson::line_string lineString; diff --git a/platform/android/src/geojson/line_string.hpp b/platform/android/src/geojson/line_string.hpp index 86033c2e6a..98dc414642 100644 --- a/platform/android/src/geojson/line_string.hpp +++ b/platform/android/src/geojson/line_string.hpp @@ -1,23 +1,27 @@ #pragma once #include <mbgl/util/geojson.hpp> +#include <mbgl/util/geometry.hpp> #include <mbgl/util/noncopyable.hpp> -#include <jni/jni.hpp> - +#include "geometry.hpp" #include "../java/util.hpp" +#include <jni/jni.hpp> + namespace mbgl { namespace android { namespace geojson { -class LineString : private mbgl::util::noncopyable { +class LineString : public Geometry { public: static constexpr auto Name() { return "com/mapbox/geojson/LineString"; }; static constexpr auto Type() { return "LineString"; }; + static jni::Object<LineString> New(jni::JNIEnv&, const mbgl::LineString<double>&); + static mapbox::geojson::line_string convert(jni::JNIEnv&, jni::Object<LineString>); static mapbox::geojson::line_string convert(jni::JNIEnv&, jni::Object<java::util::List/*<Point>*/>); diff --git a/platform/android/src/geojson/multi_line_string.cpp b/platform/android/src/geojson/multi_line_string.cpp index c748d4786f..4a6ea37dd1 100644 --- a/platform/android/src/geojson/multi_line_string.cpp +++ b/platform/android/src/geojson/multi_line_string.cpp @@ -1,11 +1,22 @@ #include "multi_line_string.hpp" #include "line_string.hpp" +#include "util.hpp" namespace mbgl { namespace android { namespace geojson { +jni::Object<MultiLineString> MultiLineString::New(jni::JNIEnv& env, const mbgl::MultiLineString<double>& multiLineString) { + auto jList = asPointsListsList(env, multiLineString); + + static auto method = javaClass.GetStaticMethod<jni::Object<MultiLineString> (jni::Object<java::util::List>)>(env, "fromLngLats"); + auto jMultiLineString = javaClass.Call(env, method, jList); + + jni::DeleteLocalRef(env, jList); + return jMultiLineString; +} + mapbox::geojson::multi_line_string MultiLineString::convert(jni::JNIEnv &env, jni::Object<MultiLineString> jMultiLineString) { mapbox::geojson::multi_line_string multiLineString; diff --git a/platform/android/src/geojson/multi_line_string.hpp b/platform/android/src/geojson/multi_line_string.hpp index 358a6b5dda..934a0cb6b5 100644 --- a/platform/android/src/geojson/multi_line_string.hpp +++ b/platform/android/src/geojson/multi_line_string.hpp @@ -3,20 +3,23 @@ #include <mbgl/util/geojson.hpp> #include <mbgl/util/noncopyable.hpp> -#include <jni/jni.hpp> - #include "../java/util.hpp" +#include "geometry.hpp" + +#include <jni/jni.hpp> namespace mbgl { namespace android { namespace geojson { -class MultiLineString : private mbgl::util::noncopyable { +class MultiLineString : public Geometry { public: static constexpr auto Name() { return "com/mapbox/geojson/MultiLineString"; }; static constexpr auto Type() { return "MultiLineString"; }; + static jni::Object<MultiLineString> New(jni::JNIEnv&, const mbgl::MultiLineString<double>&); + 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<Point>>*/>); diff --git a/platform/android/src/geojson/multi_point.cpp b/platform/android/src/geojson/multi_point.cpp index 4f9ff596b2..6f62541209 100644 --- a/platform/android/src/geojson/multi_point.cpp +++ b/platform/android/src/geojson/multi_point.cpp @@ -8,6 +8,16 @@ namespace mbgl { namespace android { namespace geojson { +jni::Object<MultiPoint> MultiPoint::New(JNIEnv& env, const mbgl::MultiPoint<double>& multiPoint) { + auto jList = asPointsList(env, multiPoint); + + static auto method = javaClass.GetStaticMethod<jni::Object<MultiPoint>(jni::Object<java::util::List>)>(env, "fromLngLats"); + auto jMultiPoint = javaClass.Call(env, method, jList); + + jni::DeleteLocalRef(env, jList); + return jMultiPoint; +} + mapbox::geojson::multi_point MultiPoint::convert(jni::JNIEnv &env, jni::Object<MultiPoint> jMultiPoint) { mapbox::geojson::multi_point multiPoint; diff --git a/platform/android/src/geojson/multi_point.hpp b/platform/android/src/geojson/multi_point.hpp index e893e879af..cfe80cd34c 100644 --- a/platform/android/src/geojson/multi_point.hpp +++ b/platform/android/src/geojson/multi_point.hpp @@ -1,22 +1,26 @@ #pragma once #include <mbgl/util/geojson.hpp> +#include <mbgl/util/geometry.hpp> #include <mbgl/util/noncopyable.hpp> -#include <jni/jni.hpp> - +#include "geometry.hpp" #include "../java/util.hpp" +#include <jni/jni.hpp> + namespace mbgl { namespace android { namespace geojson { -class MultiPoint : private mbgl::util::noncopyable { +class MultiPoint : public Geometry { public: static constexpr auto Name() { return "com/mapbox/geojson/MultiPoint"; }; static constexpr auto Type() { return "MultiPoint"; }; + static jni::Object<MultiPoint> New(jni::JNIEnv&, const mbgl::MultiPoint<double>&); + static mapbox::geojson::multi_point convert(jni::JNIEnv&, jni::Object<MultiPoint>); static jni::Object<java::util::List> coordinates(jni::JNIEnv&, jni::Object<MultiPoint>); diff --git a/platform/android/src/geojson/multi_polygon.cpp b/platform/android/src/geojson/multi_polygon.cpp index aadba8c8a6..cc872d4955 100644 --- a/platform/android/src/geojson/multi_polygon.cpp +++ b/platform/android/src/geojson/multi_polygon.cpp @@ -1,11 +1,34 @@ #include "multi_polygon.hpp" #include "polygon.hpp" +#include "util.hpp" namespace mbgl { namespace android { namespace geojson { +jni::Object<MultiPolygon> MultiPolygon::New(JNIEnv& env, const mbgl::MultiPolygon<double>& multiPolygon) { + auto jarray = jni::Array<jni::Object<java::util::List>>::New(env, multiPolygon.size(), java::util::List::javaClass); + + for (size_t i = 0; i < multiPolygon.size(); i++) { + auto& geometry = multiPolygon.at(i); + auto jPolygon = asPointsListsList(env, geometry); + jarray.Set(env, i, jPolygon); + jni::DeleteLocalRef(env, jPolygon); + } + + // Turn into array list + auto jList = java::util::Arrays::asList(env, jarray); + jni::DeleteLocalRef(env, jarray); + + // create the MultiPolygon + static auto method = javaClass.GetStaticMethod<jni::Object<MultiPolygon> (jni::Object<java::util::List>)>(env, "fromLngLats"); + auto jMultiPolygon = javaClass.Call(env, method, jList); + + jni::DeleteLocalRef(env, jList); + return jMultiPolygon; +} + mapbox::geojson::multi_polygon MultiPolygon::convert(jni::JNIEnv &env, jni::Object<MultiPolygon> jMultiPolygon) { mapbox::geojson::multi_polygon multiPolygon; diff --git a/platform/android/src/geojson/multi_polygon.hpp b/platform/android/src/geojson/multi_polygon.hpp index 6e1dfacfc8..b4657af09d 100644 --- a/platform/android/src/geojson/multi_polygon.hpp +++ b/platform/android/src/geojson/multi_polygon.hpp @@ -3,20 +3,23 @@ #include <mbgl/util/geojson.hpp> #include <mbgl/util/noncopyable.hpp> -#include <jni/jni.hpp> - #include "../java/util.hpp" +#include "geometry.hpp" + +#include <jni/jni.hpp> namespace mbgl { namespace android { namespace geojson { -class MultiPolygon : private mbgl::util::noncopyable { +class MultiPolygon : public Geometry { public: static constexpr auto Name() { return "com/mapbox/geojson/MultiPolygon"; }; static constexpr auto Type() { return "MultiPolygon"; }; + static jni::Object<MultiPolygon> New(jni::JNIEnv&, const mbgl::MultiPolygon<double>&); + static mapbox::geojson::multi_polygon convert(jni::JNIEnv&, jni::Object<MultiPolygon>); static jni::Object<java::util::List> coordinates(jni::JNIEnv&, jni::Object<MultiPolygon>); diff --git a/platform/android/src/geojson/point.cpp b/platform/android/src/geojson/point.cpp index e95376cd2e..8a9656ea14 100644 --- a/platform/android/src/geojson/point.cpp +++ b/platform/android/src/geojson/point.cpp @@ -7,6 +7,11 @@ namespace mbgl { namespace android { namespace geojson { +jni::Object<Point> Point::New(jni::JNIEnv& env, const mbgl::Point<double>& point) { + static auto method = javaClass.GetStaticMethod<jni::Object<Point> (jni::jdouble, jni::jdouble)>(env, "fromLngLat"); + return javaClass.Call(env, method, point.x, point.y); +} + mapbox::geojson::point Point::convert(jni::JNIEnv &env, jni::Object<Point> jPoint) { mapbox::geojson::point point; @@ -54,4 +59,4 @@ jni::Class<Point> Point::javaClass; } // namespace geojson } // namespace android -} // namespace mbgl
\ No newline at end of file +} // namespace mbgl diff --git a/platform/android/src/geojson/point.hpp b/platform/android/src/geojson/point.hpp index c6412299bf..627bd1b649 100644 --- a/platform/android/src/geojson/point.hpp +++ b/platform/android/src/geojson/point.hpp @@ -3,20 +3,23 @@ #include <mbgl/util/geojson.hpp> #include <mbgl/util/noncopyable.hpp> -#include <jni/jni.hpp> - #include "../java/util.hpp" +#include "geometry.hpp" + +#include <jni/jni.hpp> namespace mbgl { namespace android { namespace geojson { -class Point : private mbgl::util::noncopyable { +class Point : public Geometry { public: static constexpr auto Name() { return "com/mapbox/geojson/Point"; }; static constexpr auto Type() { return "Point"; }; + static jni::Object<Point> New(jni::JNIEnv&, const mbgl::Point<double>&); + static mapbox::geojson::point convert(jni::JNIEnv&, jni::Object<Point>); static mapbox::geojson::point convert(jni::JNIEnv&, jni::Object<java::util::List/*<Double>*/>); diff --git a/platform/android/src/geojson/polygon.cpp b/platform/android/src/geojson/polygon.cpp index 30ba996640..96058b63b3 100644 --- a/platform/android/src/geojson/polygon.cpp +++ b/platform/android/src/geojson/polygon.cpp @@ -8,6 +8,16 @@ namespace mbgl { namespace android { namespace geojson { +jni::Object<Polygon> Polygon::New(jni::JNIEnv& env, const mbgl::Polygon<double>& polygon) { + auto jList = asPointsListsList(env, polygon); + + static auto method = javaClass.GetStaticMethod<jni::Object<Polygon> (jni::Object<java::util::List>)>(env, "fromLngLats"); + auto jPolygon = javaClass.Call(env, method, jList); + + jni::DeleteLocalRef(env, jList); + return jPolygon; +} + mapbox::geojson::polygon Polygon::convert(jni::JNIEnv &env, jni::Object<Polygon> jPolygon) { mapbox::geojson::polygon polygon; diff --git a/platform/android/src/geojson/polygon.hpp b/platform/android/src/geojson/polygon.hpp index a8b2b93827..f3c23b4d7b 100644 --- a/platform/android/src/geojson/polygon.hpp +++ b/platform/android/src/geojson/polygon.hpp @@ -3,20 +3,24 @@ #include <mbgl/util/geojson.hpp> #include <mbgl/util/noncopyable.hpp> +#include "geometry.hpp" +#include "../java/util.hpp" + #include <jni/jni.hpp> -#include "../java/util.hpp" namespace mbgl { namespace android { namespace geojson { -class Polygon : private mbgl::util::noncopyable { +class Polygon : public Geometry { public: static constexpr auto Name() { return "com/mapbox/geojson/Polygon"; }; static constexpr auto Type() { return "Polygon"; }; + static jni::Object<Polygon> New(jni::JNIEnv&, const mbgl::Polygon<double>&); + 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<Point>>*/>); diff --git a/platform/android/src/geojson/util.hpp b/platform/android/src/geojson/util.hpp index ece8e52433..5e6d90a953 100644 --- a/platform/android/src/geojson/util.hpp +++ b/platform/android/src/geojson/util.hpp @@ -1,5 +1,7 @@ #pragma once +#include "point.hpp" + #include <type_traits> namespace mbgl { @@ -17,6 +19,42 @@ To convertExplicit(From&& src) { return *reinterpret_cast<std::add_pointer_t<To>>(&src); } +/** + * Geometry -> List<Point> + */ +template <class T> +static jni::Object<java::util::List> asPointsList(jni::JNIEnv& env, const T& pointsList) { + auto jarray = jni::Array<jni::Object<Point>>::New(env, pointsList.size(), Point::javaClass); + + for (jni::jsize i = 0; i < pointsList.size(); i++) { + auto jPoint = Point::New(env, pointsList.at(i)); + jarray.Set(env, i, jPoint); + jni::DeleteLocalRef(env, jPoint); + } + + auto jList = java::util::Arrays::asList(env, jarray); + jni::DeleteLocalRef(env, jarray); + return jList; +} + +/** + * Geometry -> List<List<Point>> + */ +template <class SHAPE> +static jni::Object<java::util::List> asPointsListsList(JNIEnv& env, SHAPE value) { + auto jarray = jni::Array<jni::Object<java::util::List>>::New(env, value.size(), java::util::List::javaClass); + + for (size_t i = 0; i < value.size(); i = i + 1) { + auto pointsList = asPointsList(env, value[i]); + jarray.Set(env, i, pointsList); + jni::DeleteLocalRef(env, pointsList); + } + + auto jList = java::util::Arrays::asList(env, jarray); + jni::DeleteLocalRef(env, jarray); + return jList; +} + } // namespace geojson } // namespace android } // namespace mbgl diff --git a/platform/android/src/gson/json_array.cpp b/platform/android/src/gson/json_array.cpp index d91e323ac9..e8852d77e9 100644 --- a/platform/android/src/gson/json_array.cpp +++ b/platform/android/src/gson/json_array.cpp @@ -6,7 +6,22 @@ namespace mbgl { namespace android { namespace gson { -std::vector<mapbox::geometry::value> JsonArray::convert(jni::JNIEnv &env, jni::Object<JsonArray> jsonArray) { +jni::Object<JsonArray> JsonArray::New(jni::JNIEnv& env, const std::vector<mapbox::geometry::value>& values){ + static auto constructor = JsonArray::javaClass.GetConstructor(env); + static auto addMethod = JsonArray::javaClass.GetMethod<void (jni::Object<JsonElement>)>(env, "add"); + + auto jsonArray = JsonArray::javaClass.New(env, constructor); + + for (const auto &v : values) { + auto jsonElement = JsonElement::New(env, v); + jsonArray.Call(env, addMethod, jsonElement); + jni::DeleteLocalRef(env, jsonElement); + } + + return jsonArray; +} + +std::vector<mapbox::geometry::value> JsonArray::convert(jni::JNIEnv& env, const jni::Object<JsonArray> jsonArray) { std::vector<mapbox::geometry::value> values; if (jsonArray) { @@ -28,7 +43,7 @@ std::vector<mapbox::geometry::value> JsonArray::convert(jni::JNIEnv &env, jni::O return values; } -void JsonArray::registerNative(jni::JNIEnv &env) { +void JsonArray::registerNative(jni::JNIEnv& env) { // Lookup the class javaClass = *jni::Class<JsonArray>::Find(env).NewGlobalRef(env).release(); } diff --git a/platform/android/src/gson/json_array.hpp b/platform/android/src/gson/json_array.hpp index 8571ad5dba..c9ae98692f 100644 --- a/platform/android/src/gson/json_array.hpp +++ b/platform/android/src/gson/json_array.hpp @@ -13,6 +13,8 @@ class JsonArray : private mbgl::util::noncopyable { public: static constexpr auto Name() { return "com/google/gson/JsonArray"; }; + static jni::Object<JsonArray> New(jni::JNIEnv&, const std::vector<mapbox::geometry::value>&); + static std::vector<mapbox::geometry::value> convert(JNIEnv&, jni::Object<JsonArray>); static jni::Class<JsonArray> javaClass; diff --git a/platform/android/src/gson/json_element.cpp b/platform/android/src/gson/json_element.cpp index 060b1e0fe2..5eaaf531f4 100644 --- a/platform/android/src/gson/json_element.cpp +++ b/platform/android/src/gson/json_element.cpp @@ -11,6 +11,34 @@ namespace mbgl { namespace android { namespace gson { +/** + * Turn mapbox::geometry::value into Java Gson JsonElement + */ +class JsonElementEvaluator { +public: + + jni::JNIEnv& env; + + jni::Object<JsonElement> operator()(const JsonPrimitive::value value) const { + return jni::Cast(env, JsonPrimitive::New(env, value), JsonElement::javaClass); + } + + jni::Object<JsonElement> operator()(const std::vector<mapbox::geometry::value> &values) const { + return jni::Cast(env, JsonArray::New(env, values), JsonElement::javaClass); + } + + jni::Object<JsonElement> operator()(const std::unordered_map<std::string, mapbox::geometry::value> &values) const { + return jni::Cast(env, JsonObject::New(env, values), JsonElement::javaClass); + } + +}; + + +jni::Object<JsonElement> JsonElement::New(jni::JNIEnv& env, const mapbox::geometry::value& value) { + JsonElementEvaluator evaluator { env } ; + return mapbox::geometry::value::visit(value, evaluator); +} + mapbox::geometry::value JsonElement::convert(jni::JNIEnv &env, jni::Object<JsonElement> jsonElement) { mapbox::geometry::value value; diff --git a/platform/android/src/gson/json_element.hpp b/platform/android/src/gson/json_element.hpp index 7619350617..d850caa526 100644 --- a/platform/android/src/gson/json_element.hpp +++ b/platform/android/src/gson/json_element.hpp @@ -13,6 +13,8 @@ class JsonElement : private mbgl::util::noncopyable { public: static constexpr auto Name() { return "com/google/gson/JsonElement"; }; + static jni::Object<JsonElement> New(jni::JNIEnv&, const mapbox::geometry::value&); + static mapbox::geometry::value convert(JNIEnv&, jni::Object<JsonElement>); static bool isJsonObject(JNIEnv&, jni::Object<JsonElement>); diff --git a/platform/android/src/gson/json_object.cpp b/platform/android/src/gson/json_object.cpp index a704dae9dd..61b55f8b9e 100644 --- a/platform/android/src/gson/json_object.cpp +++ b/platform/android/src/gson/json_object.cpp @@ -9,6 +9,23 @@ namespace android { namespace gson { +jni::Object<JsonObject> JsonObject::New(jni::JNIEnv& env, const std::unordered_map<std::string, mapbox::geometry::value>& values) { + static auto constructor = JsonObject::javaClass.GetConstructor(env); + static auto addMethod = JsonObject::javaClass.GetMethod<void (jni::String, jni::Object<JsonElement>)>(env, "add"); + + jni::Object<JsonObject> jsonObject = JsonObject::javaClass.New(env, constructor); + + for (auto &item : values) { + jni::Object<JsonElement> jsonElement = JsonElement::New(env, item.second); + jni::String key = jni::Make<jni::String>(env, item.first); + jsonObject.Call(env, addMethod, key, jsonElement); + jni::DeleteLocalRef(env, jsonElement); + jni::DeleteLocalRef(env, key); + } + + return jsonObject; +} + template <typename F> // void (jni::String, jni::Object<gson::JsonElement>) static void iterateEntrySet(jni::JNIEnv& env, jni::Object<JsonObject> jsonObject, F callback) { // Get Set<Map.Entry<String, JsonElement>> diff --git a/platform/android/src/gson/json_object.hpp b/platform/android/src/gson/json_object.hpp index aba8e40415..4bc61e51a2 100644 --- a/platform/android/src/gson/json_object.hpp +++ b/platform/android/src/gson/json_object.hpp @@ -13,6 +13,8 @@ class JsonObject : private mbgl::util::noncopyable { public: static constexpr auto Name() { return "com/google/gson/JsonObject"; }; + static jni::Object<JsonObject> New(jni::JNIEnv&, const std::unordered_map<std::string, mapbox::geometry::value>&); + static mapbox::geometry::property_map convert(JNIEnv&, jni::Object<JsonObject>); static jni::Class<JsonObject> javaClass; diff --git a/platform/android/src/gson/json_primitive.cpp b/platform/android/src/gson/json_primitive.cpp index 58d0b45fe7..4e171c4845 100644 --- a/platform/android/src/gson/json_primitive.cpp +++ b/platform/android/src/gson/json_primitive.cpp @@ -1,9 +1,89 @@ #include "json_primitive.hpp" +#include "../java/lang.hpp" namespace mbgl { namespace android { namespace gson { +/** + * Turn mapbox::geometry::value into Java Gson JsonPrimitives + */ +class JsonPrimitiveEvaluator { +public: + + jni::JNIEnv& env; + + /** + * Create a null primitive + */ + jni::Object<JsonPrimitive> operator()(const mapbox::geometry::null_value_t) const { + return jni::Object<JsonPrimitive>(); + } + + /** + * Create a primitive containing a string value + */ + jni::Object<JsonPrimitive> operator()(const std::string value) const { + static auto constructor = JsonPrimitive::javaClass.GetConstructor<jni::String>(env); + auto jvalue = jni::Make<jni::String>(env, value); + auto jsonPrimitive = JsonPrimitive::javaClass.New(env, constructor, jvalue); + jni::DeleteLocalRef(env, jvalue); + return jsonPrimitive; + } + + /** + * Create a primitive containing a number value with type double + */ + jni::Object<JsonPrimitive> operator()(const double value) const { + static auto constructor = JsonPrimitive::javaClass.GetConstructor<jni::Object<java::lang::Number>>(env); + auto boxedValue = java::lang::Double::valueOf(env, value); + auto number = jni::Cast(env, boxedValue, java::lang::Number::javaClass); + auto jsonPrimitive = JsonPrimitive::javaClass.New(env, constructor, number); + jni::DeleteLocalRef(env, boxedValue); + return jsonPrimitive; + } + + /** + * Create a primitive containing a number value with type long + */ + jni::Object<JsonPrimitive> operator()(const int64_t value) const { + static auto constructor = JsonPrimitive::javaClass.GetConstructor<jni::Object<java::lang::Number>>(env); + auto boxedValue = java::lang::Long::valueOf(env, value); + auto number = jni::Cast(env, boxedValue, java::lang::Number::javaClass); + auto jsonPrimitive = JsonPrimitive::javaClass.New(env, constructor, number); + jni::DeleteLocalRef(env, boxedValue); + return jsonPrimitive; + } + + /** + * Create a primitive containing a number value with type long + */ + jni::Object<JsonPrimitive> operator()(const uint64_t value) const { + static auto constructor = JsonPrimitive::javaClass.GetConstructor<jni::Object<java::lang::Number>>(env); + auto boxedValue = java::lang::Long::valueOf(env, value); + auto number = jni::Cast(env, boxedValue, java::lang::Number::javaClass); + auto jsonPrimitive = JsonPrimitive::javaClass.New(env, constructor, number); + jni::DeleteLocalRef(env, boxedValue); + return jsonPrimitive; + } + + /** + * Create a primitive containing a boolean value + */ + jni::Object<JsonPrimitive> operator()(const bool value) const { + static auto constructor = JsonPrimitive::javaClass.GetConstructor<jni::Object<java::lang::Boolean>>(env); + auto boxedValue = java::lang::Boolean::valueOf(env, value); + auto jsonPrimitive = JsonPrimitive::javaClass.New(env, constructor, boxedValue); + jni::DeleteLocalRef(env, boxedValue); + return jsonPrimitive; + } +}; + +jni::Object<JsonPrimitive> JsonPrimitive::New(jni::JNIEnv &env, const value& value) { + JsonPrimitiveEvaluator evaluator { env }; + return value::visit(value, evaluator); +} + JsonPrimitive::value JsonPrimitive::convert(jni::JNIEnv &env, jni::Object<JsonPrimitive> jsonPrimitive) { value value; if (jsonPrimitive) { diff --git a/platform/android/src/gson/json_primitive.hpp b/platform/android/src/gson/json_primitive.hpp index 5fc8a2b485..c418e0ebe8 100644 --- a/platform/android/src/gson/json_primitive.hpp +++ b/platform/android/src/gson/json_primitive.hpp @@ -15,6 +15,8 @@ public: static constexpr auto Name() { return "com/google/gson/JsonPrimitive"; }; + static jni::Object<JsonPrimitive> New(jni::JNIEnv&, const value&); + static value convert(JNIEnv&, jni::Object<JsonPrimitive>); static bool isBoolean(JNIEnv&, jni::Object<JsonPrimitive>); diff --git a/platform/android/src/http_file_source.cpp b/platform/android/src/http_file_source.cpp index 8eb9416e9d..cda84209ea 100644 --- a/platform/android/src/http_file_source.cpp +++ b/platform/android/src/http_file_source.cpp @@ -61,7 +61,7 @@ void RegisterNativeHTTPRequest(jni::JNIEnv& env) { #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name) - jni::RegisterNativePeer<HTTPRequest>(env, HTTPRequest::javaClass, "mNativePtr", + jni::RegisterNativePeer<HTTPRequest>(env, HTTPRequest::javaClass, "nativePtr", METHOD(&HTTPRequest::onFailure, "nativeOnFailure"), METHOD(&HTTPRequest::onResponse, "nativeOnResponse")); } diff --git a/platform/android/src/image.cpp b/platform/android/src/image.cpp index 2a33944b18..0456381578 100644 --- a/platform/android/src/image.cpp +++ b/platform/android/src/image.cpp @@ -16,7 +16,12 @@ PremultipliedImage decodeImage(const std::string& string) { reinterpret_cast<const signed char*>(string.data())); auto bitmap = android::BitmapFactory::DecodeByteArray(*env, array, 0, string.size()); - return android::Bitmap::GetImage(*env, bitmap); + jni::DeleteLocalRef(*env, array); + + auto image = android::Bitmap::GetImage(*env, bitmap); + jni::DeleteLocalRef(*env, bitmap); + + return image; } } // namespace mbgl diff --git a/platform/android/src/java/lang.cpp b/platform/android/src/java/lang.cpp new file mode 100644 index 0000000000..3c95737169 --- /dev/null +++ b/platform/android/src/java/lang.cpp @@ -0,0 +1,76 @@ +#include "lang.hpp" + +namespace mbgl { +namespace android { +namespace java { +namespace lang { + +// Float + +jni::Object<Float> Float::valueOf(JNIEnv &env, jfloat value) { + static auto method = javaClass.GetStaticMethod<jni::Object<Float> (jni::jfloat)>(env, "valueOf"); + return javaClass.Call(env, method, value); +} + +void Float::registerNative(jni::JNIEnv &env) { + // Lookup the class + javaClass = *jni::Class<Float>::Find(env).NewGlobalRef(env).release(); +} + +jni::Class<Float> Float::javaClass; + +// Long + +jni::Object<Long> Long::valueOf(JNIEnv &env, jlong value) { + static auto method = javaClass.GetStaticMethod<jni::Object<Long> (jni::jlong)>(env, "valueOf"); + return javaClass.Call(env, method, value); +} + +void Long::registerNative(jni::JNIEnv &env) { + // Lookup the class + javaClass = *jni::Class<Long>::Find(env).NewGlobalRef(env).release(); +} + +jni::Class<Long> Long::javaClass; + +// Double + +jni::Object<Double> Double::valueOf(JNIEnv &env, jdouble value) { + static auto method = javaClass.GetStaticMethod<jni::Object<Double> (jni::jdouble)>(env, "valueOf"); + return javaClass.Call(env, method, value); +} + +void Double::registerNative(jni::JNIEnv &env) { + // Lookup the class + javaClass = *jni::Class<Double>::Find(env).NewGlobalRef(env).release(); +} + +jni::Class<Double> Double::javaClass; + +// Boolean + +jni::Object<Boolean> Boolean::valueOf(JNIEnv &env, jboolean value) { + static auto method = javaClass.GetStaticMethod<jni::Object<Boolean> (jni::jboolean)>(env, "valueOf"); + return javaClass.Call(env, method, value); +} + +void Boolean::registerNative(jni::JNIEnv &env) { + // Lookup the class + javaClass = *jni::Class<Boolean>::Find(env).NewGlobalRef(env).release(); +} + +jni::Class<Boolean> Boolean::javaClass; + +// Number + +void Number::registerNative(jni::JNIEnv &env) { + // Lookup the class + javaClass = *jni::Class<Number>::Find(env).NewGlobalRef(env).release(); +} + +jni::Class<Number> Number::javaClass; + +} // namespace lang +} // namespace java +} // namespace android +} // namespace mbgl diff --git a/platform/android/src/java/lang.hpp b/platform/android/src/java/lang.hpp index dcf81a9d0c..981e3b14b7 100644 --- a/platform/android/src/java/lang.hpp +++ b/platform/android/src/java/lang.hpp @@ -1,18 +1,64 @@ #pragma once +#include <jni/jni.hpp> +#include <mbgl/util/noncopyable.hpp> + namespace mbgl { namespace android { namespace java { namespace lang { -class Float { +class Float : private mbgl::util::noncopyable { public: static constexpr auto Name() { return "java/lang/Float"; }; + + static jni::Object<Float> valueOf(JNIEnv&, jfloat); + + static jni::Class<Float> javaClass; + + static void registerNative(jni::JNIEnv&); +}; + +class Double : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "java/lang/Double"; }; + + static jni::Object<Double> valueOf(JNIEnv&, jdouble); + + static jni::Class<Double> javaClass; + + static void registerNative(jni::JNIEnv&); +}; + +class Long : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "java/lang/Long"; }; + + static jni::Object<Long> valueOf(JNIEnv&, jlong); + + static jni::Class<Long> javaClass; + + static void registerNative(jni::JNIEnv&); +}; + +class Boolean : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "java/lang/Boolean"; }; + + static jni::Object<Boolean> valueOf(JNIEnv&, jboolean); + + static jni::Class<Boolean> javaClass; + + static void registerNative(jni::JNIEnv&); }; -class Number { +class Number : private mbgl::util::noncopyable { public: static constexpr auto Name() { return "java/lang/Number"; }; + + static jni::Class<Number> javaClass; + + static void registerNative(jni::JNIEnv&); }; } // namespace lang diff --git a/platform/android/src/java/util.cpp b/platform/android/src/java/util.cpp index effd2ae0d0..89c4c77794 100644 --- a/platform/android/src/java/util.cpp +++ b/platform/android/src/java/util.cpp @@ -5,12 +5,14 @@ namespace android { namespace java { namespace util { +jni::Class<Arrays> Arrays::javaClass; jni::Class<List> List::javaClass; jni::Class<Set> Set::javaClass; jni::Class<Map> Map::javaClass; jni::Class<Map::Entry> Map::Entry::javaClass; void registerNative(jni::JNIEnv& env) { + Arrays::javaClass = *jni::Class<Arrays>::Find(env).NewGlobalRef(env).release(); List::javaClass = *jni::Class<List>::Find(env).NewGlobalRef(env).release(); Set::javaClass = *jni::Class<Set>::Find(env).NewGlobalRef(env).release(); Map::javaClass = *jni::Class<Map>::Find(env).NewGlobalRef(env).release(); diff --git a/platform/android/src/java/util.hpp b/platform/android/src/java/util.hpp index dedb8ac348..c6b07acac5 100644 --- a/platform/android/src/java/util.hpp +++ b/platform/android/src/java/util.hpp @@ -24,6 +24,21 @@ public: }; +class Arrays : private mbgl::util::noncopyable { +public: + + static constexpr auto Name() { return "java/util/Arrays"; }; + + template <class T> + static jni::Object<List> asList(jni::JNIEnv& env, jni::Array<jni::Object<T>> array) { + static auto asList = Arrays::javaClass.GetStaticMethod<jni::Object<List>(jni::Array<jni::Object<>>)>(env, "asList"); + return javaClass.Call(env, asList, (jni::Array<jni::Object<>>) array); + } + + static jni::Class<Arrays> javaClass; + +}; + class Set : private mbgl::util::noncopyable { public: diff --git a/platform/android/src/jni.cpp b/platform/android/src/jni.cpp index c2fd1c95ad..2f6ed96ab0 100755 --- a/platform/android/src/jni.cpp +++ b/platform/android/src/jni.cpp @@ -14,6 +14,7 @@ #include "geojson/feature.hpp" #include "geojson/feature_collection.hpp" #include "geojson/geometry.hpp" +#include "geojson/geometry_collection.hpp" #include "geojson/line_string.hpp" #include "geojson/multi_line_string.hpp" #include "geojson/multi_point.hpp" @@ -40,17 +41,13 @@ #include "offline/offline_region_error.hpp" #include "offline/offline_region_status.hpp" #include "style/transition_options.hpp" -#include "style/functions/categorical_stops.hpp" -#include "style/functions/exponential_stops.hpp" -#include "style/functions/identity_stops.hpp" -#include "style/functions/interval_stops.hpp" -#include "style/functions/stop.hpp" #include "style/layers/layers.hpp" #include "style/sources/source.hpp" #include "style/light.hpp" #include "snapshotter/map_snapshotter.hpp" #include "snapshotter/map_snapshot.hpp" #include "text/local_glyph_rasterizer_jni.hpp" +#include "java/lang.hpp" namespace mbgl { namespace android { @@ -116,11 +113,17 @@ void registerNatives(JavaVM *vm) { java::util::registerNative(env); PointF::registerNative(env); RectF::registerNative(env); + java::lang::Number::registerNative(env); + java::lang::Float::registerNative(env); + java::lang::Boolean::registerNative(env); + java::lang::Double::registerNative(env); + java::lang::Long::registerNative(env); // GeoJSON geojson::Feature::registerNative(env); geojson::FeatureCollection::registerNative(env); geojson::Geometry::registerNative(env); + geojson::GeometryCollection::registerNative(env); geojson::LineString::registerNative(env); geojson::MultiLineString::registerNative(env); geojson::MultiPoint::registerNative(env); @@ -163,11 +166,6 @@ void registerNatives(JavaVM *vm) { Source::registerNative(env); Light::registerNative(env); Position::registerNative(env); - Stop::registerNative(env); - CategoricalStops::registerNative(env); - ExponentialStops::registerNative(env); - IdentityStops::registerNative(env); - IntervalStops::registerNative(env); // Map CameraPosition::registerNative(env); diff --git a/platform/android/src/map/image.cpp b/platform/android/src/map/image.cpp index 52e0e0d255..c3b22b0054 100644 --- a/platform/android/src/map/image.cpp +++ b/platform/android/src/map/image.cpp @@ -29,7 +29,7 @@ mbgl::style::Image Image::getImage(jni::JNIEnv& env, jni::Object<Image> image) { } jni::GetArrayRegion(env, *pixels, 0, size, reinterpret_cast<jbyte*>(premultipliedImage.data.get())); - + jni::DeleteLocalRef(env, pixels); return mbgl::style::Image {name, std::move(premultipliedImage), pixelRatio}; } diff --git a/platform/android/src/map_renderer.cpp b/platform/android/src/map_renderer.cpp index 2440ac93ef..f7e16b7091 100644 --- a/platform/android/src/map_renderer.cpp +++ b/platform/android/src/map_renderer.cpp @@ -136,7 +136,7 @@ void MapRenderer::render(JNIEnv&) { renderer->render(*params); // Deliver the snapshot if requested - if (snapshotCallback) { + if (snapshotCallback && !paused) { snapshotCallback->operator()(backend->readFramebuffer()); snapshotCallback.reset(); } @@ -174,6 +174,14 @@ void MapRenderer::onSurfaceChanged(JNIEnv&, jint width, jint height) { requestRender(); } +void MapRenderer::onResume(JNIEnv&) { + paused = false; +} + +void MapRenderer::onPause(JNIEnv&) { + paused = true; +} + // Static methods // jni::Class<MapRenderer> MapRenderer::javaClass; @@ -192,7 +200,11 @@ void MapRenderer::registerNative(jni::JNIEnv& env) { METHOD(&MapRenderer::onSurfaceCreated, "nativeOnSurfaceCreated"), METHOD(&MapRenderer::onSurfaceChanged, - "nativeOnSurfaceChanged")); + "nativeOnSurfaceChanged"), + METHOD(&MapRenderer::onResume, + "nativeOnResume"), + METHOD(&MapRenderer::onPause, + "nativeOnPause")); } MapRenderer& MapRenderer::getNativePeer(JNIEnv& env, jni::Object<MapRenderer> jObject) { diff --git a/platform/android/src/map_renderer.hpp b/platform/android/src/map_renderer.hpp index c36357af7a..5fb5ef1a61 100644 --- a/platform/android/src/map_renderer.hpp +++ b/platform/android/src/map_renderer.hpp @@ -98,6 +98,10 @@ private: void onSurfaceChanged(JNIEnv&, jint width, jint height); + void onResume(JNIEnv&); + + void onPause(JNIEnv&); + private: GenericUniqueWeakObject<MapRenderer> javaPeer; @@ -120,6 +124,7 @@ private: std::mutex updateMutex; bool framebufferSizeChanged = false; + std::atomic<bool> paused {false}; std::unique_ptr<SnapshotCallback> snapshotCallback; }; diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp index 67fc132204..eecb76213b 100755 --- a/platform/android/src/native_map_view.cpp +++ b/platform/android/src/native_map_view.cpp @@ -288,13 +288,15 @@ void NativeMapView::setLatLng(jni::JNIEnv&, jni::jdouble latitude, jni::jdouble map->setLatLng(mbgl::LatLng(latitude, longitude), insets, mbgl::AnimationOptions{mbgl::Milliseconds(duration)}); } -jni::Object<CameraPosition> NativeMapView::getCameraForLatLngBounds(jni::JNIEnv& env, jni::Object<LatLngBounds> jBounds) { - return CameraPosition::New(env, map->cameraForLatLngBounds(mbgl::android::LatLngBounds::getLatLngBounds(env, jBounds), insets)); +jni::Object<CameraPosition> NativeMapView::getCameraForLatLngBounds(jni::JNIEnv& env, jni::Object<LatLngBounds> jBounds, double top, double left, double bottom, double right) { + mbgl::EdgeInsets padding = {top, left, bottom, right}; + return CameraPosition::New(env, map->cameraForLatLngBounds(mbgl::android::LatLngBounds::getLatLngBounds(env, jBounds), padding)); } -jni::Object<CameraPosition> NativeMapView::getCameraForGeometry(jni::JNIEnv& env, jni::Object<geojson::Geometry> jGeometry, double bearing) { +jni::Object<CameraPosition> NativeMapView::getCameraForGeometry(jni::JNIEnv& env, jni::Object<geojson::Geometry> jGeometry, double bearing, double top, double left, double bottom, double right) { auto geometry = geojson::Geometry::convert(env, jGeometry); - return CameraPosition::New(env, map->cameraForGeometry(geometry, insets, bearing)); + mbgl::EdgeInsets padding = {top, left, bottom, right}; + return CameraPosition::New(env, map->cameraForGeometry(geometry, padding, bearing)); } void NativeMapView::setReachability(jni::JNIEnv&, jni::jboolean reachable) { @@ -893,16 +895,9 @@ void NativeMapView::removeSource(JNIEnv& env, jni::Object<Source> obj, jlong sou 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) { - jni::NullCheck(env, &pixels); - std::size_t size = pixels.Length(env); - - mbgl::PremultipliedImage premultipliedImage({ static_cast<uint32_t>(w), static_cast<uint32_t>(h) }); - if (premultipliedImage.bytes() != uint32_t(size)) { - throw mbgl::util::SpriteImageException("Sprite image pixel count mismatch"); - } - - jni::GetArrayRegion(env, *pixels, 0, size, reinterpret_cast<jbyte*>(premultipliedImage.data.get())); +void NativeMapView::addImage(JNIEnv& env, jni::String name, jni::Object<Bitmap> bitmap, jni::jfloat scale) { + jni::NullCheck(env, &bitmap); + mbgl::PremultipliedImage premultipliedImage = Bitmap::GetImage(env, bitmap); map->getStyle().addImage(std::make_unique<mbgl::style::Image>( jni::Make<std::string>(env, name), diff --git a/platform/android/src/native_map_view.hpp b/platform/android/src/native_map_view.hpp index 507d77ac5f..aff3b51c42 100755 --- a/platform/android/src/native_map_view.hpp +++ b/platform/android/src/native_map_view.hpp @@ -104,9 +104,9 @@ public: void setLatLng(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jlong); - jni::Object<CameraPosition> getCameraForLatLngBounds(jni::JNIEnv&, jni::Object<mbgl::android::LatLngBounds>); + jni::Object<CameraPosition> getCameraForLatLngBounds(jni::JNIEnv&, jni::Object<mbgl::android::LatLngBounds>, double top, double left, double bottom, double right); - jni::Object<CameraPosition> getCameraForGeometry(jni::JNIEnv&, jni::Object<geojson::Geometry>, double bearing); + jni::Object<CameraPosition> getCameraForGeometry(jni::JNIEnv&, jni::Object<geojson::Geometry>, double bearing, double top, double left, double bottom, double right); void setReachability(jni::JNIEnv&, jni::jboolean); @@ -236,7 +236,7 @@ public: void removeSource(JNIEnv&, jni::Object<Source>, jlong nativePtr); - void addImage(JNIEnv&, jni::String, jni::jint, jni::jint, jni::jfloat, jni::Array<jbyte>); + void addImage(JNIEnv&, jni::String, jni::Object<Bitmap> bitmap, jni::jfloat); void addImages(JNIEnv&, jni::Array<jni::Object<mbgl::android::Image>>); @@ -257,7 +257,6 @@ private: MapRenderer& mapRenderer; std::string styleUrl; - std::string apiKey; float pixelRatio; diff --git a/platform/android/src/offline/offline_manager.cpp b/platform/android/src/offline/offline_manager.cpp index 02871e7fdf..4960ae2845 100644 --- a/platform/android/src/offline/offline_manager.cpp +++ b/platform/android/src/offline/offline_manager.cpp @@ -102,7 +102,9 @@ void OfflineManager::ListOfflineRegionsCallback::onError(jni::JNIEnv& env, std::exception_ptr error) { static auto method = javaClass.GetMethod<void (jni::String)>(env, "onError"); std::string message = mbgl::util::toString(error); - callback.Call(env, method, jni::Make<jni::String>(env, message)); + auto jmessage = jni::Make<jni::String>(env, message); + callback.Call(env, method, jmessage); + jni::DeleteLocalRef(env, jmessage); } void OfflineManager::ListOfflineRegionsCallback::onList(jni::JNIEnv& env, @@ -138,7 +140,9 @@ void OfflineManager::CreateOfflineRegionCallback::onError(jni::JNIEnv& env, std::exception_ptr error) { static auto method = javaClass.GetMethod<void (jni::String)>(env, "onError"); std::string message = mbgl::util::toString(error); - callback.Call(env, method, jni::Make<jni::String>(env, message)); + auto jmessage = jni::Make<jni::String>(env, message); + callback.Call(env, method, jmessage); + jni::DeleteLocalRef(env, jmessage); } void OfflineManager::CreateOfflineRegionCallback::onCreate(jni::JNIEnv& env, diff --git a/platform/android/src/offline/offline_region.cpp b/platform/android/src/offline/offline_region.cpp index 856434d266..27de76fb00 100644 --- a/platform/android/src/offline/offline_region.cpp +++ b/platform/android/src/offline/offline_region.cpp @@ -239,7 +239,9 @@ void OfflineRegion::OfflineRegionStatusCallback::onError(jni::JNIEnv& env, std::exception_ptr error) { static auto method = javaClass.GetMethod<void (jni::String)>(env, "onError"); std::string message = mbgl::util::toString(error); - callback.Call(env, method, jni::Make<jni::String>(env, message)); + auto jmessage = jni::Make<jni::String>(env, message); + callback.Call(env, method, jmessage); + jni::DeleteLocalRef(env, jmessage); } void OfflineRegion::OfflineRegionStatusCallback::onStatus(jni::JNIEnv& env, @@ -267,7 +269,9 @@ void OfflineRegion::OfflineRegionDeleteCallback::onError(jni::JNIEnv& env, std::exception_ptr error) { static auto method = javaClass.GetMethod<void (jni::String)>(env, "onError"); std::string message = mbgl::util::toString(error); - callback.Call(env, method, jni::Make<jni::String>(env, message)); + auto jmessage = jni::Make<jni::String>(env, message); + callback.Call(env, method, jmessage); + jni::DeleteLocalRef(env, jmessage); } void OfflineRegion::OfflineRegionDeleteCallback::onDelete(jni::JNIEnv& env, jni::Object<OfflineRegion::OfflineRegionDeleteCallback> callback) { @@ -289,7 +293,9 @@ void OfflineRegion::OfflineRegionUpdateMetadataCallback::onError(jni::JNIEnv& en std::exception_ptr error) { static auto method = javaClass.GetMethod<void (jni::String)>(env, "onError"); std::string message = mbgl::util::toString(error); - callback.Call(env, method, jni::Make<jni::String>(env, message)); + auto jmessage = jni::Make<jni::String>(env, message); + callback.Call(env, method, jmessage); + jni::DeleteLocalRef(env, jmessage); } void OfflineRegion::OfflineRegionUpdateMetadataCallback::onUpdate(jni::JNIEnv& env, diff --git a/platform/android/src/snapshotter/map_snapshotter.cpp b/platform/android/src/snapshotter/map_snapshotter.cpp index 71f8b4f4c0..a006953d36 100644 --- a/platform/android/src/snapshotter/map_snapshotter.cpp +++ b/platform/android/src/snapshotter/map_snapshotter.cpp @@ -71,7 +71,9 @@ void MapSnapshotter::start(JNIEnv& env) { if (err) { // error handler callback static auto onSnapshotFailed = javaClass.GetMethod<void (jni::String)>(*_env, "onSnapshotFailed"); - javaPeer->Call(*_env, onSnapshotFailed, jni::Make<jni::String>(*_env, util::toString(err))); + auto message = jni::Make<jni::String>(*_env, util::toString(err)); + javaPeer->Call(*_env, onSnapshotFailed, message); + jni::DeleteLocalRef(*_env, message); } else { // Create the wrapper auto mapSnapshot = android::MapSnapshot::New(*_env, std::move(image), pixelRatio, attributions, showLogo, pointForFn); diff --git a/platform/android/src/style/conversion/function.hpp b/platform/android/src/style/conversion/function.hpp index ad01a7afc2..d6669b4508 100644 --- a/platform/android/src/style/conversion/function.hpp +++ b/platform/android/src/style/conversion/function.hpp @@ -5,13 +5,9 @@ #include "../../conversion/constant.hpp" #include "types.hpp" #include "../../java/lang.hpp" -#include "../functions/stop.hpp" -#include "../functions/categorical_stops.hpp" -#include "../functions/exponential_stops.hpp" -#include "../functions/identity_stops.hpp" -#include "../functions/interval_stops.hpp" #include <jni/jni.hpp> +#include "../../gson/json_element.hpp" #include <tuple> #include <map> @@ -20,205 +16,33 @@ namespace mbgl { namespace android { namespace conversion { -/** - * Conversion from core composite value to java type - */ -class CategoricalValueEvaluator { -public: - - CategoricalValueEvaluator(jni::JNIEnv& _env) : env(_env) {} - - template <class T> - jni::jobject* operator()(const T &value) const { - return *convert<jni::jobject*, T>(env, value); - } - -private: - jni::JNIEnv& env; -}; - -/** - * Conversion from core composite value to java type - */ -template <> -struct Converter<jni::jobject*, mbgl::style::CategoricalValue> { - - Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::CategoricalValue& value) const { - CategoricalValueEvaluator evaluator(env); - return apply_visitor(evaluator, value); - } -}; - -template <class I, class O> -jni::Array<jni::Object<Stop>> toFunctionStopJavaArray(jni::JNIEnv& env, std::map<I, O> value) { - - auto jarray = jni::Array<jni::Object<Stop>>::New(env, value.size(), Stop::javaClass); - - size_t i = 0; - for (auto const& stop : value) { - jni::jobject* in = *convert<jni::jobject*, I>(env, stop.first); - jni::jobject* out = *convert<jni::jobject*, O>(env, stop.second); - - auto jstop = Stop::New(env, jni::Object<>(in), jni::Object<>(out)); - jarray.Set(env, i, jstop); - - jni::DeleteLocalRef(env, in); - jni::DeleteLocalRef(env, out); - jni::DeleteLocalRef(env, jstop); - - i++; - } - - return jarray; -} - -template <class I, class O> -jni::Array<jni::Object<Stop>> toFunctionStopJavaArray(jni::JNIEnv& env, std::map<float, std::map<I, O>> value) { - - auto jarray = jni::Array<jni::Object<Stop>>::New(env, value.size(), Stop::javaClass); - - for (auto const& zoomLevelMap : value) { - size_t i = 0; - for (auto const& stop: zoomLevelMap.second) { - auto zoom = jni::Object<java::lang::Number>(*convert<jni::jobject*>(env, zoomLevelMap.first)); - auto in = jni::Object<>(*convert<jni::jobject*, I>(env, stop.first)); - auto out = jni::Object<>(*convert<jni::jobject*, O>(env, stop.second)); - auto compositeValue = Stop::CompositeValue::New(env, zoom, in); - - auto jstop = Stop::New(env, compositeValue, out); - jarray.Set(env, i, jstop); - - jni::DeleteLocalRef(env, zoom); - jni::DeleteLocalRef(env, in); - jni::DeleteLocalRef(env, out); - jni::DeleteLocalRef(env, compositeValue); - jni::DeleteLocalRef(env, jstop); - - i++; - } - } - - return jarray; -} - -template <class I, typename O> -inline jni::jobject* convertCompositeStopsArray(jni::JNIEnv& env, std::map<float, std::map<I, O>> value) { - static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/mapboxsdk/style/functions/stops/Stop")).release(); - static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "(Ljava/lang/Object;Ljava/lang/Object;)V"); - - jni::jarray<jni::jobject>& jarray = jni::NewObjectArray(env, value.size(), *javaClass); - - size_t i = 0; - for (auto const& stop : value) { - jni::jobject* in = *convert<jni::jobject*, I>(env, stop.first); - jni::jobject* out = *convert<jni::jobject*, O>(env, stop.second); - jni::SetObjectArrayElement(env, jarray, i, &jni::NewObject(env, *javaClass, *constructor, in, out)); - i++; - jni::DeleteLocalRef(env, in); - jni::DeleteLocalRef(env, out); - } - - return &jarray; -} - -/** - * Conversion from core function stops to Stops java subclasses - */ template <class T> -class StopsEvaluator { -public: - - StopsEvaluator(jni::JNIEnv& _env) : env(_env) {} - - jni::jobject* operator()(const mbgl::style::CategoricalStops<T> &value) const { - return CategoricalStops::New(env, toFunctionStopJavaArray(env, value.stops)).Get(); - } - - jni::jobject* operator()(const mbgl::style::CompositeCategoricalStops<T> &value) const { - return CategoricalStops::New(env, toFunctionStopJavaArray(env, value.stops)).Get(); - } - - jni::jobject* operator()(const mbgl::style::ExponentialStops<T> &value) const { - return ExponentialStops::New(env, jni::Object<java::lang::Float>(*convert<jni::jobject*>(env, value.base)), toFunctionStopJavaArray(env, value.stops)).Get(); - } +struct Converter<jni::Object<android::gson::JsonElement>, mbgl::style::CameraFunction<T>> { - jni::jobject* operator()(const mbgl::style::CompositeExponentialStops<T> &value) const { - return ExponentialStops::New(env, jni::Object<java::lang::Float>(*convert<jni::jobject*>(env, value.base)), toFunctionStopJavaArray(env, value.stops)).Get(); + Result<jni::Object<android::gson::JsonElement>> operator()(jni::JNIEnv& env, const mbgl::style::CameraFunction<T>& value) const { + // Convert expressions + mbgl::Value expressionValue = value.getExpression().serialize(); + return gson::JsonElement::New(env, expressionValue); } - - jni::jobject* operator()(const mbgl::style::IdentityStops<T> &) const { - return IdentityStops::New(env).Get(); - } - - jni::jobject* operator()(const mbgl::style::IntervalStops<T> &value) const { - return IntervalStops::New(env, toFunctionStopJavaArray(env, value.stops)).Get(); - } - - jni::jobject* operator()(const mbgl::style::CompositeIntervalStops<T> &value) const { - return IntervalStops::New(env, toFunctionStopJavaArray(env, value.stops)).Get(); - } - -private: - jni::JNIEnv& env; }; template <class T> -struct Converter<jni::jobject*, mbgl::style::CameraFunction<T>> { +struct Converter<jni::Object<android::gson::JsonElement>, mbgl::style::SourceFunction<T>> { - Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::CameraFunction<T>& value) const { - static jni::jclass* clazz = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/mapboxsdk/style/functions/CameraFunction")).release(); - static jni::jmethodID* constructor = &jni::GetMethodID(env, *clazz, "<init>", "(Lcom/mapbox/mapboxsdk/style/functions/stops/Stops;)V"); - - StopsEvaluator<T> evaluator(env); - jni::jobject* stops = apply_visitor(evaluator, value.stops); - jni::jobject* converted = &jni::NewObject(env, *clazz, *constructor, stops); - - return { converted }; - } -}; - -template <class T> -struct Converter<jni::jobject*, mbgl::style::SourceFunction<T>> { - - Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::SourceFunction<T>& value) const { - static jni::jclass* clazz = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/mapboxsdk/style/functions/SourceFunction")).release(); - static jni::jmethodID* constructor = &jni::GetMethodID(env, *clazz, "<init>", - "(Ljava/lang/Object;Ljava/lang/String;Lcom/mapbox/mapboxsdk/style/functions/stops/Stops;)V"); - - // Convert stops - StopsEvaluator<T> evaluator(env); - jni::jobject* stops = apply_visitor(evaluator, value.stops); - - // Convert default value - jni::jobject* defaultValue = nullptr; - if (value.defaultValue) { - defaultValue = *convert<jni::jobject*>(env, *value.defaultValue); - } - - return { &jni::NewObject(env, *clazz, *constructor, defaultValue, jni::Make<jni::String>(env, value.property).Get(), stops) }; + Result<jni::Object<android::gson::JsonElement>> operator()(jni::JNIEnv& env, const mbgl::style::SourceFunction<T>& value) const { + // Convert expressions + mbgl::Value expressionValue = value.getExpression().serialize(); + return gson::JsonElement::New(env, expressionValue); } }; template <class T> -struct Converter<jni::jobject*, mbgl::style::CompositeFunction<T>> { - - Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::CompositeFunction<T>& value) const { - static jni::jclass* clazz = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/mapboxsdk/style/functions/CompositeFunction")).release(); - static jni::jmethodID* constructor = &jni::GetMethodID(env, *clazz, "<init>", - "(Ljava/lang/Object;Ljava/lang/String;Lcom/mapbox/mapboxsdk/style/functions/stops/Stops;)V"); - - // Convert stops - StopsEvaluator<T> evaluator(env); - jni::jobject* stops = apply_visitor(evaluator, value.stops); - - - // Convert default value - jni::jobject* defaultValue = nullptr; - if (value.defaultValue) { - defaultValue = *convert<jni::jobject*>(env, *value.defaultValue); - } +struct Converter<jni::Object<android::gson::JsonElement>, mbgl::style::CompositeFunction<T>> { - return { &jni::NewObject(env, *clazz, *constructor, defaultValue, jni::Make<jni::String>(env, value.property).Get(), stops) }; + Result<jni::Object<android::gson::JsonElement>> operator()(jni::JNIEnv& env, const mbgl::style::CompositeFunction<T>& value) const { + // Convert expressions + mbgl::Value expressionValue = value.getExpression().serialize(); + return gson::JsonElement::New(env, expressionValue); } }; diff --git a/platform/android/src/style/conversion/property_value.hpp b/platform/android/src/style/conversion/property_value.hpp index a58cf975a7..902d1e80b2 100644 --- a/platform/android/src/style/conversion/property_value.hpp +++ b/platform/android/src/style/conversion/property_value.hpp @@ -2,6 +2,7 @@ #include <mbgl/style/property_value.hpp> #include <mbgl/style/data_driven_property_value.hpp> +#include <mbgl/style/heatmap_color_property_value.hpp> #include "../../conversion/conversion.hpp" #include "../../conversion/constant.hpp" #include "types.hpp" @@ -30,15 +31,15 @@ public: } jni::jobject* operator()(const mbgl::style::CameraFunction<T> &value) const { - return *convert<jni::jobject*, mbgl::style::CameraFunction<T>>(env, value); + return *convert<jni::Object<android::gson::JsonElement>, mbgl::style::CameraFunction<T>>(env, value); } jni::jobject* operator()(const mbgl::style::SourceFunction<T> &value) const { - return *convert<jni::jobject*, mbgl::style::SourceFunction<T>>(env, value); + return *convert<jni::Object<android::gson::JsonElement>, mbgl::style::SourceFunction<T>>(env, value); } jni::jobject* operator()(const mbgl::style::CompositeFunction<T> &value) const { - return *convert<jni::jobject*, mbgl::style::CompositeFunction<T>>(env, value); + return *convert<jni::Object<android::gson::JsonElement>, mbgl::style::CompositeFunction<T>>(env, value); } private: @@ -70,6 +71,18 @@ struct Converter<jni::jobject*, mbgl::style::DataDrivenPropertyValue<T>> { } }; +/** + * Convert core heat map color property value to java + */ +template <> +struct Converter<jni::jobject*, mbgl::style::HeatmapColorPropertyValue> { + + Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::HeatmapColorPropertyValue value) const { + PropertyValueEvaluator<mbgl::style::HeatmapColorPropertyValue> evaluator(env); + return *convert<jni::jobject*>(env, value.evaluate(evaluator)); + } +}; + } // namespace conversion } // namespace android } // namespace mbgl diff --git a/platform/android/src/style/functions/categorical_stops.cpp b/platform/android/src/style/functions/categorical_stops.cpp deleted file mode 100644 index 2aff9730a7..0000000000 --- a/platform/android/src/style/functions/categorical_stops.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "categorical_stops.hpp" - -namespace mbgl { -namespace android { - -jni::Object<CategoricalStops> CategoricalStops::New(jni::JNIEnv& env, jni::Array<jni::Object<Stop>> stops) { - static auto constructor = CategoricalStops::javaClass.GetConstructor<jni::Array<jni::Object<Stop>>>(env); - return CategoricalStops::javaClass.New(env, constructor, stops); -} - -jni::Class<CategoricalStops> CategoricalStops::javaClass; - -void CategoricalStops::registerNative(jni::JNIEnv& env) { - CategoricalStops::javaClass = *jni::Class<CategoricalStops>::Find(env).NewGlobalRef(env).release(); -} - -} // namespace android -} // namespace mbgl diff --git a/platform/android/src/style/functions/categorical_stops.hpp b/platform/android/src/style/functions/categorical_stops.hpp deleted file mode 100644 index a198c8d5c9..0000000000 --- a/platform/android/src/style/functions/categorical_stops.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include <mbgl/util/noncopyable.hpp> -#include <jni/jni.hpp> - -#include "stop.hpp" - -namespace mbgl { -namespace android { - -class CategoricalStops : private mbgl::util::noncopyable { -public: - static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/functions/stops/CategoricalStops"; }; - - static jni::Object<CategoricalStops> New(jni::JNIEnv&, jni::Array<jni::Object<Stop>>); - - static jni::Class<CategoricalStops> javaClass; - - static void registerNative(jni::JNIEnv&); -}; - -} // namespace android -} // namespace mbgl diff --git a/platform/android/src/style/functions/exponential_stops.cpp b/platform/android/src/style/functions/exponential_stops.cpp deleted file mode 100644 index 6390a0ec35..0000000000 --- a/platform/android/src/style/functions/exponential_stops.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "exponential_stops.hpp" - -namespace mbgl { -namespace android { - -jni::Object<ExponentialStops> ExponentialStops::New(jni::JNIEnv& env, jni::Object<java::lang::Float> base, jni::Array<jni::Object<Stop>> stops) { - static auto constructor = ExponentialStops::javaClass.GetConstructor<jni::Object<java::lang::Float>, jni::Array<jni::Object<Stop>>>(env); - return ExponentialStops::javaClass.New(env, constructor, base, stops); -} - -jni::Class<ExponentialStops> ExponentialStops::javaClass; - -void ExponentialStops::registerNative(jni::JNIEnv& env) { - ExponentialStops::javaClass = *jni::Class<ExponentialStops>::Find(env).NewGlobalRef(env).release(); -} - -} // namespace android -} // namespace mbgl diff --git a/platform/android/src/style/functions/exponential_stops.hpp b/platform/android/src/style/functions/exponential_stops.hpp deleted file mode 100644 index 391d723cef..0000000000 --- a/platform/android/src/style/functions/exponential_stops.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include <mbgl/util/noncopyable.hpp> -#include <jni/jni.hpp> - -#include "../../java/lang.hpp" -#include "stop.hpp" - -namespace mbgl { -namespace android { - -class ExponentialStops : private mbgl::util::noncopyable { -public: - static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/functions/stops/ExponentialStops"; }; - - static jni::Object<ExponentialStops> New(jni::JNIEnv&, jni::Object<java::lang::Float>, jni::Array<jni::Object<Stop>>); - - static jni::Class<ExponentialStops> javaClass; - - static void registerNative(jni::JNIEnv&); -}; - -} // namespace android -} // namespace mbgl diff --git a/platform/android/src/style/functions/identity_stops.cpp b/platform/android/src/style/functions/identity_stops.cpp deleted file mode 100644 index 239b0ddb88..0000000000 --- a/platform/android/src/style/functions/identity_stops.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "identity_stops.hpp" - -namespace mbgl { -namespace android { - -jni::Object<IdentityStops> IdentityStops::New(jni::JNIEnv& env) { - static auto constructor = IdentityStops::javaClass.GetConstructor<>(env); - return IdentityStops::javaClass.New(env, constructor); -} - -jni::Class<IdentityStops> IdentityStops::javaClass; - -void IdentityStops::registerNative(jni::JNIEnv& env) { - IdentityStops::javaClass = *jni::Class<IdentityStops>::Find(env).NewGlobalRef(env).release(); -} - -} // namespace android -} // namespace mbgl diff --git a/platform/android/src/style/functions/identity_stops.hpp b/platform/android/src/style/functions/identity_stops.hpp deleted file mode 100644 index 150b2135f0..0000000000 --- a/platform/android/src/style/functions/identity_stops.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include <mbgl/util/noncopyable.hpp> -#include <jni/jni.hpp> - -namespace mbgl { -namespace android { - -class IdentityStops : private mbgl::util::noncopyable { -public: - static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/functions/stops/IdentityStops"; }; - - static jni::Object<IdentityStops> New(jni::JNIEnv&); - - static jni::Class<IdentityStops> javaClass; - - static void registerNative(jni::JNIEnv&); -}; - -} // namespace android -} // namespace mbgl diff --git a/platform/android/src/style/functions/interval_stops.cpp b/platform/android/src/style/functions/interval_stops.cpp deleted file mode 100644 index c3d9b6513f..0000000000 --- a/platform/android/src/style/functions/interval_stops.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "interval_stops.hpp" - -namespace mbgl { -namespace android { - -jni::Object<IntervalStops> IntervalStops::New(jni::JNIEnv& env, jni::Array<jni::Object<Stop>> stops) { - static auto constructor = IntervalStops::javaClass.GetConstructor<jni::Array<jni::Object<Stop>>>(env); - return IntervalStops::javaClass.New(env, constructor, stops); -} - -jni::Class<IntervalStops> IntervalStops::javaClass; - -void IntervalStops::registerNative(jni::JNIEnv& env) { - IntervalStops::javaClass = *jni::Class<IntervalStops>::Find(env).NewGlobalRef(env).release(); -} - -} // namespace android -} // namespace mbgl diff --git a/platform/android/src/style/functions/interval_stops.hpp b/platform/android/src/style/functions/interval_stops.hpp deleted file mode 100644 index e3f75159cf..0000000000 --- a/platform/android/src/style/functions/interval_stops.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include <mbgl/util/noncopyable.hpp> -#include <jni/jni.hpp> - -#include "stop.hpp" - -namespace mbgl { -namespace android { - -class IntervalStops : private mbgl::util::noncopyable { -public: - static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/functions/stops/IntervalStops"; }; - - static jni::Object<IntervalStops> New(jni::JNIEnv&, jni::Array<jni::Object<Stop>>); - - static jni::Class<IntervalStops> javaClass; - - static void registerNative(jni::JNIEnv&); -}; - -} // namespace android -} // namespace mbgl diff --git a/platform/android/src/style/functions/stop.cpp b/platform/android/src/style/functions/stop.cpp deleted file mode 100644 index f9ed4b7368..0000000000 --- a/platform/android/src/style/functions/stop.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "interval_stops.hpp" - -namespace mbgl { -namespace android { - -jni::Object<Stop::CompositeValue> Stop::CompositeValue::New(jni::JNIEnv& env, jni::Object<java::lang::Number> zoom, jni::Object<> value) { - static auto constructor = Stop::CompositeValue::javaClass.GetConstructor<jni::Object<java::lang::Number>, jni::Object<>>(env); - return Stop::CompositeValue::javaClass.New(env, constructor, zoom, value); -} - -jni::Class<Stop> Stop::javaClass; - -jni::Class<Stop::CompositeValue> Stop::CompositeValue::javaClass; - -void Stop::registerNative(jni::JNIEnv& env) { - Stop::javaClass = *jni::Class<Stop>::Find(env).NewGlobalRef(env).release(); - Stop::CompositeValue::javaClass = *jni::Class<Stop::CompositeValue>::Find(env).NewGlobalRef(env).release(); -} - -} // namespace android -} // namespace mbgl diff --git a/platform/android/src/style/functions/stop.hpp b/platform/android/src/style/functions/stop.hpp deleted file mode 100644 index 7c697db65d..0000000000 --- a/platform/android/src/style/functions/stop.hpp +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include <mbgl/util/noncopyable.hpp> -#include <jni/jni.hpp> - -#include "../../java/lang.hpp" - -namespace mbgl { -namespace android { - -class Stop : private mbgl::util::noncopyable { -public: - static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/functions/stops/Stop"; }; - - template<class I, class O> - static jni::Object<Stop> New(jni::JNIEnv& env, jni::Object<I> in, jni::Object<O> out) { - static auto constructor = Stop::javaClass.GetConstructor<jni::Object<>, jni::Object<>>(env); - return Stop::javaClass.New(env, constructor, (jni::Object<>) in, (jni::Object<>) out); - } - - static jni::Class<Stop> javaClass; - - static void registerNative(jni::JNIEnv&); - - class CompositeValue : private mbgl::util::noncopyable { - public: - static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/functions/stops/Stop$CompositeValue"; }; - - static jni::Object<Stop::CompositeValue> New(jni::JNIEnv&, jni::Object<java::lang::Number>, jni::Object<>); - - static jni::Class<Stop::CompositeValue> javaClass; - }; -}; - -} // namespace android -} // namespace mbgl diff --git a/platform/android/src/style/layers/custom_layer.cpp b/platform/android/src/style/layers/custom_layer.cpp index 51a48520bf..61e74a9cf5 100644 --- a/platform/android/src/style/layers/custom_layer.cpp +++ b/platform/android/src/style/layers/custom_layer.cpp @@ -7,14 +7,10 @@ namespace mbgl { namespace android { - CustomLayer::CustomLayer(jni::JNIEnv& env, jni::String layerId, jni::jlong initializeFunction, jni::jlong renderFunction, jni::jlong contextLostFunction, jni::jlong deinitializeFunction, jni::jlong context) + CustomLayer::CustomLayer(jni::JNIEnv& env, jni::String layerId, jni::jlong host) : Layer(env, std::make_unique<mbgl::style::CustomLayer>( jni::Make<std::string>(env, layerId), - reinterpret_cast<mbgl::style::CustomLayerInitializeFunction>(initializeFunction), - reinterpret_cast<mbgl::style::CustomLayerRenderFunction>(renderFunction), - reinterpret_cast<mbgl::style::CustomLayerContextLostFunction>(contextLostFunction), - reinterpret_cast<mbgl::style::CustomLayerDeinitializeFunction>(deinitializeFunction), - reinterpret_cast<void*>(context)) + std::unique_ptr<mbgl::style::CustomLayerHost>(reinterpret_cast<mbgl::style::CustomLayerHost*>(host))) ) { } @@ -53,7 +49,7 @@ namespace android { // Register the peer jni::RegisterNativePeer<CustomLayer>( env, CustomLayer::javaClass, "nativePtr", - std::make_unique<CustomLayer, JNIEnv&, jni::String, jni::jlong, jni::jlong, jni::jlong, jni::jlong, jni::jlong>, + std::make_unique<CustomLayer, JNIEnv&, jni::String, jni::jlong>, "initialize", "finalize", METHOD(&CustomLayer::update, "nativeUpdate")); diff --git a/platform/android/src/style/layers/custom_layer.hpp b/platform/android/src/style/layers/custom_layer.hpp index 9e079c1288..7eb649d923 100644 --- a/platform/android/src/style/layers/custom_layer.hpp +++ b/platform/android/src/style/layers/custom_layer.hpp @@ -16,7 +16,7 @@ public: static void registerNative(jni::JNIEnv&); - CustomLayer(jni::JNIEnv&, jni::String, jni::jlong, jni::jlong, jni::jlong, jni::jlong, jni::jlong); + CustomLayer(jni::JNIEnv&, jni::String, jni::jlong); CustomLayer(mbgl::Map&, mbgl::style::CustomLayer&); diff --git a/platform/android/src/style/layers/heatmap_layer.cpp b/platform/android/src/style/layers/heatmap_layer.cpp index 609499ec93..b3d90faab7 100644 --- a/platform/android/src/style/layers/heatmap_layer.cpp +++ b/platform/android/src/style/layers/heatmap_layer.cpp @@ -79,6 +79,16 @@ namespace android { layer.as<mbgl::style::HeatmapLayer>()->HeatmapLayer::setHeatmapIntensityTransition(options); } + jni::Object<jni::ObjectTag> HeatmapLayer::getHeatmapColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + auto propertyValue = layer.as<mbgl::style::HeatmapLayer>()->HeatmapLayer::getHeatmapColor(); + if (propertyValue.isUndefined()) { + propertyValue = layer.as<mbgl::style::HeatmapLayer>()->HeatmapLayer::getDefaultHeatmapColor(); + } + Result<jni::jobject*> converted = convert<jni::jobject*>(env, propertyValue); + return jni::Object<jni::ObjectTag>(*converted); + } + 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()); @@ -125,6 +135,7 @@ namespace android { METHOD(&HeatmapLayer::getHeatmapIntensityTransition, "nativeGetHeatmapIntensityTransition"), METHOD(&HeatmapLayer::setHeatmapIntensityTransition, "nativeSetHeatmapIntensityTransition"), METHOD(&HeatmapLayer::getHeatmapIntensity, "nativeGetHeatmapIntensity"), + METHOD(&HeatmapLayer::getHeatmapColor, "nativeGetHeatmapColor"), METHOD(&HeatmapLayer::getHeatmapOpacityTransition, "nativeGetHeatmapOpacityTransition"), METHOD(&HeatmapLayer::setHeatmapOpacityTransition, "nativeSetHeatmapOpacityTransition"), METHOD(&HeatmapLayer::getHeatmapOpacity, "nativeGetHeatmapOpacity")); diff --git a/platform/android/src/style/layers/heatmap_layer.hpp b/platform/android/src/style/layers/heatmap_layer.hpp index 85f9f0292e..9e8908b062 100644 --- a/platform/android/src/style/layers/heatmap_layer.hpp +++ b/platform/android/src/style/layers/heatmap_layer.hpp @@ -39,6 +39,8 @@ public: void setHeatmapIntensityTransition(jni::JNIEnv&, jlong duration, jlong delay); jni::Object<TransitionOptions> getHeatmapIntensityTransition(jni::JNIEnv&); + jni::Object<jni::ObjectTag> getHeatmapColor(jni::JNIEnv&); + jni::Object<jni::ObjectTag> getHeatmapOpacity(jni::JNIEnv&); void setHeatmapOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay); jni::Object<TransitionOptions> getHeatmapOpacityTransition(jni::JNIEnv&); diff --git a/platform/android/src/style/layers/layer.cpp b/platform/android/src/style/layers/layer.cpp index 29530879a5..6fe6e3cb29 100644 --- a/platform/android/src/style/layers/layer.cpp +++ b/platform/android/src/style/layers/layer.cpp @@ -25,6 +25,7 @@ // C++ -> Java conversion #include "../conversion/property_value.hpp" +#include <mbgl/style/filter.hpp> #include <string> @@ -134,6 +135,38 @@ namespace android { layer.accept(SetFilterEvaluator {std::move(*converted)}); } + struct GetFilterEvaluator { + mbgl::style::Filter noop(std::string layerType) { + Log::Warning(mbgl::Event::JNI, "%s doesn't support filter", layerType.c_str()); + return {}; + } + + mbgl::style::Filter operator()(style::BackgroundLayer&) { return noop("BackgroundLayer"); } + mbgl::style::Filter operator()(style::CustomLayer&) { return noop("CustomLayer"); } + mbgl::style::Filter operator()(style::RasterLayer&) { return noop("RasterLayer"); } + mbgl::style::Filter operator()(style::HillshadeLayer&) { return noop("HillshadeLayer"); } + + template <class LayerType> + mbgl::style::Filter operator()(LayerType& layer) { + return layer.getFilter(); + } + }; + + jni::Object<gson::JsonElement> Layer::getFilter(jni::JNIEnv& env) { + using namespace mbgl::style; + using namespace mbgl::style::conversion; + + Filter filter = layer.accept(GetFilterEvaluator()); + + jni::Object<gson::JsonElement> converted; + if (filter.is<ExpressionFilter>()) { + ExpressionFilter filterExpression = filter.get<ExpressionFilter>(); + mbgl::Value expressionValue = filterExpression.expression.get()->serialize(); + converted = gson::JsonElement::New(env, expressionValue); + } + return converted; + } + struct SetSourceLayerEvaluator { std::string sourceLayer; @@ -208,6 +241,7 @@ namespace android { METHOD(&Layer::setLayoutProperty, "nativeSetLayoutProperty"), METHOD(&Layer::setPaintProperty, "nativeSetPaintProperty"), METHOD(&Layer::setFilter, "nativeSetFilter"), + METHOD(&Layer::getFilter, "nativeGetFilter"), METHOD(&Layer::setSourceLayer, "nativeSetSourceLayer"), METHOD(&Layer::getSourceLayer, "nativeGetSourceLayer"), METHOD(&Layer::getMinZoom, "nativeGetMinZoom"), diff --git a/platform/android/src/style/layers/layer.cpp.ejs b/platform/android/src/style/layers/layer.cpp.ejs index 1debb096a3..b08f0ec4dc 100644 --- a/platform/android/src/style/layers/layer.cpp.ejs +++ b/platform/android/src/style/layers/layer.cpp.ejs @@ -48,12 +48,25 @@ namespace android { // Property getters <% for (const property of properties) { -%> +<% if (property.name != 'heatmap-color') { -%> jni::Object<jni::ObjectTag> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>(jni::JNIEnv& env) { using namespace mbgl::android::conversion; Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::<%- camelize(type) %>Layer>()-><%- camelize(type) %>Layer::get<%- camelize(property.name) %>()); return jni::Object<jni::ObjectTag>(*converted); } +<% } else { -%> + jni::Object<jni::ObjectTag> HeatmapLayer::getHeatmapColor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + auto propertyValue = layer.as<mbgl::style::HeatmapLayer>()->HeatmapLayer::getHeatmapColor(); + if (propertyValue.isUndefined()) { + propertyValue = layer.as<mbgl::style::HeatmapLayer>()->HeatmapLayer::getDefaultHeatmapColor(); + } + Result<jni::jobject*> converted = convert<jni::jobject*>(env, propertyValue); + return jni::Object<jni::ObjectTag>(*converted); + } + +<% } -%> <% if (property.transition) { -%> jni::Object<TransitionOptions> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>Transition(jni::JNIEnv& env) { using namespace mbgl::android::conversion; diff --git a/platform/android/src/style/layers/layer.hpp b/platform/android/src/style/layers/layer.hpp index 78c3f80b48..2486b0dfa6 100644 --- a/platform/android/src/style/layers/layer.hpp +++ b/platform/android/src/style/layers/layer.hpp @@ -3,8 +3,9 @@ #include <mbgl/util/noncopyable.hpp> #include <mbgl/map/map.hpp> #include <mbgl/style/layer.hpp> - +#include "../../gson/json_array.hpp" #include "../value.hpp" +#include "../../gson/json_element.hpp" #include <jni/jni.hpp> @@ -68,6 +69,8 @@ public: void setFilter(jni::JNIEnv&, jni::Array<jni::Object<>>); + jni::Object<gson::JsonElement> getFilter(jni::JNIEnv&); + void setSourceLayer(jni::JNIEnv&, jni::String); jni::String getSourceLayer(jni::JNIEnv&); diff --git a/platform/android/src/text/local_glyph_rasterizer.cpp b/platform/android/src/text/local_glyph_rasterizer.cpp index ce1b0fc8fd..d232058d15 100644 --- a/platform/android/src/text/local_glyph_rasterizer.cpp +++ b/platform/android/src/text/local_glyph_rasterizer.cpp @@ -46,6 +46,7 @@ PremultipliedImage LocalGlyphRasterizer::drawGlyphBitmap(const std::string& font jniFontFamily, static_cast<jni::jboolean>(bold), static_cast<jni::jchar>(glyphID)); + jni::DeleteLocalRef(*env, jniFontFamily); PremultipliedImage result = Bitmap::GetImage(*env, javaBitmap); jni::DeleteLocalRef(*env, javaBitmap); |