summaryrefslogtreecommitdiff
path: root/platform/android/src
diff options
context:
space:
mode:
Diffstat (limited to 'platform/android/src')
-rw-r--r--platform/android/src/annotation/marker.cpp31
-rw-r--r--platform/android/src/annotation/marker.hpp30
-rw-r--r--platform/android/src/annotation/multi_point.hpp42
-rw-r--r--platform/android/src/annotation/polygon.cpp49
-rw-r--r--platform/android/src/annotation/polygon.hpp40
-rw-r--r--platform/android/src/annotation/polyline.cpp49
-rw-r--r--platform/android/src/annotation/polyline.hpp40
-rw-r--r--platform/android/src/bitmap.cpp132
-rw-r--r--platform/android/src/bitmap.hpp52
-rw-r--r--platform/android/src/bitmap_factory.cpp25
-rw-r--r--platform/android/src/bitmap_factory.hpp25
-rw-r--r--platform/android/src/connectivity_listener.cpp8
-rw-r--r--platform/android/src/connectivity_listener.hpp8
-rw-r--r--platform/android/src/conversion/collection.hpp14
-rw-r--r--platform/android/src/conversion/color.hpp24
-rw-r--r--platform/android/src/conversion/constant.hpp2
-rw-r--r--platform/android/src/conversion/conversion.hpp2
-rw-r--r--platform/android/src/file_source.cpp106
-rw-r--r--platform/android/src/file_source.hpp53
-rw-r--r--platform/android/src/geometry/conversion/feature.hpp66
-rw-r--r--platform/android/src/geometry/conversion/geometry.hpp14
-rw-r--r--platform/android/src/geometry/feature.cpp20
-rw-r--r--platform/android/src/geometry/feature.hpp29
-rw-r--r--platform/android/src/geometry/geometry.hpp16
-rw-r--r--platform/android/src/geometry/lat_lng.cpp31
-rw-r--r--platform/android/src/geometry/lat_lng.hpp31
-rw-r--r--platform/android/src/geometry/lat_lng_bounds.cpp31
-rw-r--r--platform/android/src/geometry/lat_lng_bounds.hpp29
-rw-r--r--platform/android/src/geometry/projected_meters.cpp20
-rw-r--r--platform/android/src/geometry/projected_meters.hpp26
-rw-r--r--platform/android/src/graphics/pointf.cpp20
-rw-r--r--platform/android/src/graphics/pointf.hpp25
-rw-r--r--platform/android/src/graphics/rectf.cpp35
-rw-r--r--platform/android/src/graphics/rectf.hpp31
-rw-r--r--platform/android/src/gson/json_object.hpp16
-rw-r--r--platform/android/src/image.cpp22
-rw-r--r--platform/android/src/java/lang.hpp21
-rw-r--r--platform/android/src/java/util.cpp18
-rw-r--r--platform/android/src/java/util.hpp33
-rw-r--r--platform/android/src/java_types.hpp2
-rwxr-xr-xplatform/android/src/jni.cpp2049
-rw-r--r--platform/android/src/jni.hpp14
-rw-r--r--platform/android/src/jni/generic_global_ref_deleter.hpp22
-rwxr-xr-xplatform/android/src/native_map_view.cpp1304
-rwxr-xr-xplatform/android/src/native_map_view.hpp268
-rw-r--r--platform/android/src/offline/offline_manager.cpp164
-rw-r--r--platform/android/src/offline/offline_manager.hpp75
-rw-r--r--platform/android/src/offline/offline_region.cpp308
-rw-r--r--platform/android/src/offline/offline_region.hpp99
-rw-r--r--platform/android/src/offline/offline_region_definition.cpp69
-rw-r--r--platform/android/src/offline/offline_region_definition.hpp34
-rw-r--r--platform/android/src/offline/offline_region_error.cpp53
-rw-r--r--platform/android/src/offline/offline_region_error.hpp21
-rw-r--r--platform/android/src/offline/offline_region_status.cpp39
-rw-r--r--platform/android/src/offline/offline_region_status.hpp21
-rw-r--r--platform/android/src/style/android_conversion.hpp5
-rw-r--r--platform/android/src/style/conversion/function.hpp211
-rw-r--r--platform/android/src/style/conversion/geojson.hpp4
-rw-r--r--platform/android/src/style/conversion/property_value.hpp67
-rw-r--r--platform/android/src/style/conversion/types.hpp2
-rw-r--r--platform/android/src/style/conversion/types.hpp.ejs2
-rw-r--r--platform/android/src/style/conversion/types_string_values.hpp24
-rw-r--r--platform/android/src/style/conversion/types_string_values.hpp.ejs6
-rw-r--r--platform/android/src/style/conversion/url_or_tileset.hpp2
-rw-r--r--platform/android/src/style/functions/categorical_stops.cpp18
-rw-r--r--platform/android/src/style/functions/categorical_stops.hpp23
-rw-r--r--platform/android/src/style/functions/exponential_stops.cpp18
-rw-r--r--platform/android/src/style/functions/exponential_stops.hpp24
-rw-r--r--platform/android/src/style/functions/identity_stops.cpp18
-rw-r--r--platform/android/src/style/functions/identity_stops.hpp21
-rw-r--r--platform/android/src/style/functions/interval_stops.cpp18
-rw-r--r--platform/android/src/style/functions/interval_stops.hpp23
-rw-r--r--platform/android/src/style/functions/stop.cpp21
-rw-r--r--platform/android/src/style/functions/stop.hpp36
-rw-r--r--platform/android/src/style/layers/background_layer.cpp17
-rw-r--r--platform/android/src/style/layers/background_layer.hpp2
-rw-r--r--platform/android/src/style/layers/circle_layer.cpp17
-rw-r--r--platform/android/src/style/layers/circle_layer.hpp2
-rw-r--r--platform/android/src/style/layers/custom_layer.cpp4
-rw-r--r--platform/android/src/style/layers/fill_layer.cpp17
-rw-r--r--platform/android/src/style/layers/fill_layer.hpp2
-rw-r--r--platform/android/src/style/layers/layer.cpp35
-rw-r--r--platform/android/src/style/layers/layer.cpp.ejs20
-rw-r--r--platform/android/src/style/layers/layer.hpp27
-rw-r--r--platform/android/src/style/layers/layer.hpp.ejs2
-rw-r--r--platform/android/src/style/layers/layers.cpp64
-rw-r--r--platform/android/src/style/layers/layers.hpp12
-rw-r--r--platform/android/src/style/layers/line_layer.cpp17
-rw-r--r--platform/android/src/style/layers/line_layer.hpp2
-rw-r--r--platform/android/src/style/layers/raster_layer.cpp17
-rw-r--r--platform/android/src/style/layers/raster_layer.hpp2
-rw-r--r--platform/android/src/style/layers/symbol_layer.cpp17
-rw-r--r--platform/android/src/style/layers/symbol_layer.hpp2
-rw-r--r--platform/android/src/style/layers/unknown_layer.cpp49
-rw-r--r--platform/android/src/style/layers/unknown_layer.hpp30
-rw-r--r--platform/android/src/style/sources/geojson_source.cpp10
-rw-r--r--platform/android/src/style/sources/raster_source.cpp4
-rw-r--r--platform/android/src/style/sources/source.cpp18
-rw-r--r--platform/android/src/style/sources/source.hpp16
-rw-r--r--platform/android/src/style/sources/sources.cpp10
-rw-r--r--platform/android/src/style/sources/sources.hpp8
-rw-r--r--platform/android/src/style/sources/unknown_source.cpp42
-rw-r--r--platform/android/src/style/sources/unknown_source.hpp28
-rw-r--r--platform/android/src/style/sources/vector_source.cpp4
-rw-r--r--platform/android/src/style/value.cpp2
-rw-r--r--platform/android/src/test/Main.java6
-rw-r--r--platform/android/src/test/main.jni.cpp59
-rw-r--r--platform/android/src/timer.cpp2
108 files changed, 4408 insertions, 2509 deletions
diff --git a/platform/android/src/annotation/marker.cpp b/platform/android/src/annotation/marker.cpp
new file mode 100644
index 0000000000..a1fe436dbd
--- /dev/null
+++ b/platform/android/src/annotation/marker.cpp
@@ -0,0 +1,31 @@
+#include "marker.hpp"
+
+namespace mbgl {
+namespace android {
+
+jni::Class<Marker> Marker::javaClass;
+
+mbgl::Point<double> Marker::getPosition(jni::JNIEnv& env, jni::Object<Marker> marker) {
+ static auto positionField = Marker::javaClass.GetField<jni::Object<LatLng>>(env, "position");
+ auto jPosition = marker.Get(env, positionField);
+ auto position = LatLng::getGeometry(env, jPosition);
+ jni::DeleteLocalRef(env, jPosition);
+ return position;
+}
+
+std::string Marker::getIconId(jni::JNIEnv& env, jni::Object<Marker> marker) {
+ static auto iconIdField = Marker::javaClass.GetField<jni::String>(env, "iconId");
+ auto jIconId = marker.Get(env, iconIdField);
+ auto iconId = jni::Make<std::string>(env, jIconId);
+ jni::DeleteLocalRef(env, jIconId);
+ return iconId;
+}
+
+void Marker::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ Marker::javaClass = *jni::Class<Marker>::Find(env).NewGlobalRef(env).release();
+}
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/annotation/marker.hpp b/platform/android/src/annotation/marker.hpp
new file mode 100644
index 0000000000..b11a225245
--- /dev/null
+++ b/platform/android/src/annotation/marker.hpp
@@ -0,0 +1,30 @@
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+#include <jni/jni.hpp>
+
+#include <string>
+
+#include "../geometry/lat_lng.hpp"
+
+namespace mbgl {
+namespace android {
+
+class Marker : private mbgl::util::noncopyable {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/annotations/Marker"; };
+
+ static jni::Class<Marker> javaClass;
+
+ static mbgl::Point<double> getPosition(jni::JNIEnv&, jni::Object<Marker>);
+
+ static std::string getIconId(jni::JNIEnv&, jni::Object<Marker>);
+
+ static void registerNative(jni::JNIEnv&);
+
+};
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/annotation/multi_point.hpp b/platform/android/src/annotation/multi_point.hpp
new file mode 100644
index 0000000000..e1152dfd60
--- /dev/null
+++ b/platform/android/src/annotation/multi_point.hpp
@@ -0,0 +1,42 @@
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+#include <jni/jni.hpp>
+
+#include "../geometry/lat_lng.hpp"
+#include "../java/util.hpp"
+
+namespace mbgl {
+namespace android {
+
+class MultiPoint : protected mbgl::util::noncopyable {
+
+protected:
+
+ template <class Geometry>
+ static Geometry toGeometry(JNIEnv& env, jni::Object<java::util::List> pointsList) {
+ NullCheck(env, &pointsList);
+ auto jarray = java::util::List::toArray<LatLng>(env, pointsList);
+ NullCheck(env, &jarray);
+
+ std::size_t size = jarray.Length(env);
+
+ Geometry geometry;
+ geometry.reserve(size);
+
+ for (std::size_t i = 0; i < size; i++) {
+ auto latLng = jarray.Get(env, i);
+ NullCheck(env, &latLng);
+
+ geometry.push_back(LatLng::getGeometry(env, latLng));
+
+ jni::DeleteLocalRef(env, latLng);
+ }
+
+ jni::DeleteLocalRef(env, jarray);
+ return geometry;
+ }
+};
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/annotation/polygon.cpp b/platform/android/src/annotation/polygon.cpp
new file mode 100644
index 0000000000..ba82fc34dc
--- /dev/null
+++ b/platform/android/src/annotation/polygon.cpp
@@ -0,0 +1,49 @@
+#include "polygon.hpp"
+
+#include "../conversion/color.hpp"
+
+namespace mbgl {
+namespace android {
+
+jni::Class<Polygon> Polygon::javaClass;
+
+mbgl::FillAnnotation Polygon::toAnnotation(jni::JNIEnv& env, jni::Object<Polygon> polygon) {
+ auto points = Polygon::getPoints(env, polygon);
+
+ mbgl::FillAnnotation annotation { mbgl::Polygon<double> { MultiPoint::toGeometry<mbgl::LinearRing<double>>(env, points) } };
+ annotation.opacity = { Polygon::getOpacity(env, polygon) };
+ annotation.color = { Polygon::getFillColor(env, polygon) };
+ annotation.outlineColor = { Polygon::getOutlineColor(env, polygon) };
+
+ jni::DeleteLocalRef(env, points);
+
+ return annotation;
+}
+
+jni::Object<java::util::List> Polygon::getPoints(jni::JNIEnv& env, jni::Object<Polygon> polygon) {
+ static auto field = Polygon::javaClass.GetField<jni::Object<java::util::List>>(env, "points");
+ return polygon.Get(env, field);
+}
+
+float Polygon::getOpacity(jni::JNIEnv& env, jni::Object<Polygon> polygon) {
+ static auto field = Polygon::javaClass.GetField<float>(env, "alpha");
+ return polygon.Get(env, field);
+}
+
+mbgl::Color Polygon::getFillColor(jni::JNIEnv& env, jni::Object<Polygon> polygon) {
+ static auto field = Polygon::javaClass.GetField<int>(env, "fillColor");
+ return *conversion::convert<mbgl::Color, int>(env, polygon.Get(env, field));
+}
+
+mbgl::Color Polygon::getOutlineColor(jni::JNIEnv& env, jni::Object<Polygon> polygon) {
+ static auto field = Polygon::javaClass.GetField<int>(env, "strokeColor");
+ return *conversion::convert<mbgl::Color, int>(env, polygon.Get(env, field));
+}
+
+void Polygon::registerNative(jni::JNIEnv& env) {
+ Polygon::javaClass = *jni::Class<Polygon>::Find(env).NewGlobalRef(env).release();
+}
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/annotation/polygon.hpp b/platform/android/src/annotation/polygon.hpp
new file mode 100644
index 0000000000..658aa5344b
--- /dev/null
+++ b/platform/android/src/annotation/polygon.hpp
@@ -0,0 +1,40 @@
+#pragma once
+
+#include <mbgl/annotation/annotation.hpp>
+#include <mbgl/util/color.hpp>
+
+#include <string>
+
+#include "multi_point.hpp"
+
+#include "../geometry/lat_lng.hpp"
+#include "../java/util.hpp"
+
+namespace mbgl {
+namespace android {
+
+class Polygon : private MultiPoint {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/annotations/Polygon"; };
+
+ static jni::Class<Polygon> javaClass;
+
+ static mbgl::FillAnnotation toAnnotation(jni::JNIEnv&, jni::Object<Polygon>);
+
+ static void registerNative(jni::JNIEnv&);
+
+private:
+
+ static jni::Object<java::util::List> getPoints(jni::JNIEnv&, jni::Object<Polygon>);
+
+ static float getOpacity(jni::JNIEnv&, jni::Object<Polygon>);
+
+ static mbgl::Color getFillColor(jni::JNIEnv&, jni::Object<Polygon>);
+
+ static mbgl::Color getOutlineColor(jni::JNIEnv&, jni::Object<Polygon>);
+};
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/annotation/polyline.cpp b/platform/android/src/annotation/polyline.cpp
new file mode 100644
index 0000000000..3723dc1871
--- /dev/null
+++ b/platform/android/src/annotation/polyline.cpp
@@ -0,0 +1,49 @@
+#include "polyline.hpp"
+
+#include "../conversion/color.hpp"
+
+namespace mbgl {
+namespace android {
+
+jni::Class<Polyline> Polyline::javaClass;
+
+mbgl::LineAnnotation Polyline::toAnnotation(jni::JNIEnv& env, jni::Object<Polyline> polyline) {
+ auto points = Polyline::getPoints(env, polyline);
+
+ mbgl::LineAnnotation annotation { MultiPoint::toGeometry<mbgl::LineString<double>>(env, points) };
+ annotation.opacity = { Polyline::getOpacity(env, polyline) };
+ annotation.color = { Polyline::getColor(env, polyline) };
+ annotation.width = { Polyline::getWidth(env, polyline) };
+
+ jni::DeleteLocalRef(env, points);
+
+ return annotation;
+}
+
+jni::Object<java::util::List> Polyline::getPoints(jni::JNIEnv& env, jni::Object<Polyline> polyline) {
+ static auto field = Polyline::javaClass.GetField<jni::Object<java::util::List>>(env, "points");
+ return polyline.Get(env, field);
+}
+
+float Polyline::getOpacity(jni::JNIEnv& env, jni::Object<Polyline> polyline) {
+ static auto field = Polyline::javaClass.GetField<float>(env, "alpha");
+ return polyline.Get(env, field);
+}
+
+mbgl::Color Polyline::getColor(jni::JNIEnv& env, jni::Object<Polyline> polyline) {
+ static auto field = Polyline::javaClass.GetField<int>(env, "color");
+ return *conversion::convert<mbgl::Color, int>(env, polyline.Get(env, field));
+}
+
+float Polyline::getWidth(jni::JNIEnv& env, jni::Object<Polyline> polyline) {
+ static auto field = Polyline::javaClass.GetField<float>(env, "width");
+ return polyline.Get(env, field);
+}
+
+void Polyline::registerNative(jni::JNIEnv& env) {
+ Polyline::javaClass = *jni::Class<Polyline>::Find(env).NewGlobalRef(env).release();
+}
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/annotation/polyline.hpp b/platform/android/src/annotation/polyline.hpp
new file mode 100644
index 0000000000..bcc616a5f7
--- /dev/null
+++ b/platform/android/src/annotation/polyline.hpp
@@ -0,0 +1,40 @@
+#pragma once
+
+#include <mbgl/annotation/annotation.hpp>
+#include <mbgl/util/color.hpp>
+
+#include <string>
+
+#include "multi_point.hpp"
+
+#include "../geometry/lat_lng.hpp"
+#include "../java/util.hpp"
+
+namespace mbgl {
+namespace android {
+
+class Polyline : private MultiPoint {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/annotations/Polyline"; };
+
+ static jni::Class<Polyline> javaClass;
+
+ static mbgl::LineAnnotation toAnnotation(jni::JNIEnv&, jni::Object<Polyline>);
+
+ static void registerNative(jni::JNIEnv&);
+
+private:
+
+ static jni::Object<java::util::List> getPoints(jni::JNIEnv&, jni::Object<Polyline>);
+
+ static float getOpacity(jni::JNIEnv&, jni::Object<Polyline>);
+
+ static mbgl::Color getColor(jni::JNIEnv&, jni::Object<Polyline>);
+
+ static float getWidth(jni::JNIEnv&, jni::Object<Polyline>);
+};
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/bitmap.cpp b/platform/android/src/bitmap.cpp
new file mode 100644
index 0000000000..50088116f4
--- /dev/null
+++ b/platform/android/src/bitmap.cpp
@@ -0,0 +1,132 @@
+#include "bitmap.hpp"
+
+#include <android/bitmap.h>
+
+namespace mbgl {
+namespace android {
+
+class PixelGuard {
+public:
+ PixelGuard(jni::JNIEnv& env_, jni::Object<Bitmap> bitmap_) : env(env_), bitmap(bitmap_) {
+ const int result = AndroidBitmap_lockPixels(&env, jni::Unwrap(*bitmap),
+ reinterpret_cast<void**>(&address));
+ if (result != ANDROID_BITMAP_RESULT_SUCCESS) {
+ throw std::runtime_error("bitmap decoding: could not lock pixels");
+ }
+ }
+ ~PixelGuard() {
+ const int result = AndroidBitmap_unlockPixels(&env, jni::Unwrap(*bitmap));
+ if (result != ANDROID_BITMAP_RESULT_SUCCESS) {
+ throw std::runtime_error("bitmap decoding: could not unlock pixels");
+ }
+ }
+
+ auto* get() {
+ return address;
+ }
+
+ const auto* get() const {
+ return address;
+ }
+
+private:
+ jni::JNIEnv& env;
+ jni::Object<Bitmap> bitmap;
+ uint8_t* address;
+};
+
+void Bitmap::Config::registerNative(jni::JNIEnv& env) {
+ _class = *jni::Class<Config>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<Bitmap::Config> Bitmap::Config::_class;
+
+jni::Object<Bitmap::Config> Bitmap::Config::Create(jni::JNIEnv& env, Value value) {
+ switch (value) {
+ case ALPHA_8:
+ return _class.Get(env,
+ jni::StaticField<Config, jni::Object<Config>>(env, _class, "ALPHA_8"));
+ case ARGB_4444:
+ return _class.Get(env,
+ jni::StaticField<Config, jni::Object<Config>>(env, _class, "ARGB_4444"));
+ case ARGB_8888:
+ return _class.Get(env,
+ jni::StaticField<Config, jni::Object<Config>>(env, _class, "ARGB_8888"));
+ case RGB_565:
+ return _class.Get(env,
+ jni::StaticField<Config, jni::Object<Config>>(env, _class, "RGB_565"));
+ default:
+ throw std::runtime_error("invalid enum value for Bitmap.Config");
+ }
+}
+
+void Bitmap::registerNative(jni::JNIEnv& env) {
+ _class = *jni::Class<Bitmap>::Find(env).NewGlobalRef(env).release();
+ Config::registerNative(env);
+}
+
+jni::Class<Bitmap> Bitmap::_class;
+
+jni::Object<Bitmap> Bitmap::CreateBitmap(jni::JNIEnv& env,
+ jni::jint width,
+ jni::jint height,
+ jni::Object<Config> config) {
+ using Signature = jni::Object<Bitmap>(jni::jint, jni::jint, jni::Object<Config>);
+ auto method = _class.GetStaticMethod<Signature>(env, "createBitmap");
+ return _class.Call(env, method, width, height, config);
+}
+
+jni::Object<Bitmap> Bitmap::CreateBitmap(jni::JNIEnv& env, const PremultipliedImage& image) {
+ auto bitmap = CreateBitmap(env, image.size.width, image.size.height, Config::ARGB_8888);
+
+ AndroidBitmapInfo info;
+ const int result = AndroidBitmap_getInfo(&env, jni::Unwrap(*bitmap), &info);
+ if (result != ANDROID_BITMAP_RESULT_SUCCESS) {
+ // TODO: more specific information
+ throw std::runtime_error("bitmap creation: couldn't get bitmap info");
+ }
+
+ assert(info.width == image.size.width);
+ assert(info.height == image.size.height);
+ assert(info.format == ANDROID_BITMAP_FORMAT_RGBA_8888);
+
+ PixelGuard guard(env, bitmap);
+
+ // Copy the PremultipliedImage into the Android Bitmap
+ for (uint32_t y = 0; y < image.size.height; y++) {
+ auto begin = image.data.get() + y * image.stride();
+ std::copy(begin, begin + image.stride(), guard.get() + y * info.stride);
+ }
+
+ return bitmap;
+}
+
+PremultipliedImage Bitmap::GetImage(jni::JNIEnv& env, jni::Object<Bitmap> bitmap) {
+ AndroidBitmapInfo info;
+ const int result = AndroidBitmap_getInfo(&env, jni::Unwrap(*bitmap), &info);
+ if (result != ANDROID_BITMAP_RESULT_SUCCESS) {
+ // TODO: more specific information
+ throw std::runtime_error("bitmap decoding: couldn't get bitmap info");
+ }
+
+ if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
+ // TODO: convert
+ throw std::runtime_error("bitmap decoding: bitmap format invalid");
+ }
+
+ const PixelGuard guard(env, bitmap);
+
+ // Copy the Android Bitmap into the PremultipliedImage.
+ auto pixels =
+ std::make_unique<uint8_t[]>(info.width * info.height * PremultipliedImage::channels);
+ for (uint32_t y = 0; y < info.height; y++) {
+ auto begin = guard.get() + y * info.stride;
+ std::copy(begin, begin + info.width * PremultipliedImage::channels,
+ pixels.get() + y * info.width * PremultipliedImage::channels);
+ }
+
+ return { Size{ info.width, info.height }, std::move(pixels) };
+}
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/bitmap.hpp b/platform/android/src/bitmap.hpp
new file mode 100644
index 0000000000..f64f42ae87
--- /dev/null
+++ b/platform/android/src/bitmap.hpp
@@ -0,0 +1,52 @@
+#pragma once
+
+#include <mbgl/util/image.hpp>
+
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class Bitmap {
+public:
+ class Config {
+ public:
+ static constexpr auto Name() {
+ return "android/graphics/Bitmap$Config";
+ };
+ static void registerNative(jni::JNIEnv&);
+
+ enum Value {
+ ALPHA_8,
+ ARGB_4444,
+ ARGB_8888,
+ RGB_565,
+ };
+
+ static jni::Object<Config> Create(jni::JNIEnv&, Value);
+
+ private:
+ static jni::Class<Config> _class;
+ };
+
+ static constexpr auto Name() {
+ return "android/graphics/Bitmap";
+ };
+ static void registerNative(jni::JNIEnv&);
+
+ static jni::Object<Bitmap>
+ CreateBitmap(jni::JNIEnv&, jni::jint width, jni::jint height, jni::Object<Config>);
+ static jni::Object<Bitmap>
+ CreateBitmap(jni::JNIEnv& env, jni::jint width, jni::jint height, Config::Value config) {
+ return CreateBitmap(env, width, height, Config::Create(env, config));
+ }
+
+ static PremultipliedImage GetImage(jni::JNIEnv&, jni::Object<Bitmap>);
+ static jni::Object<Bitmap> CreateBitmap(jni::JNIEnv&, const PremultipliedImage&);
+
+private:
+ static jni::Class<Bitmap> _class;
+};
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/bitmap_factory.cpp b/platform/android/src/bitmap_factory.cpp
new file mode 100644
index 0000000000..7d9b068b20
--- /dev/null
+++ b/platform/android/src/bitmap_factory.cpp
@@ -0,0 +1,25 @@
+#include "bitmap_factory.hpp"
+
+namespace mbgl {
+namespace android {
+
+void BitmapFactory::registerNative(jni::JNIEnv& env) {
+ _class = *jni::Class<BitmapFactory>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<BitmapFactory> BitmapFactory::_class;
+
+jni::Object<Bitmap> BitmapFactory::DecodeByteArray(jni::JNIEnv& env,
+ jni::Array<jni::jbyte> data,
+ jni::jint offset,
+ jni::jint length) {
+
+ // Images are loaded with ARGB_8888 config, and premultiplied by default, which is exactly
+ // what we want, so we're not providing a BitmapFactory.Options object.
+ using Signature = jni::Object<Bitmap>(jni::Array<jni::jbyte>, jni::jint, jni::jint);
+ auto method = _class.GetStaticMethod<Signature>(env, "decodeByteArray");
+ return _class.Call(env, method, data, offset, length);
+}
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/bitmap_factory.hpp b/platform/android/src/bitmap_factory.hpp
new file mode 100644
index 0000000000..b0e7198260
--- /dev/null
+++ b/platform/android/src/bitmap_factory.hpp
@@ -0,0 +1,25 @@
+#pragma once
+
+#include <jni/jni.hpp>
+
+#include "bitmap.hpp"
+
+namespace mbgl {
+namespace android {
+
+class BitmapFactory {
+public:
+ static constexpr auto Name() {
+ return "android/graphics/BitmapFactory";
+ };
+ static void registerNative(jni::JNIEnv&);
+
+ static jni::Object<Bitmap>
+ DecodeByteArray(jni::JNIEnv&, jni::Array<jni::jbyte> data, jni::jint offset, jni::jint length);
+
+private:
+ static jni::Class<BitmapFactory> _class;
+};
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/connectivity_listener.cpp b/platform/android/src/connectivity_listener.cpp
index cc2f0a4a81..5b1c0a86e4 100644
--- a/platform/android/src/connectivity_listener.cpp
+++ b/platform/android/src/connectivity_listener.cpp
@@ -22,12 +22,12 @@ namespace android {
jni::Class<ConnectivityListener> ConnectivityListener::javaClass;
void ConnectivityListener::registerNative(jni::JNIEnv& env) {
- //Lookup the class
+ // Lookup the class
ConnectivityListener::javaClass = *jni::Class<ConnectivityListener>::Find(env).NewGlobalRef(env).release();
#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
- //Register the peer
+ // Register the peer
jni::RegisterNativePeer<ConnectivityListener>(
env,
ConnectivityListener::javaClass,
@@ -39,5 +39,5 @@ namespace android {
);
}
-} //android
-} //mbgl \ No newline at end of file
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/connectivity_listener.hpp b/platform/android/src/connectivity_listener.hpp
index d457dcfd5a..b0d655d027 100644
--- a/platform/android/src/connectivity_listener.hpp
+++ b/platform/android/src/connectivity_listener.hpp
@@ -27,9 +27,5 @@ public:
};
-} //android
-} //mbgl
-
-
-
-
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/conversion/collection.hpp b/platform/android/src/conversion/collection.hpp
index 4256d5f969..da5eed64d2 100644
--- a/platform/android/src/conversion/collection.hpp
+++ b/platform/android/src/conversion/collection.hpp
@@ -32,6 +32,20 @@ inline std::vector<std::string> toVector(JNIEnv& env, jni::jarray<jni::jobject>&
for (std::size_t i = 0; i < len; i++) {
jni::jstring* jstr = reinterpret_cast<jni::jstring*>(jni::GetObjectArrayElement(env, array, i));
vector.push_back(*convert<std::string, jni::String>(env, jni::String(jstr)));
+ jni::DeleteLocalRef(env, jstr);
+ }
+
+ return vector;
+}
+
+inline std::vector<std::string> toVector(JNIEnv& env, jni::Array<jni::String> array) {
+ std::vector<std::string> vector;
+ std::size_t len = array.Length(env);
+
+ for (std::size_t i = 0; i < len; i++) {
+ jni::String jstr = array.Get(env, i);
+ vector.push_back(*convert<std::string, jni::String>(env, jstr));
+ jni::DeleteLocalRef(env, jstr);
}
return vector;
diff --git a/platform/android/src/conversion/color.hpp b/platform/android/src/conversion/color.hpp
new file mode 100644
index 0000000000..40aa68d4a9
--- /dev/null
+++ b/platform/android/src/conversion/color.hpp
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "conversion.hpp"
+
+#include <mbgl/util/color.hpp>
+
+namespace mbgl {
+namespace android {
+namespace conversion {
+
+template <>
+struct Converter<mbgl::Color, int> {
+ Result<mbgl::Color> operator()(jni::JNIEnv&, const int& color) const {
+ float r = (color >> 16) & 0xFF;
+ float g = (color >> 8) & 0xFF;
+ float b = (color) & 0xFF;
+ float a = (color >> 24) & 0xFF;
+ return { mbgl::Color( r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f ) };
+ }
+};
+
+} // namespace conversion
+} // namespace style
+} // namespace mbgl
diff --git a/platform/android/src/conversion/constant.hpp b/platform/android/src/conversion/constant.hpp
index f1a8171b99..2a0b710f73 100644
--- a/platform/android/src/conversion/constant.hpp
+++ b/platform/android/src/conversion/constant.hpp
@@ -76,7 +76,7 @@ struct Converter<jni::jobject*, T, typename std::enable_if<std::is_integral<T>::
}
};
-//TODO: convert integral types to primitive jni types
+// TODO: convert integral types to primitive jni types
template <>
struct Converter<jni::jobject*, std::string> {
diff --git a/platform/android/src/conversion/conversion.hpp b/platform/android/src/conversion/conversion.hpp
index 1277f3f67e..d1766f9755 100644
--- a/platform/android/src/conversion/conversion.hpp
+++ b/platform/android/src/conversion/conversion.hpp
@@ -47,4 +47,4 @@ Result<T> convert(jni::JNIEnv& env, const V& value, Args&&...args) {
} // namespace conversion
} // namespace android
-} // namespace mbgl \ No newline at end of file
+} // namespace mbgl
diff --git a/platform/android/src/file_source.cpp b/platform/android/src/file_source.cpp
new file mode 100644
index 0000000000..30e1ff50fe
--- /dev/null
+++ b/platform/android/src/file_source.cpp
@@ -0,0 +1,106 @@
+#include "file_source.hpp"
+
+#include <mbgl/util/logging.hpp>
+
+#include <string>
+
+#include "jni/generic_global_ref_deleter.hpp"
+
+
+namespace mbgl {
+namespace android {
+
+// FileSource //
+
+FileSource::FileSource(jni::JNIEnv& _env, jni::String accessToken, jni::String _cachePath, jni::String _apkPath) {
+ // Create a core default file source
+ fileSource = std::make_unique<mbgl::DefaultFileSource>(
+ jni::Make<std::string>(_env, _cachePath) + "/mbgl-offline.db",
+ jni::Make<std::string>(_env, _apkPath));
+
+ // Set access token
+ fileSource->setAccessToken(jni::Make<std::string>(_env, accessToken));
+}
+
+FileSource::~FileSource() {
+}
+
+jni::String FileSource::getAccessToken(jni::JNIEnv& env) {
+ return jni::Make<jni::String>(env, fileSource->getAccessToken());
+}
+
+void FileSource::setAccessToken(jni::JNIEnv& env, jni::String token) {
+ fileSource->setAccessToken(jni::Make<std::string>(env, token));
+}
+
+void FileSource::setAPIBaseUrl(jni::JNIEnv& env, jni::String url) {
+ fileSource->setAPIBaseURL(jni::Make<std::string>(env, url));
+}
+
+void FileSource::setResourceTransform(jni::JNIEnv& env, jni::Object<FileSource::ResourceTransformCallback> transformCallback) {
+ if (transformCallback) {
+ // Launch transformCallback
+ fileSource->setResourceTransform([
+ // Capture the ResourceTransformCallback object as a managed global into
+ // the lambda. It is released automatically when we're setting a new ResourceTransform in
+ // a subsequent call.
+ // Note: we're converting it to shared_ptr because this lambda is converted to a std::function,
+ // which requires copyability of its captured variables.
+ callback = std::shared_ptr<jni::jobject>(transformCallback.NewGlobalRef(env).release()->Get(), GenericGlobalRefDeleter()),
+ env
+ ](mbgl::Resource::Kind kind, std::string&& url_) {
+ return FileSource::ResourceTransformCallback::onURL(const_cast<jni::JNIEnv&>(env), jni::Object<FileSource::ResourceTransformCallback>(*callback), int(kind), url_);
+ });
+ } else {
+ // Reset the callback
+ fileSource->setResourceTransform(nullptr);
+ }
+}
+
+jni::Class<FileSource> FileSource::javaClass;
+
+FileSource* FileSource::getNativePeer(jni::JNIEnv& env, jni::Object<FileSource> jFileSource) {
+ static auto field = FileSource::javaClass.GetField<jlong>(env, "nativePtr");
+ return reinterpret_cast<FileSource *>(jFileSource.Get(env, field));
+}
+
+mbgl::DefaultFileSource& FileSource::getDefaultFileSource(jni::JNIEnv& env, jni::Object<FileSource> jFileSource) {
+ FileSource* fileSource = FileSource::getNativePeer(env, jFileSource);
+ assert(fileSource != nullptr);
+ return *fileSource->fileSource;
+}
+
+void FileSource::registerNative(jni::JNIEnv& env) {
+ //Register classes
+ FileSource::javaClass = *jni::Class<FileSource>::Find(env).NewGlobalRef(env).release();
+ FileSource::ResourceTransformCallback::javaClass = *jni::Class<FileSource::ResourceTransformCallback>::Find(env).NewGlobalRef(env).release();
+
+ #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
+
+ // Register the peer
+ jni::RegisterNativePeer<FileSource>(
+ env, FileSource::javaClass, "nativePtr",
+ std::make_unique<FileSource, JNIEnv&, jni::String, jni::String, jni::String>,
+ "initialize",
+ "finalize",
+ METHOD(&FileSource::getAccessToken, "getAccessToken"),
+ METHOD(&FileSource::setAccessToken, "setAccessToken"),
+ METHOD(&FileSource::setAPIBaseUrl, "setApiBaseUrl"),
+ METHOD(&FileSource::setResourceTransform, "setResourceTransform")
+ );
+}
+
+
+// FileSource::ResourceTransformCallback //
+
+jni::Class<FileSource::ResourceTransformCallback> FileSource::ResourceTransformCallback::javaClass;
+
+std::string FileSource::ResourceTransformCallback::onURL(jni::JNIEnv& env, jni::Object<FileSource::ResourceTransformCallback> callback, int kind, std::string url_) {
+ static auto method = FileSource::ResourceTransformCallback::javaClass.GetMethod<jni::String (jni::jint, jni::String)>(env, "onURL");
+ auto url = jni::Make<jni::String>(env, url_);
+ url = callback.Call(env, method, kind, url);
+ return jni::Make<std::string>(env, url);
+}
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/file_source.hpp b/platform/android/src/file_source.hpp
new file mode 100644
index 0000000000..073e393e05
--- /dev/null
+++ b/platform/android/src/file_source.hpp
@@ -0,0 +1,53 @@
+#pragma once
+
+#include <mbgl/storage/default_file_source.hpp>
+
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+/**
+ * Peer class for the Android FileSource holder. Ensures that a single DefaultFileSource is used
+ */
+class FileSource {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/storage/FileSource"; };
+
+ struct ResourceTransformCallback {
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/storage/FileSource$ResourceTransformCallback"; }
+
+ static std::string onURL(jni::JNIEnv&, jni::Object<FileSource::ResourceTransformCallback>, int, std::string);
+
+ static jni::Class<ResourceTransformCallback> javaClass;
+ };
+
+ FileSource(jni::JNIEnv&, jni::String, jni::String, jni::String);
+
+ ~FileSource();
+
+ jni::String getAccessToken(jni::JNIEnv&);
+
+ void setAccessToken(jni::JNIEnv&, jni::String);
+
+ void setAPIBaseUrl(jni::JNIEnv&, jni::String);
+
+ void setResourceTransform(jni::JNIEnv&, jni::Object<FileSource::ResourceTransformCallback>);
+
+ static jni::Class<FileSource> javaClass;
+
+ static FileSource* getNativePeer(jni::JNIEnv&, jni::Object<FileSource>);
+
+ static mbgl::DefaultFileSource& getDefaultFileSource(jni::JNIEnv&, jni::Object<FileSource>);
+
+ static void registerNative(jni::JNIEnv&);
+
+private:
+
+ std::unique_ptr<mbgl::DefaultFileSource> fileSource;
+};
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geometry/conversion/feature.hpp b/platform/android/src/geometry/conversion/feature.hpp
index f0c77c3389..921138e859 100644
--- a/platform/android/src/geometry/conversion/feature.hpp
+++ b/platform/android/src/geometry/conversion/feature.hpp
@@ -3,6 +3,7 @@
#include "../../conversion/constant.hpp"
#include "../../conversion/conversion.hpp"
#include "geometry.hpp"
+#include "../../gson/json_object.hpp"
#include <mbgl/util/feature.hpp>
#include <mapbox/variant.hpp>
@@ -10,6 +11,7 @@
#include <jni/jni.hpp>
#include "../../jni/local_object.hpp"
+#include "../feature.hpp"
#include <string>
#include <array>
@@ -64,7 +66,7 @@ public:
static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonPrimitive")).release();
static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "(Ljava/lang/Boolean;)V");
- //Create JsonPrimitive
+ // Create JsonPrimitive
jni::LocalObject<jni::jobject> converted = jni::NewLocalObject(env, *convert<jni::jobject*, bool>(env, value));
jni::jobject* object = &jni::NewObject(env, *javaClass, *constructor, *converted);
@@ -78,7 +80,7 @@ public:
static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonPrimitive")).release();
static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "(Ljava/lang/String;)V");
- //Create JsonPrimitive
+ // Create JsonPrimitive
jni::LocalObject<jni::jobject> converted = jni::NewLocalObject(env, *convert<jni::jobject*, std::string>(env, value));
jni::jobject* object = &jni::NewObject(env, *javaClass, *constructor, converted.get());
@@ -93,7 +95,7 @@ public:
static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonPrimitive")).release();
static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "(Ljava/lang/Number;)V");
- //Create JsonPrimitive
+ // Create JsonPrimitive
jni::LocalObject<jni::jobject> converted = jni::NewLocalObject(env, *convert<jni::jobject*, Number>(env, value));
jni::jobject* object = &jni::NewObject(env, *javaClass, *constructor, converted.get());
@@ -109,10 +111,10 @@ public:
static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "()V");;
static jni::jmethodID* add = &jni::GetMethodID(env, *javaClass, "add", "(Lcom/google/gson/JsonElement;)V");
- //Create json array
+ // Create json array
jni::jobject* jarray = &jni::NewObject(env, *javaClass, *constructor);
- //Add values
+ // Add values
for (const auto &v : values) {
jni::LocalObject<jni::jobject> converted = jni::NewLocalObject(env, mbgl::Value::visit(v, *this));
jni::CallMethod<void>(env, jarray, *add, converted.get());
@@ -125,15 +127,15 @@ public:
* Json Object
*/
jni::jobject* operator()(const std::unordered_map<std::string, mbgl::Value> &value) const {
- //TODO: clean up duplication here
+ // TODO: clean up duplication here
static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonObject")).release();
static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "()V");;
static jni::jmethodID* add = &jni::GetMethodID(env, *javaClass, "add", "(Ljava/lang/String;Lcom/google/gson/JsonElement;)V");
- //Create json object
+ // Create json object
jni::jobject* jsonObject = &jni::NewObject(env, *javaClass, *constructor);
- //Add items
+ // Add items
for (auto &item : value) {
jni::LocalObject<jni::jobject> converted = jni::NewLocalObject(env, mbgl::Value::visit(item.second, *this));
jni::LocalObject<jni::jobject> key = jni::NewLocalObject(env, *convert<jni::jobject*, std::string>(env, item.first));
@@ -151,10 +153,10 @@ struct Converter<jni::jobject*, std::unordered_map<std::string, mbgl::Value>> {
static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "()V");;
static jni::jmethodID* add = &jni::GetMethodID(env, *javaClass, "add", "(Ljava/lang/String;Lcom/google/gson/JsonElement;)V");
- //Create json object
+ // Create json object
jni::jobject* jsonObject = &jni::NewObject(env, *javaClass, *constructor);
- //Add items
+ // Add items
PropertyValueEvaluator evaluator {env};
for (auto &item : value) {
jni::LocalObject<jni::jobject> converted = jni::NewLocalObject(env, mbgl::Value::visit(item.second, evaluator));
@@ -168,39 +170,45 @@ struct Converter<jni::jobject*, std::unordered_map<std::string, mbgl::Value>> {
template <>
-struct Converter<jni::jobject*, mbgl::Feature> {
- Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::Feature& value) const {
- static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/services/commons/geojson/Feature")).release();
- static jni::jmethodID* fromGeometry = &jni::GetStaticMethodID(env, *javaClass, "fromGeometry", "(Lcom/mapbox/services/commons/geojson/Geometry;Lcom/google/gson/JsonObject;Ljava/lang/String;)Lcom/mapbox/services/commons/geojson/Feature;");
+struct Converter<jni::Object<Feature>, mbgl::Feature> {
+ Result<jni::Object<Feature>> operator()(jni::JNIEnv& env, const mbgl::Feature& value) const {
- //Convert Id
+ // Convert Id
FeatureIdVisitor idEvaluator;
std::string id = (value.id) ? mapbox::geometry::identifier::visit(value.id.value(), idEvaluator) : "";
- jni::LocalObject<jni::jobject> jid = jni::NewLocalObject(env, *convert<jni::jobject*>(env, id));
+ auto jid = jni::Make<jni::String>(env, id);
- //Convert properties
- jni::LocalObject<jni::jobject> properties = jni::NewLocalObject(env, *convert<jni::jobject*>(env, value.properties));
+ // Convert properties
+ auto properties = jni::Object<JsonObject>(*convert<jni::jobject*>(env, value.properties));
- //Convert geometry
- jni::LocalObject<jni::jobject> geometry = jni::NewLocalObject(env, *convert<jni::jobject*>(env, value.geometry));
+ // Convert geometry
+ auto geometry = jni::Object<Geometry>(*convert<jni::jobject*>(env, value.geometry));
- //Create feature
- return {reinterpret_cast<jni::jobject*>(jni::CallStaticMethod<jni::jobject*>(env, *javaClass, *fromGeometry, geometry.get(), properties.get(), jid.get()))};
+ // Create feature
+ auto feature = Feature::fromGeometry(env, geometry, properties, jid);
+
+ //Cleanup
+ jni::DeleteLocalRef(env, jid);
+ jni::DeleteLocalRef(env, geometry);
+ jni::DeleteLocalRef(env, properties);
+
+ return feature;
}
};
template <>
-struct Converter<jni::jarray<jni::jobject>*, std::vector<mbgl::Feature>> {
- Result<jni::jarray<jni::jobject>*> operator()(jni::JNIEnv& env, const std::vector<mbgl::Feature>& value) const {
- static jni::jclass* featureClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/services/commons/geojson/Feature")).release();
- jni::jarray<jni::jobject>& jarray = jni::NewObjectArray(env, value.size(), *featureClass);
+struct Converter<jni::Array<jni::Object<Feature>>, std::vector<mbgl::Feature>> {
+ Result<jni::Array<jni::Object<Feature>>> operator()(jni::JNIEnv& env, const std::vector<mbgl::Feature>& value) const {
+
+ auto features = jni::Array<jni::Object<Feature>>::New(env, value.size(), Feature::javaClass);
for(size_t i = 0; i < value.size(); i = i + 1) {
- jni::LocalObject<jni::jobject> converted = jni::NewLocalObject(env, *convert<jni::jobject*, mbgl::Feature>(env, value.at(i)));
- jni::SetObjectArrayElement(env, jarray, i, converted.get());
+ auto converted = *convert<jni::Object<Feature>, mbgl::Feature>(env, value.at(i));
+ features.Set(env, i, converted);
+ jni::DeleteLocalRef(env, converted);
}
- return {&jarray};
+ return {features};
}
};
diff --git a/platform/android/src/geometry/conversion/geometry.hpp b/platform/android/src/geometry/conversion/geometry.hpp
index 385ba9034e..2ca63e2c11 100644
--- a/platform/android/src/geometry/conversion/geometry.hpp
+++ b/platform/android/src/geometry/conversion/geometry.hpp
@@ -27,7 +27,7 @@ public:
static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/services/commons/geojson/Point")).release();
static jni::jmethodID* fromCoordinates = &jni::GetStaticMethodID(env, *javaClass, "fromCoordinates", "([D)Lcom/mapbox/services/commons/geojson/Point;");
- //Create Point
+ // Create Point
jni::LocalObject<jni::jarray<jni::jdouble>> position = jni::NewLocalObject(env, toGeoJsonPosition(env, geometry.x, geometry.y));
return reinterpret_cast<jni::jobject*>(jni::CallStaticMethod<jni::jobject*>(env, *javaClass, *fromCoordinates, position.get()));
}
@@ -39,7 +39,7 @@ public:
static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/services/commons/geojson/LineString")).release();
static jni::jmethodID* fromCoordinates = &jni::GetStaticMethodID(env, *javaClass, "fromCoordinates", "([[D)Lcom/mapbox/services/commons/geojson/LineString;");
- //Create
+ // Create
jni::LocalObject<jni::jarray<jni::jobject>> coordinates = jni::NewLocalObject(env, toGeoJsonCoordinates(env, geometry));
return reinterpret_cast<jni::jobject*>(jni::CallStaticMethod<jni::jobject*>(env, *javaClass, *fromCoordinates, coordinates.get()));
}
@@ -51,7 +51,7 @@ public:
static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/services/commons/geojson/MultiPoint")).release();
static jni::jmethodID* fromCoordinates = &jni::GetStaticMethodID(env, *javaClass, "fromCoordinates", "([[D)Lcom/mapbox/services/commons/geojson/MultiPoint;");
- //Create
+ // Create
jni::LocalObject<jni::jarray<jni::jobject>> coordinates = jni::NewLocalObject(env, toGeoJsonCoordinates(env, geometry));
return reinterpret_cast<jni::jobject*>(jni::CallStaticMethod<jni::jobject*>(env, *javaClass, *fromCoordinates, coordinates.get()));
}
@@ -63,7 +63,7 @@ public:
static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/services/commons/geojson/Polygon")).release();
static jni::jmethodID* fromCoordinates = &jni::GetStaticMethodID(env, *javaClass, "fromCoordinates", "([[[D)Lcom/mapbox/services/commons/geojson/Polygon;");
- //Create
+ // Create
jni::LocalObject<jni::jarray<jni::jobject>> shape = jni::NewLocalObject(env, toShape<>(env, geometry));
return reinterpret_cast<jni::jobject*>(jni::CallStaticMethod<jni::jobject*>(env, *javaClass, *fromCoordinates, shape.get()));
}
@@ -75,7 +75,7 @@ public:
static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/services/commons/geojson/MultiLineString")).release();
static jni::jmethodID* fromCoordinates = &jni::GetStaticMethodID(env, *javaClass, "fromCoordinates", "([[[D)Lcom/mapbox/services/commons/geojson/MultiLineString;");
- //Create
+ // Create
jni::LocalObject<jni::jarray<jni::jobject>> shape = jni::NewLocalObject(env, toShape<>(env, geometry));
return reinterpret_cast<jni::jobject*>(jni::CallStaticMethod<jni::jobject*>(env, *javaClass, *fromCoordinates, shape.get()));
}
@@ -92,7 +92,7 @@ public:
jni::SetObjectArrayElement(env, *jarray, i, shape.get());
}
- //Create the MultiPolygon
+ // Create the MultiPolygon
static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/services/commons/geojson/MultiPolygon")).release();
static jni::jmethodID* fromGeometries = &jni::GetStaticMethodID(env, *javaClass, "fromCoordinates", "([[[[D)Lcom/mapbox/services/commons/geojson/MultiPolygon;");
return reinterpret_cast<jni::jobject*>(jni::CallStaticMethod<jni::jobject*>(env, *javaClass, *fromGeometries, jarray.get()));
@@ -111,7 +111,7 @@ public:
jni::SetObjectArrayElement(env, *jarray, i, converted.get());
}
- //Turn into array list and create the GeometryCollection
+ // Turn into array list and create the GeometryCollection
static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/services/commons/geojson/GeometryCollection")).release();
static jni::jmethodID* fromGeometries = &jni::GetStaticMethodID(env, *javaClass, "fromGeometries", "(Ljava/util/List;)Lcom/mapbox/services/commons/geojson/GeometryCollection;");
diff --git a/platform/android/src/geometry/feature.cpp b/platform/android/src/geometry/feature.cpp
new file mode 100644
index 0000000000..5355d50ab7
--- /dev/null
+++ b/platform/android/src/geometry/feature.cpp
@@ -0,0 +1,20 @@
+#include "feature.hpp"
+
+namespace mbgl {
+namespace android {
+
+jni::Object<Feature> Feature::fromGeometry(jni::JNIEnv& env, jni::Object<Geometry> geometry, jni::Object<JsonObject> properties, jni::String id) {
+ static auto method = Feature::javaClass.GetStaticMethod<jni::Object<Feature> (jni::Object<Geometry>, jni::Object<JsonObject>, 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<Feature>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<Feature> Feature::javaClass;
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geometry/feature.hpp b/platform/android/src/geometry/feature.hpp
new file mode 100644
index 0000000000..7f2733430c
--- /dev/null
+++ b/platform/android/src/geometry/feature.hpp
@@ -0,0 +1,29 @@
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/geometry.hpp>
+
+#include <jni/jni.hpp>
+
+#include "geometry.hpp"
+#include "../gson/json_object.hpp"
+
+namespace mbgl {
+namespace android {
+
+class Feature : private mbgl::util::noncopyable {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/services/commons/geojson/Feature"; };
+
+ static jni::Object<Feature> fromGeometry(jni::JNIEnv&, jni::Object<Geometry>, jni::Object<JsonObject>, jni::String);
+
+ static jni::Class<Feature> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+};
+
+
+} // 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
new file mode 100644
index 0000000000..5c8ae39181
--- /dev/null
+++ b/platform/android/src/geometry/geometry.hpp
@@ -0,0 +1,16 @@
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+
+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/geometry/lat_lng.cpp b/platform/android/src/geometry/lat_lng.cpp
new file mode 100644
index 0000000000..9cf3630107
--- /dev/null
+++ b/platform/android/src/geometry/lat_lng.cpp
@@ -0,0 +1,31 @@
+#include "lat_lng.hpp"
+
+namespace mbgl {
+namespace android {
+
+jni::Object<LatLng> LatLng::New(jni::JNIEnv& env, double latitude, double longitude) {
+ static auto constructor = LatLng::javaClass.GetConstructor<double, double>(env);
+ return LatLng::javaClass.New(env, constructor, latitude, longitude);
+}
+
+mbgl::Point<double> LatLng::getGeometry(jni::JNIEnv& env, jni::Object<LatLng> latLng) {
+ static auto latitudeField = LatLng::javaClass.GetField<jni::jdouble>(env, "latitude");
+ static auto longitudeField = LatLng::javaClass.GetField<jni::jdouble>(env, "longitude");
+ return mbgl::Point<double>(latLng.Get(env, longitudeField), latLng.Get(env, latitudeField));
+}
+
+mbgl::LatLng LatLng::getLatLng(jni::JNIEnv& env, jni::Object<LatLng> latLng) {
+ auto point = LatLng::getGeometry(env, latLng);
+ return mbgl::LatLng(point.y, point.x);
+}
+
+void LatLng::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ LatLng::javaClass = *jni::Class<LatLng>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<LatLng> LatLng::javaClass;
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geometry/lat_lng.hpp b/platform/android/src/geometry/lat_lng.hpp
new file mode 100644
index 0000000000..1ac32ae32e
--- /dev/null
+++ b/platform/android/src/geometry/lat_lng.hpp
@@ -0,0 +1,31 @@
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/geo.hpp>
+#include <mbgl/util/geometry.hpp>
+
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class LatLng : private mbgl::util::noncopyable {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/geometry/LatLng"; };
+
+ static jni::Object<LatLng> New(jni::JNIEnv&, double, double);
+
+ static mbgl::Point<double> getGeometry(jni::JNIEnv&, jni::Object<LatLng>);
+
+ static mbgl::LatLng getLatLng(jni::JNIEnv&, jni::Object<LatLng>);
+
+ static jni::Class<LatLng> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+};
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geometry/lat_lng_bounds.cpp b/platform/android/src/geometry/lat_lng_bounds.cpp
new file mode 100644
index 0000000000..9efacde120
--- /dev/null
+++ b/platform/android/src/geometry/lat_lng_bounds.cpp
@@ -0,0 +1,31 @@
+#include "lat_lng_bounds.hpp"
+
+namespace mbgl {
+namespace android {
+
+jni::Object<LatLngBounds> LatLngBounds::New(jni::JNIEnv& env, mbgl::LatLngBounds bounds) {
+ static auto constructor = LatLngBounds::javaClass.GetConstructor<double, double, double, double>(env);
+ return LatLngBounds::javaClass.New(env, constructor, bounds.north(), bounds.east(), bounds.south(), bounds.west());
+}
+
+mbgl::LatLngBounds LatLngBounds::getLatLngBounds(jni::JNIEnv& env, jni::Object<LatLngBounds> bounds) {
+ static auto swLat = LatLngBounds::javaClass.GetField<jni::jdouble>(env, "mLatSouth");
+ static auto swLon = LatLngBounds::javaClass.GetField<jni::jdouble>(env, "mLonWest");
+ static auto neLat = LatLngBounds::javaClass.GetField<jni::jdouble>(env, "mLatNorth");
+ static auto neLon = LatLngBounds::javaClass.GetField<jni::jdouble>(env, "mLonEast");
+ return mbgl::LatLngBounds::hull(
+ { bounds.Get(env, swLat), bounds.Get(env, swLon) },
+ { bounds.Get(env, neLat), bounds.Get(env, neLon) }
+ );
+}
+
+void LatLngBounds::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ LatLngBounds::javaClass = *jni::Class<LatLngBounds>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<LatLngBounds> LatLngBounds::javaClass;
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geometry/lat_lng_bounds.hpp b/platform/android/src/geometry/lat_lng_bounds.hpp
new file mode 100644
index 0000000000..1c853e4b67
--- /dev/null
+++ b/platform/android/src/geometry/lat_lng_bounds.hpp
@@ -0,0 +1,29 @@
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/geo.hpp>
+#include <mbgl/util/geometry.hpp>
+
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class LatLngBounds : private mbgl::util::noncopyable {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/geometry/LatLngBounds"; };
+
+ static jni::Object<LatLngBounds> New(jni::JNIEnv&, mbgl::LatLngBounds);
+
+ static mbgl::LatLngBounds getLatLngBounds(jni::JNIEnv&, jni::Object<LatLngBounds>);
+
+ static jni::Class<LatLngBounds> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+};
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geometry/projected_meters.cpp b/platform/android/src/geometry/projected_meters.cpp
new file mode 100644
index 0000000000..f3d9d1b0ef
--- /dev/null
+++ b/platform/android/src/geometry/projected_meters.cpp
@@ -0,0 +1,20 @@
+#include "projected_meters.hpp"
+
+namespace mbgl {
+namespace android {
+
+jni::Object<ProjectedMeters> ProjectedMeters::New(jni::JNIEnv& env, double northing, double easting) {
+ static auto constructor = ProjectedMeters::javaClass.GetConstructor<double, double>(env);
+ return ProjectedMeters::javaClass.New(env, constructor, northing, easting);
+}
+
+void ProjectedMeters::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ ProjectedMeters::javaClass = *jni::Class<ProjectedMeters>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<ProjectedMeters> ProjectedMeters::javaClass;
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geometry/projected_meters.hpp b/platform/android/src/geometry/projected_meters.hpp
new file mode 100644
index 0000000000..9b70967b5d
--- /dev/null
+++ b/platform/android/src/geometry/projected_meters.hpp
@@ -0,0 +1,26 @@
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/geometry.hpp>
+
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class ProjectedMeters : private mbgl::util::noncopyable {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/geometry/ProjectedMeters"; };
+
+ static jni::Object<ProjectedMeters> New(jni::JNIEnv&, double, double);
+
+ static jni::Class<ProjectedMeters> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+};
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/graphics/pointf.cpp b/platform/android/src/graphics/pointf.cpp
new file mode 100644
index 0000000000..6e91b81416
--- /dev/null
+++ b/platform/android/src/graphics/pointf.cpp
@@ -0,0 +1,20 @@
+#include "pointf.hpp"
+
+namespace mbgl {
+namespace android {
+
+jni::Object<PointF> PointF::New(jni::JNIEnv& env, float x, float y) {
+ static auto constructor = PointF::javaClass.GetConstructor<float, float>(env);
+ return PointF::javaClass.New(env, constructor, x, y);
+}
+
+void PointF::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ PointF::javaClass = *jni::Class<PointF>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<PointF> PointF::javaClass;
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/graphics/pointf.hpp b/platform/android/src/graphics/pointf.hpp
new file mode 100644
index 0000000000..ea25ad2b40
--- /dev/null
+++ b/platform/android/src/graphics/pointf.hpp
@@ -0,0 +1,25 @@
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class PointF : private mbgl::util::noncopyable {
+public:
+
+ static constexpr auto Name() { return "android/graphics/PointF"; };
+
+ static jni::Object<PointF> New(jni::JNIEnv&, float, float);
+
+ static jni::Class<PointF> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+};
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/graphics/rectf.cpp b/platform/android/src/graphics/rectf.cpp
new file mode 100644
index 0000000000..1b375dad18
--- /dev/null
+++ b/platform/android/src/graphics/rectf.cpp
@@ -0,0 +1,35 @@
+#include "rectf.hpp"
+
+namespace mbgl {
+namespace android {
+
+float RectF::getLeft(jni::JNIEnv& env, jni::Object<RectF> rectf) {
+ static auto field = RectF::javaClass.GetField<float>(env, "left");
+ return rectf.Get(env, field);
+}
+
+float RectF::getTop(jni::JNIEnv& env, jni::Object<RectF> rectf) {
+ static auto field = RectF::javaClass.GetField<float>(env, "top");
+ return rectf.Get(env, field);
+}
+
+float RectF::getRight(jni::JNIEnv& env, jni::Object<RectF> rectf) {
+ static auto field = RectF::javaClass.GetField<float>(env, "right");
+ return rectf.Get(env, field);
+}
+
+float RectF::getBottom(jni::JNIEnv& env, jni::Object<RectF> rectf) {
+ static auto field = RectF::javaClass.GetField<float>(env, "bottom");
+ return rectf.Get(env, field);
+}
+
+void RectF::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ RectF::javaClass = *jni::Class<RectF>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<RectF> RectF::javaClass;
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/graphics/rectf.hpp b/platform/android/src/graphics/rectf.hpp
new file mode 100644
index 0000000000..0f3a7756d5
--- /dev/null
+++ b/platform/android/src/graphics/rectf.hpp
@@ -0,0 +1,31 @@
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class RectF : private mbgl::util::noncopyable {
+public:
+
+ static constexpr auto Name() { return "android/graphics/RectF"; };
+
+ static float getLeft(jni::JNIEnv&, jni::Object<RectF>);
+
+ static float getTop(jni::JNIEnv&, jni::Object<RectF>);
+
+ static float getRight(jni::JNIEnv&, jni::Object<RectF>);
+
+ static float getBottom(jni::JNIEnv&, jni::Object<RectF>);
+
+ static jni::Class<RectF> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+};
+
+
+} // 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
new file mode 100644
index 0000000000..a7de0b1978
--- /dev/null
+++ b/platform/android/src/gson/json_object.hpp
@@ -0,0 +1,16 @@
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+
+namespace mbgl {
+namespace android {
+
+class JsonObject : private mbgl::util::noncopyable {
+public:
+ static constexpr auto Name() { return "com/google/gson/JsonObject"; };
+
+};
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/image.cpp b/platform/android/src/image.cpp
new file mode 100644
index 0000000000..2a33944b18
--- /dev/null
+++ b/platform/android/src/image.cpp
@@ -0,0 +1,22 @@
+#include <mbgl/util/image.hpp>
+#include <mbgl/util/string.hpp>
+
+#include <string>
+
+#include "attach_env.hpp"
+#include "bitmap_factory.hpp"
+
+namespace mbgl {
+
+PremultipliedImage decodeImage(const std::string& string) {
+ auto env{ android::AttachEnv() };
+
+ auto array = jni::Array<jni::jbyte>::New(*env, string.size());
+ jni::SetArrayRegion(*env, *array, 0, string.size(),
+ reinterpret_cast<const signed char*>(string.data()));
+
+ auto bitmap = android::BitmapFactory::DecodeByteArray(*env, array, 0, string.size());
+ return android::Bitmap::GetImage(*env, bitmap);
+}
+
+} // namespace mbgl
diff --git a/platform/android/src/java/lang.hpp b/platform/android/src/java/lang.hpp
new file mode 100644
index 0000000000..dcf81a9d0c
--- /dev/null
+++ b/platform/android/src/java/lang.hpp
@@ -0,0 +1,21 @@
+#pragma once
+
+namespace mbgl {
+namespace android {
+namespace java {
+namespace lang {
+
+class Float {
+public:
+ static constexpr auto Name() { return "java/lang/Float"; };
+};
+
+class Number {
+public:
+ static constexpr auto Name() { return "java/lang/Number"; };
+};
+
+} // namespace lang
+} // namespace java
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/java/util.cpp b/platform/android/src/java/util.cpp
new file mode 100644
index 0000000000..c630e403d9
--- /dev/null
+++ b/platform/android/src/java/util.cpp
@@ -0,0 +1,18 @@
+#include "util.hpp"
+
+namespace mbgl {
+namespace android {
+namespace java {
+namespace util {
+
+jni::Class<List> List::javaClass;
+
+void registerNative(jni::JNIEnv& env) {
+ List::javaClass = *jni::Class<List>::Find(env).NewGlobalRef(env).release();
+}
+
+
+} // namespace util
+} // namespace java
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/java/util.hpp b/platform/android/src/java/util.hpp
new file mode 100644
index 0000000000..1a552c7124
--- /dev/null
+++ b/platform/android/src/java/util.hpp
@@ -0,0 +1,33 @@
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+namespace java {
+namespace util {
+
+class List : private mbgl::util::noncopyable {
+public:
+
+ static constexpr auto Name() { return "java/util/List"; };
+
+ template<class T>
+ static jni::Array<jni::Object<T>> toArray(jni::JNIEnv& env, jni::Object<List> list) {
+ static auto toArray = List::javaClass.GetMethod<jni::Array<jni::Object<>> ()>(env, "toArray");
+ return (jni::Array<jni::Object<T>>) list.Call(env, toArray);
+ };
+
+ static jni::Class<List> javaClass;
+
+};
+
+void registerNative(jni::JNIEnv&);
+
+
+} // namespace util
+} // namespace java
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/java_types.hpp b/platform/android/src/java_types.hpp
index 2e2c5fc2d6..b416a75b91 100644
--- a/platform/android/src/java_types.hpp
+++ b/platform/android/src/java_types.hpp
@@ -32,4 +32,4 @@ namespace java {
void registerNatives(JNIEnv&);
}
}
-} \ No newline at end of file
+}
diff --git a/platform/android/src/jni.cpp b/platform/android/src/jni.cpp
index 1ef7fec8fb..bd12cff3fa 100755
--- a/platform/android/src/jni.cpp
+++ b/platform/android/src/jni.cpp
@@ -1,44 +1,37 @@
-#include <cstdint>
-#include <cinttypes>
-#include <cassert>
-#include <string>
-#include <array>
-#include <vector>
+#include "jni.hpp"
-#include <android/native_window_jni.h>
-#include <sys/system_properties.h>
+#include <mbgl/util/logging.hpp>
-#include "jni.hpp"
+#include "annotation/marker.hpp"
+#include "annotation/polygon.hpp"
+#include "annotation/polyline.hpp"
+#include "bitmap.hpp"
+#include "bitmap_factory.hpp"
+#include "connectivity_listener.hpp"
+#include "conversion/conversion.hpp"
+#include "conversion/collection.hpp"
+#include "file_source.hpp"
+#include "geometry/feature.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 "java_types.hpp"
#include "native_map_view.hpp"
-#include "connectivity_listener.hpp"
+#include "offline/offline_manager.hpp"
+#include "offline/offline_region.hpp"
+#include "offline/offline_region_definition.hpp"
+#include "offline/offline_region_error.hpp"
+#include "offline/offline_region_status.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/sources.hpp"
-#include "conversion/conversion.hpp"
-#include "conversion/collection.hpp"
-#include "geometry/conversion/feature.hpp"
-
-#include <mbgl/map/map.hpp>
-#include <mbgl/map/camera.hpp>
-#include <mbgl/annotation/annotation.hpp>
-#include <mbgl/style/layer.hpp>
-#include <mbgl/style/source.hpp>
-#include <mbgl/sprite/sprite_image.hpp>
-#include <mbgl/util/event.hpp>
-#include <mbgl/util/logging.hpp>
-#include <mbgl/storage/network_status.hpp>
-#include <mbgl/util/exception.hpp>
-#include <mbgl/util/optional.hpp>
-#include <mbgl/util/string.hpp>
-#include <mbgl/util/run_loop.hpp>
-
-#include <mapbox/geometry.hpp>
-
-#include <jni/jni.hpp>
-
-#pragma clang diagnostic ignored "-Wunused-parameter"
-
namespace mbgl {
namespace android {
@@ -46,127 +39,7 @@ void RegisterNativeHTTPRequest(JNIEnv&);
JavaVM* theJVM;
-std::string cachePath;
-std::string dataPath;
-std::string apkPath;
-std::string androidRelease;
-
-jni::jmethodID* onInvalidateId = nullptr;
-jni::jmethodID* onMapChangedId = nullptr;
-jni::jmethodID* onFpsChangedId = nullptr;
-jni::jmethodID* onSnapshotReadyId = nullptr;
-
-jni::jclass* latLngClass = nullptr;
-jni::jmethodID* latLngConstructorId = nullptr;
-jni::jfieldID* latLngLatitudeId = nullptr;
-jni::jfieldID* latLngLongitudeId = nullptr;
-
-jni::jclass* latLngBoundsClass = nullptr;
-jni::jmethodID* latLngBoundsConstructorId = nullptr;
-jni::jfieldID* latLngBoundsLatNorthId = nullptr;
-jni::jfieldID* latLngBoundsLatSouthId = nullptr;
-jni::jfieldID* latLngBoundsLonEastId = nullptr;
-jni::jfieldID* latLngBoundsLonWestId = nullptr;
-
-jni::jclass* iconClass = nullptr;
-jni::jfieldID* iconIdId = nullptr;
-
-jni::jclass* markerClass = nullptr;
-jni::jfieldID* markerPositionId = nullptr;
-jni::jfieldID* markerIconId = nullptr;
-jni::jfieldID* markerIdId = nullptr;
-
-jni::jclass* polylineClass = nullptr;
-jni::jfieldID* polylineAlphaId = nullptr;
-jni::jfieldID* polylineColorId = nullptr;
-jni::jfieldID* polylineWidthId = nullptr;
-jni::jfieldID* polylinePointsId = nullptr;
-
-jni::jclass* polygonClass = nullptr;
-jni::jfieldID* polygonAlphaId = nullptr;
-jni::jfieldID* polygonFillColorId = nullptr;
-jni::jfieldID* polygonStrokeColorId = nullptr;
-jni::jfieldID* polygonPointsId = nullptr;
-
-jni::jmethodID* listToArrayId = nullptr;
-
-jni::jclass* arrayListClass = nullptr;
-jni::jmethodID* arrayListConstructorId = nullptr;
-jni::jmethodID* arrayListAddId = nullptr;
-
-jni::jclass* projectedMetersClass = nullptr;
-jni::jmethodID* projectedMetersConstructorId = nullptr;
-jni::jfieldID* projectedMetersNorthingId = nullptr;
-jni::jfieldID* projectedMetersEastingId = nullptr;
-
-jni::jclass* pointFClass = nullptr;
-jni::jmethodID* pointFConstructorId = nullptr;
-jni::jfieldID* pointFXId = nullptr;
-jni::jfieldID* pointFYId = nullptr;
-
-jni::jclass* rectFClass = nullptr;
-jni::jmethodID* rectFConstructorId = nullptr;
-jni::jfieldID* rectFLeftId = nullptr;
-jni::jfieldID* rectFTopId = nullptr;
-jni::jfieldID* rectFRightId = nullptr;
-jni::jfieldID* rectFBottomId = nullptr;
-
-// Offline declarations start
-
-jni::jfieldID* offlineManagerClassPtrId = nullptr;
-
-jni::jmethodID* listOnListMethodId = nullptr;
-jni::jmethodID* listOnErrorMethodId = nullptr;
-
-jni::jclass* offlineRegionClass = nullptr;
-jni::jmethodID* offlineRegionConstructorId = nullptr;
-jni::jfieldID* offlineRegionOfflineManagerId = nullptr;
-jni::jfieldID* offlineRegionIdId = nullptr;
-jni::jfieldID* offlineRegionDefinitionId = nullptr;
-jni::jfieldID* offlineRegionMetadataId = nullptr;
-jni::jfieldID* offlineRegionPtrId = nullptr;
-
-jni::jclass* offlineRegionDefinitionClass = nullptr;
-jni::jmethodID* offlineRegionDefinitionConstructorId = nullptr;
-jni::jfieldID* offlineRegionDefinitionStyleURLId = nullptr;
-jni::jfieldID* offlineRegionDefinitionBoundsId = nullptr;
-jni::jfieldID* offlineRegionDefinitionMinZoomId = nullptr;
-jni::jfieldID* offlineRegionDefinitionMaxZoomId = nullptr;
-jni::jfieldID* offlineRegionDefinitionPixelRatioId = nullptr;
-
-jni::jmethodID* createOnCreateMethodId = nullptr;
-jni::jmethodID* createOnErrorMethodId = nullptr;
-
-jni::jmethodID* updateMetadataOnUpdateMethodId = nullptr;
-jni::jmethodID* updateMetadataOnErrorMethodId = nullptr;
-
-jni::jmethodID* offlineRegionObserveronStatusChangedId = nullptr;
-jni::jmethodID* offlineRegionObserveronErrorId = nullptr;
-jni::jmethodID* offlineRegionObserveronLimitId = nullptr;
-
-jni::jclass* offlineRegionStatusClass = nullptr;
-jni::jmethodID* offlineRegionStatusConstructorId = nullptr;
-jni::jfieldID* offlineRegionStatusDownloadStateId = nullptr;
-jni::jfieldID* offlineRegionStatusCompletedResourceCountId = nullptr;
-jni::jfieldID* offlineRegionStatusCompletedResourceSizeId = nullptr;
-jni::jfieldID* offlineRegionStatusCompletedTileCountId = nullptr;
-jni::jfieldID* offlineRegionStatusCompletedTileSizeId = nullptr;
-jni::jfieldID* offlineRegionStatusRequiredResourceCountId = nullptr;
-jni::jfieldID* offlineRegionStatusRequiredResourceCountIsPreciseId = nullptr;
-
-jni::jclass* offlineRegionErrorClass = nullptr;
-jni::jmethodID* offlineRegionErrorConstructorId = nullptr;
-jni::jfieldID* offlineRegionErrorReasonId = nullptr;
-jni::jfieldID* offlineRegionErrorMessageId = nullptr;
-
-jni::jmethodID* offlineRegionStatusOnStatusId = nullptr;
-jni::jmethodID* offlineRegionStatusOnErrorId = nullptr;
-
-jni::jmethodID* offlineRegionDeleteOnDeleteId = nullptr;
-jni::jmethodID* offlineRegionDeleteOnErrorId = nullptr;
-
-// Offline declarations end
-
+//TODO: remove
bool attach_jni_thread(JavaVM* vm, JNIEnv** env, std::string threadName) {
assert(vm != nullptr);
assert(env != nullptr);
@@ -194,6 +67,7 @@ bool attach_jni_thread(JavaVM* vm, JNIEnv** env, std::string threadName) {
return detach;
}
+//TODO: remove
void detach_jni_thread(JavaVM* vm, JNIEnv** env, bool detach) {
if (detach) {
assert(vm != nullptr);
@@ -208,1843 +82,62 @@ void detach_jni_thread(JavaVM* vm, JNIEnv** env, bool detach) {
*env = nullptr;
}
-std::string std_string_from_jstring(JNIEnv *env, jni::jstring* jstr) {
- return jni::Make<std::string>(*env, jni::String(jstr));
-}
-
-jni::jstring* std_string_to_jstring(JNIEnv *env, std::string str) {
- return jni::Make<jni::String>(*env, str).Get();
-}
-
-std::vector<std::string> std_vector_string_from_jobject(JNIEnv *env, jni::jobject* jlist) {
- std::vector<std::string> vector;
-
- jni::NullCheck(*env, jlist);
- jni::jarray<jni::jobject>* jarray =
- reinterpret_cast<jni::jarray<jni::jobject>*>(jni::CallMethod<jni::jobject*>(*env, jlist, *listToArrayId));
-
- jni::NullCheck(*env, jarray);
- std::size_t len = jni::GetArrayLength(*env, *jarray);
-
- for (std::size_t i = 0; i < len; i++) {
- jni::jstring* jstr = reinterpret_cast<jni::jstring*>(jni::GetObjectArrayElement(*env, *jarray, i));
- vector.push_back(std_string_from_jstring(env, jstr));
- }
-
- return vector;
-}
-
-jni::jobject* std_vector_string_to_jobject(JNIEnv *env, std::vector<std::string> vector) {
- jni::jobject* jlist = &jni::NewObject(*env, *arrayListClass, *arrayListConstructorId);
-
- for (const auto& str : vector) {
- jni::CallMethod<jboolean>(*env, jlist, *arrayListAddId, std_string_to_jstring(env, str));
- }
-
- return jlist;
-}
-
-jni::jarray<jlong>* std_vector_uint_to_jobject(JNIEnv *env, const std::vector<uint32_t>& vector) {
- jni::jarray<jlong>& jarray = jni::NewArray<jlong>(*env, vector.size());
-
- std::vector<jlong> v;
- v.reserve(vector.size());
- std::move(vector.begin(), vector.end(), std::back_inserter(v));
-
- jni::SetArrayRegion(*env, jarray, 0, v);
-
- return &jarray;
-}
-
-static std::vector<uint8_t> metadata_from_java(JNIEnv* env, jni::jarray<jbyte>& j) {
- std::size_t length = jni::GetArrayLength(*env, j);
- std::vector<uint8_t> c;
- c.resize(length);
- jni::GetArrayRegion(*env, j, 0, length, reinterpret_cast<jbyte*>(c.data()));
- return c;
-}
-
-static jni::jarray<jbyte>* metadata_from_native(JNIEnv* env, const std::vector<uint8_t>& c) {
- std::size_t length = static_cast<std::size_t>(c.size());
- jni::jarray<jbyte>& j = jni::NewArray<jbyte>(*env, length);
- jni::SetArrayRegion(*env, j, 0, c.size(), reinterpret_cast<const jbyte*>(c.data()));
- return &j;
-}
-
-static mbgl::LatLngBounds latlngbounds_from_java(JNIEnv *env, jni::jobject* latLngBounds) {
- jdouble swLat = jni::GetField<jdouble>(*env, latLngBounds, *latLngBoundsLatSouthId);
- jdouble swLon = jni::GetField<jdouble>(*env, latLngBounds, *latLngBoundsLonWestId);
- jdouble neLat = jni::GetField<jdouble>(*env, latLngBounds, *latLngBoundsLatNorthId);
- jdouble neLon = jni::GetField<jdouble>(*env, latLngBounds, *latLngBoundsLonEastId);
- return mbgl::LatLngBounds::hull({ swLat, swLon }, { neLat, neLon });
-}
-
-static jni::jobject* latlngbounds_from_native(JNIEnv *env, mbgl::LatLngBounds bounds) {
- double northLatitude = bounds.north();
- double eastLongitude = bounds.east();
- double southLatitude = bounds.south();
- double westLongitude = bounds.west();
-
- jni::jobject* jbounds = &jni::NewObject(*env, *latLngBoundsClass, *latLngBoundsConstructorId,
- northLatitude, eastLongitude, southLatitude, westLongitude);
-
- return jbounds;
-}
-
-}
-}
-
-namespace {
-
-using namespace mbgl::android;
-using DebugOptions = mbgl::MapDebugOptions;
-
-jlong nativeCreate(JNIEnv *env, jni::jobject* obj, jni::jstring* cachePath_, jni::jstring* dataPath_, jni::jstring* apkPath_, jfloat pixelRatio, jint availableProcessors, jlong totalMemory) {
- mbgl::Log::Debug(mbgl::Event::JNI, "nativeCreate");
- cachePath = std_string_from_jstring(env, cachePath_);
- dataPath = std_string_from_jstring(env, dataPath_);
- apkPath = std_string_from_jstring(env, apkPath_);
- return reinterpret_cast<jlong>(new NativeMapView(env, jni::Unwrap(obj), pixelRatio, availableProcessors, totalMemory));
-}
-
-void nativeDestroy(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- mbgl::Log::Debug(mbgl::Event::JNI, "nativeDestroy");
- assert(nativeMapViewPtr != 0);
- delete reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-}
-
-void nativeInitializeDisplay(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- mbgl::Log::Debug(mbgl::Event::JNI, "nativeInitializeDisplay");
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->initializeDisplay();
-}
-
-void nativeTerminateDisplay(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- mbgl::Log::Debug(mbgl::Event::JNI, "nativeTerminateDisplay");
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->terminateDisplay();
-}
-
-void nativeInitializeContext(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- mbgl::Log::Debug(mbgl::Event::JNI, "nativeInitializeContext");
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->initializeContext();
-}
-
-void nativeTerminateContext(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- mbgl::Log::Debug(mbgl::Event::JNI, "nativeTerminateContext");
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->terminateContext();
-}
-
-void nativeCreateSurface(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jobject* surface) {
- mbgl::Log::Debug(mbgl::Event::JNI, "nativeCreateSurface");
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->createSurface(ANativeWindow_fromSurface(env, jni::Unwrap(surface)));
-}
-
-void nativeDestroySurface(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- mbgl::Log::Debug(mbgl::Event::JNI, "nativeDestroySurface");
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->destroySurface();
-}
-
-void nativeUpdate(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->invalidate();
-}
-
-void nativeRender(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->render();
-}
-
-void nativeViewResize(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jint width, jint height) {
- mbgl::Log::Debug(mbgl::Event::JNI, "nativeViewResize");
- assert(nativeMapViewPtr != 0);
- assert(width >= 0);
- assert(height >= 0);
- assert(width <= UINT16_MAX);
- assert(height <= UINT16_MAX);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->resizeView(width, height);
-}
-
-void nativeFramebufferResize(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jint fbWidth, jint fbHeight) {
- mbgl::Log::Debug(mbgl::Event::JNI, "nativeFramebufferResize");
- assert(nativeMapViewPtr != 0);
- assert(fbWidth >= 0);
- assert(fbHeight >= 0);
- assert(fbWidth <= UINT16_MAX);
- assert(fbHeight <= UINT16_MAX);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->resizeFramebuffer(fbWidth, fbHeight);
-}
-
-void nativeRemoveClass(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* clazz) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().removeClass(std_string_from_jstring(env, clazz));
-}
-
-jboolean nativeHasClass(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* clazz) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- return nativeMapView->getMap().hasClass(std_string_from_jstring(env, clazz));
-}
-
-void nativeAddClass(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* clazz) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().addClass(std_string_from_jstring(env, clazz));
-}
-
-void nativeSetClasses(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jobject* classes) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().setClasses(std_vector_string_from_jobject(env, classes));
-}
-
-jni::jobject* nativeGetClasses(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- return std_vector_string_to_jobject(env, nativeMapView->getMap().getClasses());
-}
-
-void nativeSetAPIBaseURL(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* url) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getFileSource().setAPIBaseURL(std_string_from_jstring(env, url));
-}
-
-void nativeSetStyleUrl(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* url) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().setStyleURL(std_string_from_jstring(env, url));
-}
-
-jni::jstring* nativeGetStyleUrl(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr){
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- return std_string_to_jstring(env, nativeMapView->getMap().getStyleURL());
-}
-
-void nativeSetStyleJson(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* newStyleJson) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().setStyleJSON(std_string_from_jstring(env, newStyleJson));
-}
-
-jni::jstring* nativeGetStyleJson(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- return std_string_to_jstring(env, nativeMapView->getMap().getStyleJSON());
-}
-
-void nativeSetAccessToken(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* accessToken) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getFileSource().setAccessToken(std_string_from_jstring(env, accessToken));
-}
-
-jni::jstring* nativeGetAccessToken(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- return std_string_to_jstring(env, nativeMapView->getFileSource().getAccessToken());
-}
-
-void nativeCancelTransitions(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().cancelTransitions();
-}
-
-void nativeSetGestureInProgress(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jboolean inProgress) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().setGestureInProgress(inProgress);
-}
-
-void nativeMoveBy(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble dx, jdouble dy,
- jlong duration) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().moveBy({dx, dy}, mbgl::Milliseconds(duration));
-}
-
-void nativeSetLatLng(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble latitude, jdouble longitude, jlong duration) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().setLatLng(mbgl::LatLng(latitude, longitude), nativeMapView->getInsets(), mbgl::Duration(duration));
-}
-
-jni::jobject* nativeGetLatLng(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- mbgl::LatLng latLng = nativeMapView->getMap().getLatLng(nativeMapView->getInsets());
- return &jni::NewObject(*env, *latLngClass, *latLngConstructorId, latLng.latitude, latLng.longitude);
-}
-
-jdoubleArray nativeGetCameraValues(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- mbgl::LatLng latLng = nativeMapView->getMap().getLatLng(nativeMapView->getInsets());
- jdoubleArray output = env->NewDoubleArray(5);
- jsize start = 0;
- jsize leng = 5;
- jdouble buf[5];
- buf[0] = latLng.latitude;
- buf[1] = latLng.longitude;
- buf[2] = -nativeMapView->getMap().getBearing();
- buf[3] = nativeMapView->getMap().getPitch();
- buf[4] = nativeMapView->getMap().getZoom();
- env->SetDoubleArrayRegion(output, start, leng, buf);
-
- if (output == nullptr) {
- env->ExceptionDescribe();
- return nullptr;
- }
-
- return output;
-}
-
-void nativeResetPosition(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().resetPosition();
-}
-
-jdouble nativeGetPitch(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- return nativeMapView->getMap().getPitch();
-}
-
-void nativeSetPitch(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble pitch, jlong milliseconds) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- mbgl::Duration duration((mbgl::Milliseconds(milliseconds)));
- nativeMapView->getMap().setPitch(pitch, duration);
-}
-
-void nativeScaleBy(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble ds, jdouble cx,
- jdouble cy, jlong duration) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- mbgl::ScreenCoordinate center(cx, cy);
- nativeMapView->getMap().scaleBy(ds, center, mbgl::Milliseconds(duration));
-}
-
-void nativeSetScale(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble scale,
- jdouble cx, jdouble cy, jlong duration) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- mbgl::ScreenCoordinate center(cx, cy);
- nativeMapView->getMap().setScale(scale, center, mbgl::Milliseconds(duration));
-}
-
-jdouble nativeGetScale(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- return nativeMapView->getMap().getScale();
-}
-
-void nativeSetZoom(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble zoom, jlong duration) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().setZoom(zoom, mbgl::Milliseconds(duration));
-}
-
-jdouble nativeGetZoom(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- return nativeMapView->getMap().getZoom();
-}
-
-void nativeResetZoom(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().resetZoom();
-}
-
-void nativeSetMinZoom(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble zoom) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().setMinZoom(zoom);
-}
-
-jdouble nativeGetMinZoom(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- return nativeMapView->getMap().getMinZoom();
-}
-
-void nativeSetMaxZoom(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble zoom) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().setMaxZoom(zoom);
-}
-
-jdouble nativeGetMaxZoom(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- return nativeMapView->getMap().getMaxZoom();
-}
-
-void nativeRotateBy(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble sx,
- jdouble sy, jdouble ex, jdouble ey, jlong duration) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- mbgl::ScreenCoordinate first(sx, sy);
- mbgl::ScreenCoordinate second(ex, ey);
- nativeMapView->getMap().rotateBy(first, second, mbgl::Milliseconds(duration));
-}
-
-void nativeSetBearing(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble degrees,
- jlong milliseconds) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- mbgl::Duration duration((mbgl::Milliseconds(milliseconds)));
- nativeMapView->getMap().setBearing(degrees, duration);
-}
-
-void nativeSetBearingXY(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble degrees,
- jdouble cx, jdouble cy) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- mbgl::ScreenCoordinate center(cx, cy);
- nativeMapView->getMap().setBearing(degrees, center);
-}
-
-jdouble nativeGetBearing(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- return nativeMapView->getMap().getBearing();
-}
-
-void nativeResetNorth(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().resetNorth();
-}
-
-void nativeUpdateMarker(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jlong markerId, jdouble lat, jdouble lon, jni::jstring* jid) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- if (markerId == -1) {
- return;
- }
- std::string iconId = std_string_from_jstring(env, jid);
- // Because Java only has int, not unsigned int, we need to bump the annotation id up to a long.
- nativeMapView->getMap().updateAnnotation(markerId, mbgl::SymbolAnnotation { mbgl::Point<double>(lon, lat), iconId });
-}
-
-jni::jarray<jlong>* nativeAddMarkers(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jarray<jni::jobject>* jarray) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- NullCheck(*env, jarray);
- std::size_t len = jni::GetArrayLength(*env, *jarray);
-
- mbgl::AnnotationIDs ids;
- ids.reserve(len);
-
- for (std::size_t i = 0; i < len; i++) {
- jni::jobject* marker = jni::GetObjectArrayElement(*env, *jarray, i);
- jni::jobject* position = jni::GetField<jni::jobject*>(*env, marker, *markerPositionId);
- jni::jobject* icon = jni::GetField<jni::jobject*>(*env, marker, *markerIconId);
- jni::jstring* jid = reinterpret_cast<jni::jstring*>(jni::GetField<jni::jobject*>(*env, icon, *iconIdId));
-
- jdouble latitude = jni::GetField<jdouble>(*env, position, *latLngLatitudeId);
- jdouble longitude = jni::GetField<jdouble>(*env, position, *latLngLongitudeId);
-
- ids.push_back(nativeMapView->getMap().addAnnotation(mbgl::SymbolAnnotation {
- mbgl::Point<double>(longitude, latitude),
- std_string_from_jstring(env, jid)
- }));
-
- jni::DeleteLocalRef(*env, position);
- jni::DeleteLocalRef(*env, jid);
- jni::DeleteLocalRef(*env, icon);
- jni::DeleteLocalRef(*env, marker);
- }
-
- return std_vector_uint_to_jobject(env, ids);
-}
-
-static mbgl::Color toColor(jint color) {
- float r = (color >> 16) & 0xFF;
- float g = (color >> 8) & 0xFF;
- float b = (color) & 0xFF;
- float a = (color >> 24) & 0xFF;
- return { r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f };
-}
-
-template <class Geometry>
-Geometry toGeometry(JNIEnv *env, jni::jobject* jlist) {
- NullCheck(*env, jlist);
- jni::jarray<jni::jobject>* jarray =
- reinterpret_cast<jni::jarray<jni::jobject>*>(jni::CallMethod<jni::jobject*>(*env, jlist, *listToArrayId));
- NullCheck(*env, jarray);
-
- std::size_t size = jni::GetArrayLength(*env, *jarray);
-
- Geometry geometry;
- geometry.reserve(size);
-
- for (std::size_t i = 0; i < size; i++) {
- jni::jobject* latLng = reinterpret_cast<jni::jobject*>(jni::GetObjectArrayElement(*env, *jarray, i));
- NullCheck(*env, latLng);
-
- geometry.push_back(mbgl::Point<double>(
- jni::GetField<jdouble>(*env, latLng, *latLngLongitudeId),
- jni::GetField<jdouble>(*env, latLng, *latLngLatitudeId)));
-
- jni::DeleteLocalRef(*env, latLng);
- }
-
- jni::DeleteLocalRef(*env, jarray);
- jni::DeleteLocalRef(*env, jlist);
-
- return geometry;
-}
-
-jni::jarray<jlong>* nativeAddPolylines(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jarray<jni::jobject>* jarray) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- NullCheck(*env, jarray);
- std::size_t len = jni::GetArrayLength(*env, *jarray);
-
- mbgl::AnnotationIDs ids;
- ids.reserve(len);
-
- for (std::size_t i = 0; i < len; i++) {
- jni::jobject* polyline = jni::GetObjectArrayElement(*env, *jarray, i);
- jni::jobject* points = jni::GetField<jni::jobject*>(*env, polyline, *polylinePointsId);
-
- mbgl::LineAnnotation annotation { toGeometry<mbgl::LineString<double>>(env, points) };
- annotation.opacity = { jni::GetField<jfloat>(*env, polyline, *polylineAlphaId) };
- annotation.color = { toColor(jni::GetField<jint>(*env, polyline, *polylineColorId)) };
- annotation.width = { jni::GetField<jfloat>(*env, polyline, *polylineWidthId) };
- ids.push_back(nativeMapView->getMap().addAnnotation(annotation));
-
- jni::DeleteLocalRef(*env, polyline);
- }
-
- return std_vector_uint_to_jobject(env, ids);
-}
-
-jni::jarray<jlong>* nativeAddPolygons(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jarray<jni::jobject>* jarray) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- NullCheck(*env, jarray);
- std::size_t len = jni::GetArrayLength(*env, *jarray);
-
- mbgl::AnnotationIDs ids;
- ids.reserve(len);
-
- for (std::size_t i = 0; i < len; i++) {
- jni::jobject* polygon = jni::GetObjectArrayElement(*env, *jarray, i);
- jni::jobject* points = jni::GetField<jni::jobject*>(*env, polygon, *polygonPointsId);
-
- mbgl::FillAnnotation annotation { mbgl::Polygon<double> { toGeometry<mbgl::LinearRing<double>>(env, points) } };
- annotation.opacity = { jni::GetField<jfloat>(*env, polygon, *polygonAlphaId) };
- annotation.outlineColor = { toColor(jni::GetField<jint>(*env, polygon, *polygonStrokeColorId)) };
- annotation.color = { toColor(jni::GetField<jint>(*env, polygon, *polygonFillColorId)) };
- ids.push_back(nativeMapView->getMap().addAnnotation(annotation));
-
- jni::DeleteLocalRef(*env, polygon);
- }
-
- return std_vector_uint_to_jobject(env, ids);
-}
-
-void nativeUpdatePolygon(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jlong polygonId, jni::jobject* polygon) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- jni::jobject* points = jni::GetField<jni::jobject*>(*env, polygon, *polygonPointsId);
-
- mbgl::FillAnnotation annotation { mbgl::Polygon<double> { toGeometry<mbgl::LinearRing<double>>(env, points) } };
- annotation.opacity = { jni::GetField<jfloat>(*env, polygon, *polygonAlphaId) };
- annotation.outlineColor = { toColor(jni::GetField<jint>(*env, polygon, *polygonStrokeColorId)) };
- annotation.color = { toColor(jni::GetField<jint>(*env, polygon, *polygonFillColorId)) };
- nativeMapView->getMap().updateAnnotation(polygonId, annotation);
-}
-
-void nativeUpdatePolyline(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jlong polylineId, jni::jobject* polyline) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- jni::jobject* points = jni::GetField<jni::jobject*>(*env, polyline, *polylinePointsId);
-
- mbgl::LineAnnotation annotation { toGeometry<mbgl::LineString<double>>(env, points) };
- annotation.opacity = { jni::GetField<jfloat>(*env, polyline, *polylineAlphaId) };
- annotation.color = { toColor(jni::GetField<jint>(*env, polyline, *polylineColorId)) };
- annotation.width = { jni::GetField<jfloat>(*env, polyline, *polylineWidthId) };
- nativeMapView->getMap().updateAnnotation(polylineId, annotation);
-}
-
-void nativeRemoveAnnotations(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jarray<jlong>* jarray) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- NullCheck(*env, jarray);
- std::size_t len = jni::GetArrayLength(*env, *jarray);
- auto elements = jni::GetArrayElements(*env, *jarray);
- jlong* jids = std::get<0>(elements).get();
-
- for (std::size_t i = 0; i < len; i++) {
- if(jids[i] == -1L)
- continue;
- nativeMapView->getMap().removeAnnotation(jids[i]);
- }
-}
-
-jni::jarray<jlong>* nativeQueryPointAnnotations(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jobject* rect) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- // Conversion
- jfloat left = jni::GetField<jfloat>(*env, rect, *rectFLeftId);
- jfloat right = jni::GetField<jfloat>(*env, rect, *rectFRightId);
- jfloat top = jni::GetField<jfloat>(*env, rect, *rectFTopId);
- jfloat bottom = jni::GetField<jfloat>(*env, rect, *rectFBottomId);
- mbgl::ScreenBox box = {
- { left, top },
- { right, bottom },
- };
-
- // Assume only points for now
- mbgl::AnnotationIDs ids = nativeMapView->getMap().queryPointAnnotations(box);
-
- return std_vector_uint_to_jobject(env, ids);
-}
-
-void nativeAddAnnotationIcon(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr,
- jni::jstring* symbol, jint width, jint height, jfloat scale, jni::jarray<jbyte>* jpixels) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- const std::string symbolName = std_string_from_jstring(env, symbol);
-
- NullCheck(*env, jpixels);
- std::size_t size = jni::GetArrayLength(*env, *jpixels);
- mbgl::PremultipliedImage premultipliedImage(
- { static_cast<uint32_t>(width), static_cast<uint32_t>(height) });
-
- if (premultipliedImage.bytes() != uint32_t(size)) {
- throw mbgl::util::SpriteImageException("Sprite image pixel count mismatch");
- }
-
- jni::GetArrayRegion(*env, *jpixels, 0, size, reinterpret_cast<jbyte*>(premultipliedImage.data.get()));
-
- auto iconImage = std::make_shared<mbgl::SpriteImage>(
- std::move(premultipliedImage),
- float(scale));
-
- nativeMapView->getMap().addAnnotationIcon(symbolName, iconImage);
-}
-
-void nativeSetVisibleCoordinateBounds(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr,
- jni::jarray<jni::jobject>* coordinates, jni::jobject* padding, jdouble direction, jlong duration) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- jfloat left = jni::GetField<jfloat>(*env, padding, *rectFLeftId);
- jfloat right = jni::GetField<jfloat>(*env, padding, *rectFRightId);
- jfloat top = jni::GetField<jfloat>(*env, padding, *rectFTopId);
- jfloat bottom = jni::GetField<jfloat>(*env, padding, *rectFBottomId);
-
- NullCheck(*env, coordinates);
- std::size_t count = jni::GetArrayLength(*env, *coordinates);
-
- mbgl::EdgeInsets mbglInsets = {top, left, bottom, right};
- std::vector<mbgl::LatLng> latLngs;
- latLngs.reserve(count);
-
- for (std::size_t i = 0; i < count; i++) {
- jni::jobject* latLng = jni::GetObjectArrayElement(*env, *coordinates, i);
- jdouble latitude = jni::GetField<jdouble>(*env, latLng, *latLngLatitudeId);
- jdouble longitude = jni::GetField<jdouble>(*env, latLng, *latLngLongitudeId);
- latLngs.push_back(mbgl::LatLng(latitude, longitude));
- }
-
- mbgl::CameraOptions cameraOptions = nativeMapView->getMap().cameraForLatLngs(latLngs, mbglInsets);
- if (direction >= 0) {
- // convert from degrees to radians
- cameraOptions.angle = (-direction * M_PI) / 180;
- }
- mbgl::AnimationOptions animationOptions;
- if (duration > 0) {
- animationOptions.duration.emplace(mbgl::Milliseconds(duration));
- // equivalent to kCAMediaTimingFunctionDefault in iOS
- animationOptions.easing.emplace(mbgl::util::UnitBezier { 0.25, 0.1, 0.25, 0.1 });
- }
-
- nativeMapView->getMap().easeTo(cameraOptions, animationOptions);
-}
-
-jni::jarray<jni::jobject>* nativeQueryRenderedFeaturesForPoint(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jfloat x, jni::jfloat y, jni::jarray<jni::jobject>* layerIds) {
- using namespace mbgl::android::conversion;
- using namespace mapbox::geometry;
-
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- mbgl::optional<std::vector<std::string>> layers;
- if (layerIds != nullptr && jni::GetArrayLength(*env, *layerIds) > 0) {
- layers = toVector(*env, *layerIds);
- }
- point<double> point = {x, y};
-
- return *convert<jni::jarray<jni::jobject>*, std::vector<mbgl::Feature>>(*env, nativeMapView->getMap().queryRenderedFeatures(point, layers));
-}
-
-jni::jarray<jni::jobject>* nativeQueryRenderedFeaturesForBox(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jfloat left, jni::jfloat top, jni::jfloat right, jni::jfloat bottom, jni::jarray<jni::jobject>* layerIds) {
- using namespace mbgl::android::conversion;
- using namespace mapbox::geometry;
-
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- mbgl::optional<std::vector<std::string>> layers;
- if (layerIds != nullptr && jni::GetArrayLength(*env, *layerIds) > 0) {
- layers = toVector(*env, *layerIds);
- }
- box<double> box = { point<double>{ left, top}, point<double>{ right, bottom } };
-
- return *convert<jni::jarray<jni::jobject>*, std::vector<mbgl::Feature>>(*env, nativeMapView->getMap().queryRenderedFeatures(box, layers));
-}
-
-void nativeOnLowMemory(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().onLowMemory();
-}
-
-void nativeSetDebug(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jboolean debug) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- DebugOptions debugOptions = debug ? DebugOptions::TileBorders | DebugOptions::ParseStatus | DebugOptions::Collision
- : DebugOptions::NoDebug;
- nativeMapView->getMap().setDebug(debugOptions);
- nativeMapView->enableFps(debug);
-}
-
-void nativeToggleDebug(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().cycleDebugOptions();
- nativeMapView->enableFps(nativeMapView->getMap().getDebug() != DebugOptions::NoDebug);
-}
-
-jboolean nativeGetDebug(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- return nativeMapView->getMap().getDebug() != DebugOptions::NoDebug;
-}
-
-jboolean nativeIsFullyLoaded(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- return nativeMapView->getMap().isFullyLoaded();
-}
-
-void nativeSetReachability(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jboolean status) {
- assert(nativeMapViewPtr != 0);
- if (status) {
- mbgl::NetworkStatus::Reachable();
- }
-}
-
-jdouble nativeGetMetersPerPixelAtLatitude(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble lat, jdouble zoom) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- return nativeMapView->getMap().getMetersPerPixelAtLatitude(lat, zoom);
-}
-
-jni::jobject* nativeProjectedMetersForLatLng(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble latitude, jdouble longitude) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- mbgl::ProjectedMeters projectedMeters = nativeMapView->getMap().projectedMetersForLatLng(mbgl::LatLng(latitude, longitude));
- return &jni::NewObject(*env, *projectedMetersClass, *projectedMetersConstructorId, projectedMeters.northing, projectedMeters.easting);
-}
-
-jni::jobject* nativeLatLngForProjectedMeters(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble northing, jdouble easting) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- mbgl::LatLng latLng = nativeMapView->getMap().latLngForProjectedMeters(mbgl::ProjectedMeters(northing, easting));
- return &jni::NewObject(*env, *latLngClass, *latLngConstructorId, latLng.latitude, latLng.longitude);
-}
-
-jni::jobject* nativePixelForLatLng(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble latitude, jdouble longitude) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- mbgl::ScreenCoordinate pixel = nativeMapView->getMap().pixelForLatLng(mbgl::LatLng(latitude, longitude));
- return &jni::NewObject(*env, *pointFClass, *pointFConstructorId, static_cast<jfloat>(pixel.x), static_cast<jfloat>(pixel.y));
-}
-
-jni::jobject* nativeLatLngForPixel(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jfloat x, jfloat y) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- mbgl::LatLng latLng = nativeMapView->getMap().latLngForPixel(mbgl::ScreenCoordinate(x, y));
- return &jni::NewObject(*env, *latLngClass, *latLngConstructorId, latLng.latitude, latLng.longitude);
-}
-
-jdouble nativeGetTopOffsetPixelsForAnnotationSymbol(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* symbolName) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- return nativeMapView->getMap().getTopOffsetPixelsForAnnotationIcon(std_string_from_jstring(env, symbolName));
-}
-
-void nativeJumpTo(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble angle, jdouble latitude, jdouble longitude, jdouble pitch, jdouble zoom) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- mbgl::CameraOptions options;
- if (angle != -1) {
- options.angle = (-angle * M_PI) / 180;
- }
- options.center = mbgl::LatLng(latitude, longitude);
- options.padding = nativeMapView->getInsets();
- if (pitch != -1) {
- options.pitch = pitch * M_PI / 180;
- }
- if (zoom != -1) {
- options.zoom = zoom;
- }
-
- nativeMapView->getMap().jumpTo(options);
-}
-
-void nativeEaseTo(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble angle, jdouble latitude, jdouble longitude, jlong duration, jdouble pitch, jdouble zoom, jboolean easing) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- mbgl::CameraOptions cameraOptions;
- if (angle != -1) {
- cameraOptions.angle = (-angle * M_PI) / 180;
- }
- cameraOptions.center = mbgl::LatLng(latitude, longitude);
- cameraOptions.padding = nativeMapView->getInsets();
- if (pitch != -1) {
- cameraOptions.pitch = pitch * M_PI / 180;
- }
- if (zoom != -1) {
- cameraOptions.zoom = zoom;
- }
- mbgl::AnimationOptions animationOptions;
- animationOptions.duration.emplace(mbgl::Duration(duration));
-
- if (!easing) {
- // add a linear interpolator instead of easing
- animationOptions.easing.emplace(mbgl::util::UnitBezier { 0, 0, 1, 1 });
- }
-
- nativeMapView->getMap().easeTo(cameraOptions, animationOptions);
-}
-
-void nativeSetContentPadding(JNIEnv *env, jni::jobject* obj,long nativeMapViewPtr, double top, double left, double bottom, double right) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->setInsets({top, left, bottom, right});
-}
-
-void nativeFlyTo(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble angle, jdouble latitude, jdouble longitude, jlong duration, jdouble pitch, jdouble zoom) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- mbgl::CameraOptions cameraOptions;
- if (angle != -1) {
- cameraOptions.angle = (-angle * M_PI) / 180 ;
- }
- cameraOptions.center = mbgl::LatLng(latitude, longitude);
- cameraOptions.padding = nativeMapView->getInsets();
- if (pitch != -1) {
- cameraOptions.pitch = pitch * M_PI / 180;
- }
- if (zoom != -1) {
- cameraOptions.zoom = zoom;
- }
- mbgl::AnimationOptions animationOptions;
- animationOptions.duration.emplace(mbgl::Duration(duration));
-
- nativeMapView->getMap().flyTo(cameraOptions, animationOptions);
-}
-
-jlong nativeGetTransitionDuration(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(env);
- assert(nativeMapViewPtr != 0);
-
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- const auto transitionOptions = nativeMapView->getMap().getTransitionOptions();
- return transitionOptions.duration.value_or(mbgl::Duration::zero()).count();
-}
-
-void nativeSetTransitionDuration(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jlong duration) {
- assert(env);
- assert(nativeMapViewPtr != 0);
-
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- auto transitionOptions = nativeMapView->getMap().getTransitionOptions();
- transitionOptions.duration = std::chrono::duration_cast<mbgl::Duration>(std::chrono::duration<jlong>(duration));
- nativeMapView->getMap().setTransitionOptions(transitionOptions);
-}
-
-jlong nativeGetTransitionDelay(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(env);
- assert(nativeMapViewPtr != 0);
-
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- const auto transitionOptions = nativeMapView->getMap().getTransitionOptions();
- return transitionOptions.delay.value_or(mbgl::Duration::zero()).count();
-}
-
-void nativeSetTransitionDelay(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jlong delay) {
- assert(env);
- assert(nativeMapViewPtr != 0);
-
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- auto transitionOptions = nativeMapView->getMap().getTransitionOptions();
- transitionOptions.delay = std::chrono::duration_cast<mbgl::Duration>(std::chrono::duration<jlong>(delay));
- nativeMapView->getMap().setTransitionOptions(transitionOptions);
-}
-
-jni::jobject* nativeGetLayer(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* layerId) {
- assert(env);
- assert(nativeMapViewPtr != 0);
-
- //Get the native map peer
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- //Find the layer
- mbgl::style::Layer* coreLayer = nativeMapView->getMap().getLayer(std_string_from_jstring(env, layerId));
- if (!coreLayer) {
- mbgl::Log::Debug(mbgl::Event::JNI, "No layer found");
- return jni::Object<Layer>();
- }
-
- //Create and return the layer's native peer
- return createJavaLayerPeer(*env, nativeMapView->getMap(), *coreLayer);
-}
-
-void nativeAddLayer(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jlong nativeLayerPtr, jni::jstring* before) {
- assert(nativeMapViewPtr != 0);
- assert(nativeLayerPtr != 0);
-
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- Layer *layer = reinterpret_cast<Layer *>(nativeLayerPtr);
- try {
- layer->addToMap(nativeMapView->getMap(), before ? mbgl::optional<std::string>(std_string_from_jstring(env, before)) : mbgl::optional<std::string>());
- } catch (const std::runtime_error& error) {
- jni::ThrowNew(*env, jni::FindClass(*env, "com/mapbox/mapboxsdk/style/layers/CannotAddLayerException"), error.what());
- }
-}
-
-/**
- * Remove by layer id. Ownership is not transferred back
- */
-void nativeRemoveLayerById(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* id) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- try {
- nativeMapView->getMap().removeLayer(std_string_from_jstring(env, id));
- } catch (const std::runtime_error& error) {
- jni::ThrowNew(*env, jni::FindClass(*env, "com/mapbox/mapboxsdk/style/layers/NoSuchLayerException"), error.what());
- }
-}
-
-/**
- * Remove with wrapper object id. Ownership is transferred back to the wrapper
- */
-void nativeRemoveLayer(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jlong layerPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- mbgl::android::Layer *layer = reinterpret_cast<mbgl::android::Layer *>(layerPtr);
- try {
- std::unique_ptr<mbgl::style::Layer> coreLayer = nativeMapView->getMap().removeLayer(layer->get().getID());
- layer->setLayer(std::move(coreLayer));
- } catch (const std::runtime_error& error) {
- jni::ThrowNew(*env, jni::FindClass(*env, "com/mapbox/mapboxsdk/style/layers/NoSuchLayerException"), error.what());
- }
-}
-
-
-jni::jobject* nativeGetSource(JNIEnv *env, jni::jobject* obj, jni::jlong nativeMapViewPtr, jni::jstring* sourceId) {
- assert(env);
- assert(nativeMapViewPtr != 0);
-
- //Get the native map peer
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- //Find the source
- mbgl::style::Source* coreSource = nativeMapView->getMap().getSource(std_string_from_jstring(env, sourceId));
- if (!coreSource) {
- mbgl::Log::Debug(mbgl::Event::JNI, "No source found");
- return jni::Object<Source>();
- }
-
- //Create and return the source's native peer
- return createJavaSourcePeer(*env, nativeMapView->getMap(), *coreSource);
-}
-
-void nativeAddSource(JNIEnv *env, jni::jobject* obj, jni::jlong nativeMapViewPtr, jni::jlong nativeSourcePtr) {
- assert(nativeMapViewPtr != 0);
- assert(nativeSourcePtr != 0);
-
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- Source *source = reinterpret_cast<Source *>(nativeSourcePtr);
- try {
- source->addToMap(nativeMapView->getMap());
- } catch (const std::runtime_error& error) {
- jni::ThrowNew(*env, jni::FindClass(*env, "com/mapbox/mapboxsdk/style/sources/CannotAddSourceException"), error.what());
- }
-}
-
-void nativeRemoveSourceById(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* id) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- try {
- nativeMapView->getMap().removeSource(std_string_from_jstring(env, id));
- } catch (const std::runtime_error& error) {
- jni::ThrowNew(*env, jni::FindClass(*env, "com/mapbox/mapboxsdk/style/sources/NoSuchSourceException"), error.what());
- }
-}
-
-void nativeRemoveSource(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jlong sourcePtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- mbgl::android::Source *source = reinterpret_cast<mbgl::android::Source *>(sourcePtr);
- try {
- std::unique_ptr<mbgl::style::Source> coreSource = nativeMapView->getMap().removeSource(source->get().getID());
- source->setSource(std::move(coreSource));
- } catch (const std::runtime_error& error) {
- jni::ThrowNew(*env, jni::FindClass(*env, "com/mapbox/mapboxsdk/style/sources/NoSuchSourceException"), error.what());
- }
-}
-
-void nativeAddImage(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* name, jni::jint width, jni::jint height, jni::jfloat pixelRatio, jni::jarray<jbyte>* data) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- // Create Pre-multiplied image from byte[]
- NullCheck(*env, data);
- std::size_t size = jni::GetArrayLength(*env, *data);
- mbgl::PremultipliedImage premultipliedImage(
- { static_cast<uint32_t>(width), static_cast<uint32_t>(height) });
-
- if (premultipliedImage.bytes() != uint32_t(size)) {
- throw mbgl::util::SpriteImageException("Sprite image pixel count mismatch");
- }
-
- jni::GetArrayRegion(*env, *data, 0, size, reinterpret_cast<jbyte*>(premultipliedImage.data.get()));
-
- //Wrap in a SpriteImage with the correct pixel ratio
- auto spriteImage = std::make_unique<mbgl::SpriteImage>(std::move(premultipliedImage), float(pixelRatio));
-
- nativeMapView->getMap().addImage(std_string_from_jstring(env, name), std::move(spriteImage));
-}
-
-void nativeRemoveImage(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* name) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().removeImage(std_string_from_jstring(env, name));
-}
-
-void nativeScheduleTakeSnapshot(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->scheduleTakeSnapshot();
-}
-
-// Offline calls begin
-
-jlong createDefaultFileSource(JNIEnv *env, jni::jobject* obj, jni::jstring* cachePath_, jni::jstring* assetRoot_, jlong maximumCacheSize) {
- std::string cachePath = std_string_from_jstring(env, cachePath_);
- std::string assetRoot = std_string_from_jstring(env, assetRoot_);
- mbgl::DefaultFileSource *defaultFileSource = new mbgl::DefaultFileSource(cachePath, assetRoot, maximumCacheSize);
- jlong defaultFileSourcePtr = reinterpret_cast<jlong>(defaultFileSource);
- return defaultFileSourcePtr;
-}
-
-void setAccessToken(JNIEnv *env, jni::jobject* obj, jlong defaultFileSourcePtr, jni::jstring* accessToken_) {
- assert(defaultFileSourcePtr != 0);
- std::string accessToken = std_string_from_jstring(env, accessToken_);
- mbgl::DefaultFileSource *defaultFileSource = reinterpret_cast<mbgl::DefaultFileSource *>(defaultFileSourcePtr);
- defaultFileSource->setAccessToken(accessToken);
-}
-
-jni::jstring* getAccessToken(JNIEnv *env, jni::jobject* obj, jlong defaultFileSourcePtr) {
- assert(defaultFileSourcePtr != 0);
- mbgl::DefaultFileSource *defaultFileSource = reinterpret_cast<mbgl::DefaultFileSource *>(defaultFileSourcePtr);
- std::string accessToken = defaultFileSource->getAccessToken();
- return std_string_to_jstring(env, accessToken);
-}
-
-void listOfflineRegions(JNIEnv *env, jni::jobject* obj, jlong defaultFileSourcePtr, jni::jobject* listCallback) {
- // Checks
- assert(defaultFileSourcePtr != 0);
- NullCheck(*env, listCallback);
-
- // Makes sure the objects don't get GC'ed
- obj = jni::NewGlobalRef(*env, obj).release();
- listCallback = jni::NewGlobalRef(*env, listCallback).release();
-
- // Launch listCallback
- mbgl::DefaultFileSource *defaultFileSource = reinterpret_cast<mbgl::DefaultFileSource *>(defaultFileSourcePtr);
- defaultFileSource->listOfflineRegions([obj, defaultFileSourcePtr, listCallback](std::exception_ptr error, mbgl::optional<std::vector<mbgl::OfflineRegion>> regions) mutable {
-
- // Reattach, the callback comes from a different thread
- JNIEnv *env2;
- jboolean renderDetach = attach_jni_thread(theJVM, &env2, "Offline Thread");
- if (renderDetach) {
- mbgl::Log::Debug(mbgl::Event::JNI, "Attached.");
- }
-
- if (error) {
- std::string message = mbgl::util::toString(error);
- jni::CallMethod<void>(*env2, listCallback, *listOnErrorMethodId, std_string_to_jstring(env2, message));
- } else if (regions) {
- // Build jni::jarray<jni::jobject>*
- std::size_t index = 0;
- jni::jarray<jni::jobject>* jregions = &jni::NewObjectArray(*env2, regions->size(), *offlineRegionClass, NULL);
- for (auto& region : *regions) {
- // Create a new local reference frame (capacity 2 for the NewObject allocations below)
- // to avoid a local reference table overflow (#5629)
- jni::UniqueLocalFrame frame = jni::PushLocalFrame(*env2, 2);
-
- // Build the Region object
- jni::jobject* jregion = &jni::NewObject(*env2, *offlineRegionClass, *offlineRegionConstructorId);
- jni::SetField<jni::jobject*>(*env2, jregion, *offlineRegionOfflineManagerId, obj);
- jni::SetField<jlong>(*env2, jregion, *offlineRegionIdId, region.getID());
-
- // Definition object
- mbgl::OfflineTilePyramidRegionDefinition definition = region.getDefinition();
- jni::jobject* jdefinition = &jni::NewObject(*env2, *offlineRegionDefinitionClass, *offlineRegionDefinitionConstructorId);
- jni::SetField<jni::jobject*>(*env2, jdefinition, *offlineRegionDefinitionStyleURLId, std_string_to_jstring(env2, definition.styleURL));
- jni::SetField<jni::jobject*>(*env2, jdefinition, *offlineRegionDefinitionBoundsId, latlngbounds_from_native(env2, definition.bounds));
- jni::SetField<jdouble>(*env2, jdefinition, *offlineRegionDefinitionMinZoomId, definition.minZoom);
- jni::SetField<jdouble>(*env2, jdefinition, *offlineRegionDefinitionMaxZoomId, definition.maxZoom);
- jni::SetField<jfloat>(*env2, jdefinition, *offlineRegionDefinitionPixelRatioId, definition.pixelRatio);
- jni::SetField<jni::jobject*>(*env2, jregion, *offlineRegionDefinitionId, jdefinition);
-
- // Metadata object
- jni::jarray<jbyte>* metadata = metadata_from_native(env2, region.getMetadata());
- jni::SetField<jni::jobject*>(*env2, jregion, *offlineRegionMetadataId, metadata);
-
- // Moves the region on the stack into a heap-allocated one
- jni::SetField<jlong>(*env2, jregion, *offlineRegionPtrId,
- reinterpret_cast<jlong>(new mbgl::OfflineRegion(std::move(region))));
-
- jni::SetObjectArrayElement(*env2, *jregions, index, jregion);
- index++;
- }
-
- // Trigger callback
- jni::CallMethod<void>(*env2, listCallback, *listOnListMethodId, jregions);
- }
-
- // Delete global refs and detach when we're done
- jni::DeleteGlobalRef(*env2, jni::UniqueGlobalRef<jni::jobject>(obj));
- jni::DeleteGlobalRef(*env2, jni::UniqueGlobalRef<jni::jobject>(listCallback));
- detach_jni_thread(theJVM, &env2, renderDetach);
- });
-}
-
-void createOfflineRegion(JNIEnv *env, jni::jobject* obj, jlong defaultFileSourcePtr, jni::jobject* definition_, jni::jarray<jbyte>* metadata_, jni::jobject* createCallback) {
- // Checks
- assert(defaultFileSourcePtr != 0);
- NullCheck(*env, createCallback);
-
- // Definition fields
- jni::jstring* jStyleURL = reinterpret_cast<jni::jstring*>(jni::GetField<jni::jobject*>(*env, definition_, *offlineRegionDefinitionStyleURLId));
- std::string styleURL = std_string_from_jstring(env, jStyleURL);
- jni::jobject* jBounds = jni::GetField<jni::jobject*>(*env, definition_, *offlineRegionDefinitionBoundsId);
- jdouble jMinZoom = jni::GetField<jdouble>(*env, definition_, *offlineRegionDefinitionMinZoomId);
- jdouble jMaxZoom = jni::GetField<jdouble>(*env, definition_, *offlineRegionDefinitionMaxZoomId);
- jfloat jPixelRatio = jni::GetField<jfloat>(*env, definition_, *offlineRegionDefinitionPixelRatioId);
-
- // Convert bounds fields to native
- mbgl::LatLngBounds bounds = latlngbounds_from_java(env, jBounds);
-
- // Definition
- mbgl::OfflineTilePyramidRegionDefinition definition(styleURL, bounds, jMinZoom, jMaxZoom, jPixelRatio);
-
- // Metadata
- mbgl::OfflineRegionMetadata metadata;
- if (metadata_ != nullptr) {
- metadata = metadata_from_java(env, *metadata_);
- }
-
- // Makes sure the objects don't get GC'ed
- obj = jni::NewGlobalRef(*env, obj).release();
- createCallback = jni::NewGlobalRef(*env, createCallback).release();
-
- // Launch createCallback
- mbgl::DefaultFileSource *defaultFileSource = reinterpret_cast<mbgl::DefaultFileSource *>(defaultFileSourcePtr);
- defaultFileSource->createOfflineRegion(definition, metadata, [obj, defaultFileSourcePtr, createCallback] (std::exception_ptr error, mbgl::optional<mbgl::OfflineRegion> region) mutable {
-
- // Reattach, the callback comes from a different thread
- JNIEnv *env2;
- jboolean renderDetach = attach_jni_thread(theJVM, &env2, "Offline Thread");
- if (renderDetach) {
- mbgl::Log::Debug(mbgl::Event::JNI, "Attached.");
- }
-
- if (error) {
- std::string message = mbgl::util::toString(error);
- jni::CallMethod<void>(*env2, createCallback, *createOnErrorMethodId, std_string_to_jstring(env2, message));
- } else if (region) {
- // Build the Region object
- jni::jobject* jregion = &jni::NewObject(*env2, *offlineRegionClass, *offlineRegionConstructorId);
- jni::SetField<jni::jobject*>(*env2, jregion, *offlineRegionOfflineManagerId, obj);
- jni::SetField<jlong>(*env2, jregion, *offlineRegionIdId, region->getID());
-
- // Metadata object
- jni::jarray<jbyte>* jmetadata = metadata_from_native(env2, region->getMetadata());
- jni::SetField<jni::jobject*>(*env2, jregion, *offlineRegionMetadataId, jmetadata);
-
- // Moves the region on the stack into a heap-allocated one
- jni::SetField<jlong>(*env2, jregion, *offlineRegionPtrId,
- reinterpret_cast<jlong>(new mbgl::OfflineRegion(std::move(*region))));
-
- // Invoke Java callback
- jni::CallMethod<void>(*env2, createCallback, *createOnCreateMethodId, jregion);
- }
-
- // Delete global refs and detach when we're done
- jni::DeleteGlobalRef(*env2, jni::UniqueGlobalRef<jni::jobject>(obj));
- jni::DeleteGlobalRef(*env2, jni::UniqueGlobalRef<jni::jobject>(createCallback));
- detach_jni_thread(theJVM, &env2, renderDetach);
- });
-}
-
-void setOfflineMapboxTileCountLimit(JNIEnv *env, jni::jobject* obj, jlong defaultFileSourcePtr, jlong limit) {
- // Checks
- assert(defaultFileSourcePtr != 0);
- assert(limit > 0);
-
- // Set limit
- mbgl::DefaultFileSource *defaultFileSource = reinterpret_cast<mbgl::DefaultFileSource *>(defaultFileSourcePtr);
- defaultFileSource->setOfflineMapboxTileCountLimit(limit);
-}
-
-mbgl::OfflineRegion* getOfflineRegionPeer(JNIEnv *env, jni::jobject* offlineRegion_) {
- jlong offlineRegionPtr = jni::GetField<jlong>(*env, offlineRegion_, *offlineRegionPtrId);
- if (!offlineRegionPtr) {
- jni::ThrowNew(*env, jni::FindClass(*env, "java/lang/IllegalStateException"),
- "Use of OfflineRegion after OfflineRegion.delete");
- }
- return reinterpret_cast<mbgl::OfflineRegion *>(offlineRegionPtr);
-}
-
-void destroyOfflineRegion(JNIEnv *env, jni::jobject* offlineRegion_) {
- // Offline region
- jlong offlineRegionPtr = jni::GetField<jlong>(*env, offlineRegion_, *offlineRegionPtrId);
- if (!offlineRegionPtr) {
- return; // Already deleted
- }
-
- // File source
- jni::jobject* jmanager = jni::GetField<jni::jobject*>(*env, offlineRegion_, *offlineRegionOfflineManagerId);
- jlong defaultFileSourcePtr = jni::GetField<jlong>(*env, jmanager, *offlineManagerClassPtrId);
- mbgl::DefaultFileSource *defaultFileSource = reinterpret_cast<mbgl::DefaultFileSource *>(defaultFileSourcePtr);
-
- // Release the observer and delete the region
- mbgl::OfflineRegion *offlineRegion = reinterpret_cast<mbgl::OfflineRegion *>(offlineRegionPtr);
- defaultFileSource->setOfflineRegionObserver(*offlineRegion, nullptr);
- jni::SetField<jlong>(*env, offlineRegion_, *offlineRegionPtrId, 0);
- delete offlineRegion;
-}
-
-void setOfflineRegionObserver(JNIEnv *env, jni::jobject* offlineRegion_, jni::jobject* observerCallback) {
- // Offline region
- mbgl::OfflineRegion* offlineRegion = getOfflineRegionPeer(env, offlineRegion_);
-
- // File source
- jni::jobject* jmanager = jni::GetField<jni::jobject*>(*env, offlineRegion_, *offlineRegionOfflineManagerId);
- jlong defaultFileSourcePtr = jni::GetField<jlong>(*env, jmanager, *offlineManagerClassPtrId);
- mbgl::DefaultFileSource *defaultFileSource = reinterpret_cast<mbgl::DefaultFileSource *>(defaultFileSourcePtr);
-
- // Define the observer
- class Observer : public mbgl::OfflineRegionObserver {
- public:
- Observer(jni::UniqueGlobalRef<jni::jobject>&& observerCallback_)
- : observerCallback(std::move(observerCallback_)) {
- }
-
- ~Observer() override {
- mbgl::Log::Debug(mbgl::Event::JNI, "~Observer()");
- // Env
- JNIEnv* env2;
- jboolean renderDetach = attach_jni_thread(theJVM, &env2, "Offline Thread");
- jni::DeleteGlobalRef(*env2, std::move(observerCallback));
- detach_jni_thread(theJVM, &env2, renderDetach);
- }
-
- void statusChanged(mbgl::OfflineRegionStatus status) override {
- // Env
- JNIEnv* env2;
- jboolean renderDetach = attach_jni_thread(theJVM, &env2, "Offline Thread");
-
- // Conver to jint
- jint downloadState;
- switch(status.downloadState) {
- case mbgl::OfflineRegionDownloadState::Inactive:
- downloadState = 0;
- break;
- case mbgl::OfflineRegionDownloadState::Active:
- downloadState = 1;
- break;
- }
-
- // Create a new local reference frame (capacity 1 for the NewObject allocation below)
- // to avoid a local reference table overflow (#4706)
- jni::UniqueLocalFrame frame = jni::PushLocalFrame(*env2, 1);
-
- // Stats object
- jni::jobject* jstatus = &jni::NewObject(*env2, *offlineRegionStatusClass, *offlineRegionStatusConstructorId);
- jni::SetField<jint>(*env2, jstatus, *offlineRegionStatusDownloadStateId, downloadState);
- jni::SetField<jlong>(*env2, jstatus, *offlineRegionStatusCompletedResourceCountId, status.completedResourceCount);
- jni::SetField<jlong>(*env2, jstatus, *offlineRegionStatusCompletedResourceSizeId, status.completedResourceSize);
- jni::SetField<jlong>(*env2, jstatus, *offlineRegionStatusCompletedTileCountId, status.completedTileCount);
- jni::SetField<jlong>(*env2, jstatus, *offlineRegionStatusCompletedTileSizeId, status.completedTileSize);
- jni::SetField<jlong>(*env2, jstatus, *offlineRegionStatusRequiredResourceCountId, status.requiredResourceCount);
- jni::SetField<jboolean>(*env2, jstatus, *offlineRegionStatusRequiredResourceCountIsPreciseId, status.requiredResourceCountIsPrecise);
- jni::CallMethod<void>(*env2, observerCallback.get(), *offlineRegionObserveronStatusChangedId, jstatus);
-
- // Detach when we're done
- detach_jni_thread(theJVM, &env2, renderDetach);
- }
-
- void responseError(mbgl::Response::Error error) override {
- // Env
- JNIEnv* env2;
- jboolean renderDetach = attach_jni_thread(theJVM, &env2, "Offline Thread");
-
- // Handle the value of reason independently of the underlying int value
- std::string errorReason;
- switch(error.reason) {
- case mbgl::Response::Error::Reason::Success:
- errorReason = "REASON_SUCCESS";
- break;
- case mbgl::Response::Error::Reason::NotFound:
- errorReason = "REASON_NOT_FOUND";
- break;
- case mbgl::Response::Error::Reason::Server:
- errorReason = "REASON_SERVER";
- break;
- case mbgl::Response::Error::Reason::Connection:
- errorReason = "REASON_CONNECTION";
- break;
- case mbgl::Response::Error::Reason::RateLimit:
- errorReason = "REASON_RATE_LIMIT";
- break;
- case mbgl::Response::Error::Reason::Other:
- errorReason = "REASON_OTHER";
- break;
- }
-
- // Error object
- jni::UniqueLocalFrame frame = jni::PushLocalFrame(*env2, 3);
- jni::jobject* jerror = &jni::NewObject(*env2, *offlineRegionErrorClass, *offlineRegionErrorConstructorId);
- jni::SetField<jni::jobject*>(*env2, jerror, *offlineRegionErrorReasonId, std_string_to_jstring(env2, errorReason));
- jni::SetField<jni::jobject*>(*env2, jerror, *offlineRegionErrorMessageId, std_string_to_jstring(env2, error.message));
- jni::CallMethod<void>(*env2, observerCallback.get(), *offlineRegionObserveronErrorId, jerror);
-
- // Detach when we're done
- detach_jni_thread(theJVM, &env2, renderDetach);
- }
-
- void mapboxTileCountLimitExceeded(uint64_t limit) override {
- // Env
- JNIEnv* env2;
- jboolean renderDetach = attach_jni_thread(theJVM, &env2, "Offline Thread");
-
- // Send limit
- jni::CallMethod<void>(*env2, observerCallback.get(), *offlineRegionObserveronLimitId, jlong(limit));
-
- // Detach when we're done
- detach_jni_thread(theJVM, &env2, renderDetach);
- }
-
- jni::UniqueGlobalRef<jni::jobject> observerCallback;
- };
-
- // Set the observer
- defaultFileSource->setOfflineRegionObserver(*offlineRegion,
- std::make_unique<Observer>(jni::NewGlobalRef(*env, observerCallback)));
-}
-
-void setOfflineRegionDownloadState(JNIEnv *env, jni::jobject* offlineRegion_, jint offlineRegionDownloadState) {
- // State
- mbgl::OfflineRegionDownloadState state;
- if (offlineRegionDownloadState == 0) {
- state = mbgl::OfflineRegionDownloadState::Inactive;
- } else if (offlineRegionDownloadState == 1) {
- state = mbgl::OfflineRegionDownloadState::Active;
- } else {
- mbgl::Log::Error(mbgl::Event::JNI, "State can only be 0 (inactive) or 1 (active).");
- return;
- }
-
- // Offline region
- mbgl::OfflineRegion* offlineRegion = getOfflineRegionPeer(env, offlineRegion_);
-
- // File source
- jni::jobject* jmanager = jni::GetField<jni::jobject*>(*env, offlineRegion_, *offlineRegionOfflineManagerId);
- jlong defaultFileSourcePtr = jni::GetField<jlong>(*env, jmanager, *offlineManagerClassPtrId);
- mbgl::DefaultFileSource *defaultFileSource = reinterpret_cast<mbgl::DefaultFileSource *>(defaultFileSourcePtr);
-
- // Set new state
- defaultFileSource->setOfflineRegionDownloadState(*offlineRegion, state);
-}
-
-void getOfflineRegionStatus(JNIEnv *env, jni::jobject* offlineRegion_, jni::jobject* statusCallback) {
- // Offline region
- mbgl::OfflineRegion* offlineRegion = getOfflineRegionPeer(env, offlineRegion_);
-
- // File source
- jni::jobject* jmanager = jni::GetField<jni::jobject*>(*env, offlineRegion_, *offlineRegionOfflineManagerId);
- jlong defaultFileSourcePtr = jni::GetField<jlong>(*env, jmanager, *offlineManagerClassPtrId);
- mbgl::DefaultFileSource *defaultFileSource = reinterpret_cast<mbgl::DefaultFileSource *>(defaultFileSourcePtr);
-
- // Makes sure the callback doesn't get GC'ed
- statusCallback = jni::NewGlobalRef(*env, statusCallback).release();
-
- // Set new state
- defaultFileSource->getOfflineRegionStatus(*offlineRegion, [statusCallback](std::exception_ptr error, mbgl::optional<mbgl::OfflineRegionStatus> status) mutable {
-
- // Reattach, the callback comes from a different thread
- JNIEnv *env2;
- jboolean renderDetach = attach_jni_thread(theJVM, &env2, "Offline Thread");
- if (renderDetach) {
- mbgl::Log::Debug(mbgl::Event::JNI, "Attached.");
- }
-
- if (error) {
- std::string message = mbgl::util::toString(error);
- jni::CallMethod<void>(*env2, statusCallback, *offlineRegionStatusOnErrorId, std_string_to_jstring(env2, message));
- } else if (status) {
- // Conver to jint
- jint downloadState = -1;
- if (status->downloadState == mbgl::OfflineRegionDownloadState::Inactive) {
- downloadState = 0;
- } else if (status->downloadState == mbgl::OfflineRegionDownloadState::Active) {
- downloadState = 1;
- } else {
- mbgl::Log::Error(mbgl::Event::JNI, "Unsupported OfflineRegionDownloadState value.");
- return;
- }
-
- // Stats object
- jni::jobject* jstatus = &jni::NewObject(*env2, *offlineRegionStatusClass, *offlineRegionStatusConstructorId);
- jni::SetField<jint>(*env2, jstatus, *offlineRegionStatusDownloadStateId, downloadState);
- jni::SetField<jlong>(*env2, jstatus, *offlineRegionStatusCompletedResourceCountId, status->completedResourceCount);
- jni::SetField<jlong>(*env2, jstatus, *offlineRegionStatusCompletedResourceSizeId, status->completedResourceSize);
- jni::SetField<jlong>(*env2, jstatus, *offlineRegionStatusRequiredResourceCountId, status->requiredResourceCount);
- jni::SetField<jboolean>(*env2, jstatus, *offlineRegionStatusRequiredResourceCountIsPreciseId, status->requiredResourceCountIsPrecise);
- jni::CallMethod<void>(*env2, statusCallback, *offlineRegionStatusOnStatusId, jstatus);
- }
-
- // Delete global refs and detach when we're done
- jni::DeleteGlobalRef(*env2, jni::UniqueGlobalRef<jni::jobject>(statusCallback));
- detach_jni_thread(theJVM, &env2, renderDetach);
- });
-}
-
-void deleteOfflineRegion(JNIEnv *env, jni::jobject* offlineRegion_, jni::jobject* deleteCallback) {
- // Offline region
- mbgl::OfflineRegion* offlineRegion = getOfflineRegionPeer(env, offlineRegion_);
-
- // File source
- jni::jobject* jmanager = jni::GetField<jni::jobject*>(*env, offlineRegion_, *offlineRegionOfflineManagerId);
- jlong defaultFileSourcePtr = jni::GetField<jlong>(*env, jmanager, *offlineManagerClassPtrId);
- mbgl::DefaultFileSource *defaultFileSource = reinterpret_cast<mbgl::DefaultFileSource *>(defaultFileSourcePtr);
-
- // Makes sure the callback doesn't get GC'ed
- deleteCallback = jni::NewGlobalRef(*env, deleteCallback).release();
-
- // Set new state
- jni::SetField<jlong>(*env, offlineRegion_, *offlineRegionPtrId, 0);
- defaultFileSource->deleteOfflineRegion(std::move(*offlineRegion), [deleteCallback](std::exception_ptr error) mutable {
-
- // Reattach, the callback comes from a different thread
- JNIEnv *env2;
- jboolean renderDetach = attach_jni_thread(theJVM, &env2, "Offline Thread");
- if (renderDetach) {
- mbgl::Log::Debug(mbgl::Event::JNI, "Attached.");
- }
-
- if (error) {
- std::string message = mbgl::util::toString(error);
- jni::CallMethod<void>(*env2, deleteCallback, *offlineRegionDeleteOnErrorId, std_string_to_jstring(env2, message));
- } else {
- jni::CallMethod<void>(*env2, deleteCallback, *offlineRegionDeleteOnDeleteId);
- }
-
- // Delete global refs and detach when we're done
- jni::DeleteGlobalRef(*env2, jni::UniqueGlobalRef<jni::jobject>(deleteCallback));
- detach_jni_thread(theJVM, &env2, renderDetach);
- });
-}
-
-void updateOfflineRegionMetadata(JNIEnv *env, jni::jobject* offlineRegion_, jni::jarray<jbyte>* metadata_, jni::jobject* updateCallback) {
- // Offline region
- mbgl::OfflineRegion* offlineRegion = getOfflineRegionPeer(env, offlineRegion_);
-
- // File source
- jni::jobject* jmanager = jni::GetField<jni::jobject*>(*env, offlineRegion_, *offlineRegionOfflineManagerId);
- jlong defaultFileSourcePtr = jni::GetField<jlong>(*env, jmanager, *offlineManagerClassPtrId);
- mbgl::DefaultFileSource *defaultFileSource = reinterpret_cast<mbgl::DefaultFileSource *>(defaultFileSourcePtr);
-
- // Id conversion
- int64_t id = offlineRegion->getID();
-
- // Metadata
- mbgl::OfflineRegionMetadata metadata;
- if (metadata_ != nullptr) {
- metadata = metadata_from_java(env, *metadata_);
- }
-
- // Makes sure the objects don't get GC'ed
- updateCallback = jni::NewGlobalRef(*env, updateCallback).release();
-
- // Launch updateCallback
- defaultFileSource->updateOfflineMetadata(id, metadata, [updateCallback] (std::exception_ptr error, mbgl::optional<mbgl::OfflineRegionMetadata> data) mutable {
- // Reattach, the callback comes from a different thread
- JNIEnv *env2;
- jboolean renderDetach = attach_jni_thread(theJVM, &env2, "Offline Thread");
- if (renderDetach) {
- mbgl::Log::Debug(mbgl::Event::JNI, "Attached.");
- }
-
- if (error) {
- std::string message = mbgl::util::toString(error);
- jni::CallMethod<void>(*env2, updateCallback, *updateMetadataOnErrorMethodId, std_string_to_jstring(env2, message));
- } else if (data) {
- jni::jarray<jbyte>* jmetadata = metadata_from_native(env2, *data);
- jni::CallMethod<void>(*env2, updateCallback, *updateMetadataOnUpdateMethodId, jmetadata);
- }
-
- // Delete global refs and detach when we're done
- jni::DeleteGlobalRef(*env2, jni::UniqueGlobalRef<jni::jobject>(updateCallback));
- detach_jni_thread(theJVM, &env2, renderDetach);
- });
-}
-
-// Offline calls end
-
-} // anonymous
-
-namespace mbgl {
-namespace android {
-
void registerNatives(JavaVM *vm) {
theJVM = vm;
jni::JNIEnv& env = jni::GetEnv(*vm, jni::jni_version_1_6);
+ // For the DefaultFileSource
static mbgl::util::RunLoop mainRunLoop;
+ FileSource::registerNative(env);
- mbgl::android::RegisterNativeHTTPRequest(env);
-
+ // Basic types
java::registerNatives(env);
- registerNativeLayers(env);
- registerNativeSources(env);
- ConnectivityListener::registerNative(env);
-
- latLngClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/geometry/LatLng");
- latLngClass = jni::NewGlobalRef(env, latLngClass).release();
- latLngConstructorId = &jni::GetMethodID(env, *latLngClass, "<init>", "(DD)V");
- latLngLatitudeId = &jni::GetFieldID(env, *latLngClass, "latitude", "D");
- latLngLongitudeId = &jni::GetFieldID(env, *latLngClass, "longitude", "D");
-
- latLngBoundsClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/geometry/LatLngBounds");
- latLngBoundsClass = jni::NewGlobalRef(env, latLngBoundsClass).release();
- latLngBoundsConstructorId = &jni::GetMethodID(env, *latLngBoundsClass, "<init>", "(DDDD)V");
- latLngBoundsLatNorthId = &jni::GetFieldID(env, *latLngBoundsClass, "mLatNorth", "D");
- latLngBoundsLatSouthId = &jni::GetFieldID(env, *latLngBoundsClass, "mLatSouth", "D");
- latLngBoundsLonEastId = &jni::GetFieldID(env, *latLngBoundsClass, "mLonEast", "D");
- latLngBoundsLonWestId = &jni::GetFieldID(env, *latLngBoundsClass, "mLonWest", "D");
-
- iconClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/annotations/Icon");
- iconClass = jni::NewGlobalRef(env, iconClass).release();
- iconIdId = &jni::GetFieldID(env, *iconClass, "mId", "Ljava/lang/String;");
-
- markerClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/annotations/Marker");
- markerClass = jni::NewGlobalRef(env, markerClass).release();
- markerPositionId = &jni::GetFieldID(env, *markerClass, "position", "Lcom/mapbox/mapboxsdk/geometry/LatLng;");
- markerIconId = &jni::GetFieldID(env, *markerClass, "icon", "Lcom/mapbox/mapboxsdk/annotations/Icon;");
- markerIdId = &jni::GetFieldID(env, *markerClass, "id", "J");
-
- polylineClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/annotations/Polyline");
- polylineClass = jni::NewGlobalRef(env, polylineClass).release();
- polylineAlphaId = &jni::GetFieldID(env, *polylineClass, "alpha", "F");
- polylineColorId = &jni::GetFieldID(env, *polylineClass, "color", "I");
- polylineWidthId = &jni::GetFieldID(env, *polylineClass, "width", "F");
- polylinePointsId = &jni::GetFieldID(env, *polylineClass, "points", "Ljava/util/List;");
-
- polygonClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/annotations/Polygon");
- polygonClass = jni::NewGlobalRef(env, polygonClass).release();
- polygonAlphaId = &jni::GetFieldID(env, *polygonClass, "alpha", "F");
- polygonFillColorId = &jni::GetFieldID(env, *polygonClass, "fillColor", "I");
- polygonStrokeColorId = &jni::GetFieldID(env, *polygonClass, "strokeColor", "I");
- polygonPointsId = &jni::GetFieldID(env, *polygonClass, "points", "Ljava/util/List;");
-
- jni::jclass* listClass = &jni::FindClass(env, "java/util/List");
- listToArrayId = &jni::GetMethodID(env, *listClass, "toArray", "()[Ljava/lang/Object;");
-
- arrayListClass = &jni::FindClass(env, "java/util/ArrayList");
- arrayListClass = jni::NewGlobalRef(env, arrayListClass).release();
- arrayListConstructorId = &jni::GetMethodID(env, *arrayListClass, "<init>", "()V");
- arrayListAddId = &jni::GetMethodID(env, *arrayListClass, "add", "(Ljava/lang/Object;)Z");
-
- projectedMetersClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/geometry/ProjectedMeters");
- projectedMetersClass = jni::NewGlobalRef(env, projectedMetersClass).release();
- projectedMetersConstructorId = &jni::GetMethodID(env, *projectedMetersClass, "<init>", "(DD)V");
- projectedMetersNorthingId = &jni::GetFieldID(env, *projectedMetersClass, "northing", "D");
- projectedMetersEastingId = &jni::GetFieldID(env, *projectedMetersClass, "easting", "D");
-
- pointFClass = &jni::FindClass(env, "android/graphics/PointF");
- pointFClass = jni::NewGlobalRef(env, pointFClass).release();
- pointFConstructorId = &jni::GetMethodID(env, *pointFClass, "<init>", "(FF)V");
- pointFXId = &jni::GetFieldID(env, *pointFClass, "x", "F");
- pointFYId = &jni::GetFieldID(env, *pointFClass, "y", "F");
-
- rectFClass = &jni::FindClass(env, "android/graphics/RectF");
- rectFClass = jni::NewGlobalRef(env, rectFClass).release();
- rectFConstructorId = &jni::GetMethodID(env, *rectFClass, "<init>", "()V");
- rectFLeftId = &jni::GetFieldID(env, *rectFClass, "left", "F");
- rectFRightId = &jni::GetFieldID(env, *rectFClass, "right", "F");
- rectFTopId = &jni::GetFieldID(env, *rectFClass, "top", "F");
- rectFBottomId = &jni::GetFieldID(env, *rectFClass, "bottom", "F");
-
- jni::jclass& nativeMapViewClass = jni::FindClass(env, "com/mapbox/mapboxsdk/maps/NativeMapView");
-
- onInvalidateId = &jni::GetMethodID(env, nativeMapViewClass, "onInvalidate", "()V");
- onMapChangedId = &jni::GetMethodID(env, nativeMapViewClass, "onMapChanged", "(I)V");
- onFpsChangedId = &jni::GetMethodID(env, nativeMapViewClass, "onFpsChanged", "(D)V");
- onSnapshotReadyId = &jni::GetMethodID(env, nativeMapViewClass, "onSnapshotReady","([B)V");
-
- #define MAKE_NATIVE_METHOD(name, sig) jni::MakeNativeMethod<decltype(name), name>( #name, sig )
-
- jni::RegisterNatives(env, nativeMapViewClass,
- MAKE_NATIVE_METHOD(nativeCreate, "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;FIJ)J"),
- MAKE_NATIVE_METHOD(nativeDestroy, "(J)V"),
- MAKE_NATIVE_METHOD(nativeInitializeDisplay, "(J)V"),
- MAKE_NATIVE_METHOD(nativeTerminateDisplay, "(J)V"),
- MAKE_NATIVE_METHOD(nativeInitializeContext, "(J)V"),
- MAKE_NATIVE_METHOD(nativeTerminateContext, "(J)V"),
- MAKE_NATIVE_METHOD(nativeCreateSurface, "(JLandroid/view/Surface;)V"),
- MAKE_NATIVE_METHOD(nativeDestroySurface, "(J)V"),
- MAKE_NATIVE_METHOD(nativeUpdate, "(J)V"),
- MAKE_NATIVE_METHOD(nativeRender, "(J)V"),
- MAKE_NATIVE_METHOD(nativeViewResize, "(JII)V"),
- MAKE_NATIVE_METHOD(nativeFramebufferResize, "(JII)V"),
- MAKE_NATIVE_METHOD(nativeAddClass, "(JLjava/lang/String;)V"),
- MAKE_NATIVE_METHOD(nativeRemoveClass, "(JLjava/lang/String;)V"),
- MAKE_NATIVE_METHOD(nativeHasClass, "(JLjava/lang/String;)Z"),
- MAKE_NATIVE_METHOD(nativeSetClasses, "(JLjava/util/List;)V"),
- MAKE_NATIVE_METHOD(nativeGetClasses, "(J)Ljava/util/List;"),
- MAKE_NATIVE_METHOD(nativeSetStyleUrl, "(JLjava/lang/String;)V"),
- MAKE_NATIVE_METHOD(nativeGetStyleUrl, "(J)Ljava/lang/String;"),
- MAKE_NATIVE_METHOD(nativeSetStyleJson, "(JLjava/lang/String;)V"),
- MAKE_NATIVE_METHOD(nativeGetStyleJson, "(J)Ljava/lang/String;"),
- MAKE_NATIVE_METHOD(nativeSetAccessToken, "(JLjava/lang/String;)V"),
- MAKE_NATIVE_METHOD(nativeGetAccessToken, "(J)Ljava/lang/String;"),
- MAKE_NATIVE_METHOD(nativeCancelTransitions, "(J)V"),
- MAKE_NATIVE_METHOD(nativeSetGestureInProgress, "(JZ)V"),
- MAKE_NATIVE_METHOD(nativeMoveBy, "(JDDJ)V"),
- MAKE_NATIVE_METHOD(nativeSetLatLng, "(JDDJ)V"),
- MAKE_NATIVE_METHOD(nativeGetLatLng, "(J)Lcom/mapbox/mapboxsdk/geometry/LatLng;"),
- MAKE_NATIVE_METHOD(nativeResetPosition, "(J)V"),
- MAKE_NATIVE_METHOD(nativeGetCameraValues, "(J)[D"),
- MAKE_NATIVE_METHOD(nativeGetPitch, "(J)D"),
- MAKE_NATIVE_METHOD(nativeSetPitch, "(JDJ)V"),
- MAKE_NATIVE_METHOD(nativeScaleBy, "(JDDDJ)V"),
- MAKE_NATIVE_METHOD(nativeSetScale, "(JDDDJ)V"),
- MAKE_NATIVE_METHOD(nativeGetScale, "(J)D"),
- MAKE_NATIVE_METHOD(nativeSetZoom, "(JDJ)V"),
- MAKE_NATIVE_METHOD(nativeGetZoom, "(J)D"),
- MAKE_NATIVE_METHOD(nativeResetZoom, "(J)V"),
- MAKE_NATIVE_METHOD(nativeGetMinZoom, "(J)D"),
- MAKE_NATIVE_METHOD(nativeSetMinZoom, "(JD)V"),
- MAKE_NATIVE_METHOD(nativeGetMaxZoom, "(J)D"),
- MAKE_NATIVE_METHOD(nativeSetMaxZoom, "(JD)V"),
- MAKE_NATIVE_METHOD(nativeRotateBy, "(JDDDDJ)V"),
- MAKE_NATIVE_METHOD(nativeSetBearing, "(JDJ)V"),
- MAKE_NATIVE_METHOD(nativeSetBearingXY, "(JDDD)V"),
- MAKE_NATIVE_METHOD(nativeGetBearing, "(J)D"),
- MAKE_NATIVE_METHOD(nativeResetNorth, "(J)V"),
- MAKE_NATIVE_METHOD(nativeAddMarkers, "(J[Lcom/mapbox/mapboxsdk/annotations/Marker;)[J"),
- MAKE_NATIVE_METHOD(nativeAddPolylines, "(J[Lcom/mapbox/mapboxsdk/annotations/Polyline;)[J"),
- MAKE_NATIVE_METHOD(nativeAddPolygons, "(J[Lcom/mapbox/mapboxsdk/annotations/Polygon;)[J"),
- MAKE_NATIVE_METHOD(nativeUpdateMarker, "(JJDDLjava/lang/String;)V"),
- MAKE_NATIVE_METHOD(nativeUpdatePolygon, "(JJLcom/mapbox/mapboxsdk/annotations/Polygon;)V"),
- MAKE_NATIVE_METHOD(nativeUpdatePolyline, "(JJLcom/mapbox/mapboxsdk/annotations/Polyline;)V"),
- MAKE_NATIVE_METHOD(nativeRemoveAnnotations, "(J[J)V"),
- MAKE_NATIVE_METHOD(nativeQueryPointAnnotations, "(JLandroid/graphics/RectF;)[J"),
- MAKE_NATIVE_METHOD(nativeAddAnnotationIcon, "(JLjava/lang/String;IIF[B)V"),
- MAKE_NATIVE_METHOD(nativeSetVisibleCoordinateBounds, "(J[Lcom/mapbox/mapboxsdk/geometry/LatLng;Landroid/graphics/RectF;DJ)V"),
- MAKE_NATIVE_METHOD(nativeOnLowMemory, "(J)V"),
- MAKE_NATIVE_METHOD(nativeSetDebug, "(JZ)V"),
- MAKE_NATIVE_METHOD(nativeToggleDebug, "(J)V"),
- MAKE_NATIVE_METHOD(nativeGetDebug, "(J)Z"),
- MAKE_NATIVE_METHOD(nativeIsFullyLoaded, "(J)Z"),
- MAKE_NATIVE_METHOD(nativeSetReachability, "(JZ)V"),
- MAKE_NATIVE_METHOD(nativeGetMetersPerPixelAtLatitude, "(JDD)D"),
- MAKE_NATIVE_METHOD(nativeProjectedMetersForLatLng, "(JDD)Lcom/mapbox/mapboxsdk/geometry/ProjectedMeters;"),
- MAKE_NATIVE_METHOD(nativeLatLngForProjectedMeters, "(JDD)Lcom/mapbox/mapboxsdk/geometry/LatLng;"),
- MAKE_NATIVE_METHOD(nativePixelForLatLng, "(JDD)Landroid/graphics/PointF;"),
- MAKE_NATIVE_METHOD(nativeLatLngForPixel, "(JFF)Lcom/mapbox/mapboxsdk/geometry/LatLng;"),
- MAKE_NATIVE_METHOD(nativeGetTopOffsetPixelsForAnnotationSymbol, "(JLjava/lang/String;)D"),
- MAKE_NATIVE_METHOD(nativeJumpTo, "(JDDDDD)V"),
- MAKE_NATIVE_METHOD(nativeEaseTo, "(JDDDJDDZ)V"),
- MAKE_NATIVE_METHOD(nativeFlyTo, "(JDDDJDD)V"),
- MAKE_NATIVE_METHOD(nativeGetTransitionDuration, "(J)J"),
- MAKE_NATIVE_METHOD(nativeSetTransitionDuration, "(JJ)V"),
- MAKE_NATIVE_METHOD(nativeGetTransitionDelay, "(J)J"),
- MAKE_NATIVE_METHOD(nativeSetTransitionDelay, "(JJ)V"),
- MAKE_NATIVE_METHOD(nativeGetLayer, "(JLjava/lang/String;)Lcom/mapbox/mapboxsdk/style/layers/Layer;"),
- MAKE_NATIVE_METHOD(nativeAddLayer, "(JJLjava/lang/String;)V"),
- MAKE_NATIVE_METHOD(nativeRemoveLayerById, "(JLjava/lang/String;)V"),
- MAKE_NATIVE_METHOD(nativeRemoveLayer, "(JJ)V"),
- MAKE_NATIVE_METHOD(nativeGetSource, "(JLjava/lang/String;)Lcom/mapbox/mapboxsdk/style/sources/Source;"),
- MAKE_NATIVE_METHOD(nativeAddSource, "(JJ)V"),
- MAKE_NATIVE_METHOD(nativeRemoveSourceById, "(JLjava/lang/String;)V"),
- MAKE_NATIVE_METHOD(nativeRemoveSource, "(JJ)V"),
- MAKE_NATIVE_METHOD(nativeAddImage, "(JLjava/lang/String;IIF[B)V"),
- MAKE_NATIVE_METHOD(nativeRemoveImage, "(JLjava/lang/String;)V"),
- MAKE_NATIVE_METHOD(nativeSetContentPadding, "(JDDDD)V"),
- MAKE_NATIVE_METHOD(nativeScheduleTakeSnapshot, "(J)V"),
- MAKE_NATIVE_METHOD(nativeQueryRenderedFeaturesForPoint, "(JFF[Ljava/lang/String;)[Lcom/mapbox/services/commons/geojson/Feature;"),
- MAKE_NATIVE_METHOD(nativeQueryRenderedFeaturesForBox, "(JFFFF[Ljava/lang/String;)[Lcom/mapbox/services/commons/geojson/Feature;"),
- MAKE_NATIVE_METHOD(nativeSetAPIBaseURL, "(JLjava/lang/String;)V")
- );
+ java::util::registerNative(env);
+ PointF::registerNative(env);
+ RectF::registerNative(env);
- // Offline begin
+ // Geometry
+ Feature::registerNative(env);
+ LatLng::registerNative(env);
+ LatLngBounds::registerNative(env);
+ ProjectedMeters::registerNative(env);
- struct OfflineManager {
- static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineManager"; }
+ //Annotation
+ Marker::registerNative(env);
+ Polygon::registerNative(env);
+ Polyline::registerNative(env);
- struct ListOfflineRegionsCallback {
- static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineManager$ListOfflineRegionsCallback"; }
- };
+ // Map
+ NativeMapView::registerNative(env);
- struct CreateOfflineRegionsCallback {
- static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineManager$CreateOfflineRegionCallback"; }
- };
- };
+ // Http
+ RegisterNativeHTTPRequest(env);
- struct OfflineRegion {
- static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion"; }
- };
+ // Bitmap
+ Bitmap::registerNative(env);
+ BitmapFactory::registerNative(env);
- jni::Class<OfflineManager> offlineManagerClass = jni::Class<OfflineManager>::Find(env);
- offlineManagerClassPtrId = &jni::GetFieldID(env, offlineManagerClass, "mDefaultFileSourcePtr", "J");
-
- jni::RegisterNatives(env, offlineManagerClass,
- MAKE_NATIVE_METHOD(createDefaultFileSource, "(Ljava/lang/String;Ljava/lang/String;J)J"),
- MAKE_NATIVE_METHOD(setAccessToken, "(JLjava/lang/String;)V"),
- MAKE_NATIVE_METHOD(getAccessToken, "(J)Ljava/lang/String;"),
- MAKE_NATIVE_METHOD(listOfflineRegions, "(JLcom/mapbox/mapboxsdk/offline/OfflineManager$ListOfflineRegionsCallback;)V"),
- MAKE_NATIVE_METHOD(createOfflineRegion, "(JLcom/mapbox/mapboxsdk/offline/OfflineRegionDefinition;[BLcom/mapbox/mapboxsdk/offline/OfflineManager$CreateOfflineRegionCallback;)V"),
- MAKE_NATIVE_METHOD(setOfflineMapboxTileCountLimit, "(JJ)V")
- );
-
- jni::Class<OfflineManager::ListOfflineRegionsCallback> listOfflineRegionsCallbackClass = jni::Class<OfflineManager::ListOfflineRegionsCallback>::Find(env);
- listOnListMethodId = &jni::GetMethodID(env, listOfflineRegionsCallbackClass, "onList", "([Lcom/mapbox/mapboxsdk/offline/OfflineRegion;)V");
- listOnErrorMethodId = &jni::GetMethodID(env, listOfflineRegionsCallbackClass, "onError", "(Ljava/lang/String;)V");
-
- jni::Class<OfflineManager::CreateOfflineRegionsCallback> createOfflineRegionCallbackClass = jni::Class<OfflineManager::CreateOfflineRegionsCallback>::Find(env);
- createOnCreateMethodId = &jni::GetMethodID(env, createOfflineRegionCallbackClass, "onCreate", "(Lcom/mapbox/mapboxsdk/offline/OfflineRegion;)V");
- createOnErrorMethodId = &jni::GetMethodID(env, createOfflineRegionCallbackClass, "onError", "(Ljava/lang/String;)V");
-
- offlineRegionClass = &jni::FindClass(env, OfflineRegion::Name());
- offlineRegionClass = jni::NewGlobalRef(env, offlineRegionClass).release();
- offlineRegionConstructorId = &jni::GetMethodID(env, *offlineRegionClass, "<init>", "()V");
- offlineRegionOfflineManagerId = &jni::GetFieldID(env, *offlineRegionClass, "offlineManager", "Lcom/mapbox/mapboxsdk/offline/OfflineManager;");
- offlineRegionIdId = &jni::GetFieldID(env, *offlineRegionClass, "mId", "J");
- offlineRegionDefinitionId = &jni::GetFieldID(env, *offlineRegionClass, "mDefinition", "Lcom/mapbox/mapboxsdk/offline/OfflineRegionDefinition;");
- offlineRegionMetadataId = &jni::GetFieldID(env, *offlineRegionClass, "mMetadata", "[B");
- offlineRegionPtrId = &jni::GetFieldID(env, *offlineRegionClass, "mOfflineRegionPtr", "J");
-
- jni::RegisterNatives(env, *offlineRegionClass,
- MAKE_NATIVE_METHOD(destroyOfflineRegion, "()V"),
- MAKE_NATIVE_METHOD(setOfflineRegionObserver, "(Lcom/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionObserver;)V"),
- MAKE_NATIVE_METHOD(setOfflineRegionDownloadState, "(I)V"),
- MAKE_NATIVE_METHOD(getOfflineRegionStatus, "(Lcom/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionStatusCallback;)V"),
- MAKE_NATIVE_METHOD(deleteOfflineRegion, "(Lcom/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionDeleteCallback;)V"),
- MAKE_NATIVE_METHOD(updateOfflineRegionMetadata, "([BLcom/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionUpdateMetadataCallback;)V")
- );
-
- // This needs to be updated once we support more than one type of region definition
- offlineRegionDefinitionClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition");
- offlineRegionDefinitionClass = jni::NewGlobalRef(env, offlineRegionDefinitionClass).release();
- offlineRegionDefinitionConstructorId = &jni::GetMethodID(env, *offlineRegionDefinitionClass, "<init>", "()V");
- offlineRegionDefinitionStyleURLId = &jni::GetFieldID(env, *offlineRegionDefinitionClass, "styleURL", "Ljava/lang/String;");
- offlineRegionDefinitionBoundsId = &jni::GetFieldID(env, *offlineRegionDefinitionClass, "bounds", "Lcom/mapbox/mapboxsdk/geometry/LatLngBounds;");
- offlineRegionDefinitionMinZoomId = &jni::GetFieldID(env, *offlineRegionDefinitionClass, "minZoom", "D");
- offlineRegionDefinitionMaxZoomId = &jni::GetFieldID(env, *offlineRegionDefinitionClass, "maxZoom", "D");
- offlineRegionDefinitionPixelRatioId = &jni::GetFieldID(env, *offlineRegionDefinitionClass, "pixelRatio", "F");
-
- jni::jclass* offlineRegionObserverClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionObserver");
- offlineRegionObserveronStatusChangedId = &jni::GetMethodID(env, *offlineRegionObserverClass, "onStatusChanged", "(Lcom/mapbox/mapboxsdk/offline/OfflineRegionStatus;)V");
- offlineRegionObserveronErrorId = &jni::GetMethodID(env, *offlineRegionObserverClass, "onError", "(Lcom/mapbox/mapboxsdk/offline/OfflineRegionError;)V");
- offlineRegionObserveronLimitId = &jni::GetMethodID(env, *offlineRegionObserverClass, "mapboxTileCountLimitExceeded", "(J)V");
-
- offlineRegionStatusClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/offline/OfflineRegionStatus");
- offlineRegionStatusClass = jni::NewGlobalRef(env, offlineRegionStatusClass).release();
- offlineRegionStatusConstructorId = &jni::GetMethodID(env, *offlineRegionStatusClass, "<init>", "()V");
- offlineRegionStatusDownloadStateId = &jni::GetFieldID(env, *offlineRegionStatusClass, "downloadState", "I");
- offlineRegionStatusCompletedResourceCountId = &jni::GetFieldID(env, *offlineRegionStatusClass, "completedResourceCount", "J");
- offlineRegionStatusCompletedResourceSizeId = &jni::GetFieldID(env, *offlineRegionStatusClass, "completedResourceSize", "J");
- offlineRegionStatusCompletedTileCountId = &jni::GetFieldID(env, *offlineRegionStatusClass, "completedTileCount", "J");
- offlineRegionStatusCompletedTileSizeId = &jni::GetFieldID(env, *offlineRegionStatusClass, "completedTileSize", "J");
- offlineRegionStatusRequiredResourceCountId = &jni::GetFieldID(env, *offlineRegionStatusClass, "requiredResourceCount", "J");
- offlineRegionStatusRequiredResourceCountIsPreciseId = &jni::GetFieldID(env, *offlineRegionStatusClass, "requiredResourceCountIsPrecise", "Z");
-
- offlineRegionErrorClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/offline/OfflineRegionError");
- offlineRegionErrorClass = jni::NewGlobalRef(env, offlineRegionErrorClass).release();
- offlineRegionErrorConstructorId = &jni::GetMethodID(env, *offlineRegionErrorClass, "<init>", "()V");
- offlineRegionErrorReasonId = &jni::GetFieldID(env, *offlineRegionErrorClass, "reason", "Ljava/lang/String;");
- offlineRegionErrorMessageId = &jni::GetFieldID(env, *offlineRegionErrorClass, "message", "Ljava/lang/String;");
-
- jni::jclass* offlineRegionStatusCallbackClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionStatusCallback");
- offlineRegionStatusOnStatusId = &jni::GetMethodID(env, *offlineRegionStatusCallbackClass, "onStatus", "(Lcom/mapbox/mapboxsdk/offline/OfflineRegionStatus;)V");
- offlineRegionStatusOnErrorId = &jni::GetMethodID(env, *offlineRegionStatusCallbackClass, "onError", "(Ljava/lang/String;)V");
-
- jni::jclass* offlineRegionDeleteCallbackClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionDeleteCallback");
- offlineRegionDeleteOnDeleteId = &jni::GetMethodID(env, *offlineRegionDeleteCallbackClass, "onDelete", "()V");
- offlineRegionDeleteOnErrorId = &jni::GetMethodID(env, *offlineRegionDeleteCallbackClass, "onError", "(Ljava/lang/String;)V");
-
- jni::jclass* offlineRegionUpdateMetadataCallbackClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionUpdateMetadataCallback");
- updateMetadataOnUpdateMethodId = &jni::GetMethodID(env, *offlineRegionUpdateMetadataCallbackClass, "onUpdate", "([B)V");
- updateMetadataOnErrorMethodId = &jni::GetMethodID(env, *offlineRegionUpdateMetadataCallbackClass, "onError", "(Ljava/lang/String;)V");
+ // Style
+ registerNativeLayers(env);
+ registerNativeSources(env);
+ Stop::registerNative(env);
+ CategoricalStops::registerNative(env);
+ ExponentialStops::registerNative(env);
+ IdentityStops::registerNative(env);
+ IntervalStops::registerNative(env);
- // Offline end
+ // Connectivity
+ ConnectivityListener::registerNative(env);
- char release[PROP_VALUE_MAX] = "";
- __system_property_get("ro.build.version.release", release);
- androidRelease = std::string(release);
+ // Offline
+ OfflineManager::registerNative(env);
+ OfflineRegion::registerNative(env);
+ OfflineRegionDefinition::registerNative(env);
+ OfflineTilePyramidRegionDefinition::registerNative(env);
+ OfflineRegionError::registerNative(env);
+ OfflineRegionStatus::registerNative(env);
}
-
-} // android
-} // mbgl
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/jni.hpp b/platform/android/src/jni.hpp
index 90ec914cf2..f0c113f754 100644
--- a/platform/android/src/jni.hpp
+++ b/platform/android/src/jni.hpp
@@ -14,17 +14,11 @@ extern JavaVM* theJVM;
extern std::string cachePath;
extern std::string dataPath;
extern std::string apkPath;
-extern std::string androidRelease;
-extern jmethodID onInvalidateId;
-extern jmethodID onMapChangedId;
-extern jmethodID onFpsChangedId;
-extern jmethodID onSnapshotReadyId;
+bool attach_jni_thread(JavaVM* vm, JNIEnv** env, std::string threadName);
+void detach_jni_thread(JavaVM* vm, JNIEnv** env, bool detach);
-extern bool attach_jni_thread(JavaVM* vm, JNIEnv** env, std::string threadName);
-extern void detach_jni_thread(JavaVM* vm, JNIEnv** env, bool detach);
-
extern void registerNatives(JavaVM* vm);
-} //android
-} //mbgl
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/jni/generic_global_ref_deleter.hpp b/platform/android/src/jni/generic_global_ref_deleter.hpp
new file mode 100644
index 0000000000..4e53e0a0ce
--- /dev/null
+++ b/platform/android/src/jni/generic_global_ref_deleter.hpp
@@ -0,0 +1,22 @@
+#pragma once
+
+#include <jni/jni.hpp>
+
+#include "../attach_env.hpp"
+
+namespace mbgl {
+namespace android {
+
+// A deleter that doesn't retain an JNIEnv handle but instead tries to attach the JVM. This means
+// it can be used on any thread to delete a global ref.
+struct GenericGlobalRefDeleter {
+ void operator()(jni::jobject* p) const {
+ if (p) {
+ auto env = AttachEnv();
+ env->DeleteGlobalRef(jni::Unwrap(p));
+ }
+ }
+};
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp
index 9d467f6ede..1930d1854d 100755
--- a/platform/android/src/native_map_view.cpp
+++ b/platform/android/src/native_map_view.cpp
@@ -1,5 +1,4 @@
#include "native_map_view.hpp"
-#include "jni.hpp"
#include <cstdlib>
#include <ctime>
@@ -10,90 +9,91 @@
#include <sys/system_properties.h>
-#include <mbgl/util/platform.hpp>
-#include <mbgl/util/event.hpp>
-#include <mbgl/util/logging.hpp>
-#include <mbgl/gl/extension.hpp>
+#include <EGL/egl.h>
+#include <android/native_window_jni.h>
+
+#include <jni/jni.hpp>
+
#include <mbgl/gl/context.hpp>
+#include <mbgl/gl/extension.hpp>
+#include <mbgl/map/backend_scope.hpp>
#include <mbgl/util/constants.hpp>
+#include <mbgl/util/event.hpp>
+#include <mbgl/util/exception.hpp>
+#include <mbgl/util/geo.hpp>
#include <mbgl/util/image.hpp>
+#include <mbgl/util/shared_thread_pool.hpp>
+#include <mbgl/util/logging.hpp>
+#include <mbgl/util/platform.hpp>
+#include <mbgl/sprite/sprite_image.hpp>
-namespace mbgl {
-namespace android {
-
-NativeMapView::NativeMapView(JNIEnv *env_, jobject obj_, float pixelRatio, int availableProcessors_, size_t totalMemory_)
- : env(env_),
- availableProcessors(availableProcessors_),
- totalMemory(totalMemory_),
- threadPool(4) {
+#include "conversion/conversion.hpp"
+#include "conversion/collection.hpp"
+#include "geometry/conversion/feature.hpp"
- assert(env_ != nullptr);
- assert(obj_ != nullptr);
+#include "jni.hpp"
+#include "attach_env.hpp"
+#include "bitmap.hpp"
+#include "run_loop_impl.hpp"
+#include "java/util.hpp"
- if (env->GetJavaVM(&vm) < 0) {
- env->ExceptionDescribe();
- return;
- }
+namespace mbgl {
+namespace android {
- obj = env->NewWeakGlobalRef(obj_);
- if (obj == nullptr) {
- env->ExceptionDescribe();
+NativeMapView::NativeMapView(jni::JNIEnv& _env, jni::Object<NativeMapView> _obj, jni::Object<FileSource> jFileSource,
+ jni::jfloat _pixelRatio, jni::jint _availableProcessors, jni::jlong _totalMemory) :
+ javaPeer(_obj.NewWeakGlobalRef(_env)),
+ pixelRatio(_pixelRatio),
+ availableProcessors(_availableProcessors),
+ totalMemory(_totalMemory),
+ threadPool(sharedThreadPool()) {
+
+ // Get a reference to the JavaVM for callbacks
+ if (_env.GetJavaVM(&vm) < 0) {
+ _env.ExceptionDescribe();
return;
}
- fileSource = std::make_unique<mbgl::DefaultFileSource>(
- mbgl::android::cachePath + "/mbgl-offline.db",
- mbgl::android::apkPath);
-
+ // Create the core map
map = std::make_unique<mbgl::Map>(
*this, mbgl::Size{ static_cast<uint32_t>(width), static_cast<uint32_t>(height) },
- pixelRatio, *fileSource, threadPool, MapMode::Continuous);
+ pixelRatio, mbgl::android::FileSource::getDefaultFileSource(_env, jFileSource)
+ , *threadPool, MapMode::Continuous);
+ //Calculate a fitting cache size based on device parameters
float zoomFactor = map->getMaxZoom() - map->getMinZoom() + 1;
float cpuFactor = availableProcessors;
float memoryFactor = static_cast<float>(totalMemory) / 1000.0f / 1000.0f / 1000.0f;
float sizeFactor = (static_cast<float>(map->getSize().width) / mbgl::util::tileSize) *
- (static_cast<float>(map->getSize().height) / mbgl::util::tileSize);
-
- size_t cacheSize = zoomFactor * cpuFactor * memoryFactor * sizeFactor * 0.5f;
+ (static_cast<float>(map->getSize().height) / mbgl::util::tileSize);
- map->setSourceTileCacheSize(cacheSize);
+ map->setSourceTileCacheSize(zoomFactor * cpuFactor * memoryFactor * sizeFactor * 0.5f);
}
+/**
+ * Called through NativeMapView#destroy()
+ */
NativeMapView::~NativeMapView() {
- terminateContext();
- destroySurface();
- terminateDisplay();
-
- assert(vm != nullptr);
- assert(obj != nullptr);
+ _terminateContext();
+ _destroySurface();
+ _terminateDisplay();
map.reset();
- fileSource.reset();
-
- env->DeleteWeakGlobalRef(obj);
- obj = nullptr;
- env = nullptr;
vm = nullptr;
}
-mbgl::Size NativeMapView::getFramebufferSize() const {
- return { static_cast<uint32_t>(fbWidth), static_cast<uint32_t>(fbHeight) };
-}
-
-void NativeMapView::updateViewBinding() {
- getContext().bindFramebuffer.setCurrentValue(0);
- assert(mbgl::gl::value::BindFramebuffer::Get() == getContext().bindFramebuffer.getCurrentValue());
- getContext().viewport.setCurrentValue({ 0, 0, getFramebufferSize() });
- assert(mbgl::gl::value::Viewport::Get() == getContext().viewport.getCurrentValue());
-}
-
+/**
+ * From mbgl::View
+ */
void NativeMapView::bind() {
getContext().bindFramebuffer = 0;
getContext().viewport = { 0, 0, getFramebufferSize() };
}
+/**
+ * From mbgl::Backend.
+ */
void NativeMapView::activate() {
if (active++) {
return;
@@ -122,6 +122,9 @@ void NativeMapView::activate() {
}
}
+/**
+ * From mbgl::Backend.
+ */
void NativeMapView::deactivate() {
if (--active) {
return;
@@ -146,17 +149,57 @@ void NativeMapView::deactivate() {
}
}
+/**
+ * From mbgl::Backend. Callback to java NativeMapView#onInvalidate().
+ *
+ * May be called from any thread
+ */
void NativeMapView::invalidate() {
+ android::UniqueEnv _env = android::AttachEnv();
+ static auto onInvalidate = javaClass.GetMethod<void ()>(*_env, "onInvalidate");
+ javaPeer->Call(*_env, onInvalidate);
+}
+
+/**
+ * From mbgl::Backend. Callback to java NativeMapView#onMapChanged(int).
+ *
+ * May be called from any thread
+ */
+void NativeMapView::notifyMapChange(mbgl::MapChange change) {
assert(vm != nullptr);
- assert(obj != nullptr);
- env->CallVoidMethod(obj, onInvalidateId);
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
- }
+ android::UniqueEnv _env = android::AttachEnv();
+ static auto onMapChanged = javaClass.GetMethod<void (int)>(*_env, "onMapChanged");
+ javaPeer->Call(*_env, onMapChanged, (int) change);
+}
+
+// JNI Methods //
+
+void NativeMapView::initializeDisplay(jni::JNIEnv&) {
+ _initializeDisplay();
}
-void NativeMapView::render() {
+void NativeMapView::terminateDisplay(jni::JNIEnv&) {
+ _terminateDisplay();
+}
+
+void NativeMapView::initializeContext(jni::JNIEnv&) {
+ _initializeContext();
+}
+
+void NativeMapView::terminateContext(jni::JNIEnv&) {
+ _terminateContext();
+}
+
+void NativeMapView::createSurface(jni::JNIEnv& env, jni::Object<> _surface) {
+ _createSurface(ANativeWindow_fromSurface(&env, jni::Unwrap(*_surface)));
+}
+
+void NativeMapView::destroySurface(jni::JNIEnv&) {
+ _destroySurface();
+}
+
+void NativeMapView::render(jni::JNIEnv& env) {
BackendScope guard(*this);
if (framebufferSizeChanged) {
@@ -172,17 +215,12 @@ void NativeMapView::render() {
// take snapshot
auto image = getContext().readFramebuffer<mbgl::PremultipliedImage>(getFramebufferSize());
-
- // encode and convert to jbytes
- std::string string = encodePNG(image);
- jbyteArray arr = env->NewByteArray(string.length());
- env->SetByteArrayRegion(arr,0,string.length(),(jbyte*)string.c_str());
+ auto bitmap = Bitmap::CreateBitmap(env, std::move(image));
// invoke Mapview#OnSnapshotReady
- env->CallVoidMethod(obj, onSnapshotReadyId, arr);
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
- }
+ android::UniqueEnv _env = android::AttachEnv();
+ static auto onSnapshotReady = javaClass.GetMethod<void (jni::Object<Bitmap>)>(*_env, "onSnapshotReady");
+ javaPeer->Call(*_env, onSnapshotReady, bitmap);
}
if ((display != EGL_NO_DISPLAY) && (surface != EGL_NO_SURFACE)) {
@@ -198,11 +236,736 @@ void NativeMapView::render() {
}
}
-mbgl::Map &NativeMapView::getMap() { return *map; }
+void NativeMapView::update(jni::JNIEnv&) {
+ invalidate();
+}
+
+void NativeMapView::resizeView(jni::JNIEnv&, int w, int h) {
+ width = w;
+ height = h;
+ map->setSize({ static_cast<uint32_t>(width), static_cast<uint32_t>(height) });
+}
+
+void NativeMapView::resizeFramebuffer(jni::JNIEnv&, int w, int h) {
+ fbWidth = w;
+ fbHeight = h;
+ framebufferSizeChanged = true;
+ invalidate();
+}
+
+jni::String NativeMapView::getStyleUrl(jni::JNIEnv& env) {
+ return jni::Make<jni::String>(env, map->getStyleURL());
+}
+
+void NativeMapView::setStyleUrl(jni::JNIEnv& env, jni::String url) {
+ map->setStyleURL(jni::Make<std::string>(env, url));
+}
+
+jni::String NativeMapView::getStyleJson(jni::JNIEnv& env) {
+ return jni::Make<jni::String>(env, map->getStyleJSON());
+}
+
+void NativeMapView::setStyleJson(jni::JNIEnv& env, jni::String json) {
+ map->setStyleJSON(jni::Make<std::string>(env, json));
+}
+
+void NativeMapView::cancelTransitions(jni::JNIEnv&) {
+ map->cancelTransitions();
+}
+
+void NativeMapView::setGestureInProgress(jni::JNIEnv&, jni::jboolean inProgress) {
+ map->setGestureInProgress(inProgress);
+}
+
+void NativeMapView::moveBy(jni::JNIEnv&, jni::jdouble dx, jni::jdouble dy, jni::jlong duration) {
+ mbgl::AnimationOptions animationOptions;
+ if (duration > 0) {
+ animationOptions.duration.emplace(mbgl::Milliseconds(duration));
+ animationOptions.easing.emplace(mbgl::util::UnitBezier { 0, 0.3, 0.6, 1.0 });
+ }
+ map->moveBy({dx, dy}, animationOptions);
+}
+
+void NativeMapView::jumpTo(jni::JNIEnv&, jni::jdouble angle, jni::jdouble latitude, jni::jdouble longitude, jni::jdouble pitch, jni::jdouble zoom) {
+ mbgl::CameraOptions options;
+ if (angle != -1) {
+ options.angle = (-angle * M_PI) / 180;
+ }
+ options.center = mbgl::LatLng(latitude, longitude);
+ options.padding = insets;
+ if (pitch != -1) {
+ options.pitch = pitch * M_PI / 180;
+ }
+ if (zoom != -1) {
+ options.zoom = zoom;
+ }
+
+ map->jumpTo(options);
+}
+
+void NativeMapView::easeTo(jni::JNIEnv&, jni::jdouble angle, jni::jdouble latitude, jni::jdouble longitude, jni::jlong duration, jni::jdouble pitch, jni::jdouble zoom, jni::jboolean easing) {
+ mbgl::CameraOptions cameraOptions;
+ if (angle != -1) {
+ cameraOptions.angle = (-angle * M_PI) / 180;
+ }
+ cameraOptions.center = mbgl::LatLng(latitude, longitude);
+ cameraOptions.padding = insets;
+ if (pitch != -1) {
+ cameraOptions.pitch = pitch * M_PI / 180;
+ }
+ if (zoom != -1) {
+ cameraOptions.zoom = zoom;
+ }
+
+ mbgl::AnimationOptions animationOptions;
+ animationOptions.duration.emplace(mbgl::Duration(duration));
+ if (!easing) {
+ // add a linear interpolator instead of easing
+ animationOptions.easing.emplace(mbgl::util::UnitBezier { 0, 0, 1, 1 });
+ }
+
+ map->easeTo(cameraOptions, animationOptions);
+}
+
+void NativeMapView::flyTo(jni::JNIEnv&, jni::jdouble angle, jni::jdouble latitude, jni::jdouble longitude, jni::jlong duration, jni::jdouble pitch, jni::jdouble zoom) {
+ mbgl::CameraOptions cameraOptions;
+ if (angle != -1) {
+ cameraOptions.angle = (-angle * M_PI) / 180 ;
+ }
+ cameraOptions.center = mbgl::LatLng(latitude, longitude);
+ cameraOptions.padding = insets;
+ if (pitch != -1) {
+ cameraOptions.pitch = pitch * M_PI / 180;
+ }
+ if (zoom != -1) {
+ cameraOptions.zoom = zoom;
+ }
+
+ mbgl::AnimationOptions animationOptions;
+ animationOptions.duration.emplace(mbgl::Duration(duration));
+ map->flyTo(cameraOptions, animationOptions);
+}
+
+jni::Object<LatLng> NativeMapView::getLatLng(JNIEnv& env) {
+ mbgl::LatLng latLng = map->getLatLng(insets);
+ return LatLng::New(env, latLng.latitude, latLng.longitude);
+}
+
+void NativeMapView::setLatLng(jni::JNIEnv&, jni::jdouble latitude, jni::jdouble longitude, jni::jlong duration) {
+ map->setLatLng(mbgl::LatLng(latitude, longitude), insets, mbgl::AnimationOptions{mbgl::Milliseconds(duration)});
+}
+
+void NativeMapView::setReachability(jni::JNIEnv&, jni::jboolean reachable) {
+ if (reachable) {
+ mbgl::NetworkStatus::Reachable();
+ }
+}
+
+void NativeMapView::resetPosition(jni::JNIEnv&) {
+ map->resetPosition();
+}
+
+jni::jdouble NativeMapView::getPitch(jni::JNIEnv&) {
+ return map->getPitch();
+}
+
+void NativeMapView::setPitch(jni::JNIEnv&, jni::jdouble pitch, jni::jlong duration) {
+ map->setPitch(pitch, mbgl::AnimationOptions{mbgl::Milliseconds(duration)});
+}
+
+void NativeMapView::scaleBy(jni::JNIEnv&, jni::jdouble ds, jni::jdouble cx, jni::jdouble cy, jni::jlong duration) {
+ mbgl::ScreenCoordinate center(cx, cy);
+ map->scaleBy(ds, center, mbgl::AnimationOptions{mbgl::Milliseconds(duration)});
+}
+
+void NativeMapView::setScale(jni::JNIEnv&, jni::jdouble scale, jni::jdouble cx, jni::jdouble cy, jni::jlong duration) {
+ mbgl::ScreenCoordinate center(cx, cy);
+ map->setScale(scale, center, mbgl::AnimationOptions{mbgl::Milliseconds(duration)});
+}
+
+jni::jdouble NativeMapView::getScale(jni::JNIEnv&) {
+ return map->getScale();
+}
+
+void NativeMapView::setZoom(jni::JNIEnv&, jni::jdouble zoom, jni::jlong duration) {
+ map->setZoom(zoom, mbgl::AnimationOptions{mbgl::Milliseconds(duration)});
+}
+
+jni::jdouble NativeMapView::getZoom(jni::JNIEnv&) {
+ return map->getZoom();
+}
+
+void NativeMapView::resetZoom(jni::JNIEnv&) {
+ map->resetZoom();
+}
+
+void NativeMapView::setMinZoom(jni::JNIEnv&, jni::jdouble zoom) {
+ map->setMinZoom(zoom);
+}
+
+jni::jdouble NativeMapView::getMinZoom(jni::JNIEnv&) {
+ return map->getMinZoom();
+}
+
+void NativeMapView::setMaxZoom(jni::JNIEnv&, jni::jdouble zoom) {
+ map->setMaxZoom(zoom);
+}
+
+jni::jdouble NativeMapView::getMaxZoom(jni::JNIEnv&) {
+ return map->getMaxZoom();
+}
+
+void NativeMapView::rotateBy(jni::JNIEnv&, jni::jdouble sx, jni::jdouble sy, jni::jdouble ex, jni::jdouble ey, jni::jlong duration) {
+ mbgl::ScreenCoordinate first(sx, sy);
+ mbgl::ScreenCoordinate second(ex, ey);
+ map->rotateBy(first, second, mbgl::AnimationOptions{mbgl::Milliseconds(duration)});
+}
+
+void NativeMapView::setBearing(jni::JNIEnv&, jni::jdouble degrees, jni::jlong duration) {
+ map->setBearing(degrees, mbgl::AnimationOptions{mbgl::Milliseconds(duration)});
+}
+
+void NativeMapView::setBearingXY(jni::JNIEnv&, jni::jdouble degrees, jni::jdouble cx, jni::jdouble cy, jni::jlong duration) {
+ mbgl::ScreenCoordinate center(cx, cy);
+ map->setBearing(degrees, center, mbgl::AnimationOptions{mbgl::Milliseconds(duration)});
+}
+
+jni::jdouble NativeMapView::getBearing(jni::JNIEnv&) {
+ return map->getBearing();
+}
+
+void NativeMapView::resetNorth(jni::JNIEnv&) {
+ map->resetNorth();
+}
+
+void NativeMapView::setVisibleCoordinateBounds(JNIEnv& env, jni::Array<jni::Object<LatLng>> coordinates, jni::Object<RectF> padding, jdouble direction, jni::jlong duration) {
+ NullCheck(env, &coordinates);
+ std::size_t count = coordinates.Length(env);
+
+ std::vector<mbgl::LatLng> latLngs;
+ latLngs.reserve(count);
+
+ for (std::size_t i = 0; i < count; i++) {
+ auto latLng = coordinates.Get(env, i);
+ latLngs.push_back(LatLng::getLatLng(env, latLng));
+ jni::DeleteLocalRef(env, latLng);
+ }
+
+ mbgl::EdgeInsets mbglInsets = { RectF::getTop(env, padding), RectF::getLeft(env, padding), RectF::getBottom(env, padding), RectF::getRight(env, padding) };
+ mbgl::CameraOptions cameraOptions = map->cameraForLatLngs(latLngs, mbglInsets);
+ if (direction >= 0) {
+ // convert from degrees to radians
+ cameraOptions.angle = (-direction * M_PI) / 180;
+ }
+
+ mbgl::AnimationOptions animationOptions;
+ if (duration > 0) {
+ animationOptions.duration.emplace(mbgl::Milliseconds(duration));
+ // equivalent to kCAMediaTimingFunctionDefault in iOS
+ animationOptions.easing.emplace(mbgl::util::UnitBezier { 0.25, 0.1, 0.25, 0.1 });
+ }
+
+ map->easeTo(cameraOptions, animationOptions);
+}
+
+void NativeMapView::setContentPadding(JNIEnv&, double top, double left, double bottom, double right) {
+ insets = {top, left, bottom, right};
+}
+
+void NativeMapView::scheduleSnapshot(jni::JNIEnv&) {
+ snapshot = true;
+}
+
+void NativeMapView::enableFps(jni::JNIEnv&, jni::jboolean enable) {
+ fpsEnabled = enable;
+}
+
+jni::Array<jni::jdouble> NativeMapView::getCameraValues(jni::JNIEnv& env) {
+ //Create buffer with values
+ jdouble buf[5];
+ mbgl::LatLng latLng = map->getLatLng(insets);
+ buf[0] = latLng.latitude;
+ buf[1] = latLng.longitude;
+ buf[2] = -map->getBearing();
+ buf[3] = map->getPitch();
+ buf[4] = map->getZoom();
+
+ //Convert to Java array
+ auto output = jni::Array<jni::jdouble>::New(env, 5);
+ jni::SetArrayRegion(env, *output, 0, 5, buf);
+
+ return output;
+}
+
+void NativeMapView::updateMarker(jni::JNIEnv& env, jni::jlong markerId, jni::jdouble lat, jni::jdouble lon, jni::String jid) {
+ if (markerId == -1) {
+ return;
+ }
+
+ std::string iconId = jni::Make<std::string>(env, jid);
+ // Because Java only has int, not unsigned int, we need to bump the annotation id up to a long.
+ map->updateAnnotation(markerId, mbgl::SymbolAnnotation { mbgl::Point<double>(lon, lat), iconId });
+}
+
+jni::Array<jni::jlong> NativeMapView::addMarkers(jni::JNIEnv& env, jni::Array<jni::Object<Marker>> jmarkers) {
+ jni::NullCheck(env, &jmarkers);
+ std::size_t len = jmarkers.Length(env);
+
+ std::vector<jni::jlong> ids;
+ ids.reserve(len);
+
+ for (std::size_t i = 0; i < len; i++) {
+ jni::Object<Marker> marker = jmarkers.Get(env, i);
+ ids.push_back(map->addAnnotation(mbgl::SymbolAnnotation {
+ Marker::getPosition(env, marker),
+ Marker::getIconId(env, marker)
+ }));
+
+ jni::DeleteLocalRef(env, marker);
+ }
+
+ auto result = jni::Array<jni::jlong>::New(env, len);
+ result.SetRegion<std::vector<jni::jlong>>(env, 0, ids);
+
+ return result;
+}
+
+void NativeMapView::onLowMemory(JNIEnv&) {
+ map->onLowMemory();
+}
+
+using DebugOptions = mbgl::MapDebugOptions;
+
+void NativeMapView::setDebug(JNIEnv&, jni::jboolean debug) {
+ DebugOptions debugOptions = debug ? DebugOptions::TileBorders | DebugOptions::ParseStatus | DebugOptions::Collision
+ : DebugOptions::NoDebug;
+ map->setDebug(debugOptions);
+ fpsEnabled = debug;
+}
+
+void NativeMapView::cycleDebugOptions(JNIEnv&) {
+ map->cycleDebugOptions();
+ fpsEnabled = map->getDebug() != DebugOptions::NoDebug;
+}
+
+jni::jboolean NativeMapView::getDebug(JNIEnv&) {
+ return map->getDebug() != DebugOptions::NoDebug;
+}
+
+jni::jboolean NativeMapView::isFullyLoaded(JNIEnv&) {
+ return map->isFullyLoaded();
+}
+
+jni::jdouble NativeMapView::getMetersPerPixelAtLatitude(JNIEnv&, jni::jdouble lat, jni::jdouble zoom) {
+ return map->getMetersPerPixelAtLatitude(lat, zoom);
+}
+
+jni::Object<ProjectedMeters> NativeMapView::projectedMetersForLatLng(JNIEnv& env, jni::jdouble latitude, jni::jdouble longitude) {
+ mbgl::ProjectedMeters projectedMeters = map->projectedMetersForLatLng(mbgl::LatLng(latitude, longitude));
+ return ProjectedMeters::New(env, projectedMeters.northing, projectedMeters.easting);
+}
+
+jni::Object<PointF> NativeMapView::pixelForLatLng(JNIEnv& env, jdouble latitude, jdouble longitude) {
+ mbgl::ScreenCoordinate pixel = map->pixelForLatLng(mbgl::LatLng(latitude, longitude));
+ return PointF::New(env, static_cast<float>(pixel.x), static_cast<float>(pixel.y));
+}
+
+jni::Object<LatLng> NativeMapView::latLngForProjectedMeters(JNIEnv& env, jdouble northing, jdouble easting) {
+ mbgl::LatLng latLng = map->latLngForProjectedMeters(mbgl::ProjectedMeters(northing, easting));
+ return LatLng::New(env, latLng.latitude, latLng.longitude);
+}
+
+jni::Object<LatLng> NativeMapView::latLngForPixel(JNIEnv& env, jfloat x, jfloat y) {
+ mbgl::LatLng latLng = map->latLngForPixel(mbgl::ScreenCoordinate(x, y));
+ return LatLng::New(env, latLng.latitude, latLng.longitude);
+}
+
+jni::Array<jlong> NativeMapView::addPolylines(JNIEnv& env, jni::Array<jni::Object<Polyline>> polylines) {
+ NullCheck(env, &polylines);
+ std::size_t len = polylines.Length(env);
+
+ std::vector<jni::jlong> ids;
+ ids.reserve(len);
+
+ for (std::size_t i = 0; i < len; i++) {
+ auto polyline = polylines.Get(env, i);
+
+ mbgl::LineAnnotation annotation = Polyline::toAnnotation(env, polyline);
+ ids.push_back(map->addAnnotation(annotation));
+
+ jni::DeleteLocalRef(env, polyline);
+ }
+
+ auto result = jni::Array<jni::jlong>::New(env, len);
+ result.SetRegion<std::vector<jni::jlong>>(env, 0, ids);
+
+ return result;
+}
+
+
+jni::Array<jlong> NativeMapView::addPolygons(JNIEnv& env, jni::Array<jni::Object<Polygon>> polygons) {
+ NullCheck(env, &polygons);
+ std::size_t len = polygons.Length(env);
+
+ std::vector<jni::jlong> ids;
+ ids.reserve(len);
+
+ for (std::size_t i = 0; i < len; i++) {
+ auto polygon = polygons.Get(env, i);
+
+ mbgl::FillAnnotation annotation = Polygon::toAnnotation(env, polygon);
+ ids.push_back(map->addAnnotation(annotation));
+
+ jni::DeleteLocalRef(env, polygon);
+ }
+
+ auto result = jni::Array<jni::jlong>::New(env, len);
+ result.SetRegion<std::vector<jni::jlong>>(env, 0, ids);
+
+ return result;
+}
+
+//TODO: Move to Polyline class and make native peer
+void NativeMapView::updatePolyline(JNIEnv& env, jlong polylineId, jni::Object<Polyline> polyline) {
+ mbgl::LineAnnotation annotation = Polyline::toAnnotation(env, polyline);
+ map->updateAnnotation(polylineId, annotation);
+}
+
+//TODO: Move to Polygon class and make native peer
+void NativeMapView::updatePolygon(JNIEnv& env, jlong polygonId, jni::Object<Polygon> polygon) {
+ mbgl::FillAnnotation annotation = Polygon::toAnnotation(env, polygon);
+ map->updateAnnotation(polygonId, annotation);
+}
+
+void NativeMapView::removeAnnotations(JNIEnv& env, jni::Array<jlong> ids) {
+ NullCheck(env, &ids);
+ std::size_t len = ids.Length(env);
+ auto elements = jni::GetArrayElements(env, *ids);
+ jlong* jids = std::get<0>(elements).get();
+
+ for (std::size_t i = 0; i < len; i++) {
+ if(jids[i] == -1L) {
+ continue;
+ }
+ map->removeAnnotation(jids[i]);
+ }
+}
+
+void NativeMapView::addAnnotationIcon(JNIEnv& env, jni::String symbol, jint w, jint h, jfloat scale, jni::Array<jbyte> jpixels) {
+ const std::string symbolName = jni::Make<std::string>(env, symbol);
+
+ NullCheck(env, &jpixels);
+ std::size_t size = jpixels.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, *jpixels, 0, size, reinterpret_cast<jbyte*>(premultipliedImage.data.get()));
+ auto iconImage = std::make_shared<mbgl::SpriteImage>(std::move(premultipliedImage), float(scale));
+ map->addAnnotationIcon(symbolName, iconImage);
+}
+
+jdouble NativeMapView::getTopOffsetPixelsForAnnotationSymbol(JNIEnv& env, jni::String symbolName) {
+ return map->getTopOffsetPixelsForAnnotationIcon(jni::Make<std::string>(env, symbolName));
+}
+
+jlong NativeMapView::getTransitionDuration(JNIEnv&) {
+ const auto transitionOptions = map->getTransitionOptions();
+ return transitionOptions.duration.value_or(mbgl::Duration::zero()).count();
+}
+
+void NativeMapView::setTransitionDuration(JNIEnv&, jlong duration) {
+ auto transitionOptions = map->getTransitionOptions();
+ transitionOptions.duration = std::chrono::duration_cast<mbgl::Duration>(std::chrono::duration<jlong>(duration));
+ map->setTransitionOptions(transitionOptions);
+}
+
+jlong NativeMapView::getTransitionDelay(JNIEnv&) {
+ const auto transitionOptions = map->getTransitionOptions();
+ return transitionOptions.delay.value_or(mbgl::Duration::zero()).count();
+}
+
+void NativeMapView::setTransitionDelay(JNIEnv&, jlong delay) {
+ auto transitionOptions = map->getTransitionOptions();
+ transitionOptions.delay = std::chrono::duration_cast<mbgl::Duration>(std::chrono::duration<jlong>(delay));
+ map->setTransitionOptions(transitionOptions);
+}
+
+jni::Array<jlong> NativeMapView::queryPointAnnotations(JNIEnv& env, jni::Object<RectF> rect) {
+ // Convert input
+ mbgl::ScreenBox box = {
+ { RectF::getLeft(env, rect), RectF::getTop(env, rect) },
+ { RectF::getRight(env, rect), RectF::getBottom(env, rect) },
+ };
+
+ // Assume only points for now
+ mbgl::AnnotationIDs ids = map->queryPointAnnotations(box);
+
+ // Convert result
+ std::vector<jlong> longIds(ids.begin(), ids.end());
+ auto result = jni::Array<jni::jlong>::New(env, ids.size());
+ result.SetRegion<std::vector<jni::jlong>>(env, 0, longIds);
+
+ return result;
+}
+
+jni::Array<jni::Object<Feature>> NativeMapView::queryRenderedFeaturesForPoint(JNIEnv& env, jni::jfloat x, jni::jfloat y, jni::Array<jni::String> layerIds) {
+ using namespace mbgl::android::conversion;
+ using namespace mapbox::geometry;
+
+ mbgl::optional<std::vector<std::string>> layers;
+ if (layerIds != nullptr && layerIds.Length(env) > 0) {
+ layers = toVector(env, layerIds);
+ }
+ point<double> point = {x, y};
+
+ return *convert<jni::Array<jni::Object<Feature>>, std::vector<mbgl::Feature>>(env, map->queryRenderedFeatures(point, layers));
+}
+
+jni::Array<jni::Object<Feature>> NativeMapView::queryRenderedFeaturesForBox(JNIEnv& env, jni::jfloat left, jni::jfloat top, jni::jfloat right, jni::jfloat bottom, jni::Array<jni::String> layerIds) {
+ using namespace mbgl::android::conversion;
+ using namespace mapbox::geometry;
+
+ mbgl::optional<std::vector<std::string>> layers;
+ if (layerIds != nullptr && layerIds.Length(env) > 0) {
+ layers = toVector(env, layerIds);
+ }
+ box<double> box = { point<double>{ left, top}, point<double>{ right, bottom } };
+
+ return *convert<jni::Array<jni::Object<Feature>>, std::vector<mbgl::Feature>>(env, map->queryRenderedFeatures(box, layers));
+}
+
+jni::Array<jni::Object<Layer>> NativeMapView::getLayers(JNIEnv& env) {
+
+ // Get the core layers
+ std::vector<style::Layer*> layers = map->getLayers();
+
+ // Convert
+ jni::Array<jni::Object<Layer>> jLayers = jni::Array<jni::Object<Layer>>::New(env, layers.size(), Layer::javaClass);
+ int index = 0;
+ for (auto layer : layers) {
+ auto jLayer = jni::Object<Layer>(createJavaLayerPeer(env, *map, *layer));
+ jLayers.Set(env, index, jLayer);
+ jni::DeleteLocalRef(env, jLayer);
+ index++;
+ }
+
+ return jLayers;
+}
+
+jni::Object<Layer> NativeMapView::getLayer(JNIEnv& env, jni::String layerId) {
+
+ // Find the layer
+ mbgl::style::Layer* coreLayer = map->getLayer(jni::Make<std::string>(env, layerId));
+ if (!coreLayer) {
+ mbgl::Log::Debug(mbgl::Event::JNI, "No layer found");
+ return jni::Object<Layer>();
+ }
+
+ // Create and return the layer's native peer
+ return jni::Object<Layer>(createJavaLayerPeer(env, *map, *coreLayer));
+}
-mbgl::DefaultFileSource &NativeMapView::getFileSource() { return *fileSource; }
+void NativeMapView::addLayer(JNIEnv& env, jlong nativeLayerPtr, jni::String before) {
+ assert(nativeLayerPtr != 0);
+
+ Layer *layer = reinterpret_cast<Layer *>(nativeLayerPtr);
+ try {
+ layer->addToMap(*map, before ? mbgl::optional<std::string>(jni::Make<std::string>(env, before)) : mbgl::optional<std::string>());
+ } catch (const std::runtime_error& error) {
+ jni::ThrowNew(env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/layers/CannotAddLayerException"), error.what());
+ }
+}
+
+void NativeMapView::addLayerAbove(JNIEnv& env, jlong nativeLayerPtr, jni::String above) {
+ assert(nativeLayerPtr != 0);
+
+ Layer *layer = reinterpret_cast<Layer *>(nativeLayerPtr);
+
+ // Find the sibling
+ auto layers = map->getLayers();
+ auto siblingId = jni::Make<std::string>(env, above);
+
+ size_t index = 0;
+ for (auto l : layers) {
+ if (l->getID() == siblingId) {
+ break;
+ }
+ index++;
+ }
+
+ // Check if we found a sibling to place before
+ mbgl::optional<std::string> before;
+ if (index + 1 > layers.size()) {
+ // Not found
+ jni::ThrowNew(env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/layers/CannotAddLayerException"),
+ std::string("Could not find layer: ").append(siblingId).c_str());
+ return;
+ } else if (index + 1 < layers.size()) {
+ // Place before the sibling
+ before = { layers.at(index + 1)->getID() };
+ }
+
+ // Add the layer
+ try {
+ layer->addToMap(*map, before);
+ } catch (const std::runtime_error& error) {
+ jni::ThrowNew(env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/layers/CannotAddLayerException"), error.what());
+ }
+}
+
+void NativeMapView::addLayerAt(JNIEnv& env, jlong nativeLayerPtr, jni::jint index) {
+ assert(nativeLayerPtr != 0);
+
+ Layer *layer = reinterpret_cast<Layer *>(nativeLayerPtr);
+ auto layers = map->getLayers();
+
+ // Check index
+ int numLayers = layers.size() - 1;
+ if (index > numLayers || index < 0) {
+ Log::Error(Event::JNI, "Index out of range: %i", index);
+ jni::ThrowNew(env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/layers/CannotAddLayerException"),
+ std::string("Invalid index").c_str());
+ return;
+ }
+
+ // Insert it below the current at that index
+ try {
+ layer->addToMap(*map, layers.at(index)->getID());
+ } catch (const std::runtime_error& error) {
+ jni::ThrowNew(env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/layers/CannotAddLayerException"), error.what());
+ }
+}
+
+/**
+ * Remove by layer id.
+ */
+jni::Object<Layer> NativeMapView::removeLayerById(JNIEnv& env, jni::String id) {
+ std::unique_ptr<mbgl::style::Layer> coreLayer = map->removeLayer(jni::Make<std::string>(env, id));
+ if (coreLayer) {
+ return jni::Object<Layer>(createJavaLayerPeer(env, *map, std::move(coreLayer)));
+ } else {
+ return jni::Object<Layer>();
+ }
+}
-void NativeMapView::initializeDisplay() {
+/**
+ * Remove layer at index.
+ */
+jni::Object<Layer> NativeMapView::removeLayerAt(JNIEnv& env, jni::jint index) {
+ auto layers = map->getLayers();
+
+ // Check index
+ int numLayers = layers.size() - 1;
+ if (index > numLayers || index < 0) {
+ Log::Warning(Event::JNI, "Index out of range: %i", index);
+ return jni::Object<Layer>();
+ }
+
+ std::unique_ptr<mbgl::style::Layer> coreLayer = map->removeLayer(layers.at(index)->getID());
+ if (coreLayer) {
+ return jni::Object<Layer>(createJavaLayerPeer(env, *map, std::move(coreLayer)));
+ } else {
+ return jni::Object<Layer>();
+ }
+}
+
+/**
+ * Remove with wrapper object id. Ownership is transferred back to the wrapper
+ */
+void NativeMapView::removeLayer(JNIEnv&, jlong layerPtr) {
+ assert(layerPtr != 0);
+
+ mbgl::android::Layer *layer = reinterpret_cast<mbgl::android::Layer *>(layerPtr);
+ std::unique_ptr<mbgl::style::Layer> coreLayer = map->removeLayer(layer->get().getID());
+ if (coreLayer) {
+ layer->setLayer(std::move(coreLayer));
+ }
+}
+
+jni::Array<jni::Object<Source>> NativeMapView::getSources(JNIEnv& env) {
+ // Get the core sources
+ std::vector<style::Source*> sources = map->getSources();
+
+ // Convert
+ jni::Array<jni::Object<Source>> jSources = jni::Array<jni::Object<Source>>::New(env, sources.size(), Source::javaClass);
+ int index = 0;
+ for (auto source : sources) {
+ auto jSource = jni::Object<Source>(createJavaSourcePeer(env, *map, *source));
+ jSources.Set(env, index, jSource);
+ jni::DeleteLocalRef(env, jSource);
+ index++;
+ }
+
+ return jSources;
+}
+
+jni::Object<Source> NativeMapView::getSource(JNIEnv& env, jni::String sourceId) {
+ // Find the source
+ mbgl::style::Source* coreSource = map->getSource(jni::Make<std::string>(env, sourceId));
+ if (!coreSource) {
+ mbgl::Log::Debug(mbgl::Event::JNI, "No source found");
+ return jni::Object<Source>();
+ }
+
+ // Create and return the source's native peer
+ return jni::Object<Source>(createJavaSourcePeer(env, *map, *coreSource));
+}
+
+void NativeMapView::addSource(JNIEnv& env, jni::jlong sourcePtr) {
+ assert(sourcePtr != 0);
+
+ Source *source = reinterpret_cast<Source *>(sourcePtr);
+ try {
+ source->addToMap(*map);
+ } catch (const std::runtime_error& error) {
+ jni::ThrowNew(env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/sources/CannotAddSourceException"), error.what());
+ }
+}
+
+jni::Object<Source> NativeMapView::removeSourceById(JNIEnv& env, jni::String id) {
+ std::unique_ptr<mbgl::style::Source> coreSource = map->removeSource(jni::Make<std::string>(env, id));
+ if (coreSource) {
+ return jni::Object<Source>(createJavaSourcePeer(env, *map, *coreSource));
+ } else {
+ return jni::Object<Source>();
+ }
+}
+
+void NativeMapView::removeSource(JNIEnv&, jlong sourcePtr) {
+ assert(sourcePtr != 0);
+
+ mbgl::android::Source *source = reinterpret_cast<mbgl::android::Source *>(sourcePtr);
+ std::unique_ptr<mbgl::style::Source> coreSource = map->removeSource(source->get().getID());
+ if (coreSource) {
+ source->setSource(std::move(coreSource));
+ }
+}
+
+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()));
+ auto spriteImage = std::make_unique<mbgl::SpriteImage>(std::move(premultipliedImage), float(scale));
+
+ map->addImage(jni::Make<std::string>(env, name), std::move(spriteImage));
+}
+
+void NativeMapView::removeImage(JNIEnv& env, jni::String name) {
+ map->removeImage(jni::Make<std::string>(env, name));
+}
+
+// Private methods //
+
+void NativeMapView::_initializeDisplay() {
assert(display == EGL_NO_DISPLAY);
assert(config == nullptr);
assert(format < 0);
@@ -287,145 +1050,6 @@ void NativeMapView::initializeDisplay() {
}
}
-void NativeMapView::terminateDisplay() {
- if (display != EGL_NO_DISPLAY) {
- // Destroy the surface first, if it still exists. This call needs a valid surface.
- if (surface != EGL_NO_SURFACE) {
- if (!eglDestroySurface(display, surface)) {
- mbgl::Log::Error(mbgl::Event::OpenGL, "eglDestroySurface() returned error %d",
- eglGetError());
- throw std::runtime_error("eglDestroySurface() failed");
- }
- surface = EGL_NO_SURFACE;
- }
-
- if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
- mbgl::Log::Error(mbgl::Event::OpenGL,
- "eglMakeCurrent(EGL_NO_CONTEXT) returned error %d", eglGetError());
- throw std::runtime_error("eglMakeCurrent() failed");
- }
-
- if (!eglTerminate(display)) {
- mbgl::Log::Error(mbgl::Event::OpenGL, "eglTerminate() returned error %d",
- eglGetError());
- throw std::runtime_error("eglTerminate() failed");
- }
- }
-
- display = EGL_NO_DISPLAY;
- config = nullptr;
- format = -1;
-}
-
-void NativeMapView::initializeContext() {
- assert(display != EGL_NO_DISPLAY);
- assert(context == EGL_NO_CONTEXT);
- assert(config != nullptr);
-
- const EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
- context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
- if (context == EGL_NO_CONTEXT) {
- mbgl::Log::Error(mbgl::Event::OpenGL, "eglCreateContext() returned error %d",
- eglGetError());
- throw std::runtime_error("eglCreateContext() failed");
- }
-}
-
-void NativeMapView::terminateContext() {
- if (display != EGL_NO_DISPLAY) {
-
- if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
- mbgl::Log::Error(mbgl::Event::OpenGL,
- "eglMakeCurrent(EGL_NO_CONTEXT) returned error %d", eglGetError());
- throw std::runtime_error("eglMakeCurrent() failed");
- }
-
- if (context != EGL_NO_CONTEXT) {
- if (!eglDestroyContext(display, context)) {
- mbgl::Log::Error(mbgl::Event::OpenGL, "eglDestroyContext() returned error %d",
- eglGetError());
- throw std::runtime_error("eglDestroyContext() failed");
- }
- }
- }
-
- context = EGL_NO_CONTEXT;
-}
-
-void NativeMapView::createSurface(ANativeWindow *window_) {
- assert(window == nullptr);
- assert(window_ != nullptr);
- window = window_;
-
- assert(display != EGL_NO_DISPLAY);
- assert(surface == EGL_NO_SURFACE);
- assert(config != nullptr);
- assert(format >= 0);
-
- ANativeWindow_setBuffersGeometry(window, 0, 0, format);
-
- const EGLint surfaceAttribs[] = {EGL_NONE};
- surface = eglCreateWindowSurface(display, config, window, surfaceAttribs);
- if (surface == EGL_NO_SURFACE) {
- mbgl::Log::Error(mbgl::Event::OpenGL, "eglCreateWindowSurface() returned error %d",
- eglGetError());
- throw std::runtime_error("eglCreateWindowSurface() failed");
- }
-
- if (!firstTime) {
- firstTime = true;
-
- BackendScope guard(*this);
-
- if (!eglMakeCurrent(display, surface, surface, context)) {
- mbgl::Log::Error(mbgl::Event::OpenGL, "eglMakeCurrent() returned error %d",
- eglGetError());
- throw std::runtime_error("eglMakeCurrent() failed");
- }
-
- mbgl::gl::InitializeExtensions([] (const char * name) {
- return reinterpret_cast<mbgl::gl::glProc>(eglGetProcAddress(name));
- });
- }
-}
-
-void NativeMapView::destroySurface() {
- if (surface != EGL_NO_SURFACE) {
- if (!eglDestroySurface(display, surface)) {
- mbgl::Log::Error(mbgl::Event::OpenGL, "eglDestroySurface() returned error %d",
- eglGetError());
- throw std::runtime_error("eglDestroySurface() failed");
- }
- }
-
- surface = EGL_NO_SURFACE;
-
- if (window != nullptr) {
- ANativeWindow_release(window);
- window = nullptr;
- }
-}
-
-void NativeMapView::scheduleTakeSnapshot() {
- snapshot = true;
-}
-
-// Speed
-/*
-typedef enum {
- Format16Bit = 0,
- Format32BitNoAlpha = 1,
- Format32BitAlpha = 2,
- Format24Bit = 3,
- Unknown = 4
-} BufferFormat;
-
-typedef enum {
- Format16Depth8Stencil = 0,
- Format24Depth8Stencil = 1,
-} DepthStencilFormat;
-*/
-
// Quality
typedef enum {
Format16Bit = 3,
@@ -590,18 +1214,134 @@ EGLConfig NativeMapView::chooseConfig(const EGLConfig configs[], EGLint numConfi
return configId;
}
-void NativeMapView::notifyMapChange(mbgl::MapChange change) {
- assert(vm != nullptr);
- assert(obj != nullptr);
+void NativeMapView::_terminateDisplay() {
+ if (display != EGL_NO_DISPLAY) {
+ // Destroy the surface first, if it still exists. This call needs a valid surface.
+ if (surface != EGL_NO_SURFACE) {
+ if (!eglDestroySurface(display, surface)) {
+ mbgl::Log::Error(mbgl::Event::OpenGL, "eglDestroySurface() returned error %d",
+ eglGetError());
+ throw std::runtime_error("eglDestroySurface() failed");
+ }
+ surface = EGL_NO_SURFACE;
+ }
+
+ if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
+ mbgl::Log::Error(mbgl::Event::OpenGL,
+ "eglMakeCurrent(EGL_NO_CONTEXT) returned error %d", eglGetError());
+ throw std::runtime_error("eglMakeCurrent() failed");
+ }
+
+ if (!eglTerminate(display)) {
+ mbgl::Log::Error(mbgl::Event::OpenGL, "eglTerminate() returned error %d",
+ eglGetError());
+ throw std::runtime_error("eglTerminate() failed");
+ }
+ }
+
+ display = EGL_NO_DISPLAY;
+ config = nullptr;
+ format = -1;
+}
- env->CallVoidMethod(obj, onMapChangedId, change);
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
+void NativeMapView::_initializeContext() {
+ assert(display != EGL_NO_DISPLAY);
+ assert(context == EGL_NO_CONTEXT);
+ assert(config != nullptr);
+
+ const EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
+ context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
+ if (context == EGL_NO_CONTEXT) {
+ mbgl::Log::Error(mbgl::Event::OpenGL, "eglCreateContext() returned error %d",
+ eglGetError());
+ throw std::runtime_error("eglCreateContext() failed");
}
}
-void NativeMapView::enableFps(bool enable) {
- fpsEnabled = enable;
+void NativeMapView::_terminateContext() {
+ if (display != EGL_NO_DISPLAY) {
+
+ if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
+ mbgl::Log::Error(mbgl::Event::OpenGL,
+ "eglMakeCurrent(EGL_NO_CONTEXT) returned error %d", eglGetError());
+ throw std::runtime_error("eglMakeCurrent() failed");
+ }
+
+ if (context != EGL_NO_CONTEXT) {
+ if (!eglDestroyContext(display, context)) {
+ mbgl::Log::Error(mbgl::Event::OpenGL, "eglDestroyContext() returned error %d",
+ eglGetError());
+ throw std::runtime_error("eglDestroyContext() failed");
+ }
+ }
+ }
+
+ context = EGL_NO_CONTEXT;
+}
+
+void NativeMapView::_createSurface(ANativeWindow *window_) {
+ assert(window == nullptr);
+ assert(window_ != nullptr);
+ window = window_;
+
+ assert(display != EGL_NO_DISPLAY);
+ assert(surface == EGL_NO_SURFACE);
+ assert(config != nullptr);
+ assert(format >= 0);
+
+ ANativeWindow_setBuffersGeometry(window, 0, 0, format);
+
+ const EGLint surfaceAttribs[] = {EGL_NONE};
+ surface = eglCreateWindowSurface(display, config, window, surfaceAttribs);
+ if (surface == EGL_NO_SURFACE) {
+ mbgl::Log::Error(mbgl::Event::OpenGL, "eglCreateWindowSurface() returned error %d",
+ eglGetError());
+ throw std::runtime_error("eglCreateWindowSurface() failed");
+ }
+
+ if (firstRender) {
+ firstRender = false;
+
+ BackendScope guard(*this);
+
+ if (!eglMakeCurrent(display, surface, surface, context)) {
+ mbgl::Log::Error(mbgl::Event::OpenGL, "eglMakeCurrent() returned error %d",
+ eglGetError());
+ throw std::runtime_error("eglMakeCurrent() failed");
+ }
+
+ mbgl::gl::InitializeExtensions([] (const char * name) {
+ return reinterpret_cast<mbgl::gl::glProc>(eglGetProcAddress(name));
+ });
+ }
+}
+
+void NativeMapView::_destroySurface() {
+ if (surface != EGL_NO_SURFACE) {
+ if (!eglDestroySurface(display, surface)) {
+ mbgl::Log::Error(mbgl::Event::OpenGL, "eglDestroySurface() returned error %d",
+ eglGetError());
+ throw std::runtime_error("eglDestroySurface() failed");
+ }
+ }
+
+ surface = EGL_NO_SURFACE;
+
+ if (window != nullptr) {
+ ANativeWindow_release(window);
+ window = nullptr;
+ }
+}
+
+mbgl::Size NativeMapView::getFramebufferSize() const {
+ return { static_cast<uint32_t>(fbWidth), static_cast<uint32_t>(fbHeight) };
+}
+
+void NativeMapView::updateViewBinding() {
+ getContext().bindFramebuffer.setCurrentValue(0);
+ assert(mbgl::gl::value::BindFramebuffer::Get() == getContext().bindFramebuffer.getCurrentValue());
+ getContext().viewport.setCurrentValue({ 0, 0, getFramebufferSize() });
+ assert(mbgl::gl::value::Viewport::Get() == getContext().viewport.getCurrentValue());
}
void NativeMapView::updateFps() {
@@ -619,35 +1359,121 @@ void NativeMapView::updateFps() {
if (currentTime - timeElapsed >= 1) {
fps = frames / ((currentTime - timeElapsed) / 1E9);
- mbgl::Log::Debug(mbgl::Event::Render, "FPS: %4.2f", fps);
+ mbgl::Log::Info(mbgl::Event::Render, "FPS: %4.2f", fps);
timeElapsed = currentTime;
frames = 0;
}
assert(vm != nullptr);
- assert(obj != nullptr);
-
- env->CallVoidMethod(obj, onFpsChangedId, fps);
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
- }
-}
-void NativeMapView::resizeView(int w, int h) {
- width = w;
- height = h;
- map->setSize({ static_cast<uint32_t>(width), static_cast<uint32_t>(height) });
-}
-
-void NativeMapView::resizeFramebuffer(int w, int h) {
- fbWidth = w;
- fbHeight = h;
- framebufferSizeChanged = true;
- invalidate();
+ android::UniqueEnv _env = android::AttachEnv();
+ static auto onFpsChanged = javaClass.GetMethod<void (double)>(*_env, "onFpsChanged");
+ javaPeer->Call(*_env, onFpsChanged, fps);
}
-void NativeMapView::setInsets(mbgl::EdgeInsets insets_) {
- insets = insets_;
+// Static methods //
+
+jni::Class<NativeMapView> NativeMapView::javaClass;
+
+void NativeMapView::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ NativeMapView::javaClass = *jni::Class<NativeMapView>::Find(env).NewGlobalRef(env).release();
+
+ #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
+
+ // Register the peer
+ jni::RegisterNativePeer<NativeMapView>(env, NativeMapView::javaClass, "nativePtr",
+ std::make_unique<NativeMapView, JNIEnv&, jni::Object<NativeMapView>, jni::Object<FileSource>, jni::jfloat, jni::jint, jni::jlong>,
+ "nativeInitialize",
+ "nativeDestroy",
+ METHOD(&NativeMapView::render, "nativeRender"),
+ METHOD(&NativeMapView::update, "nativeUpdate"),
+ METHOD(&NativeMapView::resizeView, "nativeResizeView"),
+ METHOD(&NativeMapView::resizeFramebuffer, "nativeResizeFramebuffer"),
+ METHOD(&NativeMapView::initializeDisplay, "nativeInitializeDisplay"),
+ METHOD(&NativeMapView::terminateDisplay, "nativeTerminateDisplay"),
+ METHOD(&NativeMapView::initializeContext, "nativeInitializeContext"),
+ METHOD(&NativeMapView::terminateContext, "nativeTerminateContext"),
+ METHOD(&NativeMapView::createSurface, "nativeCreateSurface"),
+ METHOD(&NativeMapView::destroySurface, "nativeDestroySurface"),
+ METHOD(&NativeMapView::getStyleUrl, "nativeGetStyleUrl"),
+ METHOD(&NativeMapView::setStyleUrl, "nativeSetStyleUrl"),
+ METHOD(&NativeMapView::getStyleJson, "nativeGetStyleJson"),
+ METHOD(&NativeMapView::setStyleJson, "nativeSetStyleJson"),
+ METHOD(&NativeMapView::cancelTransitions, "nativeCancelTransitions"),
+ METHOD(&NativeMapView::setGestureInProgress, "nativeSetGestureInProgress"),
+ METHOD(&NativeMapView::moveBy, "nativeMoveBy"),
+ METHOD(&NativeMapView::jumpTo, "nativeJumpTo"),
+ METHOD(&NativeMapView::easeTo, "nativeEaseTo"),
+ METHOD(&NativeMapView::flyTo, "nativeFlyTo"),
+ METHOD(&NativeMapView::getLatLng, "nativeGetLatLng"),
+ METHOD(&NativeMapView::setLatLng, "nativeSetLatLng"),
+ METHOD(&NativeMapView::setReachability, "nativeSetReachability"),
+ METHOD(&NativeMapView::resetPosition, "nativeResetPosition"),
+ METHOD(&NativeMapView::getPitch, "nativeGetPitch"),
+ METHOD(&NativeMapView::setPitch, "nativeSetPitch"),
+ METHOD(&NativeMapView::scaleBy, "nativeScaleBy"),
+ METHOD(&NativeMapView::getScale, "nativeGetScale"),
+ METHOD(&NativeMapView::setScale, "nativeSetScale"),
+ METHOD(&NativeMapView::getZoom, "nativeGetZoom"),
+ METHOD(&NativeMapView::setZoom, "nativeSetZoom"),
+ METHOD(&NativeMapView::resetZoom, "nativeResetZoom"),
+ METHOD(&NativeMapView::setMinZoom, "nativeSetMinZoom"),
+ METHOD(&NativeMapView::getMinZoom, "nativeGetMinZoom"),
+ METHOD(&NativeMapView::setMaxZoom, "nativeSetMaxZoom"),
+ METHOD(&NativeMapView::getMaxZoom, "nativeGetMaxZoom"),
+ METHOD(&NativeMapView::rotateBy, "nativeRotateBy"),
+ METHOD(&NativeMapView::setBearing, "nativeSetBearing"),
+ METHOD(&NativeMapView::setBearingXY, "nativeSetBearingXY"),
+ METHOD(&NativeMapView::getBearing, "nativeGetBearing"),
+ METHOD(&NativeMapView::resetNorth, "nativeResetNorth"),
+ METHOD(&NativeMapView::setVisibleCoordinateBounds, "nativeSetVisibleCoordinateBounds"),
+ METHOD(&NativeMapView::setContentPadding, "nativeSetContentPadding"),
+ METHOD(&NativeMapView::scheduleSnapshot, "nativeTakeSnapshot"),
+ METHOD(&NativeMapView::enableFps, "nativeSetEnableFps"),
+ METHOD(&NativeMapView::getCameraValues, "nativeGetCameraValues"),
+ METHOD(&NativeMapView::updateMarker, "nativeUpdateMarker"),
+ METHOD(&NativeMapView::addMarkers, "nativeAddMarkers"),
+ METHOD(&NativeMapView::setDebug, "nativeSetDebug"),
+ METHOD(&NativeMapView::cycleDebugOptions, "nativeCycleDebugOptions"),
+ METHOD(&NativeMapView::getDebug, "nativeGetDebug"),
+ METHOD(&NativeMapView::isFullyLoaded, "nativeIsFullyLoaded"),
+ METHOD(&NativeMapView::onLowMemory, "nativeOnLowMemory"),
+ METHOD(&NativeMapView::getMetersPerPixelAtLatitude, "nativeGetMetersPerPixelAtLatitude"),
+ METHOD(&NativeMapView::projectedMetersForLatLng, "nativeProjectedMetersForLatLng"),
+ METHOD(&NativeMapView::pixelForLatLng, "nativePixelForLatLng"),
+ METHOD(&NativeMapView::latLngForProjectedMeters, "nativeLatLngForProjectedMeters"),
+ METHOD(&NativeMapView::latLngForPixel, "nativeLatLngForPixel"),
+ METHOD(&NativeMapView::addPolylines, "nativeAddPolylines"),
+ METHOD(&NativeMapView::addPolygons, "nativeAddPolygons"),
+ METHOD(&NativeMapView::updatePolyline, "nativeUpdatePolyline"),
+ METHOD(&NativeMapView::updatePolygon, "nativeUpdatePolygon"),
+ METHOD(&NativeMapView::removeAnnotations, "nativeRemoveAnnotations"),
+ METHOD(&NativeMapView::addAnnotationIcon, "nativeAddAnnotationIcon"),
+ METHOD(&NativeMapView::getTopOffsetPixelsForAnnotationSymbol, "nativeGetTopOffsetPixelsForAnnotationSymbol"),
+ METHOD(&NativeMapView::getTransitionDuration, "nativeGetTransitionDuration"),
+ METHOD(&NativeMapView::setTransitionDuration, "nativeSetTransitionDuration"),
+ METHOD(&NativeMapView::getTransitionDelay, "nativeGetTransitionDelay"),
+ METHOD(&NativeMapView::setTransitionDelay, "nativeSetTransitionDelay"),
+ METHOD(&NativeMapView::queryPointAnnotations, "nativeQueryPointAnnotations"),
+ METHOD(&NativeMapView::queryRenderedFeaturesForPoint, "nativeQueryRenderedFeaturesForPoint"),
+ METHOD(&NativeMapView::queryRenderedFeaturesForBox, "nativeQueryRenderedFeaturesForBox"),
+ METHOD(&NativeMapView::getLayers, "nativeGetLayers"),
+ METHOD(&NativeMapView::getLayer, "nativeGetLayer"),
+ METHOD(&NativeMapView::addLayer, "nativeAddLayer"),
+ METHOD(&NativeMapView::addLayerAbove, "nativeAddLayerAbove"),
+ METHOD(&NativeMapView::addLayerAt, "nativeAddLayerAt"),
+ METHOD(&NativeMapView::removeLayerById, "nativeRemoveLayerById"),
+ METHOD(&NativeMapView::removeLayerAt, "nativeRemoveLayerAt"),
+ METHOD(&NativeMapView::removeLayer, "nativeRemoveLayer"),
+ METHOD(&NativeMapView::getSources, "nativeGetSources"),
+ METHOD(&NativeMapView::getSource, "nativeGetSource"),
+ METHOD(&NativeMapView::addSource, "nativeAddSource"),
+ METHOD(&NativeMapView::removeSourceById, "nativeRemoveSourceById"),
+ METHOD(&NativeMapView::removeSource, "nativeRemoveSource"),
+ METHOD(&NativeMapView::addImage, "nativeAddImage"),
+ METHOD(&NativeMapView::removeImage, "nativeRemoveImage")
+ );
}
}
diff --git a/platform/android/src/native_map_view.hpp b/platform/android/src/native_map_view.hpp
index e7379700a9..c38afd3e6c 100755
--- a/platform/android/src/native_map_view.hpp
+++ b/platform/android/src/native_map_view.hpp
@@ -1,71 +1,275 @@
#pragma once
+#include <mbgl/map/backend.hpp>
+#include <mbgl/map/camera.hpp>
#include <mbgl/map/map.hpp>
#include <mbgl/map/view.hpp>
-#include <mbgl/map/backend.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/default_thread_pool.hpp>
+#include <mbgl/util/run_loop.hpp>
#include <mbgl/storage/default_file_source.hpp>
+#include <mbgl/storage/network_status.hpp>
+
+#include "file_source.hpp"
+#include "annotation/marker.hpp"
+#include "annotation/polygon.hpp"
+#include "annotation/polyline.hpp"
+#include "graphics/pointf.hpp"
+#include "graphics/rectf.hpp"
+#include "geometry/feature.hpp"
+#include "geometry/lat_lng.hpp"
+#include "geometry/projected_meters.hpp"
+#include "style/layers/layers.hpp"
+#include "style/sources/sources.hpp"
#include <string>
#include <jni.h>
#include <android/native_window.h>
#include <EGL/egl.h>
+#include <jni/jni.hpp>
namespace mbgl {
namespace android {
-class NativeMapView : public mbgl::View, public mbgl::Backend {
+class NativeMapView : public View, public Backend {
public:
- NativeMapView(JNIEnv *env, jobject obj, float pixelRatio, int availableProcessors, size_t totalMemory);
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/maps/NativeMapView"; };
+
+ static jni::Class<NativeMapView> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+ NativeMapView(jni::JNIEnv&, jni::Object<NativeMapView>, jni::Object<FileSource>, jni::jfloat, jni::jint, jni::jlong);
+
virtual ~NativeMapView();
- mbgl::Size getFramebufferSize() const;
- void updateViewBinding();
+ // mbgl::View //
+
void bind() override;
- void invalidate() override;
+ // mbgl::Backend //
+ void invalidate() override;
void notifyMapChange(mbgl::MapChange) override;
- mbgl::Map &getMap();
- mbgl::DefaultFileSource &getFileSource();
+ // JNI //
- void initializeDisplay();
- void terminateDisplay();
+ void destroy(jni::JNIEnv&);
- void initializeContext();
- void terminateContext();
+ void render(jni::JNIEnv&);
- void createSurface(ANativeWindow *window);
- void destroySurface();
+ void update(jni::JNIEnv&);
- void render();
+ void resizeView(jni::JNIEnv&, int, int);
- void enableFps(bool enable);
- void updateFps();
+ void resizeFramebuffer(jni::JNIEnv&, int, int);
+
+ void initializeDisplay(jni::JNIEnv&);
+
+ void terminateDisplay(jni::JNIEnv&);
+
+ void initializeContext(jni::JNIEnv&);
+
+ void terminateContext(jni::JNIEnv&);
+
+ void createSurface(jni::JNIEnv&, jni::Object<>);
+
+ void destroySurface(jni::JNIEnv&);
+
+ jni::String getStyleUrl(jni::JNIEnv&);
+
+ void setStyleUrl(jni::JNIEnv&, jni::String);
+
+ jni::String getStyleJson(jni::JNIEnv&);
+
+ void setStyleJson(jni::JNIEnv&, jni::String);
+
+ void cancelTransitions(jni::JNIEnv&);
+
+ void setGestureInProgress(jni::JNIEnv&, jni::jboolean);
+
+ void moveBy(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jlong);
+
+ void jumpTo(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jdouble, jni::jdouble);
+
+ void easeTo(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong, jni::jdouble, jni::jdouble, jni::jboolean);
+
+ void flyTo(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong, jni::jdouble, jni::jdouble);
+
+ jni::Object<LatLng> getLatLng(JNIEnv&);
+
+ void setLatLng(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jlong);
+
+ void setReachability(jni::JNIEnv&, jni::jboolean);
+
+ void resetPosition(jni::JNIEnv&);
+
+ jni::jdouble getPitch(jni::JNIEnv&);
+
+ void setPitch(jni::JNIEnv&, jni::jdouble, jni::jlong);
+
+ void scaleBy(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong);
+
+ void setScale(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong);
+
+ jni::jdouble getScale(jni::JNIEnv&);
+
+ void setZoom(jni::JNIEnv&, jni::jdouble, jni::jlong);
+
+ jni::jdouble getZoom(jni::JNIEnv&);
+
+ void resetZoom(jni::JNIEnv&);
+
+ void setMinZoom(jni::JNIEnv&, jni::jdouble);
+
+ jni::jdouble getMinZoom(jni::JNIEnv&);
+
+ void setMaxZoom(jni::JNIEnv&, jni::jdouble);
+
+ jni::jdouble getMaxZoom(jni::JNIEnv&);
+
+ void rotateBy(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong);
+
+ void setBearing(jni::JNIEnv&, jni::jdouble, jni::jlong);
+
+ void setBearingXY(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong);
+
+ jni::jdouble getBearing(jni::JNIEnv&);
+
+ void resetNorth(jni::JNIEnv&);
+
+ void setVisibleCoordinateBounds(JNIEnv&, jni::Array<jni::Object<LatLng>>, jni::Object<RectF>, jni::jdouble, jni::jlong);
+
+ void setContentPadding(JNIEnv&, double, double, double, double);
+
+ void scheduleSnapshot(jni::JNIEnv&);
+
+ void enableFps(jni::JNIEnv&, jni::jboolean enable);
+
+ jni::Array<jni::jdouble> getCameraValues(jni::JNIEnv&);
+
+ void updateMarker(jni::JNIEnv&, jni::jlong, jni::jdouble, jni::jdouble, jni::String);
+
+ jni::Array<jni::jlong> addMarkers(jni::JNIEnv&, jni::Array<jni::Object<Marker>>);
+
+ void onLowMemory(JNIEnv& env);
+
+ void setDebug(JNIEnv&, jni::jboolean);
- void resizeView(int width, int height);
- void resizeFramebuffer(int width, int height);
- mbgl::EdgeInsets getInsets() { return insets;}
- void setInsets(mbgl::EdgeInsets insets_);
+ void cycleDebugOptions(JNIEnv&);
- void scheduleTakeSnapshot();
+ jni::jboolean getDebug(JNIEnv&);
+
+ jni::jboolean isFullyLoaded(JNIEnv&);
+
+ jni::jdouble getMetersPerPixelAtLatitude(JNIEnv&, jni::jdouble, jni::jdouble);
+
+ jni::Object<ProjectedMeters> projectedMetersForLatLng(JNIEnv&, jni::jdouble, jni::jdouble);
+
+ jni::Object<PointF> pixelForLatLng(JNIEnv&, jdouble, jdouble);
+
+ jni::Object<LatLng> latLngForProjectedMeters(JNIEnv&, jdouble, jdouble);
+
+ jni::Object<LatLng> latLngForPixel(JNIEnv&, jfloat, jfloat);
+
+ jni::Array<jlong> addPolylines(JNIEnv&, jni::Array<jni::Object<Polyline>>);
+
+ jni::Array<jlong> addPolygons(JNIEnv&, jni::Array<jni::Object<Polygon>>);
+
+ void updatePolyline(JNIEnv&, jlong, jni::Object<Polyline>);
+
+ void updatePolygon(JNIEnv&, jlong, jni::Object<Polygon>);
+
+ void removeAnnotations(JNIEnv&, jni::Array<jlong>);
+
+ void addAnnotationIcon(JNIEnv&, jni::String, jint, jint, jfloat, jni::Array<jbyte>);
+
+ jni::jdouble getTopOffsetPixelsForAnnotationSymbol(JNIEnv&, jni::String);
+
+ jni::jlong getTransitionDuration(JNIEnv&);
+
+ void setTransitionDuration(JNIEnv&, jni::jlong);
+
+ jni::jlong getTransitionDelay(JNIEnv&);
+
+ void setTransitionDelay(JNIEnv&, jni::jlong);
+
+ jni::Array<jlong> queryPointAnnotations(JNIEnv&, jni::Object<RectF>);
+
+ jni::Array<jni::Object<Feature>> queryRenderedFeaturesForPoint(JNIEnv&, jni::jfloat, jni::jfloat, jni::Array<jni::String>);
+
+ jni::Array<jni::Object<Feature>> queryRenderedFeaturesForBox(JNIEnv&, jni::jfloat, jni::jfloat, jni::jfloat, jni::jfloat, jni::Array<jni::String>);
+
+ jni::Array<jni::Object<Layer>> getLayers(JNIEnv&);
+
+ jni::Object<Layer> getLayer(JNIEnv&, jni::String);
+
+ void addLayer(JNIEnv&, jlong, jni::String);
+
+ void addLayerAbove(JNIEnv&, jlong, jni::String);
+
+ void addLayerAt(JNIEnv&, jni::jlong, jni::jint);
+
+ jni::Object<Layer> removeLayerById(JNIEnv&, jni::String);
+
+ jni::Object<Layer> removeLayerAt(JNIEnv&, jni::jint);
+
+ void removeLayer(JNIEnv&, jlong);
+
+ jni::Array<jni::Object<Source>> getSources(JNIEnv&);
+
+ jni::Object<Source> getSource(JNIEnv&, jni::String);
+
+ void addSource(JNIEnv&, jni::jlong);
+
+ jni::Object<Source> removeSourceById(JNIEnv&, jni::String);
+
+ void removeSource(JNIEnv&, jlong);
+
+ void addImage(JNIEnv&, jni::String, jni::jint, jni::jint, jni::jfloat, jni::Array<jbyte>);
+
+ void removeImage(JNIEnv&, jni::String);
protected:
+ // mbgl::Backend //
+
void activate() override;
void deactivate() override;
private:
+ void _initializeDisplay();
+
+ void _terminateDisplay();
+
+ void _initializeContext();
+
+ void _terminateContext();
+
+ void _createSurface(ANativeWindow*);
+
+ void _destroySurface();
+
EGLConfig chooseConfig(const EGLConfig configs[], EGLint numConfigs);
+ void updateViewBinding();
+ mbgl::Size getFramebufferSize() const;
+
+ void updateFps();
+
private:
+
JavaVM *vm = nullptr;
- JNIEnv *env = nullptr;
- jweak obj = nullptr;
+ jni::UniqueWeakObject<NativeMapView> javaPeer;
+
+ std::string styleUrl;
+ std::string apiKey;
ANativeWindow *window = nullptr;
+ EGLConfig config = nullptr;
+ EGLint format = -1;
+
EGLDisplay oldDisplay = EGL_NO_DISPLAY;
EGLSurface oldReadSurface = EGL_NO_SURFACE;
EGLSurface oldDrawSurface = EGL_NO_SURFACE;
@@ -75,15 +279,11 @@ private:
EGLSurface surface = EGL_NO_SURFACE;
EGLContext context = EGL_NO_CONTEXT;
- EGLConfig config = nullptr;
- EGLint format = -1;
- std::string styleUrl;
- std::string apiKey;
-
- bool firstTime = false;
+ float pixelRatio;
bool fpsEnabled = false;
bool snapshot = false;
+ bool firstRender = true;
double fps = 0.0;
int width = 0;
@@ -96,12 +296,12 @@ private:
size_t totalMemory = 0;
// Ensure these are initialised last
- std::unique_ptr<mbgl::DefaultFileSource> fileSource;
- mbgl::ThreadPool threadPool;
+ std::shared_ptr<mbgl::ThreadPool> threadPool;
std::unique_ptr<mbgl::Map> map;
mbgl::EdgeInsets insets;
unsigned active = 0;
};
-}
-}
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/offline/offline_manager.cpp b/platform/android/src/offline/offline_manager.cpp
new file mode 100644
index 0000000000..02871e7fdf
--- /dev/null
+++ b/platform/android/src/offline/offline_manager.cpp
@@ -0,0 +1,164 @@
+#include "offline_manager.hpp"
+
+#include <mbgl/util/string.hpp>
+
+#include "../attach_env.hpp"
+#include "../jni/generic_global_ref_deleter.hpp"
+
+namespace mbgl {
+namespace android {
+
+// OfflineManager //
+
+OfflineManager::OfflineManager(jni::JNIEnv& env, jni::Object<FileSource> jFileSource)
+ : fileSource(mbgl::android::FileSource::getDefaultFileSource(env, jFileSource)) {
+}
+
+OfflineManager::~OfflineManager() {}
+
+void OfflineManager::setOfflineMapboxTileCountLimit(jni::JNIEnv&, jni::jlong limit) {
+ fileSource.setOfflineMapboxTileCountLimit(limit);
+}
+
+void OfflineManager::listOfflineRegions(jni::JNIEnv& env_, jni::Object<FileSource> jFileSource_, jni::Object<ListOfflineRegionsCallback> callback_) {
+ // list regions
+ fileSource.listOfflineRegions([
+ //Keep a shared ptr to a global reference of the callback and file source so they are not GC'd in the meanwhile
+ callback = std::shared_ptr<jni::jobject>(callback_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter()),
+ jFileSource = std::shared_ptr<jni::jobject>(jFileSource_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter())
+ ](std::exception_ptr error, mbgl::optional<std::vector<mbgl::OfflineRegion>> regions) mutable {
+
+ // Reattach, the callback comes from a different thread
+ android::UniqueEnv env = android::AttachEnv();
+
+ if (error) {
+ OfflineManager::ListOfflineRegionsCallback::onError(*env, jni::Object<ListOfflineRegionsCallback>(*callback), error);
+ } else if (regions) {
+ OfflineManager::ListOfflineRegionsCallback::onList(*env, jni::Object<FileSource>(*jFileSource), jni::Object<ListOfflineRegionsCallback>(*callback), std::move(regions));
+ }
+ });
+}
+
+void OfflineManager::createOfflineRegion(jni::JNIEnv& env_,
+ jni::Object<FileSource> jFileSource_,
+ jni::Object<OfflineRegionDefinition> definition_,
+ jni::Array<jni::jbyte> metadata_,
+ jni::Object<CreateOfflineRegionCallback> callback_) {
+ // Convert
+
+ // XXX hardcoded cast for now as we only support OfflineTilePyramidRegionDefinition
+ auto definition = OfflineTilePyramidRegionDefinition::getDefinition(env_, jni::Object<OfflineTilePyramidRegionDefinition>(*definition_));
+
+ mbgl::OfflineRegionMetadata metadata;
+ if (metadata_) {
+ metadata = OfflineRegion::metadata(env_, metadata_);
+ }
+
+ // Create region
+ fileSource.createOfflineRegion(definition, metadata, [
+ //Keep a shared ptr to a global reference of the callback and file source so they are not GC'd in the meanwhile
+ callback = std::shared_ptr<jni::jobject>(callback_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter()),
+ jFileSource = std::shared_ptr<jni::jobject>(jFileSource_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter())
+ ](std::exception_ptr error, mbgl::optional<mbgl::OfflineRegion> region) mutable {
+
+ // Reattach, the callback comes from a different thread
+ android::UniqueEnv env = android::AttachEnv();
+
+ if (error) {
+ OfflineManager::CreateOfflineRegionCallback::onError(*env, jni::Object<CreateOfflineRegionCallback>(*callback), error);
+ } else if (region) {
+ OfflineManager::CreateOfflineRegionCallback::onCreate(
+ *env,
+ jni::Object<FileSource>(*jFileSource),
+ jni::Object<CreateOfflineRegionCallback>(*callback), std::move(region)
+ );
+ }
+ });
+}
+
+jni::Class<OfflineManager> OfflineManager::javaClass;
+
+void OfflineManager::registerNative(jni::JNIEnv& env) {
+ OfflineManager::ListOfflineRegionsCallback::registerNative(env);
+ OfflineManager::CreateOfflineRegionCallback::registerNative(env);
+
+ javaClass = *jni::Class<OfflineManager>::Find(env).NewGlobalRef(env).release();
+
+ #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
+
+ jni::RegisterNativePeer<OfflineManager>( env, javaClass, "nativePtr",
+ std::make_unique<OfflineManager, JNIEnv&, jni::Object<FileSource>>,
+ "initialize",
+ "finalize",
+ METHOD(&OfflineManager::setOfflineMapboxTileCountLimit, "setOfflineMapboxTileCountLimit"),
+ METHOD(&OfflineManager::listOfflineRegions, "listOfflineRegions"),
+ METHOD(&OfflineManager::createOfflineRegion, "createOfflineRegion"));
+}
+
+// OfflineManager::ListOfflineRegionsCallback //
+
+void OfflineManager::ListOfflineRegionsCallback::onError(jni::JNIEnv& env,
+ jni::Object<OfflineManager::ListOfflineRegionsCallback> callback,
+ 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));
+}
+
+void OfflineManager::ListOfflineRegionsCallback::onList(jni::JNIEnv& env,
+ jni::Object<FileSource> jFileSource,
+ jni::Object<OfflineManager::ListOfflineRegionsCallback> callback,
+ mbgl::optional<std::vector<mbgl::OfflineRegion>> regions) {
+ //Convert the regions to java peer objects
+ std::size_t index = 0;
+ auto jregions = jni::Array<jni::Object<OfflineRegion>>::New(env, regions->size(), OfflineRegion::javaClass);
+ for (auto& region : *regions) {
+ auto jregion = OfflineRegion::New(env, jFileSource, std::move(region));
+ jregions.Set(env, index, jregion);
+ jni::DeleteLocalRef(env, jregion);
+ index++;
+ }
+
+ // Trigger callback
+ static auto method = javaClass.GetMethod<void (jni::Array<jni::Object<OfflineRegion>>)>(env, "onList");
+ callback.Call(env, method, jregions);
+ jni::DeleteLocalRef(env, jregions);
+}
+
+jni::Class<OfflineManager::ListOfflineRegionsCallback> OfflineManager::ListOfflineRegionsCallback::javaClass;
+
+void OfflineManager::ListOfflineRegionsCallback::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineManager::ListOfflineRegionsCallback>::Find(env).NewGlobalRef(env).release();
+}
+
+// OfflineManager::CreateOfflineRegionCallback //
+
+void OfflineManager::CreateOfflineRegionCallback::onError(jni::JNIEnv& env,
+ jni::Object<OfflineManager::CreateOfflineRegionCallback> callback,
+ 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));
+}
+
+void OfflineManager::CreateOfflineRegionCallback::onCreate(jni::JNIEnv& env,
+ jni::Object<FileSource> jFileSource,
+ jni::Object<OfflineManager::CreateOfflineRegionCallback> callback,
+ mbgl::optional<mbgl::OfflineRegion> region) {
+ //Convert the region to java peer object
+ auto jregion = OfflineRegion::New(env, jFileSource, std::move(*region));
+
+ // Trigger callback
+ static auto method = javaClass.GetMethod<void (jni::Object<OfflineRegion>)>(env, "onCreate");
+ callback.Call(env, method, jregion);
+ jni::DeleteLocalRef(env, jregion);
+}
+
+jni::Class<OfflineManager::CreateOfflineRegionCallback> OfflineManager::CreateOfflineRegionCallback::javaClass;
+
+void OfflineManager::CreateOfflineRegionCallback::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineManager::CreateOfflineRegionCallback>::Find(env).NewGlobalRef(env).release();
+}
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/offline/offline_manager.hpp b/platform/android/src/offline/offline_manager.hpp
new file mode 100644
index 0000000000..9ae2714ca2
--- /dev/null
+++ b/platform/android/src/offline/offline_manager.hpp
@@ -0,0 +1,75 @@
+#pragma once
+
+
+#include <mbgl/storage/default_file_source.hpp>
+#include <mbgl/storage/offline.hpp>
+#include <jni/jni.hpp>
+
+#include "../file_source.hpp"
+#include "offline_region.hpp"
+#include "offline_region_definition.hpp"
+
+
+namespace mbgl {
+namespace android {
+
+class OfflineManager {
+public:
+
+ class ListOfflineRegionsCallback {
+ public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineManager$ListOfflineRegionsCallback";}
+
+ static void onError(jni::JNIEnv&, jni::Object<OfflineManager::ListOfflineRegionsCallback>, std::exception_ptr);
+
+ static void onList(jni::JNIEnv&,
+ jni::Object<FileSource>,
+ jni::Object<OfflineManager::ListOfflineRegionsCallback>,
+ mbgl::optional<std::vector<mbgl::OfflineRegion>>);
+
+ static jni::Class<OfflineManager::ListOfflineRegionsCallback> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+ };
+
+ class CreateOfflineRegionCallback {
+ public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineManager$CreateOfflineRegionCallback"; }
+
+ static void onError(jni::JNIEnv&, jni::Object<OfflineManager::CreateOfflineRegionCallback>, std::exception_ptr);
+
+ static void onCreate(jni::JNIEnv&,
+ jni::Object<FileSource>,
+ jni::Object<OfflineManager::CreateOfflineRegionCallback>,
+ mbgl::optional<mbgl::OfflineRegion>);
+
+ static jni::Class<OfflineManager::CreateOfflineRegionCallback> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+ };
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineManager"; };
+
+ static jni::Class<OfflineManager> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+ OfflineManager(jni::JNIEnv&, jni::Object<FileSource>);
+ ~OfflineManager();
+
+ void setOfflineMapboxTileCountLimit(jni::JNIEnv&, jni::jlong limit);
+
+ void listOfflineRegions(jni::JNIEnv&, jni::Object<FileSource>, jni::Object<ListOfflineRegionsCallback> callback);
+
+ void createOfflineRegion(jni::JNIEnv&,
+ jni::Object<FileSource> jFileSource_,
+ jni::Object<OfflineRegionDefinition> definition,
+ jni::Array<jni::jbyte> metadata,
+ jni::Object<OfflineManager::CreateOfflineRegionCallback> callback);
+
+private:
+ mbgl::DefaultFileSource& fileSource;
+};
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/offline/offline_region.cpp b/platform/android/src/offline/offline_region.cpp
new file mode 100644
index 0000000000..856434d266
--- /dev/null
+++ b/platform/android/src/offline/offline_region.cpp
@@ -0,0 +1,308 @@
+#include "offline_region.hpp"
+
+#include <mbgl/util/logging.hpp>
+#include <mbgl/util/string.hpp>
+
+#include "offline_region_definition.hpp"
+#include "offline_region_error.hpp"
+#include "offline_region_status.hpp"
+#include "../attach_env.hpp"
+#include "../jni/generic_global_ref_deleter.hpp"
+
+namespace mbgl {
+namespace android {
+
+// OfflineRegion //
+
+OfflineRegion::OfflineRegion(jni::JNIEnv& env, jni::jlong offlineRegionPtr, jni::Object<FileSource> jFileSource)
+ : region(reinterpret_cast<mbgl::OfflineRegion *>(offlineRegionPtr)),
+ fileSource(mbgl::android::FileSource::getDefaultFileSource(env, jFileSource)) {}
+
+OfflineRegion::~OfflineRegion() {}
+
+void OfflineRegion::setOfflineRegionObserver(jni::JNIEnv& env_, jni::Object<OfflineRegion::OfflineRegionObserver> callback) {
+
+ // Define the observer
+ class Observer : public mbgl::OfflineRegionObserver {
+ public:
+ Observer(jni::UniqueObject<OfflineRegion::OfflineRegionObserver>&& callback_)
+ //TODO add a generic deleter for jni::Object
+ : callback(callback_.release()->Get()) {
+ }
+
+ ~Observer() override {
+ android::UniqueEnv env = android::AttachEnv();
+ env->DeleteGlobalRef(Unwrap(*callback));
+ }
+
+ void statusChanged(mbgl::OfflineRegionStatus status) override {
+ // Reattach, the callback comes from a different thread
+ android::UniqueEnv env = android::AttachEnv();
+
+ // Status object
+ auto jStatus = OfflineRegionStatus::New(*env, status);
+
+ // Call
+ static auto method = OfflineRegion::OfflineRegionObserver::javaClass
+ .GetMethod<void (jni::Object<OfflineRegionStatus>)>(*env, "onStatusChanged");
+ callback.Call(*env, method, jStatus);
+
+ // Delete references
+ jni::DeleteLocalRef(*env, jStatus);
+ }
+
+ void responseError(mbgl::Response::Error error) override {
+ // Reattach, the callback comes from a different thread
+ android::UniqueEnv env = android::AttachEnv();
+
+ // Error object
+ auto jError = OfflineRegionError::New(*env, error);
+
+ // Call
+ static auto method = OfflineRegion::OfflineRegionObserver::javaClass
+ .GetMethod<void (jni::Object<mbgl::android::OfflineRegionError>)>(*env, "onError");
+ callback.Call(*env, method, jError);
+
+ // Delete references
+ jni::DeleteLocalRef(*env, jError);
+ }
+
+ void mapboxTileCountLimitExceeded(uint64_t limit) override {
+ // Reattach, the callback comes from a different thread
+ android::UniqueEnv env = android::AttachEnv();
+
+ // Send limit
+ static auto method = OfflineRegion::OfflineRegionObserver::javaClass
+ .GetMethod<void (jni::jlong)>(*env, "mapboxTileCountLimitExceeded");
+ callback.Call(*env, method, jlong(limit));
+ }
+
+ jni::Object<OfflineRegion::OfflineRegionObserver> callback;
+ };
+
+ // Set the observer
+ fileSource.setOfflineRegionObserver(*region, std::make_unique<Observer>(callback.NewGlobalRef(env_)));
+}
+
+void OfflineRegion::setOfflineRegionDownloadState(jni::JNIEnv&, jni::jint jState) {
+ // State
+ mbgl::OfflineRegionDownloadState state;
+ switch (jState) {
+ case 0:
+ state = mbgl::OfflineRegionDownloadState::Inactive;
+ break;
+ case 1:
+ state = mbgl::OfflineRegionDownloadState::Active;
+ break;
+ default:
+ mbgl::Log::Error(mbgl::Event::JNI, "State can only be 0 (inactive) or 1 (active).");
+ return;
+ }
+
+ fileSource.setOfflineRegionDownloadState(*region, state);
+}
+
+void OfflineRegion::getOfflineRegionStatus(jni::JNIEnv& env_, jni::Object<OfflineRegionStatusCallback> callback_) {
+
+ fileSource.getOfflineRegionStatus(*region, [
+ //Ensure the object is not gc'd in the meanwhile
+ callback = std::shared_ptr<jni::jobject>(callback_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter())
+ ](std::exception_ptr error, mbgl::optional<mbgl::OfflineRegionStatus> status) mutable {
+ // Reattach, the callback comes from a different thread
+ android::UniqueEnv env = android::AttachEnv();
+
+ if (error) {
+ OfflineRegionStatusCallback::onError(*env, jni::Object<OfflineRegionStatusCallback>(*callback), error);
+ } else if (status) {
+ OfflineRegionStatusCallback::onStatus(*env, jni::Object<OfflineRegionStatusCallback>(*callback), std::move(status));
+ }
+ });
+}
+
+void OfflineRegion::deleteOfflineRegion(jni::JNIEnv& env_, jni::Object<OfflineRegionDeleteCallback> callback_) {
+ // Delete
+ fileSource.deleteOfflineRegion(std::move(*region), [
+ //Ensure the object is not gc'd in the meanwhile
+ callback = std::shared_ptr<jni::jobject>(callback_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter())
+ ](std::exception_ptr error) mutable {
+ // Reattach, the callback comes from a different thread
+ android::UniqueEnv env = android::AttachEnv();
+
+ if (error) {
+ OfflineRegionDeleteCallback::onError(*env, jni::Object<OfflineRegionDeleteCallback>(*callback), error);
+ } else {
+ OfflineRegionDeleteCallback::onDelete(*env, jni::Object<OfflineRegionDeleteCallback>(*callback));
+ }
+ });
+}
+
+void OfflineRegion::updateOfflineRegionMetadata(jni::JNIEnv& env_, jni::Array<jni::jbyte> jMetadata, jni::Object<OfflineRegionUpdateMetadataCallback> callback_) {
+
+ // Convert
+ auto metadata = OfflineRegion::metadata(env_, jMetadata);
+
+ fileSource.updateOfflineMetadata(region->getID(), metadata, [
+ //Ensure the object is not gc'd in the meanwhile
+ callback = std::shared_ptr<jni::jobject>(callback_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter())
+ ](std::exception_ptr error, mbgl::optional<mbgl::OfflineRegionMetadata> data) mutable {
+ // Reattach, the callback comes from a different thread
+ android::UniqueEnv env = android::AttachEnv();
+
+ if (error) {
+ OfflineRegionUpdateMetadataCallback::onError(*env, jni::Object<OfflineRegionUpdateMetadataCallback>(*callback), error);
+ } else if (data) {
+ OfflineRegionUpdateMetadataCallback::onUpdate(*env, jni::Object<OfflineRegionUpdateMetadataCallback>(*callback), std::move(data));
+ }
+ });
+}
+
+jni::Object<OfflineRegion> OfflineRegion::New(jni::JNIEnv& env, jni::Object<FileSource> jFileSource, mbgl::OfflineRegion region) {
+
+ // Definition
+ auto definition = jni::Object<OfflineRegionDefinition>(*OfflineTilePyramidRegionDefinition::New(env, region.getDefinition()));
+
+ // Metadata
+ auto metadata = OfflineRegion::metadata(env, region.getMetadata());
+
+ // Create region java object
+ static auto constructor = OfflineRegion::javaClass.GetConstructor<jni::jlong, jni::Object<FileSource>, jni::jlong, jni::Object<OfflineRegionDefinition>, jni::Array<jni::jbyte>>(env);
+ auto jregion = OfflineRegion::javaClass.New(env, constructor,
+ reinterpret_cast<jni::jlong>(new mbgl::OfflineRegion(std::move(region))), //Copy a region to the heap
+ jFileSource, jni::jlong(region.getID()), definition, metadata);
+
+ //Delete references
+ jni::DeleteLocalRef(env, definition);
+ jni::DeleteLocalRef(env, metadata);
+
+ return jregion;
+}
+
+jni::Array<jni::jbyte> OfflineRegion::metadata(jni::JNIEnv& env, mbgl::OfflineRegionMetadata metadata_) {
+ std::vector<jni::jbyte> convertedMetadata(metadata_.begin(), metadata_.end());
+ std::size_t length = static_cast<std::size_t>(convertedMetadata.size());
+ auto metadata = jni::Array<jni::jbyte>::New(env, length);
+ metadata.SetRegion<std::vector<jni::jbyte>>(env, 0, convertedMetadata);
+ return metadata;
+}
+
+mbgl::OfflineRegionMetadata OfflineRegion::metadata(jni::JNIEnv& env, jni::Array<jni::jbyte> metadata_) {
+ std::size_t length = metadata_.Length(env);
+ auto metadata_tmp = std::vector<jni::jbyte>();
+ metadata_tmp.resize(length);
+ metadata_.GetRegion<std::vector<jni::jbyte>>(env, 0, metadata_tmp);
+ auto metadata = std::vector<uint8_t>(metadata_tmp.begin(), metadata_tmp.end());
+ return metadata;
+}
+
+jni::Class<OfflineRegion> OfflineRegion::javaClass;
+
+void OfflineRegion::registerNative(jni::JNIEnv& env) {
+ OfflineRegion::OfflineRegionObserver::registerNative(env);
+ OfflineRegion::OfflineRegionStatusCallback::registerNative(env);
+ OfflineRegion::OfflineRegionDeleteCallback::registerNative(env);
+ OfflineRegion::OfflineRegionUpdateMetadataCallback::registerNative(env);
+
+ javaClass = *jni::Class<OfflineRegion>::Find(env).NewGlobalRef(env).release();
+
+ #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
+
+ jni::RegisterNativePeer<OfflineRegion>( env, javaClass, "nativePtr",
+ std::make_unique<OfflineRegion, JNIEnv&, jni::jlong, jni::Object<FileSource>>,
+ "initialize",
+ "finalize",
+ METHOD(&OfflineRegion::setOfflineRegionObserver, "setOfflineRegionObserver"),
+ METHOD(&OfflineRegion::setOfflineRegionDownloadState, "setOfflineRegionDownloadState"),
+ METHOD(&OfflineRegion::getOfflineRegionStatus, "getOfflineRegionStatus"),
+ METHOD(&OfflineRegion::deleteOfflineRegion, "deleteOfflineRegion"),
+ METHOD(&OfflineRegion::updateOfflineRegionMetadata, "updateOfflineRegionMetadata")
+ );
+}
+
+// OfflineRegionObserver //
+
+jni::Class<OfflineRegion::OfflineRegionObserver> OfflineRegion::OfflineRegionObserver::javaClass;
+
+void OfflineRegion::OfflineRegionObserver::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineRegion::OfflineRegionObserver>::Find(env).NewGlobalRef(env).release();
+}
+
+// OfflineRegionStatusCallback //
+
+jni::Class<OfflineRegion::OfflineRegionStatusCallback> OfflineRegion::OfflineRegionStatusCallback::javaClass;
+
+void OfflineRegion::OfflineRegionStatusCallback::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineRegionStatusCallback>::Find(env).NewGlobalRef(env).release();
+}
+
+void OfflineRegion::OfflineRegionStatusCallback::onError(jni::JNIEnv& env,
+ jni::Object<OfflineRegion::OfflineRegionStatusCallback> callback,
+ 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));
+}
+
+void OfflineRegion::OfflineRegionStatusCallback::onStatus(jni::JNIEnv& env,
+ jni::Object<OfflineRegion::OfflineRegionStatusCallback> callback,
+ mbgl::optional<mbgl::OfflineRegionStatus> status) {
+ //Convert to java peer object
+ auto jStatus = OfflineRegionStatus::New(env, std::move(*status));
+
+ // Trigger callback
+ static auto method = javaClass.GetMethod<void (jni::Object<OfflineRegionStatus>)>(env, "onStatus");
+ callback.Call(env, method, jStatus);
+ jni::DeleteLocalRef(env, jStatus);
+}
+
+// OfflineRegionDeleteCallback //
+
+jni::Class<OfflineRegion::OfflineRegionDeleteCallback> OfflineRegion::OfflineRegionDeleteCallback::javaClass;
+
+void OfflineRegion::OfflineRegionDeleteCallback::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineRegionDeleteCallback>::Find(env).NewGlobalRef(env).release();
+}
+
+void OfflineRegion::OfflineRegionDeleteCallback::onError(jni::JNIEnv& env,
+ jni::Object<OfflineRegion::OfflineRegionDeleteCallback> callback,
+ 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));
+}
+
+void OfflineRegion::OfflineRegionDeleteCallback::onDelete(jni::JNIEnv& env, jni::Object<OfflineRegion::OfflineRegionDeleteCallback> callback) {
+ // Trigger callback
+ static auto method = javaClass.GetMethod<void ()>(env, "onDelete");
+ callback.Call(env, method);
+}
+
+// OfflineRegionUpdateMetadataCallback //
+
+jni::Class<OfflineRegion::OfflineRegionUpdateMetadataCallback> OfflineRegion::OfflineRegionUpdateMetadataCallback::javaClass;
+
+void OfflineRegion::OfflineRegionUpdateMetadataCallback::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineRegionUpdateMetadataCallback>::Find(env).NewGlobalRef(env).release();
+}
+
+void OfflineRegion::OfflineRegionUpdateMetadataCallback::onError(jni::JNIEnv& env,
+ jni::Object<OfflineRegion::OfflineRegionUpdateMetadataCallback> callback,
+ 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));
+}
+
+void OfflineRegion::OfflineRegionUpdateMetadataCallback::onUpdate(jni::JNIEnv& env,
+ jni::Object<OfflineRegion::OfflineRegionUpdateMetadataCallback> callback,
+ mbgl::optional<mbgl::OfflineRegionMetadata> metadata) {
+ //Convert to java peer object
+ auto jMetadata = OfflineRegion::metadata(env, std::move(*metadata));
+
+ // Trigger callback
+ static auto method = javaClass.GetMethod<void (jni::Array<jni::jbyte>)>(env, "onUpdate");
+ callback.Call(env, method, jMetadata);
+ jni::DeleteLocalRef(env, jMetadata);
+}
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/offline/offline_region.hpp b/platform/android/src/offline/offline_region.hpp
new file mode 100644
index 0000000000..c05383a91a
--- /dev/null
+++ b/platform/android/src/offline/offline_region.hpp
@@ -0,0 +1,99 @@
+#pragma once
+
+#include <mbgl/storage/offline.hpp>
+#include <jni/jni.hpp>
+
+#include "../file_source.hpp"
+
+#include <memory>
+
+namespace mbgl {
+namespace android {
+
+class OfflineRegion {
+public:
+ class OfflineRegionObserver {
+ public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionObserver"; };
+
+ static jni::Class<OfflineRegionObserver> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+ };
+
+ class OfflineRegionStatusCallback {
+ public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionStatusCallback"; };
+
+ static void onError(jni::JNIEnv&, jni::Object<OfflineRegionStatusCallback>, std::exception_ptr);
+
+ static void onStatus(jni::JNIEnv&,
+ jni::Object<OfflineRegionStatusCallback>,
+ mbgl::optional<mbgl::OfflineRegionStatus>);
+
+ static jni::Class<OfflineRegionStatusCallback> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+ };
+
+ class OfflineRegionDeleteCallback {
+ public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionDeleteCallback"; };
+
+ static void onError(jni::JNIEnv&, jni::Object<OfflineRegionDeleteCallback>, std::exception_ptr);
+
+ static void onDelete(jni::JNIEnv&, jni::Object<OfflineRegionDeleteCallback>);
+
+ static jni::Class<OfflineRegionDeleteCallback> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+ };
+
+ class OfflineRegionUpdateMetadataCallback {
+ public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionUpdateMetadataCallback"; };
+
+ static void onError(jni::JNIEnv&, jni::Object<OfflineRegionUpdateMetadataCallback>, std::exception_ptr);
+
+ static void onUpdate(jni::JNIEnv&,
+ jni::Object<OfflineRegionUpdateMetadataCallback>,
+ mbgl::optional<mbgl::OfflineRegionMetadata>);
+
+ static jni::Class<OfflineRegionUpdateMetadataCallback> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+ };
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion"; };
+
+ OfflineRegion(jni::JNIEnv&, jni::jlong, jni::Object<FileSource>);
+
+ ~OfflineRegion();
+
+ void setOfflineRegionObserver(jni::JNIEnv&, jni::Object<OfflineRegion::OfflineRegionObserver>);
+
+ void setOfflineRegionDownloadState(jni::JNIEnv&, jni::jint);
+
+ void getOfflineRegionStatus(jni::JNIEnv&, jni::Object<OfflineRegion::OfflineRegionStatusCallback>);
+
+ void deleteOfflineRegion(jni::JNIEnv&, jni::Object<OfflineRegionDeleteCallback>);
+
+ void updateOfflineRegionMetadata(jni::JNIEnv&, jni::Array<jni::jbyte>, jni::Object<OfflineRegionUpdateMetadataCallback>);
+
+ static jni::Object<OfflineRegion> New(jni::JNIEnv&, jni::Object<FileSource>, mbgl::OfflineRegion);
+
+ static jni::Array<jni::jbyte> metadata(jni::JNIEnv&, mbgl::OfflineRegionMetadata);
+
+ static mbgl::OfflineRegionMetadata metadata(jni::JNIEnv&, jni::Array<jni::jbyte>);
+
+ static jni::Class<OfflineRegion> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+private:
+ std::unique_ptr<mbgl::OfflineRegion> region;
+ mbgl::DefaultFileSource& fileSource;
+};
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/offline/offline_region_definition.cpp b/platform/android/src/offline/offline_region_definition.cpp
new file mode 100644
index 0000000000..66a9bdf99d
--- /dev/null
+++ b/platform/android/src/offline/offline_region_definition.cpp
@@ -0,0 +1,69 @@
+#include "offline_region_definition.hpp"
+
+#include "../geometry/lat_lng_bounds.hpp"
+
+namespace mbgl {
+namespace android {
+
+// OfflineRegionDefinition //
+
+jni::Class<OfflineRegionDefinition> OfflineRegionDefinition::javaClass;
+
+void OfflineRegionDefinition::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineRegionDefinition>::Find(env).NewGlobalRef(env).release();
+}
+
+// OfflineTilePyramidRegionDefinition //
+
+jni::Object<OfflineTilePyramidRegionDefinition> OfflineTilePyramidRegionDefinition::New(jni::JNIEnv& env, mbgl::OfflineTilePyramidRegionDefinition definition) {
+
+ //Convert objects
+ auto styleURL = jni::Make<jni::String>(env, definition.styleURL);
+ auto bounds = LatLngBounds::New(env, definition.bounds);
+
+ static auto constructor = javaClass.GetConstructor<jni::String, jni::Object<LatLngBounds>, jni::jdouble, jni::jdouble, jni::jfloat>(env);
+ auto jdefinition = javaClass.New(env, constructor, styleURL, bounds, definition.minZoom, definition.maxZoom, definition.pixelRatio);
+
+ //Delete References
+ jni::DeleteLocalRef(env, styleURL);
+ jni::DeleteLocalRef(env, bounds);
+
+ return jdefinition;
+}
+
+mbgl::OfflineTilePyramidRegionDefinition OfflineTilePyramidRegionDefinition::getDefinition(jni::JNIEnv& env, jni::Object<OfflineTilePyramidRegionDefinition> jDefinition) {
+ // Field references
+ static auto styleURLF = javaClass.GetField<jni::String>(env, "styleURL");
+ static auto boundsF = javaClass.GetField<jni::Object<LatLngBounds>>(env, "bounds");
+ static auto minZoomF = javaClass.GetField<jni::jdouble>(env, "minZoom");
+ static auto maxZoomF = javaClass.GetField<jni::jdouble>(env, "maxZoom");
+ static auto pixelRatioF = javaClass.GetField<jni::jfloat>(env, "pixelRatio");
+
+ // Get objects
+ auto jStyleURL = jDefinition.Get(env, styleURLF);
+ auto jBounds = jDefinition.Get(env, boundsF);
+
+ // Create definition
+ mbgl::OfflineTilePyramidRegionDefinition definition(
+ jni::Make<std::string>(env, jStyleURL),
+ LatLngBounds::getLatLngBounds(env, jBounds),
+ jDefinition.Get(env, minZoomF),
+ jDefinition.Get(env, maxZoomF),
+ jDefinition.Get(env, pixelRatioF)
+ );
+
+ // Delete references
+ jni::DeleteLocalRef(env, jStyleURL);
+ jni::DeleteLocalRef(env, jBounds);
+
+ return definition;
+}
+
+jni::Class<OfflineTilePyramidRegionDefinition> OfflineTilePyramidRegionDefinition::javaClass;
+
+void OfflineTilePyramidRegionDefinition::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineTilePyramidRegionDefinition>::Find(env).NewGlobalRef(env).release();
+}
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/offline/offline_region_definition.hpp b/platform/android/src/offline/offline_region_definition.hpp
new file mode 100644
index 0000000000..2ca82a4d96
--- /dev/null
+++ b/platform/android/src/offline/offline_region_definition.hpp
@@ -0,0 +1,34 @@
+#pragma once
+
+#include <mbgl/storage/offline.hpp>
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class OfflineRegionDefinition {
+public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegionDefinition"; };
+
+ static jni::Class<OfflineRegionDefinition> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+};
+
+class OfflineTilePyramidRegionDefinition: public OfflineRegionDefinition {
+public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition"; };
+
+ static jni::Object<OfflineTilePyramidRegionDefinition> New(jni::JNIEnv&, mbgl::OfflineTilePyramidRegionDefinition);
+
+ static mbgl::OfflineTilePyramidRegionDefinition getDefinition(jni::JNIEnv&, jni::Object<OfflineTilePyramidRegionDefinition>);
+
+ static jni::Class<OfflineTilePyramidRegionDefinition> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+};
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/offline/offline_region_error.cpp b/platform/android/src/offline/offline_region_error.cpp
new file mode 100644
index 0000000000..b0a19f934f
--- /dev/null
+++ b/platform/android/src/offline/offline_region_error.cpp
@@ -0,0 +1,53 @@
+#include "offline_region_error.hpp"
+
+namespace mbgl {
+namespace android {
+
+jni::Object<OfflineRegionError> OfflineRegionError::New(jni::JNIEnv& env, mbgl::Response::Error error) {
+
+ // Handle the value of reason independently of the underlying int value
+ std::string reason;
+ switch(error.reason) {
+ case mbgl::Response::Error::Reason::Success:
+ reason = "REASON_SUCCESS";
+ break;
+ case mbgl::Response::Error::Reason::NotFound:
+ reason = "REASON_NOT_FOUND";
+ break;
+ case mbgl::Response::Error::Reason::Server:
+ reason = "REASON_SERVER";
+ break;
+ case mbgl::Response::Error::Reason::Connection:
+ reason = "REASON_CONNECTION";
+ break;
+ case mbgl::Response::Error::Reason::RateLimit:
+ reason = "REASON_RATE_LIMIT";
+ break;
+ case mbgl::Response::Error::Reason::Other:
+ reason = "REASON_OTHER";
+ break;
+ }
+
+ // Convert
+ auto jReason = jni::Make<jni::String>(env, reason);
+ auto jMessage = jni::Make<jni::String>(env, error.message);
+
+ // Create java object
+ static auto constructor = javaClass.GetConstructor<jni::String, jni::String>(env);
+ auto jError = javaClass.New(env, constructor, jReason, jMessage);
+
+ // Delete references
+ jni::DeleteLocalRef(env, jReason);
+ jni::DeleteLocalRef(env, jMessage);
+
+ return jError;
+}
+
+jni::Class<OfflineRegionError> OfflineRegionError::javaClass;
+
+void OfflineRegionError::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineRegionError>::Find(env).NewGlobalRef(env).release();
+}
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/offline/offline_region_error.hpp b/platform/android/src/offline/offline_region_error.hpp
new file mode 100644
index 0000000000..61efaca67e
--- /dev/null
+++ b/platform/android/src/offline/offline_region_error.hpp
@@ -0,0 +1,21 @@
+#pragma once
+
+#include <mbgl/storage/offline.hpp>
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class OfflineRegionError {
+public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegionError"; };
+
+ static jni::Object<OfflineRegionError> New(jni::JNIEnv&, mbgl::Response::Error);
+
+ static jni::Class<OfflineRegionError> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+};
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/offline/offline_region_status.cpp b/platform/android/src/offline/offline_region_status.cpp
new file mode 100644
index 0000000000..d0bbae124f
--- /dev/null
+++ b/platform/android/src/offline/offline_region_status.cpp
@@ -0,0 +1,39 @@
+#include "offline_region_status.hpp"
+
+namespace mbgl {
+namespace android {
+
+jni::Object<OfflineRegionStatus> OfflineRegionStatus::New(jni::JNIEnv& env, mbgl::OfflineRegionStatus status) {
+
+ // Convert to jint
+ jint downloadState;
+ switch(status.downloadState) {
+ case mbgl::OfflineRegionDownloadState::Inactive:
+ downloadState = 0;
+ break;
+ case mbgl::OfflineRegionDownloadState::Active:
+ downloadState = 1;
+ break;
+ }
+
+ // Create java object
+ static auto constructor = javaClass.GetConstructor<jint, jlong, jlong, jlong, jlong, jlong, jboolean>(env);
+ return javaClass.New(env, constructor,
+ downloadState,
+ jlong(status.completedResourceCount),
+ jlong(status.completedResourceSize),
+ jlong(status.completedTileCount),
+ jlong(status.completedTileSize),
+ jlong(status.requiredResourceCount),
+ jboolean(status.requiredResourceCountIsPrecise)
+ );
+}
+
+jni::Class<OfflineRegionStatus> OfflineRegionStatus::javaClass;
+
+void OfflineRegionStatus::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineRegionStatus>::Find(env).NewGlobalRef(env).release();
+}
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/offline/offline_region_status.hpp b/platform/android/src/offline/offline_region_status.hpp
new file mode 100644
index 0000000000..b29a653655
--- /dev/null
+++ b/platform/android/src/offline/offline_region_status.hpp
@@ -0,0 +1,21 @@
+#pragma once
+
+#include <mbgl/storage/offline.hpp>
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class OfflineRegionStatus {
+public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegionStatus"; };
+
+ static jni::Object<OfflineRegionStatus> New(jni::JNIEnv&, mbgl::OfflineRegionStatus status);
+
+ static jni::Class<OfflineRegionStatus> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+};
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/android_conversion.hpp b/platform/android/src/style/android_conversion.hpp
index de0ac91502..d9b88ab52b 100644
--- a/platform/android/src/style/android_conversion.hpp
+++ b/platform/android/src/style/android_conversion.hpp
@@ -4,7 +4,6 @@
#include <mbgl/util/logging.hpp>
#include <mbgl/style/conversion.hpp>
-#include <mbgl/util/feature.hpp>
#include <mbgl/util/optional.hpp>
#include <jni/jni.hpp>
@@ -45,7 +44,7 @@ inline optional<mbgl::android::Value> objectMember(const mbgl::android::Value& v
template <class Fn>
optional<Error> eachMember(const mbgl::android::Value&, Fn&&) {
- //TODO
+ // TODO
mbgl::Log::Warning(mbgl::Event::Android, "eachMember not implemented");
return {};
}
@@ -82,7 +81,7 @@ inline optional<Value> toValue(const mbgl::android::Value& value) {
} else if (value.isString()) {
return { value.toString() };
} else if (value.isNumber()) {
- //Need to cast to a double here as the float is otherwise considered a bool...
+ // Need to cast to a double here as the float is otherwise considered a bool...
return { (double) value.toNumber() };
} else {
return {};
diff --git a/platform/android/src/style/conversion/function.hpp b/platform/android/src/style/conversion/function.hpp
index 26dd5c21fd..ad01a7afc2 100644
--- a/platform/android/src/style/conversion/function.hpp
+++ b/platform/android/src/style/conversion/function.hpp
@@ -4,51 +4,224 @@
#include "../../conversion/conversion.hpp"
#include "../../conversion/constant.hpp"
#include "types.hpp"
-#include "function.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 <tuple>
-#include <vector>
+#include <map>
namespace mbgl {
namespace android {
namespace conversion {
-template <class T>
-inline jni::jobject* toFunctionStopJavaArray(jni::JNIEnv& env, std::vector<std::pair<float, T>> value) {
- static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/mapboxsdk/style/layers/Function$Stop")).release();
+/**
+ * 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);
- for(size_t i = 0; i < value.size(); i = i + 1) {
- jni::jobject* in = *convert<jni::jobject*, float>(env, value[i].first);
- jni::jobject* out = *convert<jni::jobject*, T>(env, value[i].second);
+ 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();
+ }
+
+ 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();
+ }
+
+ 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::Function<T>> {
+struct Converter<jni::jobject*, mbgl::style::CameraFunction<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) };
+ }
+};
+
+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");
- Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::Function<T>& value) const {
- static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/mapboxsdk/style/layers/Function")).release();
- static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "([Lcom/mapbox/mapboxsdk/style/layers/Function$Stop;)V");
- static jni::jmethodID* withBase = &jni::GetMethodID(env, *javaClass, "withBase", "(F)Lcom/mapbox/mapboxsdk/style/layers/Function;");
+ // Convert stops
+ StopsEvaluator<T> evaluator(env);
+ jni::jobject* stops = apply_visitor(evaluator, value.stops);
- //Create object
- jni::jobject* jfunction = &jni::NewObject(env, *javaClass, *constructor, *toFunctionStopJavaArray(env, value.getStops()));
- //Set base
- jni::CallMethod<jni::jobject*>(env, jfunction, *withBase, value.getBase());
+ // Convert default value
+ jni::jobject* defaultValue = nullptr;
+ if (value.defaultValue) {
+ defaultValue = *convert<jni::jobject*>(env, *value.defaultValue);
+ }
- return {jfunction};
+ return { &jni::NewObject(env, *clazz, *constructor, defaultValue, jni::Make<jni::String>(env, value.property).Get(), stops) };
}
};
} // namespace conversion
} // namespace android
-} // namespace mbgl \ No newline at end of file
+} // namespace mbgl
diff --git a/platform/android/src/style/conversion/geojson.hpp b/platform/android/src/style/conversion/geojson.hpp
index 6bc48b3700..415d96f467 100644
--- a/platform/android/src/style/conversion/geojson.hpp
+++ b/platform/android/src/style/conversion/geojson.hpp
@@ -19,7 +19,7 @@ namespace conversion {
template <>
Result<GeoJSON> convertGeoJSON(const mbgl::android::Value& value) {
- //Value should be a string wrapped in an object
+ // Value should be a string wrapped in an object
mbgl::android::Value jsonValue = value.get("data");
if(value.isNull()) {
return Error { "no json data found" };
@@ -54,4 +54,4 @@ struct Converter<GeoJSON> {
} // namespace conversion
} // namespace style
-} // namespace mbgl \ No newline at end of file
+} // namespace mbgl
diff --git a/platform/android/src/style/conversion/property_value.hpp b/platform/android/src/style/conversion/property_value.hpp
index 4121192f3f..a58cf975a7 100644
--- a/platform/android/src/style/conversion/property_value.hpp
+++ b/platform/android/src/style/conversion/property_value.hpp
@@ -1,6 +1,7 @@
#pragma once
#include <mbgl/style/property_value.hpp>
+#include <mbgl/style/data_driven_property_value.hpp>
#include "../../conversion/conversion.hpp"
#include "../../conversion/constant.hpp"
#include "types.hpp"
@@ -10,29 +11,65 @@ namespace mbgl {
namespace android {
namespace conversion {
+/**
+ * Conversion from core property value types to Java property value types
+ */
+template <typename T>
+class PropertyValueEvaluator {
+public:
+
+ PropertyValueEvaluator(jni::JNIEnv& _env) : env(_env) {}
+
+ jni::jobject* operator()(const mbgl::style::Undefined) const {
+ return nullptr;
+ }
+
+ jni::jobject* operator()(const T &value) const {
+ Result<jni::jobject*> result = convert<jni::jobject*>(env, value);
+ return *result;
+ }
+
+ jni::jobject* operator()(const mbgl::style::CameraFunction<T> &value) const {
+ return *convert<jni::jobject*, 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);
+ }
+
+ jni::jobject* operator()(const mbgl::style::CompositeFunction<T> &value) const {
+ return *convert<jni::jobject*, mbgl::style::CompositeFunction<T>>(env, value);
+ }
+
+private:
+ jni::JNIEnv& env;
+
+};
+
+/**
+ * Convert core property values to java
+ */
template <class T>
struct Converter<jni::jobject*, mbgl::style::PropertyValue<T>> {
Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::PropertyValue<T>& value) const {
+ PropertyValueEvaluator<T> evaluator(env);
+ return value.evaluate(evaluator);
+ }
+};
- if(value.isUndefined()) {
- //Return a nullptr representing a Java null value
- return {nullptr};
- } else if (value.isConstant()) {
- //Time to convert the constant value
- Result<jni::jobject*> result = convert<jni::jobject*, T>(env, value.asConstant());
- return {*result};
- //return converted;
- } else if (value.isFunction()) {
- //Must be a function than
- return convert<jni::jobject*, mbgl::style::Function<T>>(env, value.asFunction());
- } else {
- throw std::runtime_error("Unknown property value type");
- }
+/**
+ * Convert core data driven property values to java
+ */
+template <class T>
+struct Converter<jni::jobject*, mbgl::style::DataDrivenPropertyValue<T>> {
+ Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::DataDrivenPropertyValue<T>& value) const {
+ PropertyValueEvaluator<T> evaluator(env);
+ return value.evaluate(evaluator);
}
};
} // namespace conversion
} // namespace android
-} // namespace mbgl \ No newline at end of file
+} // namespace mbgl
diff --git a/platform/android/src/style/conversion/types.hpp b/platform/android/src/style/conversion/types.hpp
index 1c433bb264..d9921e582e 100644
--- a/platform/android/src/style/conversion/types.hpp
+++ b/platform/android/src/style/conversion/types.hpp
@@ -95,4 +95,4 @@ struct Converter<jni::jobject*, mbgl::style::CirclePitchScaleType> {
} // namespace conversion
} // namespace android
-} // namespace mbgl \ No newline at end of file
+} // namespace mbgl
diff --git a/platform/android/src/style/conversion/types.hpp.ejs b/platform/android/src/style/conversion/types.hpp.ejs
index d248d42b72..3cd4764015 100644
--- a/platform/android/src/style/conversion/types.hpp.ejs
+++ b/platform/android/src/style/conversion/types.hpp.ejs
@@ -37,4 +37,4 @@ struct Converter<jni::jobject*, mbgl::style::<%- propertyNativeType(property) %>
} // namespace conversion
} // namespace android
-} // namespace mbgl \ No newline at end of file
+} // namespace mbgl
diff --git a/platform/android/src/style/conversion/types_string_values.hpp b/platform/android/src/style/conversion/types_string_values.hpp
index 9f21a2fed9..e3108fdf5b 100644
--- a/platform/android/src/style/conversion/types_string_values.hpp
+++ b/platform/android/src/style/conversion/types_string_values.hpp
@@ -10,7 +10,7 @@ namespace mbgl {
namespace android {
namespace conversion {
- //visibility
+ // visibility
inline std::string toString(mbgl::style::VisibilityType value) {
switch (value) {
case mbgl::style::VisibilityType::Visible:
@@ -24,7 +24,7 @@ namespace conversion {
}
}
- //line-cap
+ // line-cap
inline std::string toString(mbgl::style::LineCapType value) {
switch (value) {
case mbgl::style::LineCapType::Butt:
@@ -41,7 +41,7 @@ namespace conversion {
}
}
- //line-join
+ // line-join
inline std::string toString(mbgl::style::LineJoinType value) {
switch (value) {
case mbgl::style::LineJoinType::Bevel:
@@ -58,7 +58,7 @@ namespace conversion {
}
}
- //symbol-placement
+ // symbol-placement
inline std::string toString(mbgl::style::SymbolPlacementType value) {
switch (value) {
case mbgl::style::SymbolPlacementType::Point:
@@ -72,7 +72,7 @@ namespace conversion {
}
}
- //icon-rotation-alignment
+ // icon-rotation-alignment
inline std::string toString(mbgl::style::AlignmentType value) {
switch (value) {
case mbgl::style::AlignmentType::Map:
@@ -89,7 +89,7 @@ namespace conversion {
}
}
- //icon-text-fit
+ // icon-text-fit
inline std::string toString(mbgl::style::IconTextFitType value) {
switch (value) {
case mbgl::style::IconTextFitType::None:
@@ -109,7 +109,7 @@ namespace conversion {
}
}
- //text-justify
+ // text-justify
inline std::string toString(mbgl::style::TextJustifyType value) {
switch (value) {
case mbgl::style::TextJustifyType::Left:
@@ -126,7 +126,7 @@ namespace conversion {
}
}
- //text-anchor
+ // text-anchor
inline std::string toString(mbgl::style::TextAnchorType value) {
switch (value) {
case mbgl::style::TextAnchorType::Center:
@@ -161,7 +161,7 @@ namespace conversion {
}
}
- //text-transform
+ // text-transform
inline std::string toString(mbgl::style::TextTransformType value) {
switch (value) {
case mbgl::style::TextTransformType::None:
@@ -178,7 +178,7 @@ namespace conversion {
}
}
- //fill-translate-anchor
+ // fill-translate-anchor
inline std::string toString(mbgl::style::TranslateAnchorType value) {
switch (value) {
case mbgl::style::TranslateAnchorType::Map:
@@ -192,7 +192,7 @@ namespace conversion {
}
}
- //circle-pitch-scale
+ // circle-pitch-scale
inline std::string toString(mbgl::style::CirclePitchScaleType value) {
switch (value) {
case mbgl::style::CirclePitchScaleType::Map:
@@ -209,4 +209,4 @@ namespace conversion {
} // namespace conversion
} // namespace android
-} // namespace mbgl \ No newline at end of file
+} // namespace mbgl
diff --git a/platform/android/src/style/conversion/types_string_values.hpp.ejs b/platform/android/src/style/conversion/types_string_values.hpp.ejs
index c1646baa1a..bf52919741 100644
--- a/platform/android/src/style/conversion/types_string_values.hpp.ejs
+++ b/platform/android/src/style/conversion/types_string_values.hpp.ejs
@@ -13,7 +13,7 @@ namespace mbgl {
namespace android {
namespace conversion {
- //visibility
+ // visibility
inline std::string toString(mbgl::style::VisibilityType value) {
switch (value) {
case mbgl::style::VisibilityType::Visible:
@@ -28,7 +28,7 @@ namespace conversion {
}
<% for (const property of properties) { -%>
- //<%- property.name %>
+ // <%- property.name %>
inline std::string toString(mbgl::style::<%- propertyNativeType(property) %> value) {
switch (value) {
<% for (const value in property.values) { -%>
@@ -45,4 +45,4 @@ namespace conversion {
} // namespace conversion
} // namespace android
-} // namespace mbgl \ No newline at end of file
+} // namespace mbgl
diff --git a/platform/android/src/style/conversion/url_or_tileset.hpp b/platform/android/src/style/conversion/url_or_tileset.hpp
index c1801f56d0..4e502324d0 100644
--- a/platform/android/src/style/conversion/url_or_tileset.hpp
+++ b/platform/android/src/style/conversion/url_or_tileset.hpp
@@ -35,4 +35,4 @@ struct Converter<variant<std::string, Tileset>> {
}
}
-} \ No newline at end of file
+}
diff --git a/platform/android/src/style/functions/categorical_stops.cpp b/platform/android/src/style/functions/categorical_stops.cpp
new file mode 100644
index 0000000000..2aff9730a7
--- /dev/null
+++ b/platform/android/src/style/functions/categorical_stops.cpp
@@ -0,0 +1,18 @@
+#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
new file mode 100644
index 0000000000..a198c8d5c9
--- /dev/null
+++ b/platform/android/src/style/functions/categorical_stops.hpp
@@ -0,0 +1,23 @@
+#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
new file mode 100644
index 0000000000..6390a0ec35
--- /dev/null
+++ b/platform/android/src/style/functions/exponential_stops.cpp
@@ -0,0 +1,18 @@
+#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
new file mode 100644
index 0000000000..391d723cef
--- /dev/null
+++ b/platform/android/src/style/functions/exponential_stops.hpp
@@ -0,0 +1,24 @@
+#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
new file mode 100644
index 0000000000..239b0ddb88
--- /dev/null
+++ b/platform/android/src/style/functions/identity_stops.cpp
@@ -0,0 +1,18 @@
+#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
new file mode 100644
index 0000000000..150b2135f0
--- /dev/null
+++ b/platform/android/src/style/functions/identity_stops.hpp
@@ -0,0 +1,21 @@
+#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
new file mode 100644
index 0000000000..c3d9b6513f
--- /dev/null
+++ b/platform/android/src/style/functions/interval_stops.cpp
@@ -0,0 +1,18 @@
+#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
new file mode 100644
index 0000000000..e3f75159cf
--- /dev/null
+++ b/platform/android/src/style/functions/interval_stops.hpp
@@ -0,0 +1,23 @@
+#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
new file mode 100644
index 0000000000..f9ed4b7368
--- /dev/null
+++ b/platform/android/src/style/functions/stop.cpp
@@ -0,0 +1,21 @@
+#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
new file mode 100644
index 0000000000..7c697db65d
--- /dev/null
+++ b/platform/android/src/style/functions/stop.hpp
@@ -0,0 +1,36 @@
+#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/background_layer.cpp b/platform/android/src/style/layers/background_layer.cpp
index 021ac947ad..9915f3894e 100644
--- a/platform/android/src/style/layers/background_layer.cpp
+++ b/platform/android/src/style/layers/background_layer.cpp
@@ -9,14 +9,27 @@
namespace mbgl {
namespace android {
+ /**
+ * Creates an owning peer object (for layers not attached to the map) from the JVM side
+ */
BackgroundLayer::BackgroundLayer(jni::JNIEnv& env, jni::String layerId)
: Layer(env, std::make_unique<mbgl::style::BackgroundLayer>(jni::Make<std::string>(env, layerId))) {
}
+ /**
+ * Creates a non-owning peer object (for layers currently attached to the map)
+ */
BackgroundLayer::BackgroundLayer(mbgl::Map& map, mbgl::style::BackgroundLayer& coreLayer)
: Layer(map, coreLayer) {
}
+ /**
+ * Creates an owning peer object (for layers not attached to the map)
+ */
+ BackgroundLayer::BackgroundLayer(mbgl::Map& map, std::unique_ptr<mbgl::style::BackgroundLayer> coreLayer)
+ : Layer(map, std::move(coreLayer)) {
+ }
+
BackgroundLayer::~BackgroundLayer() = default;
// Property getters
@@ -47,12 +60,12 @@ namespace android {
}
void BackgroundLayer::registerNative(jni::JNIEnv& env) {
- //Lookup the class
+ // Lookup the class
BackgroundLayer::javaClass = *jni::Class<BackgroundLayer>::Find(env).NewGlobalRef(env).release();
#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
- //Register the peer
+ // Register the peer
jni::RegisterNativePeer<BackgroundLayer>(
env, BackgroundLayer::javaClass, "nativePtr",
std::make_unique<BackgroundLayer, JNIEnv&, jni::String>,
diff --git a/platform/android/src/style/layers/background_layer.hpp b/platform/android/src/style/layers/background_layer.hpp
index bd62c024f4..2fdc948892 100644
--- a/platform/android/src/style/layers/background_layer.hpp
+++ b/platform/android/src/style/layers/background_layer.hpp
@@ -22,6 +22,8 @@ public:
BackgroundLayer(mbgl::Map&, mbgl::style::BackgroundLayer&);
+ BackgroundLayer(mbgl::Map&, std::unique_ptr<mbgl::style::BackgroundLayer>);
+
~BackgroundLayer();
// Property getters
diff --git a/platform/android/src/style/layers/circle_layer.cpp b/platform/android/src/style/layers/circle_layer.cpp
index 4a6ba95d31..948c397829 100644
--- a/platform/android/src/style/layers/circle_layer.cpp
+++ b/platform/android/src/style/layers/circle_layer.cpp
@@ -9,14 +9,27 @@
namespace mbgl {
namespace android {
+ /**
+ * Creates an owning peer object (for layers not attached to the map) from the JVM side
+ */
CircleLayer::CircleLayer(jni::JNIEnv& env, jni::String layerId, jni::String sourceId)
: Layer(env, std::make_unique<mbgl::style::CircleLayer>(jni::Make<std::string>(env, layerId), jni::Make<std::string>(env, sourceId))) {
}
+ /**
+ * Creates a non-owning peer object (for layers currently attached to the map)
+ */
CircleLayer::CircleLayer(mbgl::Map& map, mbgl::style::CircleLayer& coreLayer)
: Layer(map, coreLayer) {
}
+ /**
+ * Creates an owning peer object (for layers not attached to the map)
+ */
+ CircleLayer::CircleLayer(mbgl::Map& map, std::unique_ptr<mbgl::style::CircleLayer> coreLayer)
+ : Layer(map, std::move(coreLayer)) {
+ }
+
CircleLayer::~CircleLayer() = default;
// Property getters
@@ -89,12 +102,12 @@ namespace android {
}
void CircleLayer::registerNative(jni::JNIEnv& env) {
- //Lookup the class
+ // Lookup the class
CircleLayer::javaClass = *jni::Class<CircleLayer>::Find(env).NewGlobalRef(env).release();
#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
- //Register the peer
+ // Register the peer
jni::RegisterNativePeer<CircleLayer>(
env, CircleLayer::javaClass, "nativePtr",
std::make_unique<CircleLayer, JNIEnv&, jni::String, jni::String>,
diff --git a/platform/android/src/style/layers/circle_layer.hpp b/platform/android/src/style/layers/circle_layer.hpp
index d45984f23b..ee988d7c57 100644
--- a/platform/android/src/style/layers/circle_layer.hpp
+++ b/platform/android/src/style/layers/circle_layer.hpp
@@ -22,6 +22,8 @@ public:
CircleLayer(mbgl::Map&, mbgl::style::CircleLayer&);
+ CircleLayer(mbgl::Map&, std::unique_ptr<mbgl::style::CircleLayer>);
+
~CircleLayer();
// Property getters
diff --git a/platform/android/src/style/layers/custom_layer.cpp b/platform/android/src/style/layers/custom_layer.cpp
index d5d330a019..9bdc308d85 100644
--- a/platform/android/src/style/layers/custom_layer.cpp
+++ b/platform/android/src/style/layers/custom_layer.cpp
@@ -40,12 +40,12 @@ namespace android {
}
void CustomLayer::registerNative(jni::JNIEnv& env) {
- //Lookup the class
+ // Lookup the class
CustomLayer::javaClass = *jni::Class<CustomLayer>::Find(env).NewGlobalRef(env).release();
#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
- //Register the peer
+ // 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>,
diff --git a/platform/android/src/style/layers/fill_layer.cpp b/platform/android/src/style/layers/fill_layer.cpp
index 84d47b6afe..fc1dfccfcc 100644
--- a/platform/android/src/style/layers/fill_layer.cpp
+++ b/platform/android/src/style/layers/fill_layer.cpp
@@ -9,14 +9,27 @@
namespace mbgl {
namespace android {
+ /**
+ * Creates an owning peer object (for layers not attached to the map) from the JVM side
+ */
FillLayer::FillLayer(jni::JNIEnv& env, jni::String layerId, jni::String sourceId)
: Layer(env, std::make_unique<mbgl::style::FillLayer>(jni::Make<std::string>(env, layerId), jni::Make<std::string>(env, sourceId))) {
}
+ /**
+ * Creates a non-owning peer object (for layers currently attached to the map)
+ */
FillLayer::FillLayer(mbgl::Map& map, mbgl::style::FillLayer& coreLayer)
: Layer(map, coreLayer) {
}
+ /**
+ * Creates an owning peer object (for layers not attached to the map)
+ */
+ FillLayer::FillLayer(mbgl::Map& map, std::unique_ptr<mbgl::style::FillLayer> coreLayer)
+ : Layer(map, std::move(coreLayer)) {
+ }
+
FillLayer::~FillLayer() = default;
// Property getters
@@ -71,12 +84,12 @@ namespace android {
}
void FillLayer::registerNative(jni::JNIEnv& env) {
- //Lookup the class
+ // Lookup the class
FillLayer::javaClass = *jni::Class<FillLayer>::Find(env).NewGlobalRef(env).release();
#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
- //Register the peer
+ // Register the peer
jni::RegisterNativePeer<FillLayer>(
env, FillLayer::javaClass, "nativePtr",
std::make_unique<FillLayer, JNIEnv&, jni::String, jni::String>,
diff --git a/platform/android/src/style/layers/fill_layer.hpp b/platform/android/src/style/layers/fill_layer.hpp
index 7609a5742f..f43c263ab8 100644
--- a/platform/android/src/style/layers/fill_layer.hpp
+++ b/platform/android/src/style/layers/fill_layer.hpp
@@ -22,6 +22,8 @@ public:
FillLayer(mbgl::Map&, mbgl::style::FillLayer&);
+ FillLayer(mbgl::Map&, std::unique_ptr<mbgl::style::FillLayer>);
+
~FillLayer();
// Property getters
diff --git a/platform/android/src/style/layers/layer.cpp b/platform/android/src/style/layers/layer.cpp
index c0c57c839d..dbf71fd2af 100644
--- a/platform/android/src/style/layers/layer.cpp
+++ b/platform/android/src/style/layers/layer.cpp
@@ -5,12 +5,12 @@
#include <mbgl/util/logging.hpp>
-//Java -> C++ conversion
+// Java -> C++ conversion
#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/layer.hpp>
#include <mbgl/style/conversion/source.hpp>
-//C++ -> Java conversion
+// C++ -> Java conversion
#include "../conversion/property_value.hpp"
#include <string>
@@ -26,22 +26,35 @@ namespace android {
, layer(*ownedLayer) {
}
+ /**
+ * Takes a non-owning reference. For lookup methods
+ */
Layer::Layer(mbgl::Map& coreMap, mbgl::style::Layer& coreLayer) : layer(coreLayer) , map(&coreMap) {
}
+ /**
+ * Takes a owning reference. Ownership is transfered to this peer, eg after removing
+ * from the map
+ */
+ Layer::Layer(mbgl::Map& coreMap, std::unique_ptr<mbgl::style::Layer> coreLayer)
+ : ownedLayer(std::move(coreLayer))
+ , layer(*ownedLayer)
+ , map(&coreMap) {
+ }
+
Layer::~Layer() {
}
void Layer::addToMap(mbgl::Map& _map, mbgl::optional<std::string> before) {
- //Check to see if we own the layer first
+ // Check to see if we own the layer first
if (!ownedLayer) {
throw std::runtime_error("Cannot add layer twice");
}
- //Add layer to map
+ // Add layer to map
_map.addLayer(releaseCoreLayer(), before);
- //Save pointer to the map
+ // Save pointer to the map
this->map = &_map;
}
@@ -65,7 +78,7 @@ namespace android {
void Layer::setLayoutProperty(jni::JNIEnv& env, jni::String jname, jni::Object<> jvalue) {
Value value(env, jvalue);
- //Convert and set property
+ // Convert and set property
optional<mbgl::style::conversion::Error> error = mbgl::style::conversion::setLayoutProperty(layer, jni::Make<std::string>(env, jname), value);
if (error) {
mbgl::Log::Error(mbgl::Event::JNI, "Error setting property: " + jni::Make<std::string>(env, jname) + " " + error->message);
@@ -76,7 +89,7 @@ namespace android {
void Layer::setPaintProperty(jni::JNIEnv& env, jni::String jname, jni::Object<> jvalue) {
Value value(env, jvalue);
- //Convert and set property
+ // Convert and set property
optional<mbgl::style::conversion::Error> error = mbgl::style::conversion::setPaintProperty(layer, jni::Make<std::string>(env, jname), value, mbgl::optional<std::string>());
if (error) {
mbgl::Log::Error(mbgl::Event::JNI, "Error setting property: " + jni::Make<std::string>(env, jname) + " " + error->message);
@@ -153,12 +166,12 @@ namespace android {
jni::Class<Layer> Layer::javaClass;
void Layer::registerNative(jni::JNIEnv& env) {
- //Lookup the class
+ // Lookup the class
Layer::javaClass = *jni::Class<Layer>::Find(env).NewGlobalRef(env).release();
#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
- //Register the peer
+ // Register the peer
jni::RegisterNativePeer<Layer>(env, Layer::javaClass, "nativePtr",
METHOD(&Layer::getId, "nativeGetId"),
METHOD(&Layer::setLayoutProperty, "nativeSetLayoutProperty"),
@@ -174,5 +187,5 @@ namespace android {
}
-} //android
-} //mbgl \ No newline at end of file
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/layers/layer.cpp.ejs b/platform/android/src/style/layers/layer.cpp.ejs
index 500c76ea7a..5da397d77d 100644
--- a/platform/android/src/style/layers/layer.cpp.ejs
+++ b/platform/android/src/style/layers/layer.cpp.ejs
@@ -14,18 +14,34 @@ namespace mbgl {
namespace android {
<% if (type === 'background') { -%>
+ /**
+ * Creates an owning peer object (for layers not attached to the map) from the JVM side
+ */
<%- camelize(type) %>Layer::<%- camelize(type) %>Layer(jni::JNIEnv& env, jni::String layerId)
: Layer(env, std::make_unique<mbgl::style::<%- camelize(type) %>Layer>(jni::Make<std::string>(env, layerId))) {
<% } else { -%>
+ /**
+ * Creates an owning peer object (for layers not attached to the map) from the JVM side
+ */
<%- camelize(type) %>Layer::<%- camelize(type) %>Layer(jni::JNIEnv& env, jni::String layerId, jni::String sourceId)
: Layer(env, std::make_unique<mbgl::style::<%- camelize(type) %>Layer>(jni::Make<std::string>(env, layerId), jni::Make<std::string>(env, sourceId))) {
<% } -%>
}
+ /**
+ * Creates a non-owning peer object (for layers currently attached to the map)
+ */
<%- camelize(type) %>Layer::<%- camelize(type) %>Layer(mbgl::Map& map, mbgl::style::<%- camelize(type) %>Layer& coreLayer)
: Layer(map, coreLayer) {
}
+ /**
+ * Creates an owning peer object (for layers not attached to the map)
+ */
+ <%- camelize(type) %>Layer::<%- camelize(type) %>Layer(mbgl::Map& map, std::unique_ptr<mbgl::style::<%- camelize(type) %>Layer> coreLayer)
+ : Layer(map, std::move(coreLayer)) {
+ }
+
<%- camelize(type) %>Layer::~<%- camelize(type) %>Layer() = default;
// Property getters
@@ -46,12 +62,12 @@ namespace android {
}
void <%- camelize(type) %>Layer::registerNative(jni::JNIEnv& env) {
- //Lookup the class
+ // Lookup the class
<%- camelize(type) %>Layer::javaClass = *jni::Class<<%- camelize(type) %>Layer>::Find(env).NewGlobalRef(env).release();
#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
- //Register the peer
+ // Register the peer
jni::RegisterNativePeer<<%- camelize(type) %>Layer>(
env, <%- camelize(type) %>Layer::javaClass, "nativePtr",
<% if (type === 'background') { -%>
diff --git a/platform/android/src/style/layers/layer.hpp b/platform/android/src/style/layers/layer.hpp
index f3cd073552..deea7a6613 100644
--- a/platform/android/src/style/layers/layer.hpp
+++ b/platform/android/src/style/layers/layer.hpp
@@ -21,11 +21,16 @@ public:
static void registerNative(jni::JNIEnv&);
/*
- * Called when a Java object is created on the c++ side
+ * Called when a non-owning peer object is created on the c++ side
*/
Layer(mbgl::Map&, mbgl::style::Layer&);
/*
+ * Called when a owning peer object is created on the c++ side
+ */
+ Layer(mbgl::Map&, std::unique_ptr<mbgl::style::Layer>);
+
+ /*
* Called when a Java object was created from the jvm side
*/
Layer(jni::JNIEnv&, std::unique_ptr<mbgl::style::Layer>);
@@ -49,7 +54,7 @@ public:
void setPaintProperty(jni::JNIEnv&, jni::String, jni::Object<> value);
- //Zoom
+ // Zoom
jni::jfloat getMinZoom(jni::JNIEnv&);
@@ -65,28 +70,24 @@ public:
void setSourceLayer(jni::JNIEnv& env, jni::String sourceLayer);
- //Property getters
+ // Property getters
jni::Object<jni::ObjectTag> getVisibility(jni::JNIEnv&);
protected:
- //Release the owned view and return it
+ // Release the owned view and return it
std::unique_ptr<mbgl::style::Layer> releaseCoreLayer();
- //Owned layer is set when creating a new layer, before adding it to the map
+ // Owned layer is set when creating a new layer, before adding it to the map
std::unique_ptr<mbgl::style::Layer> ownedLayer;
- //Raw reference to the layer
+ // Raw reference to the layer
mbgl::style::Layer& layer;
- //Map is set when the layer is retrieved or after adding to the map
+ // Map is set when the layer is retrieved or after adding to the map
mbgl::Map* map;
};
-} //android
-} //mbgl
-
-
-
-
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/layers/layer.hpp.ejs b/platform/android/src/style/layers/layer.hpp.ejs
index 3d715746ff..102efd2d4d 100644
--- a/platform/android/src/style/layers/layer.hpp.ejs
+++ b/platform/android/src/style/layers/layer.hpp.ejs
@@ -30,6 +30,8 @@ public:
<%- camelize(type) %>Layer(mbgl::Map&, mbgl::style::<%- camelize(type) %>Layer&);
+ <%- camelize(type) %>Layer(mbgl::Map&, std::unique_ptr<mbgl::style::<%- camelize(type) %>Layer>);
+
~<%- camelize(type) %>Layer();
// Property getters
diff --git a/platform/android/src/style/layers/layers.cpp b/platform/android/src/style/layers/layers.cpp
index 57dbf6f4b1..5c6ee1ae8f 100644
--- a/platform/android/src/style/layers/layers.cpp
+++ b/platform/android/src/style/layers/layers.cpp
@@ -1,5 +1,6 @@
#include "layers.hpp"
+#include <mbgl/style/layer.hpp>
#include <mbgl/style/layers/background_layer.hpp>
#include <mbgl/style/layers/circle_layer.hpp>
#include <mbgl/style/layers/fill_layer.hpp>
@@ -10,55 +11,86 @@
#include "background_layer.hpp"
#include "circle_layer.hpp"
+#include "custom_layer.hpp"
#include "fill_layer.hpp"
#include "line_layer.hpp"
#include "raster_layer.hpp"
#include "symbol_layer.hpp"
-#include "custom_layer.hpp"
+#include "unknown_layer.hpp"
namespace mbgl {
namespace android {
-Layer* initializeLayerPeer(mbgl::Map& map, mbgl::style::Layer& coreLayer) {
- Layer* layer;
+static Layer* initializeLayerPeer(mbgl::Map& map, mbgl::style::Layer& coreLayer) {
if (coreLayer.is<mbgl::style::BackgroundLayer>()) {
- layer = new BackgroundLayer(map, *coreLayer.as<mbgl::style::BackgroundLayer>());
+ return new BackgroundLayer(map, *coreLayer.as<mbgl::style::BackgroundLayer>());
} else if (coreLayer.is<mbgl::style::CircleLayer>()) {
- layer = new CircleLayer(map, *coreLayer.as<mbgl::style::CircleLayer>());
+ return new CircleLayer(map, *coreLayer.as<mbgl::style::CircleLayer>());
} else if (coreLayer.is<mbgl::style::FillLayer>()) {
- layer = new FillLayer(map, *coreLayer.as<mbgl::style::FillLayer>());
+ return new FillLayer(map, *coreLayer.as<mbgl::style::FillLayer>());
} else if (coreLayer.is<mbgl::style::LineLayer>()) {
- layer = new LineLayer(map, *coreLayer.as<mbgl::style::LineLayer>());
+ return new LineLayer(map, *coreLayer.as<mbgl::style::LineLayer>());
} else if (coreLayer.is<mbgl::style::RasterLayer>()) {
- layer = new RasterLayer(map, *coreLayer.as<mbgl::style::RasterLayer>());
+ return new RasterLayer(map, *coreLayer.as<mbgl::style::RasterLayer>());
} else if (coreLayer.is<mbgl::style::SymbolLayer>()) {
- layer = new SymbolLayer(map, *coreLayer.as<mbgl::style::SymbolLayer>());
+ return new SymbolLayer(map, *coreLayer.as<mbgl::style::SymbolLayer>());
} else if (coreLayer.is<mbgl::style::CustomLayer>()) {
- layer = new CustomLayer(map, *coreLayer.as<mbgl::style::CustomLayer>());
+ return new CustomLayer(map, *coreLayer.as<mbgl::style::CustomLayer>());
} else {
- throw new std::runtime_error("Layer type not implemented");
+ return new UnknownLayer(map, coreLayer);
}
+}
- return layer;
+template <class LayerType, class PeerType>
+static PeerType* createPeer(Map& map, std::unique_ptr<mbgl::style::Layer> layer) {
+ return new PeerType(map, std::move(std::unique_ptr<LayerType>(layer.release()->as<LayerType>())));
+}
+
+static Layer* initializeLayerPeer(Map& map, std::unique_ptr<mbgl::style::Layer> coreLayer) {
+ if (coreLayer->is<style::BackgroundLayer>()) {
+ return createPeer<style::BackgroundLayer, BackgroundLayer>(map, std::move(coreLayer));
+ } else if (coreLayer->is<style::CircleLayer>()) {
+ return createPeer<style::CircleLayer, CircleLayer>(map, std::move(coreLayer));
+ } else if (coreLayer->is<style::FillLayer>()) {
+ return createPeer<style::FillLayer, FillLayer>(map, std::move(coreLayer));
+ } else if (coreLayer->is<style::LineLayer>()) {
+ return createPeer<style::LineLayer, LineLayer>(map, std::move(coreLayer));
+ } else if (coreLayer->is<style::RasterLayer>()) {
+ return createPeer<style::RasterLayer, RasterLayer>(map, std::move(coreLayer));
+ } else if (coreLayer->is<style::SymbolLayer>()) {
+ return createPeer<style::SymbolLayer, SymbolLayer>(map, std::move(coreLayer));
+ } else if (coreLayer->is<mbgl::style::CustomLayer>()) {
+ return createPeer<style::SymbolLayer, SymbolLayer>(map, std::move(coreLayer));
+ } else {
+ return new UnknownLayer(map, std::move(coreLayer));
+ }
}
-jni::jobject* createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, mbgl::style::Layer& coreLayer) {
+jni::jobject* createJavaLayerPeer(jni::JNIEnv& env, Map& map, style::Layer& coreLayer) {
std::unique_ptr<Layer> peerLayer = std::unique_ptr<Layer>(initializeLayerPeer(map, coreLayer));
jni::jobject* result = peerLayer->createJavaPeer(env);
peerLayer.release();
return result;
}
+jni::jobject* createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr<mbgl::style::Layer> coreLayer) {
+ std::unique_ptr<Layer> peerLayer = std::unique_ptr<Layer>(initializeLayerPeer(map, std::move(coreLayer)));
+ jni::jobject* result = peerLayer->createJavaPeer(env);
+ peerLayer.release();
+ return result;
+}
+
void registerNativeLayers(jni::JNIEnv& env) {
Layer::registerNative(env);
BackgroundLayer::registerNative(env);
CircleLayer::registerNative(env);
+ CustomLayer::registerNative(env);
FillLayer::registerNative(env);
LineLayer::registerNative(env);
RasterLayer::registerNative(env);
SymbolLayer::registerNative(env);
- CustomLayer::registerNative(env);
+ UnknownLayer::registerNative(env);
}
-} //android
-} //mbgl \ No newline at end of file
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/layers/layers.hpp b/platform/android/src/style/layers/layers.hpp
index 0c979ec2cf..75863a324a 100644
--- a/platform/android/src/style/layers/layers.hpp
+++ b/platform/android/src/style/layers/layers.hpp
@@ -10,11 +10,17 @@
namespace mbgl {
namespace android {
-mbgl::android::Layer* initializeLayerPeer(mbgl::Map&, mbgl::style::Layer&);
-
+/**
+ * Create a non-owning peer
+ */
jni::jobject* createJavaLayerPeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Layer&);
+/**
+ * Create an owning peer
+ */
+jni::jobject* createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr<mbgl::style::Layer>);
+
void registerNativeLayers(jni::JNIEnv&);
}
-} \ No newline at end of file
+}
diff --git a/platform/android/src/style/layers/line_layer.cpp b/platform/android/src/style/layers/line_layer.cpp
index 2dce8b618a..1a3a666a7b 100644
--- a/platform/android/src/style/layers/line_layer.cpp
+++ b/platform/android/src/style/layers/line_layer.cpp
@@ -9,14 +9,27 @@
namespace mbgl {
namespace android {
+ /**
+ * Creates an owning peer object (for layers not attached to the map) from the JVM side
+ */
LineLayer::LineLayer(jni::JNIEnv& env, jni::String layerId, jni::String sourceId)
: Layer(env, std::make_unique<mbgl::style::LineLayer>(jni::Make<std::string>(env, layerId), jni::Make<std::string>(env, sourceId))) {
}
+ /**
+ * Creates a non-owning peer object (for layers currently attached to the map)
+ */
LineLayer::LineLayer(mbgl::Map& map, mbgl::style::LineLayer& coreLayer)
: Layer(map, coreLayer) {
}
+ /**
+ * Creates an owning peer object (for layers not attached to the map)
+ */
+ LineLayer::LineLayer(mbgl::Map& map, std::unique_ptr<mbgl::style::LineLayer> coreLayer)
+ : Layer(map, std::move(coreLayer)) {
+ }
+
LineLayer::~LineLayer() = default;
// Property getters
@@ -113,12 +126,12 @@ namespace android {
}
void LineLayer::registerNative(jni::JNIEnv& env) {
- //Lookup the class
+ // Lookup the class
LineLayer::javaClass = *jni::Class<LineLayer>::Find(env).NewGlobalRef(env).release();
#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
- //Register the peer
+ // Register the peer
jni::RegisterNativePeer<LineLayer>(
env, LineLayer::javaClass, "nativePtr",
std::make_unique<LineLayer, JNIEnv&, jni::String, jni::String>,
diff --git a/platform/android/src/style/layers/line_layer.hpp b/platform/android/src/style/layers/line_layer.hpp
index e2fc93329e..a79c8b9021 100644
--- a/platform/android/src/style/layers/line_layer.hpp
+++ b/platform/android/src/style/layers/line_layer.hpp
@@ -22,6 +22,8 @@ public:
LineLayer(mbgl::Map&, mbgl::style::LineLayer&);
+ LineLayer(mbgl::Map&, std::unique_ptr<mbgl::style::LineLayer>);
+
~LineLayer();
// Property getters
diff --git a/platform/android/src/style/layers/raster_layer.cpp b/platform/android/src/style/layers/raster_layer.cpp
index 25b26155ae..8a324b88f2 100644
--- a/platform/android/src/style/layers/raster_layer.cpp
+++ b/platform/android/src/style/layers/raster_layer.cpp
@@ -9,14 +9,27 @@
namespace mbgl {
namespace android {
+ /**
+ * Creates an owning peer object (for layers not attached to the map) from the JVM side
+ */
RasterLayer::RasterLayer(jni::JNIEnv& env, jni::String layerId, jni::String sourceId)
: Layer(env, std::make_unique<mbgl::style::RasterLayer>(jni::Make<std::string>(env, layerId), jni::Make<std::string>(env, sourceId))) {
}
+ /**
+ * Creates a non-owning peer object (for layers currently attached to the map)
+ */
RasterLayer::RasterLayer(mbgl::Map& map, mbgl::style::RasterLayer& coreLayer)
: Layer(map, coreLayer) {
}
+ /**
+ * Creates an owning peer object (for layers not attached to the map)
+ */
+ RasterLayer::RasterLayer(mbgl::Map& map, std::unique_ptr<mbgl::style::RasterLayer> coreLayer)
+ : Layer(map, std::move(coreLayer)) {
+ }
+
RasterLayer::~RasterLayer() = default;
// Property getters
@@ -71,12 +84,12 @@ namespace android {
}
void RasterLayer::registerNative(jni::JNIEnv& env) {
- //Lookup the class
+ // Lookup the class
RasterLayer::javaClass = *jni::Class<RasterLayer>::Find(env).NewGlobalRef(env).release();
#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
- //Register the peer
+ // Register the peer
jni::RegisterNativePeer<RasterLayer>(
env, RasterLayer::javaClass, "nativePtr",
std::make_unique<RasterLayer, JNIEnv&, jni::String, jni::String>,
diff --git a/platform/android/src/style/layers/raster_layer.hpp b/platform/android/src/style/layers/raster_layer.hpp
index 3cc2d96dde..2f5d4f6fcd 100644
--- a/platform/android/src/style/layers/raster_layer.hpp
+++ b/platform/android/src/style/layers/raster_layer.hpp
@@ -22,6 +22,8 @@ public:
RasterLayer(mbgl::Map&, mbgl::style::RasterLayer&);
+ RasterLayer(mbgl::Map&, std::unique_ptr<mbgl::style::RasterLayer>);
+
~RasterLayer();
// Property getters
diff --git a/platform/android/src/style/layers/symbol_layer.cpp b/platform/android/src/style/layers/symbol_layer.cpp
index 9318d42d5b..e42eeb4c77 100644
--- a/platform/android/src/style/layers/symbol_layer.cpp
+++ b/platform/android/src/style/layers/symbol_layer.cpp
@@ -9,14 +9,27 @@
namespace mbgl {
namespace android {
+ /**
+ * Creates an owning peer object (for layers not attached to the map) from the JVM side
+ */
SymbolLayer::SymbolLayer(jni::JNIEnv& env, jni::String layerId, jni::String sourceId)
: Layer(env, std::make_unique<mbgl::style::SymbolLayer>(jni::Make<std::string>(env, layerId), jni::Make<std::string>(env, sourceId))) {
}
+ /**
+ * Creates a non-owning peer object (for layers currently attached to the map)
+ */
SymbolLayer::SymbolLayer(mbgl::Map& map, mbgl::style::SymbolLayer& coreLayer)
: Layer(map, coreLayer) {
}
+ /**
+ * Creates an owning peer object (for layers not attached to the map)
+ */
+ SymbolLayer::SymbolLayer(mbgl::Map& map, std::unique_ptr<mbgl::style::SymbolLayer> coreLayer)
+ : Layer(map, std::move(coreLayer)) {
+ }
+
SymbolLayer::~SymbolLayer() = default;
// Property getters
@@ -317,12 +330,12 @@ namespace android {
}
void SymbolLayer::registerNative(jni::JNIEnv& env) {
- //Lookup the class
+ // Lookup the class
SymbolLayer::javaClass = *jni::Class<SymbolLayer>::Find(env).NewGlobalRef(env).release();
#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
- //Register the peer
+ // Register the peer
jni::RegisterNativePeer<SymbolLayer>(
env, SymbolLayer::javaClass, "nativePtr",
std::make_unique<SymbolLayer, JNIEnv&, jni::String, jni::String>,
diff --git a/platform/android/src/style/layers/symbol_layer.hpp b/platform/android/src/style/layers/symbol_layer.hpp
index 1048b01b14..98ce5572e9 100644
--- a/platform/android/src/style/layers/symbol_layer.hpp
+++ b/platform/android/src/style/layers/symbol_layer.hpp
@@ -22,6 +22,8 @@ public:
SymbolLayer(mbgl::Map&, mbgl::style::SymbolLayer&);
+ SymbolLayer(mbgl::Map&, std::unique_ptr<mbgl::style::SymbolLayer>);
+
~SymbolLayer();
// Property getters
diff --git a/platform/android/src/style/layers/unknown_layer.cpp b/platform/android/src/style/layers/unknown_layer.cpp
new file mode 100644
index 0000000000..9ec963a41b
--- /dev/null
+++ b/platform/android/src/style/layers/unknown_layer.cpp
@@ -0,0 +1,49 @@
+#include "unknown_layer.hpp"
+
+#include <string>
+
+namespace {
+
+ // Dummy initializer (We don't support initializing this from the JVM)
+ std::unique_ptr<mbgl::android::UnknownLayer> init(jni::JNIEnv&) {
+ throw new std::runtime_error("UnknownLayer should not be initialized from the JVM");
+ }
+
+} // namespace
+
+namespace mbgl {
+namespace android {
+
+ UnknownLayer::UnknownLayer(mbgl::Map& map, mbgl::style::Layer& coreLayer)
+ : Layer(map, coreLayer) {
+ }
+
+ UnknownLayer::UnknownLayer(mbgl::Map& map, std::unique_ptr<mbgl::style::Layer> coreLayer)
+ : Layer(map, std::move(coreLayer)) {
+ }
+
+ jni::Class<UnknownLayer> UnknownLayer::javaClass;
+
+ jni::jobject* UnknownLayer::createJavaPeer(jni::JNIEnv& env) {
+ static auto constructor = UnknownLayer::javaClass.template GetConstructor<jni::jlong>(env);
+ return UnknownLayer::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this));
+ }
+
+ void UnknownLayer::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ UnknownLayer::javaClass = *jni::Class<UnknownLayer>::Find(env).NewGlobalRef(env).release();
+
+ #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
+
+ std::function<std::unique_ptr<UnknownLayer>(JNIEnv&)> initializer = nullptr;
+
+ // Register the peer
+ jni::RegisterNativePeer<UnknownLayer>(
+ env, UnknownLayer::javaClass, "nativePtr",
+ init,
+ "initialize",
+ "finalize");
+ }
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/layers/unknown_layer.hpp b/platform/android/src/style/layers/unknown_layer.hpp
new file mode 100644
index 0000000000..67992ea007
--- /dev/null
+++ b/platform/android/src/style/layers/unknown_layer.hpp
@@ -0,0 +1,30 @@
+#pragma once
+
+#include "layer.hpp"
+#include <mbgl/style/layer.hpp>
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class UnknownLayer : public Layer {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/UnknownLayer"; };
+
+ static jni::Class<UnknownLayer> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+ UnknownLayer(mbgl::Map&, mbgl::style::Layer&);
+
+ UnknownLayer(mbgl::Map&, std::unique_ptr<mbgl::style::Layer>);
+
+ ~UnknownLayer() = default;
+
+ jni::jobject* createJavaPeer(jni::JNIEnv&);
+
+}; // class UnknownLayer
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/sources/geojson_source.cpp b/platform/android/src/style/sources/geojson_source.cpp
index 234dccb315..37ce0644c1 100644
--- a/platform/android/src/style/sources/geojson_source.cpp
+++ b/platform/android/src/style/sources/geojson_source.cpp
@@ -27,19 +27,19 @@ namespace android {
void GeoJSONSource::setGeoJSON(jni::JNIEnv& env, jni::Object<> json) {
using namespace mbgl::style::conversion;
- //Convert the jni object
+ // Convert the jni object
Result<GeoJSON> converted = convert<GeoJSON>(Value(env, json));
if(!converted) {
mbgl::Log::Error(mbgl::Event::JNI, "Error setting geo json: " + converted.error().message);
return;
}
- //Update the core source
+ // Update the core source
source.as<mbgl::style::GeoJSONSource>()->GeoJSONSource::setGeoJSON(*converted);
}
void GeoJSONSource::setURL(jni::JNIEnv& env, jni::String url) {
- //Update the core source
+ // Update the core source
source.as<mbgl::style::GeoJSONSource>()->GeoJSONSource::setURL(jni::Make<std::string>(env, url));
}
@@ -51,12 +51,12 @@ namespace android {
}
void GeoJSONSource::registerNative(jni::JNIEnv& env) {
- //Lookup the class
+ // Lookup the class
GeoJSONSource::javaClass = *jni::Class<GeoJSONSource>::Find(env).NewGlobalRef(env).release();
#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
- //Register the peer
+ // Register the peer
jni::RegisterNativePeer<GeoJSONSource>(
env, GeoJSONSource::javaClass, "nativePtr",
std::make_unique<GeoJSONSource, JNIEnv&, jni::String, jni::Object<>>,
diff --git a/platform/android/src/style/sources/raster_source.cpp b/platform/android/src/style/sources/raster_source.cpp
index b56b56676d..42ac4cda99 100644
--- a/platform/android/src/style/sources/raster_source.cpp
+++ b/platform/android/src/style/sources/raster_source.cpp
@@ -36,12 +36,12 @@ namespace android {
}
void RasterSource::registerNative(jni::JNIEnv& env) {
- //Lookup the class
+ // Lookup the class
RasterSource::javaClass = *jni::Class<RasterSource>::Find(env).NewGlobalRef(env).release();
#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
- //Register the peer
+ // Register the peer
jni::RegisterNativePeer<RasterSource>(
env, RasterSource::javaClass, "nativePtr",
std::make_unique<RasterSource, JNIEnv&, jni::String, jni::Object<>, jni::jint>,
diff --git a/platform/android/src/style/sources/source.cpp b/platform/android/src/style/sources/source.cpp
index aca7bd6a84..b780de5627 100644
--- a/platform/android/src/style/sources/source.cpp
+++ b/platform/android/src/style/sources/source.cpp
@@ -5,11 +5,11 @@
#include <mbgl/util/logging.hpp>
-//Java -> C++ conversion
+// Java -> C++ conversion
#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/source.hpp>
-//C++ -> Java conversion
+// C++ -> Java conversion
#include "../conversion/property_value.hpp"
#include <string>
@@ -44,15 +44,15 @@ namespace android {
}
void Source::addToMap(mbgl::Map& _map) {
- //Check to see if we own the source first
+ // Check to see if we own the source first
if (!ownedSource) {
throw std::runtime_error("Cannot add source twice");
}
- //Add source to map
+ // Add source to map
_map.addSource(releaseCoreSource());
- //Save pointer to the map
+ // Save pointer to the map
this->map = &_map;
}
@@ -64,17 +64,17 @@ namespace android {
jni::Class<Source> Source::javaClass;
void Source::registerNative(jni::JNIEnv& env) {
- //Lookup the class
+ // Lookup the class
Source::javaClass = *jni::Class<Source>::Find(env).NewGlobalRef(env).release();
#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
- //Register the peer
+ // Register the peer
jni::RegisterNativePeer<Source>(env, Source::javaClass, "nativePtr",
METHOD(&Source::getId, "nativeGetId")
);
}
-} //android
-} //mbgl \ No newline at end of file
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/sources/source.hpp b/platform/android/src/style/sources/source.hpp
index 0e5d354d93..9a9d504d68 100644
--- a/platform/android/src/style/sources/source.hpp
+++ b/platform/android/src/style/sources/source.hpp
@@ -46,22 +46,18 @@ public:
jni::String getId(jni::JNIEnv&);
protected:
- //Release the owned view and return it
+ // Release the owned view and return it
std::unique_ptr<mbgl::style::Source> releaseCoreSource();
- //Set on newly created sources until added to the map
+ // Set on newly created sources until added to the map
std::unique_ptr<mbgl::style::Source> ownedSource;
- //Raw pointer that is valid until the source is removed from the map
+ // Raw pointer that is valid until the source is removed from the map
mbgl::style::Source& source;
- //Map pointer is valid for newly created sources only after adding to the map
+ // Map pointer is valid for newly created sources only after adding to the map
mbgl::Map* map;
};
-} //android
-} //mbgl
-
-
-
-
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/sources/sources.cpp b/platform/android/src/style/sources/sources.cpp
index 210acd607f..b4e70202b4 100644
--- a/platform/android/src/style/sources/sources.cpp
+++ b/platform/android/src/style/sources/sources.cpp
@@ -8,6 +8,7 @@
#include "source.hpp"
#include "geojson_source.hpp"
#include "raster_source.hpp"
+#include "unknown_source.hpp"
#include "vector_source.hpp"
namespace mbgl {
@@ -22,7 +23,7 @@ Source* initializeSourcePeer(mbgl::Map& map, mbgl::style::Source& coreSource) {
} else if (coreSource.is<mbgl::style::GeoJSONSource>()) {
source = new GeoJSONSource(map, *coreSource.as<mbgl::style::GeoJSONSource>());
} else {
- throw new std::runtime_error("Source type not implemented");
+ source = new UnknownSource(map, coreSource);
}
return source;
@@ -37,10 +38,11 @@ jni::jobject* createJavaSourcePeer(jni::JNIEnv& env, mbgl::Map& map, mbgl::style
void registerNativeSources(jni::JNIEnv& env) {
Source::registerNative(env);
- VectorSource::registerNative(env);
- RasterSource::registerNative(env);
GeoJSONSource::registerNative(env);
+ RasterSource::registerNative(env);
+ UnknownSource::registerNative(env);
+ VectorSource::registerNative(env);
}
}
-} \ No newline at end of file
+}
diff --git a/platform/android/src/style/sources/sources.hpp b/platform/android/src/style/sources/sources.hpp
index 3038873733..09a8b35067 100644
--- a/platform/android/src/style/sources/sources.hpp
+++ b/platform/android/src/style/sources/sources.hpp
@@ -9,12 +9,12 @@
namespace mbgl {
namespace android {
-
+
mbgl::android::Source* initializeSourcePeer(mbgl::Map&, mbgl::style::Source&);
-
+
jni::jobject* createJavaSourcePeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Source&);
-
+
void registerNativeSources(jni::JNIEnv&);
}
-} \ No newline at end of file
+}
diff --git a/platform/android/src/style/sources/unknown_source.cpp b/platform/android/src/style/sources/unknown_source.cpp
new file mode 100644
index 0000000000..c1b1cc8c02
--- /dev/null
+++ b/platform/android/src/style/sources/unknown_source.cpp
@@ -0,0 +1,42 @@
+#include "unknown_source.hpp"
+
+namespace {
+
+ // Dummy initializer (We don't support initializing this from the JVM)
+ std::unique_ptr<mbgl::android::UnknownSource> init(jni::JNIEnv&) {
+ throw new std::runtime_error("UnknownSource should not be initialized from the JVM");
+ }
+
+} // namespace
+
+namespace mbgl {
+namespace android {
+
+ UnknownSource::UnknownSource(mbgl::Map& map, mbgl::style::Source& coreSource)
+ : Source(map, coreSource) {
+ }
+
+ jni::Class<UnknownSource> UnknownSource::javaClass;
+
+ jni::jobject* UnknownSource::createJavaPeer(jni::JNIEnv& env) {
+ static auto constructor = UnknownSource::javaClass.template GetConstructor<jni::jlong>(env);
+ return UnknownSource::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this));
+ }
+
+ void UnknownSource::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ UnknownSource::javaClass = *jni::Class<UnknownSource>::Find(env).NewGlobalRef(env).release();
+
+ #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
+
+ // Register the peer
+ jni::RegisterNativePeer<UnknownSource>(
+ env, UnknownSource::javaClass, "nativePtr",
+ init,
+ "initialize",
+ "finalize"
+ );
+ }
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/sources/unknown_source.hpp b/platform/android/src/style/sources/unknown_source.hpp
new file mode 100644
index 0000000000..3c37239792
--- /dev/null
+++ b/platform/android/src/style/sources/unknown_source.hpp
@@ -0,0 +1,28 @@
+#pragma once
+
+#include "source.hpp"
+#include <mbgl/style/source.hpp>
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class UnknownSource : public Source {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/sources/UnknownSource"; };
+
+ static jni::Class<UnknownSource> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+ UnknownSource(mbgl::Map&, mbgl::style::Source&);
+
+ ~UnknownSource() = default;
+
+ jni::jobject* createJavaPeer(jni::JNIEnv&);
+
+}; // class UnknownSource
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/sources/vector_source.cpp b/platform/android/src/style/sources/vector_source.cpp
index 0d065a3348..e60d8d4641 100644
--- a/platform/android/src/style/sources/vector_source.cpp
+++ b/platform/android/src/style/sources/vector_source.cpp
@@ -35,12 +35,12 @@ namespace android {
}
void VectorSource::registerNative(jni::JNIEnv& env) {
- //Lookup the class
+ // Lookup the class
VectorSource::javaClass = *jni::Class<VectorSource>::Find(env).NewGlobalRef(env).release();
#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
- //Register the peer
+ // Register the peer
jni::RegisterNativePeer<VectorSource>(
env, VectorSource::javaClass, "nativePtr",
std::make_unique<VectorSource, JNIEnv&, jni::String, jni::Object<>>,
diff --git a/platform/android/src/style/value.cpp b/platform/android/src/style/value.cpp
index c8aad1682b..0b5d81feb1 100644
--- a/platform/android/src/style/value.cpp
+++ b/platform/android/src/style/value.cpp
@@ -20,7 +20,7 @@ namespace android {
JNIEnv& env;
};
- //Instance
+ // Instance
Value::Value(jni::JNIEnv& env, jni::jobject* _value) : jenv(env), value(_value, ObjectDeleter(env)) {}
diff --git a/platform/android/src/test/Main.java b/platform/android/src/test/Main.java
index b6f540f666..b0f3aeb7b9 100644
--- a/platform/android/src/test/Main.java
+++ b/platform/android/src/test/Main.java
@@ -3,13 +3,13 @@ public class Main {
public native void runAllTests(String[] args);
public static void main(String[] args) throws Exception {
- //Load the tests
+ // Load the tests
System.loadLibrary("mbgl-test");
- //Run the tests
+ // Run the tests
new Main().runAllTests(args);
- //Exit explicitly otherwise dalvikvm won't quit
+ // Exit explicitly otherwise dalvikvm won't quit
System.exit(0);
}
}
diff --git a/platform/android/src/test/main.jni.cpp b/platform/android/src/test/main.jni.cpp
index f79d7671cb..f96dd6aa5e 100644
--- a/platform/android/src/test/main.jni.cpp
+++ b/platform/android/src/test/main.jni.cpp
@@ -1,7 +1,5 @@
#include "../jni.hpp"
-#include <android/log.h>
-#include <jni/jni.hpp>
#include <jni/jni.hpp>
#include <mbgl/util/logging.hpp>
@@ -9,10 +7,6 @@
#include <vector>
-#pragma clang diagnostic ignored "-Wunused-parameter"
-
-#define MAKE_NATIVE_METHOD(name, sig) jni::MakeNativeMethod<decltype(name), name>( #name, sig )
-
namespace {
// Main class (entry point for tests from dalvikvm)
@@ -48,31 +42,26 @@ struct Main {
} // namespace
-// JNI Bindings to stub the android.util.Log implementation
-
-static jboolean isLoggable(JNIEnv* env, jni::jobject* clazz, jni::jstring* tag, jint level) {
- return true;
-}
-
-static jint println_native(JNIEnv* env, jni::jobject* clazz, jint bufID, jint priority, jni::jstring* jtag, jni::jstring* jmessage) {
- if (jtag == nullptr || jmessage == nullptr) {
- return false;
- }
-
- std::string tag = jni::Make<std::string>(*env, jni::String(jtag));
- std::string message = jni::Make<std::string>(*env, jni::String(jmessage));
-
- return __android_log_print(priority, tag.c_str(), "%s", message.c_str());
-}
-
-static jint logger_entry_max_payload_native(JNIEnv* env, jni::jobject* clazz) {
- return static_cast<jint>(4068);
-}
-
+// We're declaring the function, which is libandroid_runtime.so.
+// It is defined in AndroidRuntime.cpp:
+// https://github.com/android/platform_frameworks_base/blob/master/core/jni/AndroidRuntime.cpp
+// Once this symbol goes away, we'll have to revisit.
+// This method loads and registers all of the Android-native frameworks so that we can use
+// android.util.Log, android.graphics.Bitmap and so on.
+// Setting the weak attribute tells the linker that this symbol is loaded at runtime and avoids
+// a missing symbol error.
+namespace android {
+struct AndroidRuntime {
+ static int startReg(JNIEnv* env) __attribute__((weak));
+};
+} // namespace android
// Main entry point
+extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *) {
+ // Load Android-native jni bindings
+ jni::JNIEnv& env = jni::GetEnv(*vm, jni::jni_version_1_6);
+ android::AndroidRuntime::startReg(&env);
-extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
// Load the main library jni bindings
mbgl::Log::Info(mbgl::Event::JNI, "Registering main JNI Methods");
mbgl::android::registerNatives(vm);
@@ -80,22 +69,8 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
// Load the test library jni bindings
mbgl::Log::Info(mbgl::Event::JNI, "Registering test JNI Methods");
- jni::JNIEnv& env = jni::GetEnv(*vm, jni::jni_version_1_6);
-
jni::RegisterNatives(env, jni::Class<Main>::Find(env),
jni::MakeNativeMethod<decltype(Main::runAllTests), &Main::runAllTests>("runAllTests"));
- // Bindings for system classes
- struct Log { static constexpr auto Name() { return "android/util/Log"; } };
- try {
- jni::RegisterNatives(env, jni::Class<Log>::Find(env),
- MAKE_NATIVE_METHOD(isLoggable, "(Ljava/lang/String;I)Z"),
- MAKE_NATIVE_METHOD(logger_entry_max_payload_native, "()I"),
- MAKE_NATIVE_METHOD(println_native, "(IILjava/lang/String;Ljava/lang/String;)I")
- );
- } catch (jni::PendingJavaException ex) {
- env.ThrowNew(jni::JavaErrorClass(env), "Could not register Log mocks");
- }
-
return JNI_VERSION_1_6;
}
diff --git a/platform/android/src/timer.cpp b/platform/android/src/timer.cpp
index 2eb003b2bd..2d9ee49e9b 100644
--- a/platform/android/src/timer.cpp
+++ b/platform/android/src/timer.cpp
@@ -23,7 +23,7 @@ public:
repeat = repeat_;
task = std::move(task_);
- //Prevent overflows when timeout is set to Duration::max()
+ // Prevent overflows when timeout is set to Duration::max()
due = (timeout == Duration::max()) ? std::chrono::time_point<Clock>::max() : Clock::now() + timeout;
loop->addRunnable(this);
}