From fa7489fb7ea8ec85cb746e0bc497518d72c638b9 Mon Sep 17 00:00:00 2001 From: Ivo van Dongen Date: Wed, 22 Mar 2017 15:05:03 +0200 Subject: [PATCH] [android] geojson conversion optimisation --- .../style/sources/GeoJsonSource.java | 21 ++---- .../mapboxsdk/style/sources/Source.java | 14 ---- platform/android/config.cmake | 34 +++++++++- .../conversion/feature.hpp | 18 ++--- .../conversion/geometry.hpp | 0 platform/android/src/geojson/feature.cpp | 63 ++++++++++++++++++ .../src/{geometry => geojson}/feature.hpp | 16 ++++- .../src/geojson/feature_collection.cpp | 40 +++++++++++ .../src/geojson/feature_collection.hpp | 29 ++++++++ platform/android/src/geojson/geometry.cpp | 52 +++++++++++++++ platform/android/src/geojson/geometry.hpp | 27 ++++++++ platform/android/src/geojson/line_string.cpp | 54 +++++++++++++++ platform/android/src/geojson/line_string.hpp | 34 ++++++++++ .../android/src/geojson/multi_line_string.cpp | 56 ++++++++++++++++ .../android/src/geojson/multi_line_string.hpp | 33 ++++++++++ platform/android/src/geojson/multi_point.cpp | 35 ++++++++++ platform/android/src/geojson/multi_point.hpp | 31 +++++++++ .../android/src/geojson/multi_polygon.cpp | 46 +++++++++++++ .../android/src/geojson/multi_polygon.hpp | 31 +++++++++ platform/android/src/geojson/point.cpp | 28 ++++++++ platform/android/src/geojson/point.hpp | 31 +++++++++ platform/android/src/geojson/polygon.cpp | 48 ++++++++++++++ platform/android/src/geojson/polygon.hpp | 33 ++++++++++ platform/android/src/geojson/position.cpp | 27 ++++++++ platform/android/src/geojson/position.hpp | 27 ++++++++ platform/android/src/geometry/feature.cpp | 20 ------ platform/android/src/geometry/geometry.hpp | 16 ----- platform/android/src/gson/json_array.cpp | 40 +++++++++++ platform/android/src/gson/json_array.hpp | 25 +++++++ platform/android/src/gson/json_element.cpp | 62 +++++++++++++++++ platform/android/src/gson/json_element.hpp | 33 ++++++++++ platform/android/src/gson/json_object.cpp | 64 ++++++++++++++++++ platform/android/src/gson/json_object.hpp | 11 +++- platform/android/src/gson/json_primitive.cpp | 66 +++++++++++++++++++ platform/android/src/gson/json_primitive.hpp | 39 +++++++++++ platform/android/src/java/util.cpp | 6 ++ platform/android/src/java/util.hpp | 42 ++++++++++++ platform/android/src/jni.cpp | 34 +++++++++- platform/android/src/native_map_view.cpp | 17 +++-- platform/android/src/native_map_view.hpp | 6 +- .../android/src/style/conversion/geojson.hpp | 10 +-- .../src/style/sources/geojson_source.cpp | 23 +++++-- .../src/style/sources/geojson_source.hpp | 10 ++- .../src/style/sources/vector_source.cpp | 6 +- .../src/style/sources/vector_source.hpp | 6 +- platform/android/src/style/value.cpp | 32 ++++----- platform/android/src/style/value.hpp | 4 +- 47 files changed, 1266 insertions(+), 134 deletions(-) rename platform/android/src/{geometry => geojson}/conversion/feature.hpp (88%) rename platform/android/src/{geometry => geojson}/conversion/geometry.hpp (100%) create mode 100644 platform/android/src/geojson/feature.cpp rename platform/android/src/{geometry => geojson}/feature.hpp (55%) create mode 100644 platform/android/src/geojson/feature_collection.cpp create mode 100644 platform/android/src/geojson/feature_collection.hpp create mode 100644 platform/android/src/geojson/geometry.cpp create mode 100644 platform/android/src/geojson/geometry.hpp create mode 100644 platform/android/src/geojson/line_string.cpp create mode 100644 platform/android/src/geojson/line_string.hpp create mode 100644 platform/android/src/geojson/multi_line_string.cpp create mode 100644 platform/android/src/geojson/multi_line_string.hpp create mode 100644 platform/android/src/geojson/multi_point.cpp create mode 100644 platform/android/src/geojson/multi_point.hpp create mode 100644 platform/android/src/geojson/multi_polygon.cpp create mode 100644 platform/android/src/geojson/multi_polygon.hpp create mode 100644 platform/android/src/geojson/point.cpp create mode 100644 platform/android/src/geojson/point.hpp create mode 100644 platform/android/src/geojson/polygon.cpp create mode 100644 platform/android/src/geojson/polygon.hpp create mode 100644 platform/android/src/geojson/position.cpp create mode 100644 platform/android/src/geojson/position.hpp delete mode 100644 platform/android/src/geometry/feature.cpp delete mode 100644 platform/android/src/geometry/geometry.hpp create mode 100644 platform/android/src/gson/json_array.cpp create mode 100644 platform/android/src/gson/json_array.hpp create mode 100644 platform/android/src/gson/json_element.cpp create mode 100644 platform/android/src/gson/json_element.hpp create mode 100644 platform/android/src/gson/json_object.cpp create mode 100644 platform/android/src/gson/json_primitive.cpp create mode 100644 platform/android/src/gson/json_primitive.hpp diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java index b25359571..3c1a32516 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java @@ -11,7 +11,6 @@ import com.mapbox.services.commons.geojson.FeatureCollection; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashMap; import java.util.List; /** @@ -133,8 +132,7 @@ public class GeoJsonSource extends Source { * @param features the GeoJSON {@link FeatureCollection} */ public void setGeoJson(FeatureCollection features) { - checkValidity(); - setGeoJson(features.toJson()); + nativeSetFeatureCollection(features); } /** @@ -143,8 +141,7 @@ public class GeoJsonSource extends Source { * @param json the raw GeoJson FeatureCollection string */ public void setGeoJson(String json) { - checkValidity(); - setRawJson(json); + nativeSetGeoJsonString(json); } /** @@ -153,7 +150,6 @@ public class GeoJsonSource extends Source { * @param url the GeoJSON FeatureCollection url */ public void setUrl(URL url) { - checkValidity(); setUrl(url.toExternalForm()); } @@ -163,7 +159,6 @@ public class GeoJsonSource extends Source { * @param url the GeoJSON FeatureCollection url */ public void setUrl(String url) { - checkValidity(); nativeSetUrl(url); } @@ -179,19 +174,13 @@ public class GeoJsonSource extends Source { return features != null ? Arrays.asList(features) : new ArrayList(); } - protected void setRawJson(String geoJson) { - // Wrap the String in a map as an Object is expected by the - // style conversion template - HashMap wrapper = new HashMap<>(); - wrapper.put("data", geoJson); - nativeSetGeoJson(wrapper); - } - protected native void initialize(String layerId, Object options); protected native void nativeSetUrl(String url); - private native void nativeSetGeoJson(Object geoJson); + private native void nativeSetGeoJsonString(String geoJson); + + private native void nativeSetFeatureCollection(FeatureCollection geoJson); private native Feature[] querySourceFeatures(Object[] filter); diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java index 6826fed1b..62bfcb818 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java @@ -5,7 +5,6 @@ package com.mapbox.mapboxsdk.style.sources; */ public abstract class Source { private long nativePtr; - private boolean invalidated; /** * Internal use @@ -25,7 +24,6 @@ public abstract class Source { * @return the source id */ public String getId() { - checkValidity(); return nativeGetId(); } @@ -40,16 +38,4 @@ public abstract class Source { protected native String nativeGetId(); - protected void checkValidity() { - if (invalidated) { - throw new RuntimeException("Layer has been invalidated. Request a new reference after adding"); - } - } - - /** - * Internal use - invalidates the source for further use (after adding it to the map) - */ - public final void invalidate() { - this.invalidated = true; - } } diff --git a/platform/android/config.cmake b/platform/android/config.cmake index 86413d0d1..8a590b1f2 100644 --- a/platform/android/config.cmake +++ b/platform/android/config.cmake @@ -184,9 +184,29 @@ add_library(mbgl-android STATIC platform/android/src/graphics/rectf.cpp platform/android/src/graphics/rectf.hpp + # GeoJSON + platform/android/src/geojson/feature.cpp + platform/android/src/geojson/feature.hpp + platform/android/src/geojson/feature_collection.cpp + platform/android/src/geojson/feature_collection.hpp + platform/android/src/geojson/geometry.cpp + platform/android/src/geojson/geometry.hpp + platform/android/src/geojson/line_string.cpp + platform/android/src/geojson/line_string.hpp + platform/android/src/geojson/multi_line_string.cpp + platform/android/src/geojson/multi_line_string.hpp + platform/android/src/geojson/multi_point.cpp + platform/android/src/geojson/multi_point.hpp + platform/android/src/geojson/multi_polygon.cpp + platform/android/src/geojson/multi_polygon.hpp + platform/android/src/geojson/point.cpp + platform/android/src/geojson/point.hpp + platform/android/src/geojson/polygon.cpp + platform/android/src/geojson/polygon.hpp + platform/android/src/geojson/position.cpp + platform/android/src/geojson/position.hpp + # Geometry - platform/android/src/geometry/feature.cpp - platform/android/src/geometry/feature.hpp platform/android/src/geometry/lat_lng.cpp platform/android/src/geometry/lat_lng.hpp platform/android/src/geometry/lat_lng_bounds.cpp @@ -194,6 +214,16 @@ add_library(mbgl-android STATIC platform/android/src/geometry/projected_meters.cpp platform/android/src/geometry/projected_meters.hpp + # GSon + platform/android/src/gson/json_array.cpp + platform/android/src/gson/json_array.hpp + platform/android/src/gson/json_element.cpp + platform/android/src/gson/json_element.hpp + platform/android/src/gson/json_object.cpp + platform/android/src/gson/json_object.hpp + platform/android/src/gson/json_primitive.cpp + platform/android/src/gson/json_primitive.hpp + # Annotation platform/android/src/annotation/marker.cpp platform/android/src/annotation/marker.hpp diff --git a/platform/android/src/geometry/conversion/feature.hpp b/platform/android/src/geojson/conversion/feature.hpp similarity index 88% rename from platform/android/src/geometry/conversion/feature.hpp rename to platform/android/src/geojson/conversion/feature.hpp index 921138e85..86aa5fc03 100644 --- a/platform/android/src/geometry/conversion/feature.hpp +++ b/platform/android/src/geojson/conversion/feature.hpp @@ -170,8 +170,8 @@ struct Converter> { template <> -struct Converter, mbgl::Feature> { - Result> operator()(jni::JNIEnv& env, const mbgl::Feature& value) const { +struct Converter, mbgl::Feature> { + Result> operator()(jni::JNIEnv& env, const mbgl::Feature& value) const { // Convert Id FeatureIdVisitor idEvaluator; @@ -179,13 +179,13 @@ struct Converter, mbgl::Feature> { auto jid = jni::Make(env, id); // Convert properties - auto properties = jni::Object(*convert(env, value.properties)); + auto properties = jni::Object(*convert(env, value.properties)); // Convert geometry - auto geometry = jni::Object(*convert(env, value.geometry)); + auto geometry = jni::Object(*convert(env, value.geometry)); // Create feature - auto feature = Feature::fromGeometry(env, geometry, properties, jid); + auto feature = android::geojson::Feature::fromGeometry(env, geometry, properties, jid); //Cleanup jni::DeleteLocalRef(env, jid); @@ -197,13 +197,13 @@ struct Converter, mbgl::Feature> { }; template <> -struct Converter>, std::vector> { - Result>> operator()(jni::JNIEnv& env, const std::vector& value) const { - +struct Converter>, std::vector> { + Result>> operator()(jni::JNIEnv& env, const std::vector& value) const { + using namespace mbgl::android::geojson; auto features = jni::Array>::New(env, value.size(), Feature::javaClass); for(size_t i = 0; i < value.size(); i = i + 1) { - auto converted = *convert, mbgl::Feature>(env, value.at(i)); + auto converted = *convert, mbgl::Feature>(env, value.at(i)); features.Set(env, i, converted); jni::DeleteLocalRef(env, converted); } diff --git a/platform/android/src/geometry/conversion/geometry.hpp b/platform/android/src/geojson/conversion/geometry.hpp similarity index 100% rename from platform/android/src/geometry/conversion/geometry.hpp rename to platform/android/src/geojson/conversion/geometry.hpp diff --git a/platform/android/src/geojson/feature.cpp b/platform/android/src/geojson/feature.cpp new file mode 100644 index 000000000..a6b387cd1 --- /dev/null +++ b/platform/android/src/geojson/feature.cpp @@ -0,0 +1,63 @@ +#include "feature.hpp" + +#include "geometry.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +mbgl::Feature Feature::convert(jni::JNIEnv& env, jni::Object jFeature) { + // Convert + auto jGeometry = getGeometry(env, jFeature); + auto jProperties = Feature::getProperties(env, jFeature); + + std::experimental::optional id; + auto jId = Feature::getId(env, jFeature); + if (jId) { + id = { jni::Make(env, jId) }; + } + + auto feature = mbgl::Feature { + Geometry::convert(env, jGeometry), + gson::JsonObject::convert(env, jProperties), + id + }; + + // Cleanup + jni::DeleteLocalRef(env, jGeometry); + jni::DeleteLocalRef(env, jProperties); + jni::DeleteLocalRef(env, jId); + + return feature; +} + +jni::Object Feature::getGeometry(jni::JNIEnv& env, jni::Object jFeature) { + static auto method = Feature::javaClass.GetMethod ()>(env, "getGeometry"); + return jFeature.Call(env, method); +} + +jni::Object Feature::getProperties(jni::JNIEnv& env, jni::Object jFeature) { + static auto method = Feature::javaClass.GetMethod ()>(env, "getProperties"); + return jFeature.Call(env, method); +} + +jni::String Feature::getId(jni::JNIEnv& env, jni::Object jFeature) { + static auto method = Feature::javaClass.GetMethod(env, "getId"); + return jFeature.Call(env, method); +} + +jni::Object Feature::fromGeometry(jni::JNIEnv& env, jni::Object geometry, jni::Object properties, jni::String id) { + static auto method = Feature::javaClass.GetStaticMethod (jni::Object, jni::Object, jni::String)>(env, "fromGeometry"); + return Feature::javaClass.Call(env, method, geometry, properties, id); +} + +void Feature::registerNative(jni::JNIEnv& env) { + // Lookup the class + Feature::javaClass = *jni::Class::Find(env).NewGlobalRef(env).release(); +} + +jni::Class Feature::javaClass; + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/geometry/feature.hpp b/platform/android/src/geojson/feature.hpp similarity index 55% rename from platform/android/src/geometry/feature.hpp rename to platform/android/src/geojson/feature.hpp index 7f2733430..b5d856cc4 100644 --- a/platform/android/src/geometry/feature.hpp +++ b/platform/android/src/geojson/feature.hpp @@ -1,7 +1,8 @@ #pragma once -#include +#include #include +#include #include @@ -10,13 +11,22 @@ namespace mbgl { namespace android { +namespace geojson { class Feature : private mbgl::util::noncopyable { public: static constexpr auto Name() { return "com/mapbox/services/commons/geojson/Feature"; }; - static jni::Object fromGeometry(jni::JNIEnv&, jni::Object, jni::Object, jni::String); + static jni::Object fromGeometry(jni::JNIEnv&, jni::Object, jni::Object, jni::String); + + static mbgl::Feature convert(jni::JNIEnv&, jni::Object); + + static jni::Object getGeometry(jni::JNIEnv&, jni::Object); + + static jni::String getId(jni::JNIEnv&, jni::Object); + + static jni::Object getProperties(jni::JNIEnv&, jni::Object); static jni::Class javaClass; @@ -24,6 +34,6 @@ public: }; - +} // namespace geojson } // namespace android } // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/geojson/feature_collection.cpp b/platform/android/src/geojson/feature_collection.cpp new file mode 100644 index 000000000..2f156532a --- /dev/null +++ b/platform/android/src/geojson/feature_collection.cpp @@ -0,0 +1,40 @@ +#include "feature_collection.hpp" + +#include "feature.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +mbgl::FeatureCollection FeatureCollection::convert(jni::JNIEnv& env, jni::Object jCollection) { + auto jFeatureList = FeatureCollection::getFeatures(env, jCollection); + auto jFeatures = java::util::List::toArray(env, jFeatureList); + auto size = size_t(jFeatures.Length(env)); + + auto collection = mbgl::FeatureCollection(); + collection.reserve(size); + + for (size_t i = 0; i < size; i++) { + auto jFeature = jFeatures.Get(env, i); + collection.push_back(Feature::convert(env, jFeature)); + jni::DeleteLocalRef(env, jFeature); + } + + return collection; +} + +jni::Object FeatureCollection::getFeatures(jni::JNIEnv& env, jni::Object jCollection) { + static auto method = FeatureCollection::javaClass.GetMethod ()>(env, "getFeatures"); + return jCollection.Call(env, method); +} + +void FeatureCollection::registerNative(jni::JNIEnv& env) { + // Lookup the class + javaClass = *jni::Class::Find(env).NewGlobalRef(env).release(); +} + +jni::Class FeatureCollection::javaClass; + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/geojson/feature_collection.hpp b/platform/android/src/geojson/feature_collection.hpp new file mode 100644 index 000000000..8e9717e82 --- /dev/null +++ b/platform/android/src/geojson/feature_collection.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include "../java/util.hpp" + +#include +#include + +#include + +namespace mbgl { +namespace android { +namespace geojson { + +class FeatureCollection : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "com/mapbox/services/commons/geojson/FeatureCollection"; }; + + static mbgl::FeatureCollection convert(jni::JNIEnv&, jni::Object); + + static jni::Object getFeatures(jni::JNIEnv&, jni::Object); + + static jni::Class 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/geometry.cpp b/platform/android/src/geojson/geometry.cpp new file mode 100644 index 000000000..33bb4ee3d --- /dev/null +++ b/platform/android/src/geojson/geometry.cpp @@ -0,0 +1,52 @@ +#include "geometry.hpp" + +#include "point.hpp" +#include "multi_point.hpp" +#include "line_string.hpp" +#include "multi_line_string.hpp" +#include "polygon.hpp" +#include "multi_polygon.hpp" + +#include + +namespace mbgl { +namespace android { +namespace geojson { + +mapbox::geojson::geometry Geometry::convert(jni::JNIEnv &env, jni::Object jGeometry) { + auto type = Geometry::getType(env, jGeometry); + if (type == Point::Type()) { + return { Point::convert(env, jni::Object(jGeometry.Get())) }; + } else if (type == MultiPoint::Type()) { + return { MultiPoint::convert(env, jni::Object(jGeometry.Get())) }; + } else if (type == LineString::Type()) { + return { LineString::convert(env, jni::Object(jGeometry.Get())) }; + } else if (type == MultiLineString::Type()) { + return { MultiLineString::convert(env, jni::Object(jGeometry.Get())) }; + } else if (type == Polygon::Type()) { + return { Polygon::convert(env, jni::Object(jGeometry.Get())) }; + } else if (type == MultiPolygon::Type()) { + return { MultiPolygon::convert(env, jni::Object(jGeometry.Get())) }; + } + + throw std::runtime_error(std::string {"Unsupported GeoJSON type: " } + type); +} + +std::string Geometry::getType(jni::JNIEnv &env, jni::Object jGeometry) { + static auto method = Geometry::javaClass.GetMethod(env, "getType"); + auto jType = jGeometry.Call(env, method); + auto type = jni::Make(env, jType); + jni::DeleteLocalRef(env, jType); + return type; +} + +void Geometry::registerNative(jni::JNIEnv &env) { + // Lookup the class + javaClass = *jni::Class::Find(env).NewGlobalRef(env).release(); +} + +jni::Class Geometry::javaClass; + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/geojson/geometry.hpp b/platform/android/src/geojson/geometry.hpp new file mode 100644 index 000000000..bdcff6bb3 --- /dev/null +++ b/platform/android/src/geojson/geometry.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include +#include + +#include + +namespace mbgl { +namespace android { +namespace geojson { + +class Geometry : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "com/mapbox/services/commons/geojson/Geometry"; }; + + static mapbox::geojson::geometry convert(jni::JNIEnv&, jni::Object); + + static std::string getType(jni::JNIEnv&, jni::Object); + + static jni::Class 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 new file mode 100644 index 000000000..d0719f253 --- /dev/null +++ b/platform/android/src/geojson/line_string.cpp @@ -0,0 +1,54 @@ +#include "line_string.hpp" + +#include "position.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +mapbox::geojson::line_string LineString::convert(jni::JNIEnv &env, jni::Object jLineString) { + mapbox::geojson::line_string lineString; + + if (jLineString) { + auto jPositionList = LineString::getCoordinates(env, jLineString); + lineString = LineString::convert(env, jPositionList); + jni::DeleteLocalRef(env, jPositionList); + } + + return lineString; +} + +mapbox::geojson::line_string LineString::convert(jni::JNIEnv &env, jni::Object*/> jPositionList) { + mapbox::geojson::line_string lineString; + + if (jPositionList) { + auto jPositionArray = java::util::List::toArray(env, jPositionList); + + auto size = jPositionArray.Length(env); + for (std::size_t i = 0; i < size; i++) { + auto jPosition = jPositionArray.Get(env, i); + lineString.push_back(Position::convert(env, jPosition)); + jni::DeleteLocalRef(env, jPosition); + } + + jni::DeleteLocalRef(env, jPositionArray); + } + + return lineString; +} + +jni::Object LineString::getCoordinates(jni::JNIEnv &env, jni::Object jLineString) { + static auto method = LineString::javaClass.GetMethod ()>(env, "getCoordinates"); + return jLineString.Call(env, method); +} + +void LineString::registerNative(jni::JNIEnv &env) { + // Lookup the class + javaClass = *jni::Class::Find(env).NewGlobalRef(env).release(); +} + +jni::Class LineString::javaClass; + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/geojson/line_string.hpp b/platform/android/src/geojson/line_string.hpp new file mode 100644 index 000000000..d3be68d0a --- /dev/null +++ b/platform/android/src/geojson/line_string.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include +#include + +#include + +#include "../java/util.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + + +class LineString : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "com/mapbox/services/commons/geojson/LineString"; }; + + static constexpr auto Type() { return "LineString"; }; + + static mapbox::geojson::line_string convert(jni::JNIEnv&, jni::Object); + + static mapbox::geojson::line_string convert(jni::JNIEnv&, jni::Object*/>); + + static jni::Object getCoordinates(jni::JNIEnv&, jni::Object); + + static jni::Class 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/multi_line_string.cpp b/platform/android/src/geojson/multi_line_string.cpp new file mode 100644 index 000000000..b676144bf --- /dev/null +++ b/platform/android/src/geojson/multi_line_string.cpp @@ -0,0 +1,56 @@ +#include "multi_line_string.hpp" + +#include "line_string.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +mapbox::geojson::multi_line_string MultiLineString::convert(jni::JNIEnv &env, jni::Object jMultiLineString) { + mapbox::geojson::multi_line_string multiLineString; + + if (jMultiLineString) { + auto jPositionListsList = MultiLineString::getCoordinates(env, jMultiLineString); + multiLineString = MultiLineString::convert(env, jPositionListsList); + jni::DeleteLocalRef(env, jPositionListsList); + } + + return multiLineString; +} + +mapbox::geojson::multi_line_string MultiLineString::convert(jni::JNIEnv &env, jni::Object>*/> jPositionListsList) { + mapbox::geojson::multi_line_string multiLineString; + + if (jPositionListsList) { + auto jPositionListsArray = java::util::List::toArray(env, jPositionListsList); + + auto size = jPositionListsArray.Length(env); + multiLineString.reserve(size); + + for (std::size_t i = 0; i < size; i++) { + auto jPositionList = jPositionListsArray.Get(env, i); + multiLineString.push_back(LineString::convert(env, jPositionList)); + jni::DeleteLocalRef(env, jPositionList); + } + + jni::DeleteLocalRef(env, jPositionListsArray); + } + + return multiLineString; +} + +jni::Object MultiLineString::getCoordinates(jni::JNIEnv &env, jni::Object jLineString) { + static auto method = MultiLineString::javaClass.GetMethod ()>(env, "getCoordinates"); + return jLineString.Call(env, method); +} + +void MultiLineString::registerNative(jni::JNIEnv &env) { + // Lookup the class + javaClass = *jni::Class::Find(env).NewGlobalRef(env).release(); +} + +jni::Class MultiLineString::javaClass; + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/geojson/multi_line_string.hpp b/platform/android/src/geojson/multi_line_string.hpp new file mode 100644 index 000000000..af33fe72d --- /dev/null +++ b/platform/android/src/geojson/multi_line_string.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include +#include + +#include + +#include "../java/util.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +class MultiLineString : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "com/mapbox/services/commons/geojson/MultiLineString"; }; + + static constexpr auto Type() { return "MultiLineString"; }; + + static mapbox::geojson::multi_line_string convert(jni::JNIEnv&, jni::Object); + + static mapbox::geojson::multi_line_string convert(jni::JNIEnv&, jni::Object>*/>); + + static jni::Object getCoordinates(jni::JNIEnv&, jni::Object); + + static jni::Class 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/multi_point.cpp b/platform/android/src/geojson/multi_point.cpp new file mode 100644 index 000000000..df4fdd7df --- /dev/null +++ b/platform/android/src/geojson/multi_point.cpp @@ -0,0 +1,35 @@ +#include "multi_point.hpp" + +#include "line_string.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +mapbox::geojson::multi_point MultiPoint::convert(jni::JNIEnv &env, jni::Object jMultiPoint) { + mapbox::geojson::multi_point multiPoint; + + if (jMultiPoint) { + auto jPositionListsList = MultiPoint::getCoordinates(env, jMultiPoint); + multiPoint = LineString::convert(env, jPositionListsList); + jni::DeleteLocalRef(env, jPositionListsList); + } + + return multiPoint; +} + +jni::Object MultiPoint::getCoordinates(jni::JNIEnv &env, jni::Object jMultiPoint) { + static auto method = MultiPoint::javaClass.GetMethod ()>(env, "getCoordinates"); + return jMultiPoint.Call(env, method); +} + +void MultiPoint::registerNative(jni::JNIEnv &env) { + // Lookup the class + javaClass = *jni::Class::Find(env).NewGlobalRef(env).release(); +} + +jni::Class MultiPoint::javaClass; + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/geojson/multi_point.hpp b/platform/android/src/geojson/multi_point.hpp new file mode 100644 index 000000000..7a698287e --- /dev/null +++ b/platform/android/src/geojson/multi_point.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include +#include + +#include + +#include "../java/util.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +class MultiPoint : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "com/mapbox/services/commons/geojson/MultiPoint"; }; + + static constexpr auto Type() { return "MultiPoint"; }; + + static mapbox::geojson::multi_point convert(jni::JNIEnv&, jni::Object); + + static jni::Object getCoordinates(jni::JNIEnv&, jni::Object); + + static jni::Class 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/multi_polygon.cpp b/platform/android/src/geojson/multi_polygon.cpp new file mode 100644 index 000000000..a55884a11 --- /dev/null +++ b/platform/android/src/geojson/multi_polygon.cpp @@ -0,0 +1,46 @@ +#include "multi_polygon.hpp" + +#include "polygon.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +mapbox::geojson::multi_polygon MultiPolygon::convert(jni::JNIEnv &env, jni::Object jMultiPolygon) { + mapbox::geojson::multi_polygon multiPolygon; + + if (jMultiPolygon) { + auto jPositionListsListList = MultiPolygon::getCoordinates(env, jMultiPolygon); + auto jPositionListsListArray = java::util::List::toArray(env, jPositionListsListList); + + auto size = jPositionListsListArray.Length(env); + multiPolygon.reserve(size); + + for (size_t i = 0; i < size; i++) { + auto jPositionListsList = jPositionListsListArray.Get(env, i); + multiPolygon.push_back(Polygon::convert(env, jPositionListsList)); + jni::DeleteLocalRef(env, jPositionListsList); + } + + jni::DeleteLocalRef(env, jPositionListsListList); + jni::DeleteLocalRef(env, jPositionListsListArray); + } + + return multiPolygon; +} + +jni::Object MultiPolygon::getCoordinates(jni::JNIEnv &env, jni::Object jPolygon) { + static auto method = MultiPolygon::javaClass.GetMethod ()>(env, "getCoordinates"); + return jPolygon.Call(env, method); +} + +void MultiPolygon::registerNative(jni::JNIEnv &env) { + // Lookup the class + javaClass = *jni::Class::Find(env).NewGlobalRef(env).release(); +} + +jni::Class MultiPolygon::javaClass; + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/geojson/multi_polygon.hpp b/platform/android/src/geojson/multi_polygon.hpp new file mode 100644 index 000000000..1f144cffd --- /dev/null +++ b/platform/android/src/geojson/multi_polygon.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include +#include + +#include + +#include "../java/util.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +class MultiPolygon : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "com/mapbox/services/commons/geojson/MultiPolygon"; }; + + static constexpr auto Type() { return "MultiPolygon"; }; + + static mapbox::geojson::multi_polygon convert(jni::JNIEnv&, jni::Object); + + static jni::Object getCoordinates(jni::JNIEnv&, jni::Object); + + static jni::Class 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/point.cpp b/platform/android/src/geojson/point.cpp new file mode 100644 index 000000000..3d19a119d --- /dev/null +++ b/platform/android/src/geojson/point.cpp @@ -0,0 +1,28 @@ +#include "point.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +mapbox::geojson::point Point::convert(jni::JNIEnv &env, jni::Object jPoint) { + auto jPosition = Point::getPosition(env, jPoint); + auto point = Position::convert(env, jPosition); + jni::DeleteLocalRef(env, jPosition); + return point; +} + +jni::Object Point::getPosition(JNIEnv& env, jni::Object jPoint) { + static auto method = Point::javaClass.GetMethod ()>(env, "getCoordinates"); + return jPoint.Call(env, method); +} + +void Point::registerNative(jni::JNIEnv &env) { + // Lookup the class + javaClass = *jni::Class::Find(env).NewGlobalRef(env).release(); +} + +jni::Class Point::javaClass; + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/geojson/point.hpp b/platform/android/src/geojson/point.hpp new file mode 100644 index 000000000..64ac0af9c --- /dev/null +++ b/platform/android/src/geojson/point.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include +#include + +#include "position.hpp" + +#include + +namespace mbgl { +namespace android { +namespace geojson { + +class Point : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "com/mapbox/services/commons/geojson/Point"; }; + + static constexpr auto Type() { return "Point"; }; + + static mapbox::geojson::point convert(jni::JNIEnv&, jni::Object); + + static jni::Object getPosition(JNIEnv&, jni::Object); + + static jni::Class 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/polygon.cpp b/platform/android/src/geojson/polygon.cpp new file mode 100644 index 000000000..bb37b8d99 --- /dev/null +++ b/platform/android/src/geojson/polygon.cpp @@ -0,0 +1,48 @@ +#include "polygon.hpp" + +#include "multi_line_string.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +mapbox::geojson::polygon Polygon::convert(jni::JNIEnv &env, jni::Object jPolygon) { + mapbox::geojson::polygon polygon; + + if (jPolygon) { + auto jPositionListsList = Polygon::getCoordinates(env, jPolygon); + polygon = Polygon::convert(env, jPositionListsList); + jni::DeleteLocalRef(env, jPositionListsList); + } + + return polygon; +} + +mapbox::geojson::polygon Polygon::convert(jni::JNIEnv &env, jni::Object>*/> jPositionListsList) { + mapbox::geojson::polygon polygon; + + if (jPositionListsList) { + auto multiLine = MultiLineString::convert(env, jPositionListsList); + polygon.reserve(multiLine.size()); + polygon.insert(std::end(polygon), std::begin(multiLine), std::end(multiLine)); + } + + return polygon; +} + + +jni::Object Polygon::getCoordinates(jni::JNIEnv &env, jni::Object jPolygon) { + static auto method = Polygon::javaClass.GetMethod ()>(env, "getCoordinates"); + return jPolygon.Call(env, method); +} + +void Polygon::registerNative(jni::JNIEnv &env) { + // Lookup the class + javaClass = *jni::Class::Find(env).NewGlobalRef(env).release(); +} + +jni::Class Polygon::javaClass; + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/geojson/polygon.hpp b/platform/android/src/geojson/polygon.hpp new file mode 100644 index 000000000..e5362cedf --- /dev/null +++ b/platform/android/src/geojson/polygon.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include +#include + +#include + +#include "../java/util.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +class Polygon : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "com/mapbox/services/commons/geojson/Polygon"; }; + + static constexpr auto Type() { return "Polygon"; }; + + static mapbox::geojson::polygon convert(jni::JNIEnv &, jni::Object); + + static mapbox::geojson::polygon convert(jni::JNIEnv&, jni::Object>*/>); + + static jni::Object getCoordinates(jni::JNIEnv&, jni::Object); + + static jni::Class 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/position.cpp b/platform/android/src/geojson/position.cpp new file mode 100644 index 000000000..c0e6da388 --- /dev/null +++ b/platform/android/src/geojson/position.cpp @@ -0,0 +1,27 @@ +#include "position.hpp" + +namespace mbgl { +namespace android { +namespace geojson { + +mapbox::geojson::point Position::convert(jni::JNIEnv &env, jni::Object jPosition) { + static auto method = Position::javaClass.GetMethod ()>(env, "getCoordinates"); + // Array with 0: longitude, 1: latitude (and optionally 2: altitude) + auto coordinates = jPosition.Call(env, method); + jdouble lngLat[2]; + coordinates.GetRegion(env, 0, lngLat); + mapbox::geojson::point point(lngLat[0], lngLat[1]); + jni::DeleteLocalRef(env, coordinates); + return point; +} + +void Position::registerNative(jni::JNIEnv &env) { + // Lookup the class + javaClass = *jni::Class::Find(env).NewGlobalRef(env).release(); +} + +jni::Class Position::javaClass; + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/geojson/position.hpp b/platform/android/src/geojson/position.hpp new file mode 100644 index 000000000..7017a8172 --- /dev/null +++ b/platform/android/src/geojson/position.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include +#include + +#include + +namespace mbgl { +namespace android { +namespace geojson { + +class Position : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "com/mapbox/services/commons/models/Position"; }; + + static constexpr auto Type() { return "Position"; }; + + static mapbox::geojson::point convert(jni::JNIEnv&, jni::Object); + + static jni::Class javaClass; + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace geojson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/geometry/feature.cpp b/platform/android/src/geometry/feature.cpp deleted file mode 100644 index 5355d50ab..000000000 --- a/platform/android/src/geometry/feature.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "feature.hpp" - -namespace mbgl { -namespace android { - -jni::Object Feature::fromGeometry(jni::JNIEnv& env, jni::Object geometry, jni::Object properties, jni::String id) { - static auto method = Feature::javaClass.GetStaticMethod (jni::Object, jni::Object, jni::String)>(env, "fromGeometry"); - return Feature::javaClass.Call(env, method, geometry, properties, id); -} - -void Feature::registerNative(jni::JNIEnv& env) { - // Lookup the class - Feature::javaClass = *jni::Class::Find(env).NewGlobalRef(env).release(); -} - -jni::Class Feature::javaClass; - - -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/geometry/geometry.hpp b/platform/android/src/geometry/geometry.hpp deleted file mode 100644 index 5c8ae3918..000000000 --- a/platform/android/src/geometry/geometry.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include - -namespace mbgl { -namespace android { - -class Geometry : private mbgl::util::noncopyable { -public: - static constexpr auto Name() { return "com/mapbox/services/commons/geojson/Geometry"; }; - -}; - - -} // namespace android -} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/gson/json_array.cpp b/platform/android/src/gson/json_array.cpp new file mode 100644 index 000000000..d91e323ac --- /dev/null +++ b/platform/android/src/gson/json_array.cpp @@ -0,0 +1,40 @@ +#include "json_array.hpp" + +#include "json_element.hpp" + +namespace mbgl { +namespace android { +namespace gson { + +std::vector JsonArray::convert(jni::JNIEnv &env, jni::Object jsonArray) { + std::vector values; + + if (jsonArray) { + static auto getMethod = JsonArray::javaClass.GetMethod (jni::jint)>(env, "get"); + static auto sizeMethod = JsonArray::javaClass.GetMethod(env, "size"); + + int size = jsonArray.Call(env, sizeMethod); + values.reserve(uint(size)); + + for (int i = 0; i < size; i++) { + auto entry = jsonArray.Call(env, getMethod, i); + if (entry) { + values.push_back(JsonElement::convert(env, entry)); + } + jni::DeleteLocalRef(env, entry); + } + } + + return values; +} + +void JsonArray::registerNative(jni::JNIEnv &env) { + // Lookup the class + javaClass = *jni::Class::Find(env).NewGlobalRef(env).release(); +} + +jni::Class JsonArray::javaClass; + +} // namespace gson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/gson/json_array.hpp b/platform/android/src/gson/json_array.hpp new file mode 100644 index 000000000..8571ad5db --- /dev/null +++ b/platform/android/src/gson/json_array.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include +#include + +#include + +namespace mbgl { +namespace android { +namespace gson { + +class JsonArray : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "com/google/gson/JsonArray"; }; + + static std::vector convert(JNIEnv&, jni::Object); + + static jni::Class javaClass; + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace gson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/gson/json_element.cpp b/platform/android/src/gson/json_element.cpp new file mode 100644 index 000000000..060b1e0fe --- /dev/null +++ b/platform/android/src/gson/json_element.cpp @@ -0,0 +1,62 @@ +#include "json_element.hpp" + +#include "json_array.hpp" +#include "json_object.hpp" +#include "json_primitive.hpp" + +#include +#include + +namespace mbgl { +namespace android { +namespace gson { + +mapbox::geometry::value JsonElement::convert(jni::JNIEnv &env, jni::Object jsonElement) { + mapbox::geometry::value value; + + if (jsonElement) { + if (isJsonPrimitive(env, jsonElement)) { + auto primitive = JsonPrimitive::convert(env, jni::Cast(env, jsonElement, JsonPrimitive::javaClass)); + value = mapbox::util::apply_visitor([](auto t) { return mapbox::geometry::value { t }; }, primitive); + } else if (isJsonObject(env, jsonElement)) { + mapbox::geometry::property_map map = JsonObject::convert(env, jni::Cast(env, jsonElement, JsonObject::javaClass)); + value = mapbox::util::recursive_wrapper> { map } ; + } else if (isJsonArray(env, jsonElement)) { + value = JsonArray::convert(env, jni::Cast(env, jsonElement, JsonArray::javaClass)); + } else { + value = mapbox::geometry::null_value; + } + } + return value; +} + +bool JsonElement::isJsonObject(JNIEnv& env, jni::Object jsonElement) { + static auto method = JsonElement::javaClass.GetMethod(env, "isJsonObject"); + return jsonElement.Call(env, method); +} + +bool JsonElement::isJsonArray(JNIEnv& env, jni::Object jsonElement) { + static auto method = JsonElement::javaClass.GetMethod(env, "isJsonArray"); + return jsonElement.Call(env, method); +} + +bool JsonElement::isJsonPrimitive(JNIEnv& env, jni::Object jsonElement) { + static auto method = JsonElement::javaClass.GetMethod(env, "isJsonPrimitive"); + return jsonElement.Call(env, method); +} + +bool JsonElement::isJsonNull(JNIEnv& env, jni::Object jsonElement) { + static auto method = JsonElement::javaClass.GetMethod(env, "isJsonNull"); + return jsonElement.Call(env, method); +} + +void JsonElement::registerNative(jni::JNIEnv &env) { + // Lookup the class + javaClass = *jni::Class::Find(env).NewGlobalRef(env).release(); +} + +jni::Class JsonElement::javaClass; + +} // namespace gson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/gson/json_element.hpp b/platform/android/src/gson/json_element.hpp new file mode 100644 index 000000000..761935061 --- /dev/null +++ b/platform/android/src/gson/json_element.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include +#include + +#include + +namespace mbgl { +namespace android { +namespace gson { + +class JsonElement : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "com/google/gson/JsonElement"; }; + + static mapbox::geometry::value convert(JNIEnv&, jni::Object); + + static bool isJsonObject(JNIEnv&, jni::Object); + + static bool isJsonArray(JNIEnv&, jni::Object); + + static bool isJsonPrimitive(JNIEnv&, jni::Object); + + static bool isJsonNull(JNIEnv&, jni::Object); + + static jni::Class javaClass; + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace gson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/gson/json_object.cpp b/platform/android/src/gson/json_object.cpp new file mode 100644 index 000000000..a704dae9d --- /dev/null +++ b/platform/android/src/gson/json_object.cpp @@ -0,0 +1,64 @@ +#include "json_object.hpp" + +#include "json_element.hpp" + +#include "../java/util.hpp" + +namespace mbgl { +namespace android { +namespace gson { + + +template // void (jni::String, jni::Object) +static void iterateEntrySet(jni::JNIEnv& env, jni::Object jsonObject, F callback) { + // Get Set> + static auto method = JsonObject::javaClass.GetMethod ()>(env, "entrySet"); + auto entrySet = jsonObject.Call(env, method); + jni::Array> entryArray = java::util::Set::toArray(env, entrySet); + + size_t size = entryArray.Length(env); + for (size_t i = 0; i < size; i++) { + auto entry = entryArray.Get(env, i); + if (entry) { + // Convert + auto jKey = java::util::Map::Entry::getKey(env, entry); + auto jKeyString = jni::String(reinterpret_cast(jKey.Get())); + auto jValue = java::util::Map::Entry::getValue(env, entry); + + // Callback + callback(jKeyString, jValue); + + // Cleanup + // Skip jKey as it points to the same as jKeyString + jni::DeleteLocalRef(env, jKeyString); + jni::DeleteLocalRef(env, jValue); + } + jni::DeleteLocalRef(env, entry); + } + + jni::DeleteLocalRef(env, entrySet); + jni::DeleteLocalRef(env, entryArray); +} + +mapbox::geometry::property_map JsonObject::convert(jni::JNIEnv &env, jni::Object jsonObject) { + mapbox::geometry::property_map map; + + if (jsonObject) { + iterateEntrySet(env, jsonObject, [&map, &env](jni::String jId, jni::Object jsonElement) { + map[jni::Make(env, jId)] = JsonElement::convert(env, jsonElement); + }); + } + + return map; +} + +void JsonObject::registerNative(jni::JNIEnv &env) { + // Lookup the class + javaClass = *jni::Class::Find(env).NewGlobalRef(env).release(); +} + +jni::Class JsonObject::javaClass; + +} // namespace gson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/gson/json_object.hpp b/platform/android/src/gson/json_object.hpp index a7de0b197..aba8e4041 100644 --- a/platform/android/src/gson/json_object.hpp +++ b/platform/android/src/gson/json_object.hpp @@ -1,16 +1,25 @@ #pragma once +#include #include +#include + namespace mbgl { namespace android { +namespace gson { class JsonObject : private mbgl::util::noncopyable { public: static constexpr auto Name() { return "com/google/gson/JsonObject"; }; + static mapbox::geometry::property_map convert(JNIEnv&, jni::Object); + + static jni::Class javaClass; + + static void registerNative(jni::JNIEnv&); }; - +} // namespace gson } // namespace android } // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/gson/json_primitive.cpp b/platform/android/src/gson/json_primitive.cpp new file mode 100644 index 000000000..58d0b45fe --- /dev/null +++ b/platform/android/src/gson/json_primitive.cpp @@ -0,0 +1,66 @@ +#include "json_primitive.hpp" + +namespace mbgl { +namespace android { +namespace gson { + +JsonPrimitive::value JsonPrimitive::convert(jni::JNIEnv &env, jni::Object jsonPrimitive) { + value value; + if (jsonPrimitive) { + if (isBoolean(env, jsonPrimitive)) { + value = getAsBoolean(env, jsonPrimitive); + } else if (isNumber(env, jsonPrimitive)) { + //TODO: how to differentiate types here? + value = getAsDouble(env, jsonPrimitive); + } else if (isString(env, jsonPrimitive)) { + value = getAsString(env, jsonPrimitive); + } else { + value = mapbox::geometry::null_value; + } + } + return value; +} + +bool JsonPrimitive::isBoolean(JNIEnv& env, jni::Object jsonPrimitive) { + static auto method = JsonPrimitive::javaClass.GetMethod(env, "isBoolean"); + return jsonPrimitive.Call(env, method); +} + +bool JsonPrimitive::isString(JNIEnv& env, jni::Object jsonPrimitive) { + static auto method = JsonPrimitive::javaClass.GetMethod(env, "isString"); + return jsonPrimitive.Call(env, method); +} + +bool JsonPrimitive::isNumber(JNIEnv& env, jni::Object jsonPrimitive) { + static auto method = JsonPrimitive::javaClass.GetMethod(env, "isNumber"); + return jsonPrimitive.Call(env, method); +} + +bool JsonPrimitive::getAsBoolean(JNIEnv& env, jni::Object jsonPrimitive) { + static auto method = JsonPrimitive::javaClass.GetMethod(env, "getAsBoolean"); + return jsonPrimitive.Call(env, method); +} + +std::string JsonPrimitive::getAsString(JNIEnv& env, jni::Object jsonPrimitive) { + static auto method = JsonPrimitive::javaClass.GetMethod(env, "getAsString"); + auto jString = jsonPrimitive.Call(env, method); + auto string = jni::Make(env, jString); + jni::DeleteLocalRef(env, jString); + return string; +} + +double JsonPrimitive::getAsDouble(JNIEnv& env, jni::Object jsonPrimitive) { + static auto method = JsonPrimitive::javaClass.GetMethod(env, "getAsDouble"); + return jsonPrimitive.Call(env, method); +} + +void JsonPrimitive::registerNative(jni::JNIEnv &env) { + // Lookup the class + javaClass = *jni::Class::Find(env).NewGlobalRef(env).release(); +} + +jni::Class JsonPrimitive::javaClass; + +} // namespace gson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/gson/json_primitive.hpp b/platform/android/src/gson/json_primitive.hpp new file mode 100644 index 000000000..5fc8a2b48 --- /dev/null +++ b/platform/android/src/gson/json_primitive.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include +#include + +#include + +namespace mbgl { +namespace android { +namespace gson { + +class JsonPrimitive : private mbgl::util::noncopyable { +public: + using value = mapbox::util::variant; + + static constexpr auto Name() { return "com/google/gson/JsonPrimitive"; }; + + static value convert(JNIEnv&, jni::Object); + + static bool isBoolean(JNIEnv&, jni::Object); + + static bool isString(JNIEnv&, jni::Object); + + static bool isNumber(JNIEnv&, jni::Object); + + static bool getAsBoolean(JNIEnv&, jni::Object); + + static std::string getAsString(JNIEnv&, jni::Object); + + static double getAsDouble(JNIEnv&, jni::Object); + + static jni::Class javaClass; + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace gson +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/java/util.cpp b/platform/android/src/java/util.cpp index c630e403d..effd2ae0d 100644 --- a/platform/android/src/java/util.cpp +++ b/platform/android/src/java/util.cpp @@ -6,9 +6,15 @@ namespace java { namespace util { jni::Class List::javaClass; +jni::Class Set::javaClass; +jni::Class Map::javaClass; +jni::Class Map::Entry::javaClass; void registerNative(jni::JNIEnv& env) { List::javaClass = *jni::Class::Find(env).NewGlobalRef(env).release(); + Set::javaClass = *jni::Class::Find(env).NewGlobalRef(env).release(); + Map::javaClass = *jni::Class::Find(env).NewGlobalRef(env).release(); + Map::Entry::javaClass = *jni::Class::Find(env).NewGlobalRef(env).release(); } diff --git a/platform/android/src/java/util.hpp b/platform/android/src/java/util.hpp index 1a552c712..dedb8ac34 100644 --- a/platform/android/src/java/util.hpp +++ b/platform/android/src/java/util.hpp @@ -24,6 +24,48 @@ public: }; +class Set : private mbgl::util::noncopyable { +public: + + static constexpr auto Name() { return "java/util/Set"; }; + + template + static jni::Array> toArray(jni::JNIEnv& env, jni::Object list) { + static auto toArray = Set::javaClass.GetMethod> ()>(env, "toArray"); + return (jni::Array>) list.Call(env, toArray); + }; + + static jni::Class javaClass; + +}; + +class Map : private mbgl::util::noncopyable { +public: + + class Entry : private mbgl::util::noncopyable { + public: + static constexpr auto Name() { return "java/util/Map$Entry"; }; + + template + static jni::Object getKey(jni::JNIEnv& env, jni::Object entry) { + static auto method = Entry::javaClass.GetMethod ()>(env, "getKey"); + return (jni::Object) entry.Call(env, method); + } + + template + static jni::Object getValue(jni::JNIEnv& env, jni::Object entry) { + static auto method = Entry::javaClass.GetMethod ()>(env, "getValue"); + return (jni::Object) entry.Call(env, method).Get(); + } + + static jni::Class javaClass; + }; + + static constexpr auto Name() { return "java/util/Map"; }; + + static jni::Class javaClass; +}; + void registerNative(jni::JNIEnv&); diff --git a/platform/android/src/jni.cpp b/platform/android/src/jni.cpp index bd12cff3f..54cb0867d 100755 --- a/platform/android/src/jni.cpp +++ b/platform/android/src/jni.cpp @@ -11,12 +11,25 @@ #include "conversion/conversion.hpp" #include "conversion/collection.hpp" #include "file_source.hpp" -#include "geometry/feature.hpp" +#include "geojson/feature.hpp" +#include "geojson/feature_collection.hpp" +#include "geojson/geometry.hpp" +#include "geojson/line_string.hpp" +#include "geojson/multi_line_string.hpp" +#include "geojson/multi_point.hpp" +#include "geojson/multi_polygon.hpp" +#include "geojson/point.hpp" +#include "geojson/polygon.hpp" +#include "geojson/position.hpp" #include "geometry/lat_lng.hpp" #include "geometry/lat_lng_bounds.hpp" #include "geometry/projected_meters.hpp" #include "graphics/pointf.hpp" #include "graphics/rectf.hpp" +#include "gson/json_array.hpp" +#include "gson/json_element.hpp" +#include "gson/json_object.hpp" +#include "gson/json_primitive.hpp" #include "java_types.hpp" #include "native_map_view.hpp" #include "offline/offline_manager.hpp" @@ -97,12 +110,29 @@ void registerNatives(JavaVM *vm) { PointF::registerNative(env); RectF::registerNative(env); + // GeoJSON + geojson::Feature::registerNative(env); + geojson::FeatureCollection::registerNative(env); + geojson::Geometry::registerNative(env); + geojson::LineString::registerNative(env); + geojson::MultiLineString::registerNative(env); + geojson::MultiPoint::registerNative(env); + geojson::MultiPolygon::registerNative(env); + geojson::Point::registerNative(env); + geojson::Polygon::registerNative(env); + geojson::Position::registerNative(env); + // Geometry - Feature::registerNative(env); LatLng::registerNative(env); LatLngBounds::registerNative(env); ProjectedMeters::registerNative(env); + // GSon + gson::JsonArray::registerNative(env); + gson::JsonElement::registerNative(env); + gson::JsonObject::registerNative(env); + gson::JsonPrimitive::registerNative(env); + //Annotation Marker::registerNative(env); Polygon::registerNative(env); diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp index 4547eeff2..f1345c01f 100755 --- a/platform/android/src/native_map_view.cpp +++ b/platform/android/src/native_map_view.cpp @@ -35,7 +35,7 @@ #include "conversion/conversion.hpp" #include "conversion/collection.hpp" #include "style/conversion/filter.hpp" -#include "geometry/conversion/feature.hpp" +#include "geojson/conversion/feature.hpp" #include "jni.hpp" #include "attach_env.hpp" @@ -793,32 +793,35 @@ jni::Array NativeMapView::queryPointAnnotations(JNIEnv& env, jni::Object< return result; } -jni::Array> NativeMapView::queryRenderedFeaturesForPoint(JNIEnv& env, jni::jfloat x, jni::jfloat y, +jni::Array> NativeMapView::queryRenderedFeaturesForPoint(JNIEnv& env, jni::jfloat x, jni::jfloat y, jni::Array layerIds, jni::Array> jfilter) { using namespace mbgl::android::conversion; - using namespace mapbox::geometry; + using namespace mbgl::android::geojson; mbgl::optional> layers; if (layerIds != nullptr && layerIds.Length(env) > 0) { layers = android::conversion::toVector(env, layerIds); } - point point = {x, y}; + mapbox::geometry::point point = {x, y}; return *convert>, std::vector>(env, map->queryRenderedFeatures(point, { layers, toFilter(env, jfilter) })); } -jni::Array> NativeMapView::queryRenderedFeaturesForBox(JNIEnv& env, jni::jfloat left, jni::jfloat top, +jni::Array> NativeMapView::queryRenderedFeaturesForBox(JNIEnv& env, jni::jfloat left, jni::jfloat top, jni::jfloat right, jni::jfloat bottom, jni::Array layerIds, jni::Array> jfilter) { using namespace mbgl::android::conversion; - using namespace mapbox::geometry; + using namespace mbgl::android::geojson; mbgl::optional> layers; if (layerIds != nullptr && layerIds.Length(env) > 0) { layers = toVector(env, layerIds); } - box box = { point{ left, top}, point{ right, bottom } }; + mapbox::geometry::box box = { + mapbox::geometry::point{ left, top}, + mapbox::geometry::point{ right, bottom } + }; return *convert>, std::vector>(env, map->queryRenderedFeatures(box, { layers, toFilter(env, jfilter) })); } diff --git a/platform/android/src/native_map_view.hpp b/platform/android/src/native_map_view.hpp index 4651ed81e..d48d5a107 100755 --- a/platform/android/src/native_map_view.hpp +++ b/platform/android/src/native_map_view.hpp @@ -17,7 +17,7 @@ #include "annotation/polyline.hpp" #include "graphics/pointf.hpp" #include "graphics/rectf.hpp" -#include "geometry/feature.hpp" +#include "geojson/feature.hpp" #include "geometry/lat_lng.hpp" #include "geometry/projected_meters.hpp" #include "style/layers/layers.hpp" @@ -222,11 +222,11 @@ public: jni::Array queryPointAnnotations(JNIEnv&, jni::Object); - jni::Array> queryRenderedFeaturesForPoint(JNIEnv&, jni::jfloat, jni::jfloat, + jni::Array> queryRenderedFeaturesForPoint(JNIEnv&, jni::jfloat, jni::jfloat, jni::Array, jni::Array> jfilter); - jni::Array> queryRenderedFeaturesForBox(JNIEnv&, jni::jfloat, jni::jfloat, jni::jfloat, + jni::Array> queryRenderedFeaturesForBox(JNIEnv&, jni::jfloat, jni::jfloat, jni::jfloat, jni::jfloat, jni::Array, jni::Array> jfilter); diff --git a/platform/android/src/style/conversion/geojson.hpp b/platform/android/src/style/conversion/geojson.hpp index db474e854..32a473b09 100644 --- a/platform/android/src/style/conversion/geojson.hpp +++ b/platform/android/src/style/conversion/geojson.hpp @@ -1,11 +1,8 @@ #pragma once -#include "../value.hpp" - #include #include #include -#include #include namespace mbgl { @@ -14,14 +11,13 @@ namespace conversion { template <> optional convertGeoJSON(const mbgl::android::Value& value, Error& error) { - // Value should be a string wrapped in an object - mbgl::android::Value jsonValue = value.get("data"); - if(value.isNull()) { + + if(value.isNull() || !value.isString()) { error = { "no json data found" }; return {}; } - return convertGeoJSON(value.get("data").toString(), error); + return convertGeoJSON(value.toString(), error); } template <> diff --git a/platform/android/src/style/sources/geojson_source.cpp b/platform/android/src/style/sources/geojson_source.cpp index 0c2d25f9f..ad5588985 100644 --- a/platform/android/src/style/sources/geojson_source.cpp +++ b/platform/android/src/style/sources/geojson_source.cpp @@ -8,8 +8,8 @@ // C++ -> Java conversion #include "../../conversion/conversion.hpp" #include "../../conversion/collection.hpp" -#include "../../geometry/conversion/feature.hpp" - +#include "../../geojson/conversion/feature.hpp" +#include "../conversion/url_or_tileset.hpp" #include #include @@ -47,7 +47,7 @@ namespace android { GeoJSONSource::~GeoJSONSource() = default; - void GeoJSONSource::setGeoJSON(jni::JNIEnv& env, jni::Object<> json) { + void GeoJSONSource::setGeoJSONString(jni::JNIEnv& env, jni::String json) { using namespace mbgl::style::conversion; // Convert the jni object @@ -62,15 +62,25 @@ namespace android { source.as()->GeoJSONSource::setGeoJSON(*converted); } + void GeoJSONSource::setFeatureCollection(jni::JNIEnv& env, jni::Object jFeatures) { + using namespace mbgl::android::geojson; + + // Convert the jni object + auto features = FeatureCollection::convert(env, jFeatures); + + // Update the core source + source.as()->GeoJSONSource::setGeoJSON(GeoJSON(features)); + } + void GeoJSONSource::setURL(jni::JNIEnv& env, jni::String url) { // Update the core source source.as()->GeoJSONSource::setURL(jni::Make(env, url)); } - jni::Array> GeoJSONSource::querySourceFeatures(jni::JNIEnv& env, + jni::Array> GeoJSONSource::querySourceFeatures(jni::JNIEnv& env, jni::Array> jfilter) { using namespace mbgl::android::conversion; - using namespace mapbox::geometry; + using namespace mbgl::android::geojson; auto filter = toFilter(env, jfilter); auto features = source.querySourceFeatures({ {}, filter }); @@ -96,7 +106,8 @@ namespace android { std::make_unique>, "initialize", "finalize", - METHOD(&GeoJSONSource::setGeoJSON, "nativeSetGeoJson"), + METHOD(&GeoJSONSource::setGeoJSONString, "nativeSetGeoJsonString"), + METHOD(&GeoJSONSource::setFeatureCollection, "nativeSetFeatureCollection"), METHOD(&GeoJSONSource::setURL, "nativeSetUrl"), METHOD(&GeoJSONSource::querySourceFeatures, "querySourceFeatures") ); diff --git a/platform/android/src/style/sources/geojson_source.hpp b/platform/android/src/style/sources/geojson_source.hpp index 5b529fc52..98d98e26b 100644 --- a/platform/android/src/style/sources/geojson_source.hpp +++ b/platform/android/src/style/sources/geojson_source.hpp @@ -2,7 +2,8 @@ #include "source.hpp" #include -#include "../../geometry/feature.hpp" +#include "../../geojson/feature.hpp" +#include "../../geojson/feature_collection.hpp" #include namespace mbgl { @@ -23,11 +24,14 @@ public: ~GeoJSONSource(); - void setGeoJSON(jni::JNIEnv&, jni::Object<>); + void setGeoJSONString(jni::JNIEnv&, jni::String); + + void setFeatureCollection(jni::JNIEnv&, jni::Object); void setURL(jni::JNIEnv&, jni::String); - jni::Array> querySourceFeatures(jni::JNIEnv&, jni::Array> jfilter); + jni::Array> querySourceFeatures(jni::JNIEnv&, + jni::Array> jfilter); jni::jobject* createJavaPeer(jni::JNIEnv&); diff --git a/platform/android/src/style/sources/vector_source.cpp b/platform/android/src/style/sources/vector_source.cpp index 4852a9b84..53aa14445 100644 --- a/platform/android/src/style/sources/vector_source.cpp +++ b/platform/android/src/style/sources/vector_source.cpp @@ -7,7 +7,7 @@ // C++ -> Java conversion #include "../../conversion/conversion.hpp" #include "../../conversion/collection.hpp" -#include "../../geometry/conversion/feature.hpp" +#include "../../geojson/conversion/feature.hpp" #include "../conversion/url_or_tileset.hpp" #include @@ -34,11 +34,11 @@ namespace android { VectorSource::~VectorSource() = default; - jni::Array> VectorSource::querySourceFeatures(jni::JNIEnv& env, + jni::Array> VectorSource::querySourceFeatures(jni::JNIEnv& env, jni::Array jSourceLayerIds, jni::Array> jfilter) { using namespace mbgl::android::conversion; - using namespace mapbox::geometry; + using namespace mbgl::android::geojson; mbgl::optional> sourceLayerIds = { toVector(env, jSourceLayerIds) }; auto filter = toFilter(env, jfilter); diff --git a/platform/android/src/style/sources/vector_source.hpp b/platform/android/src/style/sources/vector_source.hpp index f7e7645c5..cac687bb6 100644 --- a/platform/android/src/style/sources/vector_source.hpp +++ b/platform/android/src/style/sources/vector_source.hpp @@ -2,7 +2,7 @@ #include "source.hpp" #include -#include "../../geometry/feature.hpp" +#include "../../geojson/feature.hpp" #include namespace mbgl { @@ -23,8 +23,8 @@ public: ~VectorSource(); - jni::Array> querySourceFeatures(jni::JNIEnv&, jni::Array, - jni::Array> jfilter); + jni::Array> querySourceFeatures(jni::JNIEnv&, jni::Array, + jni::Array> jfilter); jni::jobject* createJavaPeer(jni::JNIEnv&); diff --git a/platform/android/src/style/value.cpp b/platform/android/src/style/value.cpp index da953c14b..e1cd81d7f 100644 --- a/platform/android/src/style/value.cpp +++ b/platform/android/src/style/value.cpp @@ -22,7 +22,7 @@ namespace android { // Instance - Value::Value(jni::JNIEnv& env, jni::jobject* _value) : jenv(env), value(_value, ObjectDeleter(env)) {} + Value::Value(jni::JNIEnv& _env, jni::jobject* _value) : env(_env), value(_value, ObjectDeleter(env)) {} Value::~Value() = default; @@ -31,59 +31,59 @@ namespace android { } bool Value::isArray() const { - return jni::IsInstanceOf(jenv, value.get(), *java::ObjectArray::jclass); + return jni::IsInstanceOf(env, value.get(), *java::ObjectArray::jclass); } bool Value::isObject() const { - return jni::IsInstanceOf(jenv, value.get(), *java::Map::jclass);; + return jni::IsInstanceOf(env, value.get(), *java::Map::jclass);; } bool Value::isString() const { - return jni::IsInstanceOf(jenv, value.get(), *java::String::jclass); + return jni::IsInstanceOf(env, value.get(), *java::String::jclass); } bool Value::isBool() const { - return jni::IsInstanceOf(jenv, value.get(), *java::Boolean::jclass); + return jni::IsInstanceOf(env, value.get(), *java::Boolean::jclass); } bool Value::isNumber() const { - return jni::IsInstanceOf(jenv, value.get(), *java::Number::jclass); + return jni::IsInstanceOf(env, value.get(), *java::Number::jclass); } std::string Value::toString() const { jni::jstring* string = reinterpret_cast(value.get()); - return jni::Make(jenv, jni::String(string)); + return jni::Make(env, jni::String(string)); } float Value::toFloat() const { - return jni::CallMethod(jenv, value.get(), *java::Number::floatValueMethodId); + return jni::CallMethod(env, value.get(), *java::Number::floatValueMethodId); } double Value::toDouble() const { - return jni::CallMethod(jenv, value.get(), *java::Number::doubleValueMethodId); + return jni::CallMethod(env, value.get(), *java::Number::doubleValueMethodId); } long Value::toLong() const { - return jni::CallMethod(jenv, value.get(), *java::Number::longValueMethodId); + return jni::CallMethod(env, value.get(), *java::Number::longValueMethodId); } bool Value::toBool() const { - return jni::CallMethod(jenv, value.get(), *java::Boolean::booleanValueMethodId); + return jni::CallMethod(env, value.get(), *java::Boolean::booleanValueMethodId); } Value Value::get(const char* key) const { - jni::jobject* member = jni::CallMethod(jenv, value.get(), *java::Map::getMethodId, jni::Make(jenv, std::string(key)).Get()); - return Value(jenv, member); + jni::jobject* member = jni::CallMethod(env, value.get(), *java::Map::getMethodId, jni::Make(env, std::string(key)).Get()); + return Value(env, member); } int Value::getLength() const { auto array = (jni::jarray*) value.get(); - return jni::GetArrayLength(jenv, *array); + return jni::GetArrayLength(env, *array); } - Value Value::get(const int index ) const { + Value Value::get(const int index) const { auto array = (jni::jarray*) value.get(); - return Value(jenv, jni::GetObjectArrayElement(jenv, *array, index)); + return Value(env, jni::GetObjectArrayElement(env, *array, index)); } } } diff --git a/platform/android/src/style/value.hpp b/platform/android/src/style/value.hpp index 761ce4d73..7464bae83 100644 --- a/platform/android/src/style/value.hpp +++ b/platform/android/src/style/value.hpp @@ -29,9 +29,7 @@ public: int getLength() const; Value get(const int index ) const; -private: - - jni::JNIEnv& jenv; + jni::JNIEnv& env; std::shared_ptr value; };