summaryrefslogtreecommitdiff
path: root/platform/android/src
diff options
context:
space:
mode:
Diffstat (limited to 'platform/android/src')
-rwxr-xr-xplatform/android/src/android_renderer_backend.cpp63
-rwxr-xr-xplatform/android/src/android_renderer_backend.hpp41
-rw-r--r--platform/android/src/android_renderer_frontend.cpp117
-rw-r--r--platform/android/src/android_renderer_frontend.hpp49
-rw-r--r--platform/android/src/asset_manager_file_source.cpp18
-rw-r--r--platform/android/src/asset_manager_file_source.hpp5
-rw-r--r--platform/android/src/conversion/constant.hpp1
-rw-r--r--platform/android/src/example_custom_layer.cpp8
-rw-r--r--platform/android/src/file_source.cpp22
-rw-r--r--platform/android/src/file_source.hpp8
-rw-r--r--platform/android/src/geometry/lat_lng_quad.cpp39
-rw-r--r--platform/android/src/geometry/lat_lng_quad.hpp30
-rw-r--r--platform/android/src/http_file_source.cpp4
-rwxr-xr-xplatform/android/src/jni.cpp10
-rw-r--r--platform/android/src/jni/generic_global_ref_deleter.hpp29
-rw-r--r--platform/android/src/map/camera_position.cpp18
-rw-r--r--platform/android/src/map/camera_position.hpp2
-rw-r--r--platform/android/src/map_renderer.cpp200
-rw-r--r--platform/android/src/map_renderer.hpp126
-rw-r--r--platform/android/src/map_renderer_runnable.cpp49
-rw-r--r--platform/android/src/map_renderer_runnable.hpp50
-rwxr-xr-xplatform/android/src/native_map_view.cpp729
-rwxr-xr-xplatform/android/src/native_map_view.hpp107
-rw-r--r--platform/android/src/run_loop.cpp24
-rw-r--r--platform/android/src/snapshotter/map_snapshotter.cpp110
-rw-r--r--platform/android/src/snapshotter/map_snapshotter.hpp61
-rw-r--r--platform/android/src/style/android_conversion.hpp9
-rw-r--r--platform/android/src/style/conversion/latlngquad.hpp24
-rw-r--r--platform/android/src/style/conversion/transition_options.hpp1
-rw-r--r--platform/android/src/style/conversion/types.hpp8
-rw-r--r--platform/android/src/style/conversion/types_string_values.hpp56
-rw-r--r--platform/android/src/style/layers/circle_layer.cpp7
-rw-r--r--platform/android/src/style/layers/circle_layer.hpp2
-rw-r--r--platform/android/src/style/layers/custom_layer.cpp9
-rw-r--r--platform/android/src/style/layers/custom_layer.hpp4
-rw-r--r--platform/android/src/style/layers/layer.cpp96
-rw-r--r--platform/android/src/style/layers/layers.cpp82
-rw-r--r--platform/android/src/style/layers/symbol_layer.cpp14
-rw-r--r--platform/android/src/style/layers/symbol_layer.hpp4
-rw-r--r--platform/android/src/style/sources/geojson_source.cpp10
-rw-r--r--platform/android/src/style/sources/geojson_source.hpp2
-rw-r--r--platform/android/src/style/sources/image_source.cpp72
-rw-r--r--platform/android/src/style/sources/image_source.hpp38
-rw-r--r--platform/android/src/style/sources/raster_source.cpp4
-rw-r--r--platform/android/src/style/sources/raster_source.hpp2
-rw-r--r--platform/android/src/style/sources/source.cpp14
-rw-r--r--platform/android/src/style/sources/source.hpp10
-rw-r--r--platform/android/src/style/sources/sources.cpp44
-rw-r--r--platform/android/src/style/sources/sources.hpp10
-rw-r--r--platform/android/src/style/sources/unknown_source.cpp4
-rw-r--r--platform/android/src/style/sources/unknown_source.hpp2
-rw-r--r--platform/android/src/style/sources/vector_source.cpp10
-rw-r--r--platform/android/src/style/sources/vector_source.hpp2
53 files changed, 1532 insertions, 928 deletions
diff --git a/platform/android/src/android_renderer_backend.cpp b/platform/android/src/android_renderer_backend.cpp
new file mode 100755
index 0000000000..9e49915650
--- /dev/null
+++ b/platform/android/src/android_renderer_backend.cpp
@@ -0,0 +1,63 @@
+#include "android_renderer_backend.hpp"
+
+#include <mbgl/gl/context.hpp>
+
+#include <EGL/egl.h>
+
+#include <cassert>
+
+namespace mbgl {
+namespace android {
+
+/**
+ * From mbgl::View
+ */
+void AndroidRendererBackend::bind() {
+ assert(BackendScope::exists());
+ setFramebufferBinding(0);
+ setViewport(0, 0, getFramebufferSize());
+}
+
+/**
+ * From mbgl::RendererBackend.
+ */
+gl::ProcAddress AndroidRendererBackend::initializeExtension(const char* name) {
+ assert(BackendScope::exists());
+ return eglGetProcAddress(name);
+}
+
+void AndroidRendererBackend::updateViewPort() {
+ assert(BackendScope::exists());
+ setViewport(0, 0, getFramebufferSize());
+}
+
+void AndroidRendererBackend::resizeFramebuffer(int width, int height) {
+ fbWidth = width;
+ fbHeight = height;
+}
+
+PremultipliedImage AndroidRendererBackend::readFramebuffer() const {
+ assert(BackendScope::exists());
+ return RendererBackend::readFramebuffer(getFramebufferSize());
+}
+
+mbgl::Size AndroidRendererBackend::getFramebufferSize() const {
+ return { static_cast<uint32_t>(fbWidth), static_cast<uint32_t>(fbHeight) };
+}
+
+/**
+ * From mbgl::RendererBackend.
+ */
+void AndroidRendererBackend::updateAssumedState() {
+ assumeFramebufferBinding(0);
+ assumeViewport(0, 0, getFramebufferSize());
+}
+
+void AndroidRendererBackend::markContextLost() {
+ if (context) {
+ context->setCleanupOnDestruction(false);
+ }
+}
+
+} // namespace android
+} // namspace mbgl
diff --git a/platform/android/src/android_renderer_backend.hpp b/platform/android/src/android_renderer_backend.hpp
new file mode 100755
index 0000000000..c5c552459f
--- /dev/null
+++ b/platform/android/src/android_renderer_backend.hpp
@@ -0,0 +1,41 @@
+#pragma once
+
+#include <mbgl/renderer/renderer_backend.hpp>
+
+namespace mbgl {
+namespace android {
+
+class AndroidRendererBackend : public RendererBackend {
+public:
+
+ // mbgl::RendererBackend //
+ void bind() override;
+ void updateAssumedState() override;
+ mbgl::Size getFramebufferSize() const override;
+
+ // Ensures the current context is not
+ // cleaned up when destroyed
+ void markContextLost();
+
+ void updateViewPort();
+
+ void resizeFramebuffer(int width, int height);
+ PremultipliedImage readFramebuffer() const;
+
+protected:
+ // mbgl::RendererBackend //
+ gl::ProcAddress initializeExtension(const char*) override;
+ void activate() override {};
+ void deactivate() override {};
+
+
+private:
+
+ // Minimum texture size according to OpenGL ES 2.0 specification.
+ int fbWidth = 64;
+ int fbHeight = 64;
+
+};
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/android_renderer_frontend.cpp b/platform/android/src/android_renderer_frontend.cpp
new file mode 100644
index 0000000000..b80e23e21f
--- /dev/null
+++ b/platform/android/src/android_renderer_frontend.cpp
@@ -0,0 +1,117 @@
+#include "android_renderer_frontend.hpp"
+
+#include <mbgl/actor/scheduler.hpp>
+#include <mbgl/renderer/renderer.hpp>
+#include <mbgl/renderer/renderer_observer.hpp>
+#include <mbgl/storage/file_source.hpp>
+#include <mbgl/util/thread.hpp>
+#include <mbgl/util/run_loop.hpp>
+
+#include "android_renderer_backend.hpp"
+
+namespace mbgl {
+namespace android {
+
+// Forwards RendererObserver signals to the given
+// Delegate RendererObserver on the given RunLoop
+class ForwardingRendererObserver : public RendererObserver {
+public:
+ ForwardingRendererObserver(util::RunLoop& mapRunLoop, RendererObserver& delegate_)
+ : mailbox(std::make_shared<Mailbox>(mapRunLoop))
+ , delegate(delegate_, mailbox) {
+ }
+
+ ~ForwardingRendererObserver() {
+ mailbox->close();
+ }
+
+ void onInvalidate() override {
+ delegate.invoke(&RendererObserver::onInvalidate);
+ }
+
+ void onResourceError(std::exception_ptr err) override {
+ delegate.invoke(&RendererObserver::onResourceError, err);
+ }
+
+ void onWillStartRenderingMap() override {
+ delegate.invoke(&RendererObserver::onWillStartRenderingMap);
+ }
+
+ void onWillStartRenderingFrame() override {
+ delegate.invoke(&RendererObserver::onWillStartRenderingFrame);
+ }
+
+ void onDidFinishRenderingFrame(RenderMode mode, bool repaintNeeded) override {
+ delegate.invoke(&RendererObserver::onDidFinishRenderingFrame, mode, repaintNeeded);
+ }
+
+ void onDidFinishRenderingMap() override {
+ delegate.invoke(&RendererObserver::onDidFinishRenderingMap);
+ }
+
+private:
+ std::shared_ptr<Mailbox> mailbox;
+ ActorRef<RendererObserver> delegate;
+};
+
+AndroidRendererFrontend::AndroidRendererFrontend(MapRenderer& mapRenderer_)
+ : mapRenderer(mapRenderer_)
+ , mapRunLoop(util::RunLoop::Get()) {
+}
+
+AndroidRendererFrontend::~AndroidRendererFrontend() = default;
+
+void AndroidRendererFrontend::reset() {
+ mapRenderer.reset();
+}
+
+void AndroidRendererFrontend::setObserver(RendererObserver& observer) {
+ assert (util::RunLoop::Get());
+ // Don't call the Renderer directly, but use MapRenderer#setObserver to make sure
+ // the Renderer may be re-initialised without losing the RendererObserver reference.
+ mapRenderer.setObserver(std::make_unique<ForwardingRendererObserver>(*mapRunLoop, observer));
+}
+
+void AndroidRendererFrontend::update(std::shared_ptr<UpdateParameters> params) {
+ mapRenderer.update(std::move(params));
+ mapRenderer.requestRender();
+}
+
+void AndroidRendererFrontend::onLowMemory() {
+ mapRenderer.actor().invoke(&Renderer::onLowMemory);
+}
+
+std::vector<Feature> AndroidRendererFrontend::querySourceFeatures(const std::string& sourceID,
+ const SourceQueryOptions& options) const {
+ // Waits for the result from the orchestration thread and returns
+ return mapRenderer.actor().ask(&Renderer::querySourceFeatures, sourceID, options).get();
+}
+
+std::vector<Feature> AndroidRendererFrontend::queryRenderedFeatures(const ScreenBox& box,
+ const RenderedQueryOptions& options) const {
+
+ // Select the right overloaded method
+ std::vector<Feature> (Renderer::*fn)(const ScreenBox&, const RenderedQueryOptions&) const = &Renderer::queryRenderedFeatures;
+
+ // Waits for the result from the orchestration thread and returns
+ return mapRenderer.actor().ask(fn, box, options).get();
+}
+
+std::vector<Feature> AndroidRendererFrontend::queryRenderedFeatures(const ScreenCoordinate& point,
+ const RenderedQueryOptions& options) const {
+
+ // Select the right overloaded method
+ std::vector<Feature> (Renderer::*fn)(const ScreenCoordinate&, const RenderedQueryOptions&) const = &Renderer::queryRenderedFeatures;
+
+ // Waits for the result from the orchestration thread and returns
+ return mapRenderer.actor().ask(fn, point, options).get();
+}
+
+AnnotationIDs AndroidRendererFrontend::queryPointAnnotations(const ScreenBox& box) const {
+ // Waits for the result from the orchestration thread and returns
+ return mapRenderer.actor().ask(&Renderer::queryPointAnnotations, box).get();
+}
+
+} // namespace android
+} // namespace mbgl
+
diff --git a/platform/android/src/android_renderer_frontend.hpp b/platform/android/src/android_renderer_frontend.hpp
new file mode 100644
index 0000000000..94508fd816
--- /dev/null
+++ b/platform/android/src/android_renderer_frontend.hpp
@@ -0,0 +1,49 @@
+#pragma once
+
+#include <mbgl/actor/actor.hpp>
+#include <mbgl/annotation/annotation.hpp>
+#include <mbgl/renderer/renderer_frontend.hpp>
+#include <mbgl/util/geo.hpp>
+#include <mbgl/util/run_loop.hpp>
+
+#include <functional>
+#include <memory>
+#include <vector>
+#include <string>
+
+#include "map_renderer.hpp"
+
+namespace mbgl {
+
+class RenderedQueryOptions;
+class SourceQueryOptions;
+
+namespace android {
+
+class AndroidRendererFrontend : public RendererFrontend {
+public:
+
+ AndroidRendererFrontend(MapRenderer&);
+ ~AndroidRendererFrontend() override;
+
+ void reset() override;
+ void setObserver(RendererObserver&) override;
+
+ void update(std::shared_ptr<UpdateParameters>) override;
+
+ // Feature querying
+ std::vector<Feature> queryRenderedFeatures(const ScreenCoordinate&, const RenderedQueryOptions&) const;
+ std::vector<Feature> queryRenderedFeatures(const ScreenBox&, const RenderedQueryOptions&) const;
+ std::vector<Feature> querySourceFeatures(const std::string& sourceID, const SourceQueryOptions&) const;
+ AnnotationIDs queryPointAnnotations(const ScreenBox& box) const;
+
+ // Memory
+ void onLowMemory();
+
+private:
+ MapRenderer& mapRenderer;
+ util::RunLoop* mapRunLoop;
+};
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/asset_manager_file_source.cpp b/platform/android/src/asset_manager_file_source.cpp
index 6a3113d696..aa65e3ff48 100644
--- a/platform/android/src/asset_manager_file_source.cpp
+++ b/platform/android/src/asset_manager_file_source.cpp
@@ -1,5 +1,6 @@
#include "asset_manager_file_source.hpp"
+#include <mbgl/storage/file_source_request.hpp>
#include <mbgl/storage/response.hpp>
#include <mbgl/util/util.hpp>
#include <mbgl/util/thread.hpp>
@@ -12,10 +13,10 @@ namespace mbgl {
class AssetManagerFileSource::Impl {
public:
- Impl(AAssetManager* assetManager_) : assetManager(assetManager_) {
+ Impl(ActorRef<Impl>, AAssetManager* assetManager_) : assetManager(assetManager_) {
}
- void request(const std::string& url, FileSource::Callback callback) {
+ void request(const std::string& url, ActorRef<FileSourceRequest> req) {
// Note: AssetManager already prepends "assets" to the filename.
const std::string path = mbgl::util::percentDecode(url.substr(8));
@@ -30,7 +31,7 @@ public:
"Could not read asset");
}
- callback(response);
+ req.invoke(&FileSourceRequest::setResponse, response);
}
private:
@@ -39,15 +40,18 @@ private:
AssetManagerFileSource::AssetManagerFileSource(jni::JNIEnv& env, jni::Object<android::AssetManager> assetManager_)
: assetManager(assetManager_.NewGlobalRef(env)),
- thread(std::make_unique<util::Thread<Impl>>(
- util::ThreadContext{"AssetManagerFileSource", util::ThreadPriority::Low},
- AAssetManager_fromJava(&env, jni::Unwrap(**assetManager)))) {
+ impl(std::make_unique<util::Thread<Impl>>("AssetManagerFileSource",
+ AAssetManager_fromJava(&env, jni::Unwrap(**assetManager)))) {
}
AssetManagerFileSource::~AssetManagerFileSource() = default;
std::unique_ptr<AsyncRequest> AssetManagerFileSource::request(const Resource& resource, Callback callback) {
- return thread->invokeWithCallback(&Impl::request, resource.url, callback);
+ auto req = std::make_unique<FileSourceRequest>(std::move(callback));
+
+ impl->actor().invoke(&Impl::request, resource.url, req->actor());
+
+ return std::move(req);
}
} // namespace mbgl
diff --git a/platform/android/src/asset_manager_file_source.hpp b/platform/android/src/asset_manager_file_source.hpp
index 7a447a2c61..dcad95664a 100644
--- a/platform/android/src/asset_manager_file_source.hpp
+++ b/platform/android/src/asset_manager_file_source.hpp
@@ -20,9 +20,10 @@ public:
std::unique_ptr<AsyncRequest> request(const Resource&, Callback) override;
private:
- jni::UniqueObject<android::AssetManager> assetManager;
class Impl;
- std::unique_ptr<util::Thread<Impl>> thread;
+
+ jni::UniqueObject<android::AssetManager> assetManager;
+ std::unique_ptr<util::Thread<Impl>> impl;
};
} // namespace mbgl
diff --git a/platform/android/src/conversion/constant.hpp b/platform/android/src/conversion/constant.hpp
index 2a0b710f73..f1c72eb5dd 100644
--- a/platform/android/src/conversion/constant.hpp
+++ b/platform/android/src/conversion/constant.hpp
@@ -3,6 +3,7 @@
#include "conversion.hpp"
#include <mbgl/util/optional.hpp>
+#include <mbgl/util/color.hpp>
#include <jni/jni.hpp>
#include <string>
diff --git a/platform/android/src/example_custom_layer.cpp b/platform/android/src/example_custom_layer.cpp
index c55c9c3527..1ed68d0835 100644
--- a/platform/android/src/example_custom_layer.cpp
+++ b/platform/android/src/example_custom_layer.cpp
@@ -92,6 +92,10 @@ void nativeRender(void *context, const mbgl::style::CustomLayerRenderParameters&
reinterpret_cast<ExampleCustomLayer*>(context)->render();
}
+void nativeContextLost(void */*context*/) {
+ mbgl::Log::Info(mbgl::Event::General, "nativeContextLost");
+}
+
void nativeDenitialize(void *context) {
mbgl::Log::Info(mbgl::Event::General, "nativeDeinitialize");
delete reinterpret_cast<ExampleCustomLayer*>(context);
@@ -123,6 +127,10 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) {
reinterpret_cast<jlong>(nativeRender));
env->SetStaticLongField(customLayerClass,
+ env->GetStaticFieldID(customLayerClass, "ContextLostFunction", "J"),
+ reinterpret_cast<jlong>(nativeContextLost));
+
+ env->SetStaticLongField(customLayerClass,
env->GetStaticFieldID(customLayerClass, "DeinitializeFunction", "J"),
reinterpret_cast<jlong>(nativeDenitialize));
diff --git a/platform/android/src/file_source.cpp b/platform/android/src/file_source.cpp
index 16c09b7b52..262e3d3c6a 100644
--- a/platform/android/src/file_source.cpp
+++ b/platform/android/src/file_source.cpp
@@ -1,5 +1,8 @@
#include "file_source.hpp"
+#include <mbgl/actor/actor.hpp>
+#include <mbgl/actor/scheduler.hpp>
+#include <mbgl/storage/resource_transform.hpp>
#include <mbgl/util/logging.hpp>
#include "asset_manager_file_source.hpp"
@@ -42,21 +45,22 @@ void FileSource::setAPIBaseUrl(jni::JNIEnv& env, jni::String url) {
void FileSource::setResourceTransform(jni::JNIEnv& env, jni::Object<FileSource::ResourceTransformCallback> transformCallback) {
if (transformCallback) {
- // Launch transformCallback
- fileSource->setResourceTransform([
+ resourceTransform = std::make_unique<Actor<ResourceTransform>>(*Scheduler::GetCurrent(),
// 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())
- ](mbgl::Resource::Kind kind, std::string&& url_) {
- android::UniqueEnv _env = android::AttachEnv();
- return FileSource::ResourceTransformCallback::onURL(*_env, jni::Object<FileSource::ResourceTransformCallback>(*callback), int(kind), url_);
- });
+ [callback = std::shared_ptr<jni::jobject>(transformCallback.NewGlobalRef(env).release()->Get(), GenericGlobalRefDeleter())]
+ (mbgl::Resource::Kind kind, const std::string&& url_) {
+ android::UniqueEnv _env = android::AttachEnv();
+ return FileSource::ResourceTransformCallback::onURL(*_env, jni::Object<FileSource::ResourceTransformCallback>(*callback), int(kind), url_);
+ });
+ fileSource->setResourceTransform(resourceTransform->self());
} else {
// Reset the callback
- fileSource->setResourceTransform(nullptr);
+ resourceTransform.reset();
+ fileSource->setResourceTransform({});
}
}
@@ -106,4 +110,4 @@ std::string FileSource::ResourceTransformCallback::onURL(jni::JNIEnv& env, jni::
}
} // namespace android
-} // namespace mbgl \ No newline at end of file
+} // namespace mbgl
diff --git a/platform/android/src/file_source.hpp b/platform/android/src/file_source.hpp
index 55e70f34d9..4abe352bff 100644
--- a/platform/android/src/file_source.hpp
+++ b/platform/android/src/file_source.hpp
@@ -7,6 +7,10 @@
#include <jni/jni.hpp>
namespace mbgl {
+
+template <typename T> class Actor;
+class ResourceTransform;
+
namespace android {
/**
@@ -46,10 +50,10 @@ public:
static void registerNative(jni::JNIEnv&);
private:
-
+ std::unique_ptr<Actor<ResourceTransform>> resourceTransform;
std::unique_ptr<mbgl::DefaultFileSource> fileSource;
};
} // namespace android
-} // namespace mbgl \ No newline at end of file
+} // namespace mbgl
diff --git a/platform/android/src/geometry/lat_lng_quad.cpp b/platform/android/src/geometry/lat_lng_quad.cpp
new file mode 100644
index 0000000000..2b36139e18
--- /dev/null
+++ b/platform/android/src/geometry/lat_lng_quad.cpp
@@ -0,0 +1,39 @@
+#include "lat_lng_quad.hpp"
+#include "lat_lng.hpp"
+
+namespace mbgl {
+namespace android {
+
+jni::Object<LatLngQuad> LatLngQuad::New(jni::JNIEnv& env, std::array<mbgl::LatLng, 4> coordinates) {
+ static auto quadConstructor = LatLngQuad::javaClass.GetConstructor<jni::Object<LatLng>, jni::Object<LatLng>, jni::Object<LatLng>, jni::Object<LatLng>>(env);
+ return LatLngQuad::javaClass.New(env, quadConstructor,
+ LatLng::New(env, coordinates[0]),
+ LatLng::New(env, coordinates[1]),
+ LatLng::New(env, coordinates[2]),
+ LatLng::New(env, coordinates[3]));
+}
+
+std::array<mbgl::LatLng, 4> LatLngQuad::getLatLngArray(jni::JNIEnv& env, jni::Object<LatLngQuad> quad) {
+ static auto topLeftField = LatLngQuad::javaClass.GetField <jni::Object<LatLng>>(env, "topLeft");
+ static auto topRightField = LatLngQuad::javaClass.GetField <jni::Object<LatLng>>(env, "topRight");
+ static auto bottomRightField = LatLngQuad::javaClass.GetField <jni::Object<LatLng>>(env, "bottomRight");
+ static auto bottomLeftField = LatLngQuad::javaClass.GetField <jni::Object<LatLng>>(env, "bottomLeft");
+
+ return std::array < mbgl::LatLng, 4 > {{
+ LatLng::getLatLng(env, quad.Get(env, topLeftField)),
+ LatLng::getLatLng(env, quad.Get(env, topRightField)),
+ LatLng::getLatLng(env, quad.Get(env, bottomRightField)),
+ LatLng::getLatLng(env, quad.Get(env, bottomLeftField))
+ }};
+}
+
+void LatLngQuad::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ LatLngQuad::javaClass = *jni::Class<LatLngQuad>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<LatLngQuad> LatLngQuad::javaClass;
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geometry/lat_lng_quad.hpp b/platform/android/src/geometry/lat_lng_quad.hpp
new file mode 100644
index 0000000000..8f8c9abeef
--- /dev/null
+++ b/platform/android/src/geometry/lat_lng_quad.hpp
@@ -0,0 +1,30 @@
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/geo.hpp>
+#include <mbgl/util/geometry.hpp>
+
+#include <jni/jni.hpp>
+#include <array>
+
+namespace mbgl {
+namespace android {
+
+class LatLngQuad : private mbgl::util::noncopyable {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/geometry/LatLngQuad"; };
+
+ static jni::Object<LatLngQuad> New(jni::JNIEnv&, std::array<mbgl::LatLng, 4>);
+
+ static std::array<mbgl::LatLng, 4> getLatLngArray(jni::JNIEnv&, jni::Object<LatLngQuad>);
+
+ static jni::Class<LatLngQuad> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+};
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/http_file_source.cpp b/platform/android/src/http_file_source.cpp
index ee1429bd74..8eb9416e9d 100644
--- a/platform/android/src/http_file_source.cpp
+++ b/platform/android/src/http_file_source.cpp
@@ -117,7 +117,9 @@ void HTTPRequest::onResponse(jni::JNIEnv& env, int code,
}
if (cacheControl) {
- response.expires = http::CacheControl::parse(jni::Make<std::string>(env, cacheControl).c_str()).toTimePoint();
+ const auto cc = http::CacheControl::parse(jni::Make<std::string>(env, cacheControl).c_str());
+ response.expires = cc.toTimePoint();
+ response.mustRevalidate = cc.mustRevalidate;
}
if (expires) {
diff --git a/platform/android/src/jni.cpp b/platform/android/src/jni.cpp
index 6c490fad5c..6acb6a3664 100755
--- a/platform/android/src/jni.cpp
+++ b/platform/android/src/jni.cpp
@@ -23,6 +23,7 @@
#include "geojson/position.hpp"
#include "geometry/lat_lng.hpp"
#include "geometry/lat_lng_bounds.hpp"
+#include "geometry/lat_lng_quad.hpp"
#include "geometry/projected_meters.hpp"
#include "graphics/pointf.hpp"
#include "graphics/rectf.hpp"
@@ -31,6 +32,8 @@
#include "gson/json_object.hpp"
#include "gson/json_primitive.hpp"
#include "java_types.hpp"
+#include "map_renderer.hpp"
+#include "map_renderer_runnable.hpp"
#include "native_map_view.hpp"
#include "offline/offline_manager.hpp"
#include "offline/offline_region.hpp"
@@ -46,6 +49,7 @@
#include "style/layers/layers.hpp"
#include "style/sources/sources.hpp"
#include "style/light.hpp"
+#include "snapshotter/map_snapshotter.hpp"
namespace mbgl {
namespace android {
@@ -127,6 +131,7 @@ void registerNatives(JavaVM *vm) {
// Geometry
LatLng::registerNative(env);
LatLngBounds::registerNative(env);
+ LatLngQuad::registerNative(env);
ProjectedMeters::registerNative(env);
// GSon
@@ -141,6 +146,8 @@ void registerNatives(JavaVM *vm) {
Polyline::registerNative(env);
// Map
+ MapRenderer::registerNative(env);
+ MapRendererRunnable::registerNative(env);
NativeMapView::registerNative(env);
// Http
@@ -175,6 +182,9 @@ void registerNatives(JavaVM *vm) {
OfflineTilePyramidRegionDefinition::registerNative(env);
OfflineRegionError::registerNative(env);
OfflineRegionStatus::registerNative(env);
+
+ // Snapshotter
+ MapSnapshotter::registerNative(env);
}
} // namespace android
diff --git a/platform/android/src/jni/generic_global_ref_deleter.hpp b/platform/android/src/jni/generic_global_ref_deleter.hpp
index 4e53e0a0ce..7239e361a7 100644
--- a/platform/android/src/jni/generic_global_ref_deleter.hpp
+++ b/platform/android/src/jni/generic_global_ref_deleter.hpp
@@ -18,5 +18,34 @@ struct GenericGlobalRefDeleter {
}
};
+
+template < class TagType >
+class GenericWeakObjectRefDeleter;
+
+template < class TagType = jni::ObjectTag >
+using GenericUniqueWeakObject = std::unique_ptr< const jni::Object<TagType>, GenericWeakObjectRefDeleter<TagType> >;
+
+template < class TagType >
+class GenericWeakObjectRefDeleter
+{
+public:
+ using pointer = jni::PointerToValue< jni::Object<TagType> >;
+
+ void operator()(pointer p) const
+ {
+ if (p)
+ {
+ auto env = AttachEnv();
+ env->DeleteWeakGlobalRef(jni::Unwrap(p->Get()));
+ }
+ }
+};
+
+template < class TagType >
+GenericUniqueWeakObject<TagType> SeizeGenericWeakRef(JNIEnv&, jni::Object<TagType>&& object)
+{
+ return GenericUniqueWeakObject<TagType>(jni::PointerToValue<jni::Object<TagType>>(std::move(object)), GenericWeakObjectRefDeleter<TagType>());
+};
+
} // namespace android
} // namespace mbgl
diff --git a/platform/android/src/map/camera_position.cpp b/platform/android/src/map/camera_position.cpp
index d6f2cb83e8..1fc5f9789f 100644
--- a/platform/android/src/map/camera_position.cpp
+++ b/platform/android/src/map/camera_position.cpp
@@ -27,6 +27,24 @@ jni::Object<CameraPosition> CameraPosition::New(jni::JNIEnv &env, mbgl::CameraOp
return CameraPosition::javaClass.New(env, constructor, LatLng::New(env, center), options.zoom.value_or(0), tilt_degrees, bearing_degrees);
}
+mbgl::CameraOptions CameraPosition::getCameraOptions(jni::JNIEnv& env, jni::Object<CameraPosition> position) {
+ static auto bearing = CameraPosition::javaClass.GetField<jni::jdouble>(env, "bearing");
+ static auto target = CameraPosition::javaClass.GetField<jni::Object<LatLng>>(env, "target");
+ static auto tilt = CameraPosition::javaClass.GetField<jni::jdouble>(env, "tilt");
+ static auto zoom = CameraPosition::javaClass.GetField<jni::jdouble>(env, "zoom");
+
+ auto center = LatLng::getLatLng(env, position.Get(env, target));
+
+ return mbgl::CameraOptions {
+ center,
+ {},
+ {},
+ position.Get(env, zoom),
+ position.Get(env, bearing) * util::DEG2RAD,
+ position.Get(env, tilt)
+ };
+}
+
void CameraPosition::registerNative(jni::JNIEnv &env) {
// Lookup the class
CameraPosition::javaClass = *jni::Class<CameraPosition>::Find(env).NewGlobalRef(env).release();
diff --git a/platform/android/src/map/camera_position.hpp b/platform/android/src/map/camera_position.hpp
index b9f1646cc9..4eee8be758 100644
--- a/platform/android/src/map/camera_position.hpp
+++ b/platform/android/src/map/camera_position.hpp
@@ -15,6 +15,8 @@ public:
static jni::Object<CameraPosition> New(jni::JNIEnv&, mbgl::CameraOptions);
+ static mbgl::CameraOptions getCameraOptions(jni::JNIEnv&, jni::Object<CameraPosition>);
+
static jni::Class<CameraPosition> javaClass;
static void registerNative(jni::JNIEnv&);
diff --git a/platform/android/src/map_renderer.cpp b/platform/android/src/map_renderer.cpp
new file mode 100644
index 0000000000..7655455210
--- /dev/null
+++ b/platform/android/src/map_renderer.cpp
@@ -0,0 +1,200 @@
+#include "map_renderer.hpp"
+
+#include <mbgl/renderer/renderer.hpp>
+#include <mbgl/util/shared_thread_pool.hpp>
+#include <mbgl/util/run_loop.hpp>
+
+#include <string>
+
+#include "attach_env.hpp"
+#include "android_renderer_backend.hpp"
+#include "map_renderer_runnable.hpp"
+#include "file_source.hpp"
+
+namespace mbgl {
+namespace android {
+
+MapRenderer::MapRenderer(jni::JNIEnv& _env, jni::Object<MapRenderer> obj,
+ jni::Object<FileSource> _fileSource, jni::jfloat pixelRatio_,
+ jni::String programCacheDir_)
+ : javaPeer(SeizeGenericWeakRef(_env, jni::Object<MapRenderer>(jni::NewWeakGlobalRef(_env, obj.Get()).release()))), pixelRatio(pixelRatio_)
+ , fileSource(FileSource::getDefaultFileSource(_env, _fileSource))
+ , programCacheDir(jni::Make<std::string>(_env, programCacheDir_))
+ , threadPool(sharedThreadPool())
+ , mailbox(std::make_shared<Mailbox>(*this)) {
+}
+
+MapRenderer::~MapRenderer() = default;
+
+void MapRenderer::reset() {
+ // Make sure to destroy the renderer on the GL Thread
+ auto self = ActorRef<MapRenderer>(*this, mailbox);
+ self.ask(&MapRenderer::resetRenderer).wait();
+
+ // Lock to make sure there is no concurrent initialisation on the gl thread
+ std::lock_guard<std::mutex> lock(initialisationMutex);
+ rendererObserver.reset();
+}
+
+ActorRef<Renderer> MapRenderer::actor() const {
+ return *rendererRef;
+}
+
+void MapRenderer::schedule(std::weak_ptr<Mailbox> scheduled) {
+ // Create a runnable and schedule it on the gl thread
+ android::UniqueEnv _env = android::AttachEnv();
+ auto runnable = std::make_unique<MapRendererRunnable>(*_env, std::move(scheduled));
+
+ static auto queueEvent = javaClass.GetMethod<void(
+ jni::Object<MapRendererRunnable>)>(*_env, "queueEvent");
+ javaPeer->Call(*_env, queueEvent, runnable->getPeer());
+
+ // Release the object as it will be destroyed on GC of the Java Peer
+ runnable.release();
+}
+
+void MapRenderer::requestRender() {
+ android::UniqueEnv _env = android::AttachEnv();
+ static auto onInvalidate = javaClass.GetMethod<void()>(*_env, "requestRender");
+ javaPeer->Call(*_env, onInvalidate);
+}
+
+void MapRenderer::update(std::shared_ptr<UpdateParameters> params) {
+ // Lock on the parameters
+ std::lock_guard<std::mutex> lock(updateMutex);
+ updateParameters = std::move(params);
+}
+
+void MapRenderer::setObserver(std::shared_ptr<RendererObserver> _rendererObserver) {
+ // Lock as the initialization can come from the main thread or the GL thread first
+ std::lock_guard<std::mutex> lock(initialisationMutex);
+
+ rendererObserver = std::move(_rendererObserver);
+
+ // Set the new observer on the Renderer implementation
+ if (renderer) {
+ renderer->setObserver(rendererObserver.get());
+ }
+}
+
+void MapRenderer::requestSnapshot(SnapshotCallback callback) {
+ auto self = ActorRef<MapRenderer>(*this, mailbox);
+ self.invoke(
+ &MapRenderer::scheduleSnapshot,
+ std::make_unique<SnapshotCallback>([&, callback=std::move(callback), runloop=util::RunLoop::Get()](PremultipliedImage image) {
+ runloop->invoke([callback=std::move(callback), image=std::move(image)]() mutable {
+ callback(std::move(image));
+ });
+ snapshotCallback.reset();
+ })
+ );
+}
+
+// Called on OpenGL thread //
+
+void MapRenderer::resetRenderer() {
+ assert (renderer);
+ renderer.reset();
+}
+
+void MapRenderer::scheduleSnapshot(std::unique_ptr<SnapshotCallback> callback) {
+ snapshotCallback = std::move(callback);
+ requestRender();
+}
+
+void MapRenderer::render(JNIEnv&) {
+ assert (renderer);
+
+ std::shared_ptr<UpdateParameters> params;
+ {
+ // Lock on the parameters
+ std::unique_lock<std::mutex> lock(updateMutex);
+ if (!updateParameters) return;
+
+ // Hold on to the update parameters during render
+ params = updateParameters;
+ }
+
+ // Activate the backend
+ BackendScope backendGuard { *backend };
+
+ // Ensure that the "current" scheduler on the render thread is
+ // this scheduler.
+ Scheduler::SetCurrent(this);
+
+ if (framebufferSizeChanged) {
+ backend->updateViewPort();
+ framebufferSizeChanged = false;
+ }
+
+ renderer->render(*params);
+
+ // Deliver the snapshot if requested
+ if (snapshotCallback) {
+ snapshotCallback->operator()(backend->readFramebuffer());
+ snapshotCallback.reset();
+ }
+}
+
+void MapRenderer::onSurfaceCreated(JNIEnv&) {
+ // Lock as the initialization can come from the main thread or the GL thread first
+ std::lock_guard<std::mutex> lock(initialisationMutex);
+
+ // The android system will have already destroyed the underlying
+ // GL resources if this is not the first intialization and an
+ // attempt to clean them up will fail
+ if (backend) backend->markContextLost();
+ if (renderer) renderer->markContextLost();
+
+ // Reset in opposite order
+ renderer.reset();
+ backend.reset();
+
+ // Create the new backend and renderer
+ backend = std::make_unique<AndroidRendererBackend>();
+ renderer = std::make_unique<Renderer>(*backend, pixelRatio, fileSource, *threadPool,
+ GLContextMode::Unique, programCacheDir);
+ rendererRef = std::make_unique<ActorRef<Renderer>>(*renderer, mailbox);
+
+ // Set the observer on the new Renderer implementation
+ if (rendererObserver) {
+ renderer->setObserver(rendererObserver.get());
+ }
+}
+
+void MapRenderer::onSurfaceChanged(JNIEnv&, jint width, jint height) {
+ backend->resizeFramebuffer(width, height);
+ framebufferSizeChanged = true;
+ requestRender();
+}
+
+// Static methods //
+
+jni::Class<MapRenderer> MapRenderer::javaClass;
+
+void MapRenderer::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ MapRenderer::javaClass = *jni::Class<MapRenderer>::Find(env).NewGlobalRef(env).release();
+
+#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
+
+ // Register the peer
+ jni::RegisterNativePeer<MapRenderer>(env, MapRenderer::javaClass, "nativePtr",
+ std::make_unique<MapRenderer, JNIEnv&, jni::Object<MapRenderer>, jni::Object<FileSource>, jni::jfloat, jni::String>,
+ "nativeInitialize", "finalize",
+ METHOD(&MapRenderer::render, "nativeRender"),
+ METHOD(&MapRenderer::onSurfaceCreated,
+ "nativeOnSurfaceCreated"),
+ METHOD(&MapRenderer::onSurfaceChanged,
+ "nativeOnSurfaceChanged"));
+}
+
+MapRenderer& MapRenderer::getNativePeer(JNIEnv& env, jni::Object<MapRenderer> jObject) {
+ static auto field = MapRenderer::javaClass.GetField<jlong>(env, "nativePtr");
+ MapRenderer* mapRenderer = reinterpret_cast<MapRenderer*>(jObject.Get(env, field));
+ assert(mapRenderer != nullptr);
+ return *mapRenderer;
+}
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/map_renderer.hpp b/platform/android/src/map_renderer.hpp
new file mode 100644
index 0000000000..0d614912a9
--- /dev/null
+++ b/platform/android/src/map_renderer.hpp
@@ -0,0 +1,126 @@
+#pragma once
+
+#include <mbgl/actor/scheduler.hpp>
+#include <mbgl/util/image.hpp>
+
+#include <memory>
+#include <utility>
+
+#include <jni/jni.hpp>
+#include <mbgl/storage/default_file_source.hpp>
+
+#include "jni/generic_global_ref_deleter.hpp"
+
+namespace mbgl {
+
+template <class>
+class ActorRef;
+class Mailbox;
+class Renderer;
+class RendererBackend;
+class RendererObserver;
+class ThreadPool;
+class UpdateParameters;
+
+namespace android {
+
+class AndroidRendererBackend;
+class FileSource;
+
+/**
+ * The MapRenderer is a peer class that encapsulates the actions
+ * performed on the GL Thread.
+ *
+ * The public methods are safe to call from the main thread, others are not.
+ */
+class MapRenderer : public Scheduler {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/maps/renderer/MapRenderer"; };
+
+ static jni::Class<MapRenderer> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+ static MapRenderer& getNativePeer(JNIEnv&, jni::Object<MapRenderer>);
+
+ MapRenderer(jni::JNIEnv& _env,
+ jni::Object<MapRenderer>,
+ jni::Object<FileSource>,
+ jni::jfloat pixelRatio,
+ jni::String programCacheDir);
+
+ ~MapRenderer() override;
+
+ // Resets the renderer to clean up on the calling thread
+ void reset();
+
+ // Takes the RendererObserver by shared_ptr so we
+ // don't have to make the header public. Use
+ // this instead of Renderer#setObserver directly
+ void setObserver(std::shared_ptr<RendererObserver>);
+
+ // Sets the new update parameters to use on subsequent
+ // renders. Be sure to trigger a render with
+ // requestRender().
+ void update(std::shared_ptr<UpdateParameters>);
+
+ // Gives a handle to the Renderer to enable actions on
+ // any thread.
+ ActorRef<Renderer> actor() const;
+
+ // From Scheduler. Schedules by using callbacks to the
+ // JVM to process the mailbox on the right thread.
+ void schedule(std::weak_ptr<Mailbox> scheduled) override;
+
+ void requestRender();
+
+ // Snapshot - requires a RunLoop on the calling thread
+ using SnapshotCallback = std::function<void (PremultipliedImage)>;
+ void requestSnapshot(SnapshotCallback);
+
+protected:
+ // Called from the GL Thread //
+
+ void scheduleSnapshot(std::unique_ptr<SnapshotCallback>);
+
+private:
+ // Called from the GL Thread //
+
+ // Resets the renderer
+ void resetRenderer();
+
+ // Renders a frame.
+ void render(JNIEnv&);
+
+ void onSurfaceCreated(JNIEnv&);
+
+ void onSurfaceChanged(JNIEnv&, jint width, jint height);
+
+private:
+ GenericUniqueWeakObject<MapRenderer> javaPeer;
+
+ float pixelRatio;
+ DefaultFileSource& fileSource;
+ std::string programCacheDir;
+
+ std::shared_ptr<ThreadPool> threadPool;
+ std::shared_ptr<Mailbox> mailbox;
+
+ std::mutex initialisationMutex;
+ std::shared_ptr<RendererObserver> rendererObserver;
+
+ std::unique_ptr<AndroidRendererBackend> backend;
+ std::unique_ptr<Renderer> renderer;
+ std::unique_ptr<ActorRef<Renderer>> rendererRef;
+
+ std::shared_ptr<UpdateParameters> updateParameters;
+ std::mutex updateMutex;
+
+ bool framebufferSizeChanged = false;
+
+ std::unique_ptr<SnapshotCallback> snapshotCallback;
+};
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/map_renderer_runnable.cpp b/platform/android/src/map_renderer_runnable.cpp
new file mode 100644
index 0000000000..df8cba5e55
--- /dev/null
+++ b/platform/android/src/map_renderer_runnable.cpp
@@ -0,0 +1,49 @@
+#include "map_renderer_runnable.hpp"
+
+#include <mbgl/util/logging.hpp>
+
+namespace mbgl {
+namespace android {
+
+MapRendererRunnable::MapRendererRunnable(jni::JNIEnv& env, std::weak_ptr<Mailbox> mailbox_)
+ : mailbox(std::move(mailbox_)) {
+
+ // Create the Java peer
+ jni::UniqueLocalFrame frame = jni::PushLocalFrame(env, 5);
+ static auto constructor = javaClass.GetConstructor<jlong>(env);
+ auto instance = javaClass.New(env, constructor, reinterpret_cast<jlong>(this));
+ javaPeer = SeizeGenericWeakRef(env, jni::Object<MapRendererRunnable>(jni::NewWeakGlobalRef(env, instance.Get()).release()));
+}
+
+MapRendererRunnable::~MapRendererRunnable() = default;
+
+void MapRendererRunnable::run(jni::JNIEnv&) {
+ Mailbox::maybeReceive(mailbox);
+}
+
+jni::Object<MapRendererRunnable> MapRendererRunnable::getPeer() {
+ return *javaPeer;
+}
+
+// Static methods //
+
+jni::Class<MapRendererRunnable> MapRendererRunnable::javaClass;
+
+void MapRendererRunnable::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ MapRendererRunnable::javaClass = *jni::Class<MapRendererRunnable>::Find(env).NewGlobalRef(env).release();
+
+#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
+
+ jni::RegisterNativePeer<MapRendererRunnable>(
+ env,
+ MapRendererRunnable::javaClass,
+ "nativePtr",
+ std::make_unique<MapRendererRunnable, JNIEnv&>,
+ "nativeInitialize",
+ "finalize",
+ METHOD(&MapRendererRunnable::run, "run"));
+}
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/map_renderer_runnable.hpp b/platform/android/src/map_renderer_runnable.hpp
new file mode 100644
index 0000000000..75646a442d
--- /dev/null
+++ b/platform/android/src/map_renderer_runnable.hpp
@@ -0,0 +1,50 @@
+#pragma once
+
+#include <mbgl/actor/mailbox.hpp>
+#include <mbgl/actor/scheduler.hpp>
+
+#include <memory>
+#include <utility>
+
+#include <jni/jni.hpp>
+
+#include "jni/generic_global_ref_deleter.hpp"
+
+namespace mbgl {
+namespace android {
+
+/**
+ * The MapRendererRunnable is a peer class that encapsulates
+ * a scheduled mailbox in a Java Runnable so it can be
+ * scheduled on the map renderer thread.
+ *
+ */
+class MapRendererRunnable {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/maps/renderer/MapRendererRunnable"; };
+
+ static jni::Class<MapRendererRunnable> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+ MapRendererRunnable(jni::JNIEnv&, std::weak_ptr<Mailbox>);
+
+ // Only for jni registration, unused
+ MapRendererRunnable(jni::JNIEnv&) {
+ assert(false);
+ }
+
+ ~MapRendererRunnable();
+
+ void run(jni::JNIEnv&);
+
+ jni::Object<MapRendererRunnable> getPeer();
+
+private:
+ GenericUniqueWeakObject<MapRendererRunnable> javaPeer;
+ std::weak_ptr<Mailbox> mailbox;
+};
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp
index 159ba70508..a9ed6d5ead 100755
--- a/platform/android/src/native_map_view.cpp
+++ b/platform/android/src/native_map_view.cpp
@@ -9,12 +9,10 @@
#include <sys/system_properties.h>
-#include <EGL/egl.h>
#include <android/native_window_jni.h>
#include <jni/jni.hpp>
-#include <mbgl/map/backend_scope.hpp>
#include <mbgl/math/minmax.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/event.hpp>
@@ -25,8 +23,10 @@
#include <mbgl/util/logging.hpp>
#include <mbgl/util/platform.hpp>
#include <mbgl/util/projection.hpp>
+#include <mbgl/style/style.hpp>
#include <mbgl/style/image.hpp>
#include <mbgl/style/filter.hpp>
+#include <mbgl/renderer/query.hpp>
// Java -> C++ conversion
#include "style/android_conversion.hpp"
@@ -41,12 +41,16 @@
#include "jni.hpp"
#include "attach_env.hpp"
+#include "map_renderer.hpp"
+#include "android_renderer_frontend.hpp"
+#include "file_source.hpp"
#include "bitmap.hpp"
#include "run_loop_impl.hpp"
#include "java/util.hpp"
#include "geometry/lat_lng_bounds.hpp"
#include "map/camera_position.hpp"
#include "style/light.hpp"
+#include "bitmap_factory.hpp"
namespace mbgl {
namespace android {
@@ -54,15 +58,12 @@ namespace android {
NativeMapView::NativeMapView(jni::JNIEnv& _env,
jni::Object<NativeMapView> _obj,
jni::Object<FileSource> jFileSource,
- jni::jfloat _pixelRatio,
- jni::String _programCacheDir,
- jni::jint _availableProcessors,
- jni::jlong _totalMemory)
- : javaPeer(_obj.NewWeakGlobalRef(_env)),
- pixelRatio(_pixelRatio),
- availableProcessors(_availableProcessors),
- totalMemory(_totalMemory),
- threadPool(sharedThreadPool()) {
+ jni::Object<MapRenderer> jMapRenderer,
+ jni::jfloat _pixelRatio)
+ : javaPeer(_obj.NewWeakGlobalRef(_env))
+ , mapRenderer(MapRenderer::getNativePeer(_env, jMapRenderer))
+ , pixelRatio(_pixelRatio)
+ , threadPool(sharedThreadPool()) {
// Get a reference to the JavaVM for callbacks
if (_env.GetJavaVM(&vm) < 0) {
@@ -70,116 +71,30 @@ NativeMapView::NativeMapView(jni::JNIEnv& _env,
return;
}
- // Create the core map
- map = std::make_unique<mbgl::Map>(
- *this, mbgl::Size{ static_cast<uint32_t>(width), static_cast<uint32_t>(height) },
- pixelRatio, mbgl::android::FileSource::getDefaultFileSource(_env, jFileSource), *threadPool,
- MapMode::Continuous, GLContextMode::Unique, ConstrainMode::HeightOnly,
- ViewportMode::Default, jni::Make<std::string>(_env, _programCacheDir));
-
- recalculateSourceTileCacheSize();
-}
+ // Get native peer for file source
+ mbgl::FileSource& fileSource = mbgl::android::FileSource::getDefaultFileSource(_env, jFileSource);
-void NativeMapView::recalculateSourceTileCacheSize() {
- //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);
+ // Create a renderer frontend
+ rendererFrontend = std::make_unique<AndroidRendererFrontend>(mapRenderer);
- map->setSourceTileCacheSize(zoomFactor * cpuFactor * memoryFactor * sizeFactor * 0.5f);
+ // Create the core map
+ map = std::make_unique<mbgl::Map>(*rendererFrontend, *this,
+ mbgl::Size{ static_cast<uint32_t>(width),
+ static_cast<uint32_t>(height) }, pixelRatio,
+ fileSource, *threadPool, MapMode::Continuous,
+ ConstrainMode::HeightOnly, ViewportMode::Default);
}
/**
* Called through NativeMapView#destroy()
*/
NativeMapView::~NativeMapView() {
- _terminateContext();
- _destroySurface();
- _terminateDisplay();
-
map.reset();
-
vm = nullptr;
}
/**
- * From mbgl::View
- */
-void NativeMapView::bind() {
- setFramebufferBinding(0);
- setViewportSize(getFramebufferSize());
-}
-
-/**
- * From mbgl::Backend.
- */
-gl::ProcAddress NativeMapView::initializeExtension(const char* name) {
- return eglGetProcAddress(name);
-}
-
-void NativeMapView::activate() {
-
- oldDisplay = eglGetCurrentDisplay();
- oldReadSurface = eglGetCurrentSurface(EGL_READ);
- oldDrawSurface = eglGetCurrentSurface(EGL_DRAW);
- oldContext = eglGetCurrentContext();
-
- assert(vm != nullptr);
-
- if ((display != EGL_NO_DISPLAY) && (surface != EGL_NO_SURFACE) && (context != EGL_NO_CONTEXT)) {
- if (!eglMakeCurrent(display, surface, surface, context)) {
- mbgl::Log::Error(mbgl::Event::OpenGL, "eglMakeCurrent() returned error %d",
- eglGetError());
- throw std::runtime_error("eglMakeCurrent() failed");
- }
-
- if (!eglSwapInterval(display, 0)) {
- mbgl::Log::Error(mbgl::Event::OpenGL, "eglSwapInterval() returned error %d", eglGetError());
- throw std::runtime_error("eglSwapInterval() failed");
- }
- } else {
- mbgl::Log::Info(mbgl::Event::Android, "Not activating as we are not ready");
- }
-}
-
-/**
- * From mbgl::Backend.
- */
-void NativeMapView::deactivate() {
- assert(vm != nullptr);
-
- if (oldContext != context && oldContext != EGL_NO_CONTEXT) {
- if (!eglMakeCurrent(oldDisplay, oldDrawSurface, oldReadSurface, oldContext)) {
- mbgl::Log::Error(mbgl::Event::OpenGL, "eglMakeCurrent() returned error %d",
- eglGetError());
- throw std::runtime_error("eglMakeCurrent() failed");
- }
- } else 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");
- }
- } else {
- mbgl::Log::Info(mbgl::Event::Android, "Not deactivating as we are not ready");
- }
-}
-
-/**
- * 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).
+ * From mbgl::RendererBackend. Callback to java NativeMapView#onMapChanged(int).
*
* May be called from any thread
*/
@@ -257,98 +172,26 @@ void NativeMapView::onSourceChanged(mbgl::style::Source&) {
// JNI Methods //
-void NativeMapView::initializeDisplay(jni::JNIEnv&) {
- _initializeDisplay();
-}
-
-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) {
- setViewportSize(getFramebufferSize());
- framebufferSizeChanged = false;
- }
-
- map->render(*this);
-
- if(snapshot){
- snapshot = false;
-
- // take snapshot
- auto image = readFramebuffer(getFramebufferSize());
- auto bitmap = Bitmap::CreateBitmap(env, std::move(image));
-
- // invoke Mapview#OnSnapshotReady
- 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)) {
- if (!eglSwapBuffers(display, surface)) {
- mbgl::Log::Error(mbgl::Event::OpenGL, "eglSwapBuffers() returned error %d",
- eglGetError());
- throw std::runtime_error("eglSwapBuffers() failed");
- }
-
- updateFps();
- } else {
- mbgl::Log::Info(mbgl::Event::Android, "Not swapping as we are not ready");
- }
-}
-
-void NativeMapView::update(jni::JNIEnv&) {
- invalidate();
-}
-
void NativeMapView::resizeView(jni::JNIEnv&, int w, int h) {
width = util::max(64, w);
height = util::max(64, h);
map->setSize({ static_cast<uint32_t>(width), static_cast<uint32_t>(height) });
- recalculateSourceTileCacheSize();
-}
-
-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());
+ return jni::Make<jni::String>(env, map->getStyle().getURL());
}
void NativeMapView::setStyleUrl(jni::JNIEnv& env, jni::String url) {
- map->setStyleURL(jni::Make<std::string>(env, url));
+ map->getStyle().loadURL(jni::Make<std::string>(env, url));
}
jni::String NativeMapView::getStyleJson(jni::JNIEnv& env) {
- return jni::Make<jni::String>(env, map->getStyleJSON());
+ return jni::Make<jni::String>(env, map->getStyle().getJSON());
}
void NativeMapView::setStyleJson(jni::JNIEnv& env, jni::String json) {
- map->setStyleJSON(jni::Make<std::string>(env, json));
+ map->getStyle().loadJSON(jni::Make<std::string>(env, json));
}
void NativeMapView::setLatLngBounds(jni::JNIEnv& env, jni::Object<mbgl::android::LatLngBounds> jBounds) {
@@ -480,7 +323,6 @@ void NativeMapView::resetZoom(jni::JNIEnv&) {
void NativeMapView::setMinZoom(jni::JNIEnv&, jni::jdouble zoom) {
map->setMinZoom(zoom);
- recalculateSourceTileCacheSize();
}
jni::jdouble NativeMapView::getMinZoom(jni::JNIEnv&) {
@@ -489,7 +331,6 @@ jni::jdouble NativeMapView::getMinZoom(jni::JNIEnv&) {
void NativeMapView::setMaxZoom(jni::JNIEnv&, jni::jdouble zoom) {
map->setMaxZoom(zoom);
- recalculateSourceTileCacheSize();
}
jni::jdouble NativeMapView::getMaxZoom(jni::JNIEnv&) {
@@ -554,11 +395,15 @@ void NativeMapView::setContentPadding(JNIEnv&, double top, double left, double b
}
void NativeMapView::scheduleSnapshot(jni::JNIEnv&) {
- snapshot = true;
-}
+ mapRenderer.requestSnapshot([&](PremultipliedImage image) {
+ auto _env = android::AttachEnv();
+ // Convert image to bitmap
+ auto bitmap = Bitmap::CreateBitmap(*_env, std::move(image));
-void NativeMapView::enableFps(jni::JNIEnv&, jni::jboolean enable) {
- fpsEnabled = enable;
+ // invoke Mapview#OnSnapshotReady
+ static auto onSnapshotReady = javaClass.GetMethod<void (jni::Object<Bitmap>)>(*_env, "onSnapshotReady");
+ javaPeer->Call(*_env, onSnapshotReady, bitmap);
+ });
}
jni::Object<CameraPosition> NativeMapView::getCameraPosition(jni::JNIEnv& env) {
@@ -599,7 +444,7 @@ jni::Array<jni::jlong> NativeMapView::addMarkers(jni::JNIEnv& env, jni::Array<jn
}
void NativeMapView::onLowMemory(JNIEnv&) {
- map->onLowMemory();
+ rendererFrontend->onLowMemory();
}
using DebugOptions = mbgl::MapDebugOptions;
@@ -608,12 +453,10 @@ 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&) {
@@ -729,8 +572,13 @@ void NativeMapView::addAnnotationIcon(JNIEnv& env, jni::String symbol, jint w, j
}
jni::GetArrayRegion(env, *jpixels, 0, size, reinterpret_cast<jbyte*>(premultipliedImage.data.get()));
- map->addAnnotationImage(symbolName,
- std::make_unique<mbgl::style::Image>(std::move(premultipliedImage), float(scale)));
+ map->addAnnotationImage(std::make_unique<mbgl::style::Image>(
+ symbolName, std::move(premultipliedImage), float(scale)));
+}
+
+void NativeMapView::removeAnnotationIcon(JNIEnv& env, jni::String symbol) {
+ const std::string symbolName = jni::Make<std::string>(env, symbol);
+ map->removeAnnotationImage(symbolName);
}
jdouble NativeMapView::getTopOffsetPixelsForAnnotationSymbol(JNIEnv& env, jni::String symbolName) {
@@ -738,25 +586,25 @@ jdouble NativeMapView::getTopOffsetPixelsForAnnotationSymbol(JNIEnv& env, jni::S
}
jlong NativeMapView::getTransitionDuration(JNIEnv&) {
- const auto transitionOptions = map->getTransitionOptions();
+ const auto transitionOptions = map->getStyle().getTransitionOptions();
return std::chrono::duration_cast<std::chrono::milliseconds>(transitionOptions.duration.value_or(mbgl::Duration::zero())).count();
}
void NativeMapView::setTransitionDuration(JNIEnv&, jlong duration) {
- auto transitionOptions = map->getTransitionOptions();
+ auto transitionOptions = map->getStyle().getTransitionOptions();
transitionOptions.duration.emplace(mbgl::Milliseconds(duration));
- map->setTransitionOptions(transitionOptions);
+ map->getStyle().setTransitionOptions(transitionOptions);
}
jlong NativeMapView::getTransitionDelay(JNIEnv&) {
- const auto transitionOptions = map->getTransitionOptions();
+ const auto transitionOptions = map->getStyle().getTransitionOptions();
return std::chrono::duration_cast<std::chrono::milliseconds>(transitionOptions.delay.value_or(mbgl::Duration::zero())).count();
}
void NativeMapView::setTransitionDelay(JNIEnv&, jlong delay) {
- auto transitionOptions = map->getTransitionOptions();
+ auto transitionOptions = map->getStyle().getTransitionOptions();
transitionOptions.delay.emplace(mbgl::Milliseconds(delay));
- map->setTransitionOptions(transitionOptions);
+ map->getStyle().setTransitionOptions(transitionOptions);
}
jni::Array<jlong> NativeMapView::queryPointAnnotations(JNIEnv& env, jni::Object<RectF> rect) {
@@ -770,7 +618,7 @@ jni::Array<jlong> NativeMapView::queryPointAnnotations(JNIEnv& env, jni::Object<
};
// Assume only points for now
- mbgl::AnnotationIDs ids = map->queryPointAnnotations(box);
+ mbgl::AnnotationIDs ids = rendererFrontend->queryPointAnnotations(box);
// Convert result
std::vector<jlong> longIds(ids.begin(), ids.end());
@@ -792,7 +640,9 @@ jni::Array<jni::Object<geojson::Feature>> NativeMapView::queryRenderedFeaturesFo
}
mapbox::geometry::point<double> point = {x, y};
- return *convert<jni::Array<jni::Object<Feature>>, std::vector<mbgl::Feature>>(env, map->queryRenderedFeatures(point, { layers, toFilter(env, jfilter) }));
+ return *convert<jni::Array<jni::Object<Feature>>, std::vector<mbgl::Feature>>(
+ env,
+ rendererFrontend->queryRenderedFeatures(point, { layers, toFilter(env, jfilter) }));
}
jni::Array<jni::Object<geojson::Feature>> NativeMapView::queryRenderedFeaturesForBox(JNIEnv& env, jni::jfloat left, jni::jfloat top,
@@ -810,11 +660,13 @@ jni::Array<jni::Object<geojson::Feature>> NativeMapView::queryRenderedFeaturesFo
mapbox::geometry::point<double>{ right, bottom }
};
- return *convert<jni::Array<jni::Object<Feature>>, std::vector<mbgl::Feature>>(env, map->queryRenderedFeatures(box, { layers, toFilter(env, jfilter) }));
+ return *convert<jni::Array<jni::Object<Feature>>, std::vector<mbgl::Feature>>(
+ env,
+ rendererFrontend->queryRenderedFeatures(box, { layers, toFilter(env, jfilter) }));
}
jni::Object<Light> NativeMapView::getLight(JNIEnv& env) {
- mbgl::style::Light* light = map->getLight();
+ mbgl::style::Light* light = map->getStyle().getLight();
if (light) {
return jni::Object<Light>(Light::createJavaLightPeer(env, *map, *light));
} else {
@@ -825,7 +677,7 @@ jni::Object<Light> NativeMapView::getLight(JNIEnv& env) {
jni::Array<jni::Object<Layer>> NativeMapView::getLayers(JNIEnv& env) {
// Get the core layers
- std::vector<style::Layer*> layers = map->getLayers();
+ std::vector<style::Layer*> layers = map->getStyle().getLayers();
// Convert
jni::Array<jni::Object<Layer>> jLayers = jni::Array<jni::Object<Layer>>::New(env, layers.size(), Layer::javaClass);
@@ -843,7 +695,7 @@ jni::Array<jni::Object<Layer>> NativeMapView::getLayers(JNIEnv& env) {
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));
+ mbgl::style::Layer* coreLayer = map->getStyle().getLayer(jni::Make<std::string>(env, layerId));
if (!coreLayer) {
mbgl::Log::Debug(mbgl::Event::JNI, "No layer found");
return jni::Object<Layer>();
@@ -870,7 +722,7 @@ void NativeMapView::addLayerAbove(JNIEnv& env, jlong nativeLayerPtr, jni::String
Layer *layer = reinterpret_cast<Layer *>(nativeLayerPtr);
// Find the sibling
- auto layers = map->getLayers();
+ auto layers = map->getStyle().getLayers();
auto siblingId = jni::Make<std::string>(env, above);
size_t index = 0;
@@ -905,7 +757,7 @@ void NativeMapView::addLayerAt(JNIEnv& env, jlong nativeLayerPtr, jni::jint inde
assert(nativeLayerPtr != 0);
Layer *layer = reinterpret_cast<Layer *>(nativeLayerPtr);
- auto layers = map->getLayers();
+ auto layers = map->getStyle().getLayers();
// Check index
int numLayers = layers.size() - 1;
@@ -928,7 +780,7 @@ void NativeMapView::addLayerAt(JNIEnv& env, jlong nativeLayerPtr, jni::jint inde
* 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));
+ std::unique_ptr<mbgl::style::Layer> coreLayer = map->getStyle().removeLayer(jni::Make<std::string>(env, id));
if (coreLayer) {
return jni::Object<Layer>(createJavaLayerPeer(env, *map, std::move(coreLayer)));
} else {
@@ -940,7 +792,7 @@ jni::Object<Layer> NativeMapView::removeLayerById(JNIEnv& env, jni::String id) {
* Remove layer at index.
*/
jni::Object<Layer> NativeMapView::removeLayerAt(JNIEnv& env, jni::jint index) {
- auto layers = map->getLayers();
+ auto layers = map->getStyle().getLayers();
// Check index
int numLayers = layers.size() - 1;
@@ -949,7 +801,7 @@ jni::Object<Layer> NativeMapView::removeLayerAt(JNIEnv& env, jni::jint index) {
return jni::Object<Layer>();
}
- std::unique_ptr<mbgl::style::Layer> coreLayer = map->removeLayer(layers.at(index)->getID());
+ std::unique_ptr<mbgl::style::Layer> coreLayer = map->getStyle().removeLayer(layers.at(index)->getID());
if (coreLayer) {
return jni::Object<Layer>(createJavaLayerPeer(env, *map, std::move(coreLayer)));
} else {
@@ -964,7 +816,7 @@ 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());
+ std::unique_ptr<mbgl::style::Layer> coreLayer = map->getStyle().removeLayer(layer->get().getID());
if (coreLayer) {
layer->setLayer(std::move(coreLayer));
}
@@ -972,13 +824,13 @@ void NativeMapView::removeLayer(JNIEnv&, jlong layerPtr) {
jni::Array<jni::Object<Source>> NativeMapView::getSources(JNIEnv& env) {
// Get the core sources
- std::vector<style::Source*> sources = map->getSources();
+ std::vector<style::Source*> sources = map->getStyle().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));
+ auto jSource = jni::Object<Source>(createJavaSourcePeer(env, *rendererFrontend, *source));
jSources.Set(env, index, jSource);
jni::DeleteLocalRef(env, jSource);
index++;
@@ -989,14 +841,14 @@ jni::Array<jni::Object<Source>> NativeMapView::getSources(JNIEnv& env) {
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));
+ mbgl::style::Source* coreSource = map->getStyle().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));
+ return jni::Object<Source>(createJavaSourcePeer(env, *rendererFrontend, *coreSource));
}
void NativeMapView::addSource(JNIEnv& env, jni::jlong sourcePtr) {
@@ -1005,15 +857,16 @@ void NativeMapView::addSource(JNIEnv& env, jni::jlong sourcePtr) {
Source *source = reinterpret_cast<Source *>(sourcePtr);
try {
source->addToMap(*map);
+ source->setRendererFrontend(*rendererFrontend);
} catch (const std::runtime_error& error) {
jni::ThrowNew(env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/sources/CannotAddSourceException"), error.what());
}
}
jni::Object<Source> NativeMapView::removeSourceById(JNIEnv& env, jni::String id) {
- std::unique_ptr<mbgl::style::Source> coreSource = map->removeSource(jni::Make<std::string>(env, id));
+ std::unique_ptr<mbgl::style::Source> coreSource = map->getStyle().removeSource(jni::Make<std::string>(env, id));
if (coreSource) {
- return jni::Object<Source>(createJavaSourcePeer(env, *map, *coreSource));
+ return jni::Object<Source>(createJavaSourcePeer(env, *rendererFrontend, *coreSource));
} else {
return jni::Object<Source>();
}
@@ -1023,7 +876,7 @@ 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());
+ std::unique_ptr<mbgl::style::Source> coreSource = map->getStyle().removeSource(source->get().getID());
if (coreSource) {
source->setSource(std::move(coreSource));
}
@@ -1040,415 +893,31 @@ void NativeMapView::addImage(JNIEnv& env, jni::String name, jni::jint w, jni::ji
jni::GetArrayRegion(env, *pixels, 0, size, reinterpret_cast<jbyte*>(premultipliedImage.data.get()));
- map->addImage(jni::Make<std::string>(env, name),
- std::make_unique<mbgl::style::Image>(std::move(premultipliedImage), float(scale)));
+ map->getStyle().addImage(std::make_unique<mbgl::style::Image>(
+ jni::Make<std::string>(env, name),
+ std::move(premultipliedImage),
+ float(scale)));
}
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);
-
- display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- if (display == EGL_NO_DISPLAY) {
- mbgl::Log::Error(mbgl::Event::OpenGL, "eglGetDisplay() returned error %d", eglGetError());
- throw std::runtime_error("eglGetDisplay() failed");
- }
-
- EGLint major, minor;
- if (!eglInitialize(display, &major, &minor)) {
- mbgl::Log::Error(mbgl::Event::OpenGL, "eglInitialize() returned error %d", eglGetError());
- throw std::runtime_error("eglInitialize() failed");
- }
- if ((major <= 1) && (minor < 3)) {
- mbgl::Log::Error(mbgl::Event::OpenGL, "EGL version is too low, need 1.3, got %d.%d", major,
- minor);
- throw std::runtime_error("EGL version is too low");
- }
-
- // Detect if we are in emulator.
- const bool inEmulator = []() {
- char prop[PROP_VALUE_MAX];
- __system_property_get("ro.kernel.qemu", prop);
- return strtol(prop, nullptr, 0) == 1;
- }();
-
- if (inEmulator) {
- // XXX https://code.google.com/p/android/issues/detail?id=78977
- mbgl::Log::Warning(mbgl::Event::Android, "Running SDK in emulator!");
- }
-
- if (!eglBindAPI(EGL_OPENGL_ES_API)) {
- mbgl::Log::Error(mbgl::Event::OpenGL, "eglBindAPI(EGL_OPENGL_ES_API) returned error %d", eglGetError());
- throw std::runtime_error("eglBindAPI() failed");
- }
-
- // Get all configs at least RGB 565 with 16 depth and 8 stencil
- EGLint configAttribs[] = {
- EGL_CONFIG_CAVEAT, EGL_NONE,
- EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
- EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
- EGL_BUFFER_SIZE, 16,
- EGL_RED_SIZE, 5,
- EGL_GREEN_SIZE, 6,
- EGL_BLUE_SIZE, 5,
- EGL_DEPTH_SIZE, 16,
- EGL_STENCIL_SIZE, 8,
- (inEmulator ? EGL_NONE : EGL_CONFORMANT), EGL_OPENGL_ES2_BIT,
- (inEmulator ? EGL_NONE : EGL_COLOR_BUFFER_TYPE), EGL_RGB_BUFFER,
- EGL_NONE
- };
-
- EGLint numConfigs;
- if (!eglChooseConfig(display, configAttribs, nullptr, 0, &numConfigs)) {
- mbgl::Log::Error(mbgl::Event::OpenGL, "eglChooseConfig(NULL) returned error %d",
- eglGetError());
- throw std::runtime_error("eglChooseConfig() failed");
- }
- if (numConfigs < 1) {
- mbgl::Log::Error(mbgl::Event::OpenGL, "eglChooseConfig() returned no configs.");
- throw std::runtime_error("eglChooseConfig() failed");
- }
-
- const auto configs = std::make_unique<EGLConfig[]>(numConfigs);
- if (!eglChooseConfig(display, configAttribs, configs.get(), numConfigs, &numConfigs)) {
- mbgl::Log::Error(mbgl::Event::OpenGL, "eglChooseConfig() returned error %d", eglGetError());
- throw std::runtime_error("eglChooseConfig() failed");
- }
-
- config = chooseConfig(configs.get(), numConfigs);
- if (config == nullptr) {
- mbgl::Log::Error(mbgl::Event::OpenGL, "No config chosen");
- throw std::runtime_error("No config chosen");
- }
-
- if (!eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format)) {
- mbgl::Log::Error(mbgl::Event::OpenGL, "eglGetConfigAttrib() returned error %d",
- eglGetError());
- throw std::runtime_error("eglGetConfigAttrib() failed");
- }
-}
-
-// Quality
-typedef enum {
- Format16Bit = 3,
- Format32BitNoAlpha = 1,
- Format32BitAlpha = 2,
- Format24Bit = 0,
- Unknown = 4
-} BufferFormat;
-
-typedef enum {
- Format16Depth8Stencil = 1,
- Format24Depth8Stencil = 0,
-} DepthStencilFormat;
-
-// Tuple is <buffer_format, depth_stencil_format, is_not_conformant, is_caveat, config_num,
-// config_id>
-typedef std::tuple<BufferFormat, DepthStencilFormat, bool, bool, int, EGLConfig> ConfigProperties;
-
-EGLConfig NativeMapView::chooseConfig(const EGLConfig configs[], EGLint numConfigs) {
- // Create a list of configs that pass our filters
- std::list<ConfigProperties> configList;
- for (int i = 0; i < numConfigs; i++) {
- EGLint caveat, conformant, bits, red, green, blue, alpha, alphaMask, depth, stencil,
- sampleBuffers, samples;
-
- if (!eglGetConfigAttrib(display, configs[i], EGL_CONFIG_CAVEAT, &caveat)) {
- mbgl::Log::Error(mbgl::Event::OpenGL,
- "eglGetConfigAttrib(EGL_CONFIG_CAVEAT) returned error %d",
- eglGetError());
- throw std::runtime_error("eglGetConfigAttrib() failed");
- }
-
- if (!eglGetConfigAttrib(display, configs[i], EGL_CONFORMANT, &conformant)) {
- mbgl::Log::Error(mbgl::Event::OpenGL,
- "eglGetConfigAttrib(EGL_CONFORMANT) returned error %d", eglGetError());
- throw std::runtime_error("eglGetConfigAttrib() failed");
- }
-
- if (!eglGetConfigAttrib(display, configs[i], EGL_BUFFER_SIZE, &bits)) {
- mbgl::Log::Error(mbgl::Event::OpenGL,
- "eglGetConfigAttrib(EGL_BUFFER_SIZE) returned error %d",
- eglGetError());
- throw std::runtime_error("eglGetConfigAttrib() failed");
- }
-
- if (!eglGetConfigAttrib(display, configs[i], EGL_RED_SIZE, &red)) {
- mbgl::Log::Error(mbgl::Event::OpenGL,
- "eglGetConfigAttrib(EGL_RED_SIZE) returned error %d", eglGetError());
- throw std::runtime_error("eglGetConfigAttrib() failed");
- }
-
- if (!eglGetConfigAttrib(display, configs[i], EGL_GREEN_SIZE, &green)) {
- mbgl::Log::Error(mbgl::Event::OpenGL,
- "eglGetConfigAttrib(EGL_GREEN_SIZE) returned error %d", eglGetError());
- throw std::runtime_error("eglGetConfigAttrib() failed");
- }
-
- if (!eglGetConfigAttrib(display, configs[i], EGL_BLUE_SIZE, &blue)) {
- mbgl::Log::Error(mbgl::Event::OpenGL,
- "eglGetConfigAttrib(EGL_BLUE_SIZE) returned error %d", eglGetError());
- throw std::runtime_error("eglGetConfigAttrib() failed");
- }
-
- if (!eglGetConfigAttrib(display, configs[i], EGL_ALPHA_SIZE, &alpha)) {
- mbgl::Log::Error(mbgl::Event::OpenGL,
- "eglGetConfigAttrib(EGL_ALPHA_SIZE) returned error %d", eglGetError());
- throw std::runtime_error("eglGetConfigAttrib() failed");
- }
-
- if (!eglGetConfigAttrib(display, configs[i], EGL_ALPHA_MASK_SIZE, &alphaMask)) {
- mbgl::Log::Error(mbgl::Event::OpenGL,
- "eglGetConfigAttrib(EGL_ALPHA_MASK_SIZE) returned error %d",
- eglGetError());
- throw std::runtime_error("eglGetConfigAttrib() failed");
- }
-
- if (!eglGetConfigAttrib(display, configs[i], EGL_DEPTH_SIZE, &depth)) {
- mbgl::Log::Error(mbgl::Event::OpenGL,
- "eglGetConfigAttrib(EGL_DEPTH_SIZE) returned error %d", eglGetError());
- throw std::runtime_error("eglGetConfigAttrib() failed");
- }
-
- if (!eglGetConfigAttrib(display, configs[i], EGL_STENCIL_SIZE, &stencil)) {
- mbgl::Log::Error(mbgl::Event::OpenGL,
- "eglGetConfigAttrib(EGL_STENCIL_SIZE) returned error %d",
- eglGetError());
- throw std::runtime_error("eglGetConfigAttrib() failed");
- }
-
- if (!eglGetConfigAttrib(display, configs[i], EGL_SAMPLE_BUFFERS, &sampleBuffers)) {
- mbgl::Log::Error(mbgl::Event::OpenGL,
- "eglGetConfigAttrib(EGL_SAMPLE_BUFFERS) returned error %d",
- eglGetError());
- throw std::runtime_error("eglGetConfigAttrib() failed");
- }
-
- if (!eglGetConfigAttrib(display, configs[i], EGL_SAMPLES, &samples)) {
- mbgl::Log::Error(mbgl::Event::OpenGL,
- "eglGetConfigAttrib(EGL_SAMPLES) returned error %d", eglGetError());
- throw std::runtime_error("eglGetConfigAttrib() failed");
- }
-
- bool configOk = true;
- configOk &= (depth == 24) || (depth == 16);
- configOk &= stencil == 8;
- configOk &= sampleBuffers == 0;
- configOk &= samples == 0;
-
- // Filter our configs first for depth, stencil and anti-aliasing
- if (configOk) {
- // Work out the config's buffer format
- BufferFormat bufferFormat;
- if ((bits == 16) && (red == 5) && (green == 6) && (blue == 5) && (alpha == 0)) {
- bufferFormat = Format16Bit;
- } else if ((bits == 32) && (red == 8) && (green == 8) && (blue == 8) && (alpha == 0)) {
- bufferFormat = Format32BitNoAlpha;
- } else if ((bits == 32) && (red == 8) && (green == 8) && (blue == 8) && (alpha == 8)) {
- bufferFormat = Format32BitAlpha;
- } else if ((bits == 24) && (red == 8) && (green == 8) && (blue == 8) && (alpha == 0)) {
- bufferFormat = Format24Bit;
- } else {
- bufferFormat = Unknown;
- }
-
- // Work out the config's depth stencil format
- DepthStencilFormat depthStencilFormat;
- if ((depth == 16) && (stencil == 8)) {
- depthStencilFormat = Format16Depth8Stencil;
- } else {
- depthStencilFormat = Format24Depth8Stencil;
- }
-
- bool isNotConformant = (conformant & EGL_OPENGL_ES2_BIT) != EGL_OPENGL_ES2_BIT;
- bool isCaveat = caveat != EGL_NONE;
- EGLConfig configId = configs[i];
-
- // Ignore formats we don't recognise
- if (bufferFormat != Unknown) {
- configList.push_back(std::make_tuple(bufferFormat, depthStencilFormat,
- isNotConformant, isCaveat, i, configId));
- }
- }
- }
-
- if (configList.empty()) {
- mbgl::Log::Error(mbgl::Event::OpenGL, "Config list was empty.");
- }
-
- // Sort the configs to find the best one
- configList.sort();
- bool isConformant = !std::get<2>(configList.front());
- bool isCaveat = std::get<3>(configList.front());
- EGLConfig configId = std::get<5>(configList.front());
-
- if (isCaveat) {
- mbgl::Log::Warning(mbgl::Event::OpenGL, "Chosen config has a caveat.");
- }
- if (!isConformant) {
- mbgl::Log::Warning(mbgl::Event::OpenGL, "Chosen config is not conformant.");
- }
-
- return configId;
+ map->getStyle().removeImage(jni::Make<std::string>(env, name));
}
-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 (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");
- }
- }
-}
-
-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;
- firstRender = true;
-
- if (window != nullptr) {
- ANativeWindow_release(window);
- window = nullptr;
+jni::Object<Bitmap> NativeMapView::getImage(JNIEnv& env, jni::String name) {
+ const mbgl::style::Image *image = map->getStyle().getImage(jni::Make<std::string>(env, name));
+ if (image) {
+ return Bitmap::CreateBitmap(env, image->getImage());
+ } else {
+ return jni::Object<Bitmap>();
}
}
-mbgl::Size NativeMapView::getFramebufferSize() const {
- return { static_cast<uint32_t>(fbWidth), static_cast<uint32_t>(fbHeight) };
+void NativeMapView::setPrefetchesTiles(JNIEnv&, jni::jboolean enable) {
+ map->setPrefetchZoomDelta(enable ? util::DEFAULT_PREFETCH_ZOOM_DELTA : uint8_t(0));
}
-void NativeMapView::updateAssumedState() {
- assumeFramebufferBinding(0);
- assumeViewportSize(getFramebufferSize());
-}
-
-void NativeMapView::updateFps() {
- if (!fpsEnabled) {
- return;
- }
-
- static int frames = 0;
- static int64_t timeElapsed = 0LL;
-
- frames++;
- struct timespec now;
- clock_gettime(CLOCK_MONOTONIC, &now);
- int64_t currentTime = now.tv_sec * 1000000000LL + now.tv_nsec;
-
- if (currentTime - timeElapsed >= 1) {
- fps = frames / ((currentTime - timeElapsed) / 1E9);
- mbgl::Log::Info(mbgl::Event::Render, "FPS: %4.2f", fps);
- timeElapsed = currentTime;
- frames = 0;
- }
-
- assert(vm != nullptr);
-
- android::UniqueEnv _env = android::AttachEnv();
- static auto onFpsChanged = javaClass.GetMethod<void (double)>(*_env, "onFpsChanged");
- javaPeer->Call(*_env, onFpsChanged, fps);
+jni::jboolean NativeMapView::getPrefetchesTiles(JNIEnv&) {
+ return jni::jboolean(map->getPrefetchZoomDelta() > 0);
}
// Static methods //
@@ -1463,19 +932,10 @@ void NativeMapView::registerNative(jni::JNIEnv& env) {
// Register the peer
jni::RegisterNativePeer<NativeMapView>(env, NativeMapView::javaClass, "nativePtr",
- std::make_unique<NativeMapView, JNIEnv&, jni::Object<NativeMapView>, jni::Object<FileSource>, jni::jfloat, jni::String, jni::jint, jni::jlong>,
+ std::make_unique<NativeMapView, JNIEnv&, jni::Object<NativeMapView>, jni::Object<FileSource>, jni::Object<MapRenderer>, jni::jfloat>,
"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"),
@@ -1508,7 +968,6 @@ void NativeMapView::registerNative(jni::JNIEnv& env) {
METHOD(&NativeMapView::setVisibleCoordinateBounds, "nativeSetVisibleCoordinateBounds"),
METHOD(&NativeMapView::setContentPadding, "nativeSetContentPadding"),
METHOD(&NativeMapView::scheduleSnapshot, "nativeTakeSnapshot"),
- METHOD(&NativeMapView::enableFps, "nativeSetEnableFps"),
METHOD(&NativeMapView::getCameraPosition, "nativeGetCameraPosition"),
METHOD(&NativeMapView::updateMarker, "nativeUpdateMarker"),
METHOD(&NativeMapView::addMarkers, "nativeAddMarkers"),
@@ -1528,6 +987,7 @@ void NativeMapView::registerNative(jni::JNIEnv& env) {
METHOD(&NativeMapView::updatePolygon, "nativeUpdatePolygon"),
METHOD(&NativeMapView::removeAnnotations, "nativeRemoveAnnotations"),
METHOD(&NativeMapView::addAnnotationIcon, "nativeAddAnnotationIcon"),
+ METHOD(&NativeMapView::removeAnnotationIcon, "nativeRemoveAnnotationIcon"),
METHOD(&NativeMapView::getTopOffsetPixelsForAnnotationSymbol, "nativeGetTopOffsetPixelsForAnnotationSymbol"),
METHOD(&NativeMapView::getTransitionDuration, "nativeGetTransitionDuration"),
METHOD(&NativeMapView::setTransitionDuration, "nativeSetTransitionDuration"),
@@ -1552,9 +1012,12 @@ void NativeMapView::registerNative(jni::JNIEnv& env) {
METHOD(&NativeMapView::removeSource, "nativeRemoveSource"),
METHOD(&NativeMapView::addImage, "nativeAddImage"),
METHOD(&NativeMapView::removeImage, "nativeRemoveImage"),
- METHOD(&NativeMapView::setLatLngBounds, "nativeSetLatLngBounds")
+ METHOD(&NativeMapView::getImage, "nativeGetImage"),
+ METHOD(&NativeMapView::setLatLngBounds, "nativeSetLatLngBounds"),
+ METHOD(&NativeMapView::setPrefetchesTiles, "nativeSetPrefetchesTiles"),
+ METHOD(&NativeMapView::getPrefetchesTiles, "nativeGetPrefetchesTiles")
);
}
-}
-}
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/native_map_view.hpp b/platform/android/src/native_map_view.hpp
index c638de44fb..72c7b1a9eb 100755
--- a/platform/android/src/native_map_view.hpp
+++ b/platform/android/src/native_map_view.hpp
@@ -1,17 +1,14 @@
#pragma once
-#include <mbgl/map/backend.hpp>
#include <mbgl/map/change.hpp>
#include <mbgl/map/camera.hpp>
#include <mbgl/map/map.hpp>
-#include <mbgl/map/view.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"
@@ -25,6 +22,7 @@
#include "geometry/lat_lng_bounds.hpp"
#include "map/camera_position.hpp"
#include "style/light.hpp"
+#include "bitmap.hpp"
#include <exception>
#include <string>
@@ -36,7 +34,11 @@
namespace mbgl {
namespace android {
-class NativeMapView : public View, public Backend {
+class AndroidRendererFrontend;
+class FileSource;
+class MapRenderer;
+
+class NativeMapView : public MapObserver {
public:
static constexpr auto Name() { return "com/mapbox/mapboxsdk/maps/NativeMapView"; };
@@ -48,26 +50,15 @@ public:
NativeMapView(jni::JNIEnv&,
jni::Object<NativeMapView>,
jni::Object<FileSource>,
- jni::jfloat pixelRatio,
- jni::String programCacheDir,
- jni::jint availableProcessors,
- jni::jlong totalMemory);
+ jni::Object<MapRenderer>,
+ jni::jfloat pixelRatio);
virtual ~NativeMapView();
- // mbgl::View //
-
- void bind() override;
-
- // mbgl::Backend //
-
- void updateAssumedState() override;
- void invalidate() override;
-
// Deprecated //
void notifyMapChange(mbgl::MapChange);
- // mbgl::Backend (mbgl::MapObserver) //
+ // mbgl::RendererBackend (mbgl::MapObserver) //
void onCameraWillChange(MapObserver::CameraChangeMode) override;
void onCameraIsChanging() override;
void onCameraDidChange(MapObserver::CameraChangeMode) override;
@@ -83,28 +74,8 @@ public:
// JNI //
- void destroy(jni::JNIEnv&);
-
- void render(jni::JNIEnv&);
-
- void update(jni::JNIEnv&);
-
void resizeView(jni::JNIEnv&, int, int);
- 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);
@@ -171,8 +142,6 @@ public:
void scheduleSnapshot(jni::JNIEnv&);
- void enableFps(jni::JNIEnv&, jni::jboolean enable);
-
jni::Object<CameraPosition> getCameraPosition(jni::JNIEnv&);
void updateMarker(jni::JNIEnv&, jni::jlong, jni::jdouble, jni::jdouble, jni::String);
@@ -211,6 +180,8 @@ public:
void addAnnotationIcon(JNIEnv&, jni::String, jint, jint, jfloat, jni::Array<jbyte>);
+ void removeAnnotationIcon(JNIEnv&, jni::String);
+
jni::jdouble getTopOffsetPixelsForAnnotationSymbol(JNIEnv&, jni::String);
jni::jlong getTransitionDuration(JNIEnv&);
@@ -263,72 +234,28 @@ public:
void removeImage(JNIEnv&, jni::String);
-protected:
- // mbgl::Backend //
+ jni::Object<Bitmap> getImage(JNIEnv&, jni::String);
- gl::ProcAddress initializeExtension(const char*) override;
- void activate() override;
- void deactivate() override;
+ void setPrefetchesTiles(JNIEnv&, jni::jboolean);
-private:
- void _initializeDisplay();
-
- void _terminateDisplay();
-
- void _initializeContext();
-
- void _terminateContext();
-
- void _createSurface(ANativeWindow*);
-
- void _destroySurface();
-
- EGLConfig chooseConfig(const EGLConfig configs[], EGLint numConfigs);
-
- mbgl::Size getFramebufferSize() const;
-
- void updateFps();
+ jni::jboolean getPrefetchesTiles(JNIEnv&);
private:
- void recalculateSourceTileCacheSize();
+ std::unique_ptr<AndroidRendererFrontend> rendererFrontend;
JavaVM *vm = nullptr;
jni::UniqueWeakObject<NativeMapView> javaPeer;
+ MapRenderer& mapRenderer;
+
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;
- EGLContext oldContext = EGL_NO_CONTEXT;
-
- EGLDisplay display = EGL_NO_DISPLAY;
- EGLSurface surface = EGL_NO_SURFACE;
- EGLContext context = EGL_NO_CONTEXT;
-
-
float pixelRatio;
- bool fpsEnabled = false;
- bool snapshot = false;
- bool firstRender = true;
- double fps = 0.0;
// Minimum texture size according to OpenGL ES 2.0 specification.
int width = 64;
int height = 64;
- int fbWidth = 64;
- int fbHeight = 64;
-
- bool framebufferSizeChanged = true;
-
- int availableProcessors = 0;
- size_t totalMemory = 0;
// Ensure these are initialised last
std::shared_ptr<mbgl::ThreadPool> threadPool;
diff --git a/platform/android/src/run_loop.cpp b/platform/android/src/run_loop.cpp
index 49d28f2ebb..dff7d1d984 100644
--- a/platform/android/src/run_loop.cpp
+++ b/platform/android/src/run_loop.cpp
@@ -1,10 +1,10 @@
#include "run_loop_impl.hpp"
#include <mbgl/util/platform.hpp>
-#include <mbgl/util/thread.hpp>
-#include <mbgl/util/thread_context.hpp>
#include <mbgl/util/thread_local.hpp>
+#include <mbgl/util/thread.hpp>
#include <mbgl/util/timer.hpp>
+#include <mbgl/actor/scheduler.hpp>
#include <android/looper.h>
@@ -24,7 +24,6 @@
namespace {
using namespace mbgl::util;
-static ThreadLocal<RunLoop>& current = *new ThreadLocal<RunLoop>;
int looperCallbackNew(int fd, int, void* data) {
int buffer[1];
@@ -62,9 +61,13 @@ namespace util {
// timeout, but on the main thread `ALooper_pollAll` is called by the activity
// automatically, thus we cannot set the timeout. Instead we wake the loop
// with an external file descriptor event coming from this thread.
+//
+// Usually an actor should not carry pointers to other threads, but in
+// this case the RunLoop itself owns the Alarm and calling wake() is the most
+// efficient way of waking up the RunLoop and it is also thread-safe.
class Alarm {
public:
- Alarm(RunLoop::Impl* loop_) : loop(loop_) {}
+ Alarm(ActorRef<Alarm>, RunLoop::Impl* loop_) : loop(loop_) {}
void set(const Milliseconds& timeout) {
alarm.start(timeout, mbgl::Duration::zero(), [this]() { loop->wake(); });
@@ -102,7 +105,7 @@ RunLoop::Impl::Impl(RunLoop* runLoop_, RunLoop::Type type) : runLoop(runLoop_) {
case Type::Default:
ret = ALooper_addFd(loop, fds[PIPE_OUT], ALOOPER_POLL_CALLBACK,
ALOOPER_EVENT_INPUT, looperCallbackDefault, this);
- alarm = std::make_unique<Thread<Alarm>>(ThreadContext{"Alarm"}, this);
+ alarm = std::make_unique<Thread<Alarm>>("Alarm", this);
running = true;
break;
}
@@ -190,26 +193,27 @@ Milliseconds RunLoop::Impl::processRunnables() {
auto timeout = std::chrono::duration_cast<Milliseconds>(nextDue - now);
if (alarm) {
- alarm->invoke(&Alarm::set, timeout);
+ alarm->actor().invoke(&Alarm::set, timeout);
}
return timeout;
}
RunLoop* RunLoop::Get() {
- return current.get();
+ assert(static_cast<RunLoop*>(Scheduler::GetCurrent()));
+ return static_cast<RunLoop*>(Scheduler::GetCurrent());
}
RunLoop::RunLoop(Type type) : impl(std::make_unique<Impl>(this, type)) {
- current.set(this);
+ Scheduler::SetCurrent(this);
}
RunLoop::~RunLoop() {
- current.set(nullptr);
+ Scheduler::SetCurrent(nullptr);
}
LOOP_HANDLE RunLoop::getLoopHandle() {
- return current.get()->impl.get();
+ return Get()->impl.get();
}
void RunLoop::push(std::shared_ptr<WorkTask> task) {
diff --git a/platform/android/src/snapshotter/map_snapshotter.cpp b/platform/android/src/snapshotter/map_snapshotter.cpp
new file mode 100644
index 0000000000..d64218d11a
--- /dev/null
+++ b/platform/android/src/snapshotter/map_snapshotter.cpp
@@ -0,0 +1,110 @@
+#include "map_snapshotter.hpp"
+
+#include <mbgl/renderer/renderer.hpp>
+#include <mbgl/style/style.hpp>
+#include <mbgl/util/shared_thread_pool.hpp>
+#include <mbgl/util/logging.hpp>
+#include <mbgl/util/string.hpp>
+#include <mbgl/actor/scheduler.hpp>
+
+#include "../attach_env.hpp"
+#include "../bitmap.hpp"
+
+namespace mbgl {
+namespace android {
+
+MapSnapshotter::MapSnapshotter(jni::JNIEnv& _env,
+ jni::Object<MapSnapshotter> _obj,
+ jni::Object<FileSource> jFileSource,
+ jni::jfloat _pixelRatio,
+ jni::jint width,
+ jni::jint height,
+ jni::String styleURL,
+ jni::Object<LatLngBounds> region,
+ jni::Object<CameraPosition> position,
+ jni::String _programCacheDir)
+ : javaPeer(SeizeGenericWeakRef(_env, jni::Object<MapSnapshotter>(jni::NewWeakGlobalRef(_env, _obj.Get()).release())))
+ , pixelRatio(_pixelRatio)
+ , threadPool(sharedThreadPool()) {
+
+ // Get a reference to the JavaVM for callbacks
+ if (_env.GetJavaVM(&vm) < 0) {
+ _env.ExceptionDescribe();
+ return;
+ }
+
+ auto& fileSource = mbgl::android::FileSource::getDefaultFileSource(_env, jFileSource);
+ auto size = mbgl::Size { static_cast<uint32_t>(width), static_cast<uint32_t>(height) };
+ auto cameraOptions = position ? CameraPosition::getCameraOptions(_env, position) : CameraOptions();
+ optional<mbgl::LatLngBounds> bounds;
+ if (region) {
+ bounds = LatLngBounds::getLatLngBounds(_env, region);
+ }
+
+ // Create the core snapshotter
+ snapshotter = std::make_unique<mbgl::MapSnapshotter>(fileSource,
+ *threadPool,
+ jni::Make<std::string>(_env, styleURL),
+ size,
+ pixelRatio,
+ cameraOptions,
+ bounds,
+ jni::Make<std::string>(_env, _programCacheDir));
+
+}
+
+MapSnapshotter::~MapSnapshotter() = default;
+
+void MapSnapshotter::start(JNIEnv&) {
+ MBGL_VERIFY_THREAD(tid);
+
+ snapshotCallback = std::make_unique<Actor<mbgl::MapSnapshotter::Callback>>(*Scheduler::GetCurrent(), [this](std::exception_ptr err, PremultipliedImage image) {
+ MBGL_VERIFY_THREAD(tid);
+ android::UniqueEnv _env = android::AttachEnv();
+
+ if (err) {
+ // error handler callback
+ static auto onSnapshotFailed = javaClass.GetMethod<void (jni::String)>(*_env, "onSnapshotFailed");
+ javaPeer->Call(*_env, onSnapshotFailed, jni::Make<jni::String>(*_env, util::toString(err)));
+ } else {
+ // Create the bitmap
+ auto bitmap = Bitmap::CreateBitmap(*_env, std::move(image));
+
+ // invoke callback
+ static auto onSnapshotReady = javaClass.GetMethod<void (jni::Object<Bitmap>)>(*_env, "onSnapshotReady");
+ javaPeer->Call(*_env, onSnapshotReady, bitmap);
+ }
+ });
+
+ snapshotter->snapshot(snapshotCallback->self());
+}
+
+void MapSnapshotter::cancel(JNIEnv&) {
+ MBGL_VERIFY_THREAD(tid);
+
+ snapshotCallback.reset();
+ snapshotter.reset();
+}
+
+// Static methods //
+
+jni::Class<MapSnapshotter> MapSnapshotter::javaClass;
+
+void MapSnapshotter::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ MapSnapshotter::javaClass = *jni::Class<MapSnapshotter>::Find(env).NewGlobalRef(env).release();
+
+#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
+
+ // Register the peer
+ jni::RegisterNativePeer<MapSnapshotter>(env, MapSnapshotter::javaClass, "nativePtr",
+ std::make_unique<MapSnapshotter, JNIEnv&, jni::Object<MapSnapshotter>, jni::Object<FileSource>, jni::jfloat, jni::jint, jni::jint, jni::String, jni::Object<LatLngBounds>, jni::Object<CameraPosition>, jni::String>,
+ "nativeInitialize",
+ "finalize",
+ METHOD(&MapSnapshotter::start, "nativeStart"),
+ METHOD(&MapSnapshotter::cancel, "nativeCancel")
+ );
+}
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/snapshotter/map_snapshotter.hpp b/platform/android/src/snapshotter/map_snapshotter.hpp
new file mode 100644
index 0000000000..093f589c05
--- /dev/null
+++ b/platform/android/src/snapshotter/map_snapshotter.hpp
@@ -0,0 +1,61 @@
+#pragma once
+
+#include <mbgl/map/map_snapshotter.hpp>
+#include <mbgl/util/default_thread_pool.hpp>
+#include <mbgl/util/util.hpp>
+
+#include "../file_source.hpp"
+#include "../geometry/lat_lng_bounds.hpp"
+#include "../map/camera_position.hpp"
+
+#include <jni/jni.hpp>
+#include "../jni/generic_global_ref_deleter.hpp"
+
+#include <memory>
+
+namespace mbgl {
+namespace android {
+
+class SnapshotterRendererFrontend;
+
+class MapSnapshotter {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/snapshotter/MapSnapshotter"; };
+
+ static jni::Class<MapSnapshotter> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+ MapSnapshotter(jni::JNIEnv&,
+ jni::Object<MapSnapshotter>,
+ jni::Object<FileSource>,
+ jni::jfloat pixelRatio,
+ jni::jint width,
+ jni::jint height,
+ jni::String styleURL,
+ jni::Object<LatLngBounds> region,
+ jni::Object<CameraPosition> position,
+ jni::String programCacheDir);
+
+ ~MapSnapshotter();
+
+ void start(JNIEnv&);
+
+ void cancel(JNIEnv&);
+
+private:
+ MBGL_STORE_THREAD(tid);
+
+ JavaVM *vm = nullptr;
+ GenericUniqueWeakObject<MapSnapshotter> javaPeer;
+
+ float pixelRatio;
+
+ std::shared_ptr<mbgl::ThreadPool> threadPool;
+ std::unique_ptr<Actor<mbgl::MapSnapshotter::Callback>> snapshotCallback;
+ std::unique_ptr<mbgl::MapSnapshotter> snapshotter;
+};
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/style/android_conversion.hpp b/platform/android/src/style/android_conversion.hpp
index e2b2685928..082fe411e2 100644
--- a/platform/android/src/style/android_conversion.hpp
+++ b/platform/android/src/style/android_conversion.hpp
@@ -2,6 +2,7 @@
#include "value.hpp"
+#include <mbgl/util/feature.hpp>
#include <mbgl/util/logging.hpp>
#include <mbgl/style/conversion.hpp>
#include <mbgl/util/optional.hpp>
@@ -66,6 +67,14 @@ inline optional<float> toNumber(const mbgl::android::Value& value) {
}
}
+inline optional<double> toDouble(const mbgl::android::Value& value) {
+ if (value.isNumber()) {
+ return value.toDouble();
+ } else {
+ return {};
+ }
+}
+
inline optional<std::string> toString(const mbgl::android::Value& value) {
if (value.isString()) {
return value.toString();
diff --git a/platform/android/src/style/conversion/latlngquad.hpp b/platform/android/src/style/conversion/latlngquad.hpp
new file mode 100644
index 0000000000..9d1a83e164
--- /dev/null
+++ b/platform/android/src/style/conversion/latlngquad.hpp
@@ -0,0 +1,24 @@
+#pragma once
+
+#include <mapbox/geojson.hpp>
+#include <mbgl/style/conversion.hpp>
+#include <mbgl/style/conversion/geojson.hpp>
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace style {
+namespace conversion {
+
+template <>
+optional<std::array<LatLng, 4>> Converter<std::array<LatLng, 4>>::operator()(const mbgl::android::Value& value, Error& error) const {
+ if (value.isNull() || !value.isArray()) {
+ error = { "value cannot be converted to LatLng array" };
+ return {};
+ }
+
+ return convert<GeoJSON>(value.toString(), error);
+}
+
+} // namespace conversion
+} // namespace style
+} // namespace mbgl
diff --git a/platform/android/src/style/conversion/transition_options.hpp b/platform/android/src/style/conversion/transition_options.hpp
index 3614878f43..ae65a32194 100644
--- a/platform/android/src/style/conversion/transition_options.hpp
+++ b/platform/android/src/style/conversion/transition_options.hpp
@@ -3,6 +3,7 @@
#include "../../conversion/conversion.hpp"
#include <jni/jni.hpp>
+#include <mbgl/style/transition_options.hpp>
#include "../../jni/local_object.hpp"
#include "../transition_options.hpp"
diff --git a/platform/android/src/style/conversion/types.hpp b/platform/android/src/style/conversion/types.hpp
index a00f668c24..375d1a33aa 100644
--- a/platform/android/src/style/conversion/types.hpp
+++ b/platform/android/src/style/conversion/types.hpp
@@ -58,15 +58,15 @@ struct Converter<jni::jobject*, mbgl::style::IconTextFitType> {
};
template <>
-struct Converter<jni::jobject*, mbgl::style::TextJustifyType> {
- Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::TextJustifyType& value) const {
+struct Converter<jni::jobject*, mbgl::style::SymbolAnchorType> {
+ Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::SymbolAnchorType& value) const {
return convert<jni::jobject*, std::string>(env, toString(value));
}
};
template <>
-struct Converter<jni::jobject*, mbgl::style::TextAnchorType> {
- Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::TextAnchorType& value) const {
+struct Converter<jni::jobject*, mbgl::style::TextJustifyType> {
+ Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::TextJustifyType& value) const {
return convert<jni::jobject*, std::string>(env, toString(value));
}
};
diff --git a/platform/android/src/style/conversion/types_string_values.hpp b/platform/android/src/style/conversion/types_string_values.hpp
index e96de3b01e..a19ca33a2f 100644
--- a/platform/android/src/style/conversion/types_string_values.hpp
+++ b/platform/android/src/style/conversion/types_string_values.hpp
@@ -109,51 +109,34 @@ namespace conversion {
}
}
- // text-justify
- inline std::string toString(mbgl::style::TextJustifyType value) {
- switch (value) {
- case mbgl::style::TextJustifyType::Left:
- return "left";
- break;
- case mbgl::style::TextJustifyType::Center:
- return "center";
- break;
- case mbgl::style::TextJustifyType::Right:
- return "right";
- break;
- default:
- throw std::runtime_error("Not implemented");
- }
- }
-
- // text-anchor
- inline std::string toString(mbgl::style::TextAnchorType value) {
+ // icon-anchor
+ inline std::string toString(mbgl::style::SymbolAnchorType value) {
switch (value) {
- case mbgl::style::TextAnchorType::Center:
+ case mbgl::style::SymbolAnchorType::Center:
return "center";
break;
- case mbgl::style::TextAnchorType::Left:
+ case mbgl::style::SymbolAnchorType::Left:
return "left";
break;
- case mbgl::style::TextAnchorType::Right:
+ case mbgl::style::SymbolAnchorType::Right:
return "right";
break;
- case mbgl::style::TextAnchorType::Top:
+ case mbgl::style::SymbolAnchorType::Top:
return "top";
break;
- case mbgl::style::TextAnchorType::Bottom:
+ case mbgl::style::SymbolAnchorType::Bottom:
return "bottom";
break;
- case mbgl::style::TextAnchorType::TopLeft:
+ case mbgl::style::SymbolAnchorType::TopLeft:
return "top-left";
break;
- case mbgl::style::TextAnchorType::TopRight:
+ case mbgl::style::SymbolAnchorType::TopRight:
return "top-right";
break;
- case mbgl::style::TextAnchorType::BottomLeft:
+ case mbgl::style::SymbolAnchorType::BottomLeft:
return "bottom-left";
break;
- case mbgl::style::TextAnchorType::BottomRight:
+ case mbgl::style::SymbolAnchorType::BottomRight:
return "bottom-right";
break;
default:
@@ -161,6 +144,23 @@ namespace conversion {
}
}
+ // text-justify
+ inline std::string toString(mbgl::style::TextJustifyType value) {
+ switch (value) {
+ case mbgl::style::TextJustifyType::Left:
+ return "left";
+ break;
+ case mbgl::style::TextJustifyType::Center:
+ return "center";
+ break;
+ case mbgl::style::TextJustifyType::Right:
+ return "right";
+ break;
+ default:
+ throw std::runtime_error("Not implemented");
+ }
+ }
+
// text-transform
inline std::string toString(mbgl::style::TextTransformType value) {
switch (value) {
diff --git a/platform/android/src/style/layers/circle_layer.cpp b/platform/android/src/style/layers/circle_layer.cpp
index 96a9356679..4c7f69e956 100644
--- a/platform/android/src/style/layers/circle_layer.cpp
+++ b/platform/android/src/style/layers/circle_layer.cpp
@@ -142,6 +142,12 @@ namespace android {
return jni::Object<jni::ObjectTag>(*converted);
}
+ jni::Object<jni::ObjectTag> CircleLayer::getCirclePitchAlignment(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::CircleLayer>()->CircleLayer::getCirclePitchAlignment());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
jni::Object<jni::ObjectTag> CircleLayer::getCircleStrokeWidth(jni::JNIEnv& env) {
using namespace mbgl::android::conversion;
Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::CircleLayer>()->CircleLayer::getCircleStrokeWidth());
@@ -236,6 +242,7 @@ namespace android {
METHOD(&CircleLayer::getCircleTranslate, "nativeGetCircleTranslate"),
METHOD(&CircleLayer::getCircleTranslateAnchor, "nativeGetCircleTranslateAnchor"),
METHOD(&CircleLayer::getCirclePitchScale, "nativeGetCirclePitchScale"),
+ METHOD(&CircleLayer::getCirclePitchAlignment, "nativeGetCirclePitchAlignment"),
METHOD(&CircleLayer::getCircleStrokeWidthTransition, "nativeGetCircleStrokeWidthTransition"),
METHOD(&CircleLayer::setCircleStrokeWidthTransition, "nativeSetCircleStrokeWidthTransition"),
METHOD(&CircleLayer::getCircleStrokeWidth, "nativeGetCircleStrokeWidth"),
diff --git a/platform/android/src/style/layers/circle_layer.hpp b/platform/android/src/style/layers/circle_layer.hpp
index 81737e8996..9d323e92bb 100644
--- a/platform/android/src/style/layers/circle_layer.hpp
+++ b/platform/android/src/style/layers/circle_layer.hpp
@@ -53,6 +53,8 @@ public:
jni::Object<jni::ObjectTag> getCirclePitchScale(jni::JNIEnv&);
+ jni::Object<jni::ObjectTag> getCirclePitchAlignment(jni::JNIEnv&);
+
jni::Object<jni::ObjectTag> getCircleStrokeWidth(jni::JNIEnv&);
void setCircleStrokeWidthTransition(jni::JNIEnv&, jlong duration, jlong delay);
jni::Object<TransitionOptions> getCircleStrokeWidthTransition(jni::JNIEnv&);
diff --git a/platform/android/src/style/layers/custom_layer.cpp b/platform/android/src/style/layers/custom_layer.cpp
index 9bdc308d85..51a48520bf 100644
--- a/platform/android/src/style/layers/custom_layer.cpp
+++ b/platform/android/src/style/layers/custom_layer.cpp
@@ -7,11 +7,12 @@
namespace mbgl {
namespace android {
- CustomLayer::CustomLayer(jni::JNIEnv& env, jni::String layerId, jni::jlong initializeFunction, jni::jlong renderFunction, jni::jlong deinitializeFunction, jni::jlong context)
+ CustomLayer::CustomLayer(jni::JNIEnv& env, jni::String layerId, jni::jlong initializeFunction, jni::jlong renderFunction, jni::jlong contextLostFunction, jni::jlong deinitializeFunction, jni::jlong context)
: Layer(env, std::make_unique<mbgl::style::CustomLayer>(
jni::Make<std::string>(env, layerId),
reinterpret_cast<mbgl::style::CustomLayerInitializeFunction>(initializeFunction),
reinterpret_cast<mbgl::style::CustomLayerRenderFunction>(renderFunction),
+ reinterpret_cast<mbgl::style::CustomLayerContextLostFunction>(contextLostFunction),
reinterpret_cast<mbgl::style::CustomLayerDeinitializeFunction>(deinitializeFunction),
reinterpret_cast<void*>(context))
) {
@@ -21,6 +22,10 @@ namespace android {
: Layer(map, coreLayer) {
}
+ CustomLayer::CustomLayer(mbgl::Map& map, std::unique_ptr<mbgl::style::CustomLayer> coreLayer)
+ : Layer(map, std::move(coreLayer)) {
+ }
+
CustomLayer::~CustomLayer() = default;
void CustomLayer::update(jni::JNIEnv&) {
@@ -48,7 +53,7 @@ namespace android {
// Register the peer
jni::RegisterNativePeer<CustomLayer>(
env, CustomLayer::javaClass, "nativePtr",
- std::make_unique<CustomLayer, JNIEnv&, jni::String, jni::jlong, jni::jlong, jni::jlong, jni::jlong>,
+ std::make_unique<CustomLayer, JNIEnv&, jni::String, jni::jlong, jni::jlong, jni::jlong, jni::jlong, jni::jlong>,
"initialize",
"finalize",
METHOD(&CustomLayer::update, "nativeUpdate"));
diff --git a/platform/android/src/style/layers/custom_layer.hpp b/platform/android/src/style/layers/custom_layer.hpp
index 1173d21bfd..9e079c1288 100644
--- a/platform/android/src/style/layers/custom_layer.hpp
+++ b/platform/android/src/style/layers/custom_layer.hpp
@@ -16,10 +16,12 @@ public:
static void registerNative(jni::JNIEnv&);
- CustomLayer(jni::JNIEnv&, jni::String, jni::jlong, jni::jlong, jni::jlong, jni::jlong);
+ CustomLayer(jni::JNIEnv&, jni::String, jni::jlong, jni::jlong, jni::jlong, jni::jlong, jni::jlong);
CustomLayer(mbgl::Map&, mbgl::style::CustomLayer&);
+ CustomLayer(mbgl::Map&, std::unique_ptr<mbgl::style::CustomLayer>);
+
~CustomLayer();
void update(jni::JNIEnv&);
diff --git a/platform/android/src/style/layers/layer.cpp b/platform/android/src/style/layers/layer.cpp
index d571c3fd2e..02a1f0be82 100644
--- a/platform/android/src/style/layers/layer.cpp
+++ b/platform/android/src/style/layers/layer.cpp
@@ -3,6 +3,7 @@
#include <jni/jni.hpp>
+#include <mbgl/style/style.hpp>
#include <mbgl/style/transition_options.hpp>
#include <mbgl/util/logging.hpp>
@@ -53,7 +54,7 @@ namespace android {
}
// Add layer to map
- _map.addLayer(releaseCoreLayer(), before);
+ _map.getStyle().addLayer(releaseCoreLayer(), before);
// Save pointer to the map
this->map = &_map;
@@ -91,19 +92,31 @@ namespace android {
Value value(env, jvalue);
// Convert and set property
- optional<mbgl::style::conversion::Error> error = mbgl::style::conversion::setPaintProperty(layer, jni::Make<std::string>(env, jname), value, mbgl::optional<std::string>());
+ optional<mbgl::style::conversion::Error> error = mbgl::style::conversion::setPaintProperty(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);
return;
}
}
+ struct SetFilterEvaluator {
+ style::Filter filter;
+
+ void operator()(style::BackgroundLayer&) { Log::Warning(mbgl::Event::JNI, "BackgroundLayer doesn't support filters"); }
+ void operator()(style::CustomLayer&) { Log::Warning(mbgl::Event::JNI, "CustomLayer doesn't support filters"); }
+ void operator()(style::RasterLayer&) { Log::Warning(mbgl::Event::JNI, "RasterLayer doesn't support filters"); }
+
+ template <class LayerType>
+ void operator()(LayerType& layer) {
+ layer.setFilter(filter);
+ }
+ };
+
void Layer::setFilter(jni::JNIEnv& env, jni::Array<jni::Object<>> jfilter) {
using namespace mbgl::style;
using namespace mbgl::style::conversion;
Value wrapped(env, jfilter);
- Filter filter;
Error error;
optional<Filter> converted = convert<Filter>(wrapped, error);
@@ -111,62 +124,45 @@ namespace android {
mbgl::Log::Error(mbgl::Event::JNI, "Error setting filter: " + error.message);
return;
}
- filter = std::move(*converted);
-
- if (layer.is<FillLayer>()) {
- layer.as<FillLayer>()->setFilter(filter);
- } else if (layer.is<LineLayer>()) {
- layer.as<LineLayer>()->setFilter(filter);
- } else if (layer.is<SymbolLayer>()) {
- layer.as<SymbolLayer>()->setFilter(filter);
- } else if (layer.is<CircleLayer>()) {
- layer.as<CircleLayer>()->setFilter(filter);
- } else if (layer.is<FillExtrusionLayer>()){
- layer.as<FillExtrusionLayer>()->setFilter(filter);
- } else {
- mbgl::Log::Warning(mbgl::Event::JNI, "Layer doesn't support filters");
- }
+
+ layer.accept(SetFilterEvaluator {std::move(*converted)});
}
- void Layer::setSourceLayer(jni::JNIEnv& env, jni::String sourceLayer) {
- using namespace mbgl::style;
+ struct SetSourceLayerEvaluator {
+ std::string sourceLayer;
- std::string layerId = jni::Make<std::string>(env, sourceLayer);
-
- if (layer.is<FillLayer>()) {
- layer.as<FillLayer>()->setSourceLayer(layerId);
- } else if (layer.is<LineLayer>()) {
- layer.as<LineLayer>()->setSourceLayer(layerId);
- } else if (layer.is<SymbolLayer>()) {
- layer.as<SymbolLayer>()->setSourceLayer(layerId);
- } else if (layer.is<CircleLayer>()) {
- layer.as<CircleLayer>()->setSourceLayer(layerId);
- } else if(layer.is<FillExtrusionLayer>()) {
- layer.as<FillExtrusionLayer>()->setSourceLayer(layerId);
- } else {
- mbgl::Log::Warning(mbgl::Event::JNI, "Layer doesn't support source layer");
+ void operator()(style::BackgroundLayer&) { Log::Warning(mbgl::Event::JNI, "BackgroundLayer doesn't support source layer"); }
+ void operator()(style::CustomLayer&) { Log::Warning(mbgl::Event::JNI, "CustomLayer doesn't support source layer"); }
+ void operator()(style::RasterLayer&) { Log::Warning(mbgl::Event::JNI, "RasterLayer doesn't support source layer"); }
+
+ template <class LayerType>
+ void operator()(LayerType& layer) {
+ layer.setSourceLayer(sourceLayer);
}
+ };
+
+ void Layer::setSourceLayer(jni::JNIEnv& env, jni::String sourceLayer) {
+ layer.accept(SetSourceLayerEvaluator {jni::Make<std::string>(env, sourceLayer)});
}
- jni::String Layer::getSourceLayer(jni::JNIEnv& env) {
- using namespace mbgl::style;
+ struct GetSourceLayerEvaluator {
+ std::string noop(std::string layerType) {
+ Log::Warning(mbgl::Event::JNI, "%s doesn't support source layer", layerType.c_str());
+ return {};
+ }
- std::string sourceLayerId;
- if (layer.is<FillLayer>()) {
- sourceLayerId = layer.as<FillLayer>()->getSourceLayer();
- } else if (layer.is<LineLayer>()) {
- sourceLayerId = layer.as<LineLayer>()->getSourceLayer();
- } else if (layer.is<SymbolLayer>()) {
- sourceLayerId = layer.as<SymbolLayer>()->getSourceLayer();
- } else if (layer.is<CircleLayer>()) {
- sourceLayerId = layer.as<CircleLayer>()->getSourceLayer();
- } else if (layer.is<FillExtrusionLayer>()) {
- sourceLayerId = layer.as<FillExtrusionLayer>()->getSourceLayer();
- } else {
- mbgl::Log::Warning(mbgl::Event::JNI, "Layer doesn't support source layer");
+ std::string operator()(style::BackgroundLayer&) { return noop("BackgroundLayer"); }
+ std::string operator()(style::CustomLayer&) { return noop("CustomLayer"); }
+ std::string operator()(style::RasterLayer&) { return noop("RasterLayer"); }
+
+ template <class LayerType>
+ std::string operator()(LayerType& layer) {
+ return layer.getSourceLayer();
}
+ };
- return jni::Make<jni::String>(env, sourceLayerId);
+ jni::String Layer::getSourceLayer(jni::JNIEnv& env) {
+ return jni::Make<jni::String>(env, layer.accept(GetSourceLayerEvaluator()));
}
jni::jfloat Layer::getMinZoom(jni::JNIEnv&){
diff --git a/platform/android/src/style/layers/layers.cpp b/platform/android/src/style/layers/layers.cpp
index 5c49f875ee..9803b6f841 100644
--- a/platform/android/src/style/layers/layers.cpp
+++ b/platform/android/src/style/layers/layers.cpp
@@ -24,53 +24,51 @@
namespace mbgl {
namespace android {
-static Layer* initializeLayerPeer(mbgl::Map& map, mbgl::style::Layer& coreLayer) {
- if (coreLayer.is<mbgl::style::BackgroundLayer>()) {
- return new BackgroundLayer(map, *coreLayer.as<mbgl::style::BackgroundLayer>());
- } else if (coreLayer.is<mbgl::style::CircleLayer>()) {
- return new CircleLayer(map, *coreLayer.as<mbgl::style::CircleLayer>());
- } else if (coreLayer.is<mbgl::style::FillExtrusionLayer>()) {
- return new FillExtrusionLayer(map, *coreLayer.as<mbgl::style::FillExtrusionLayer>());
- } else if (coreLayer.is<mbgl::style::FillLayer>()) {
- return new FillLayer(map, *coreLayer.as<mbgl::style::FillLayer>());
- } else if (coreLayer.is<mbgl::style::LineLayer>()) {
- return new LineLayer(map, *coreLayer.as<mbgl::style::LineLayer>());
- } else if (coreLayer.is<mbgl::style::RasterLayer>()) {
- return new RasterLayer(map, *coreLayer.as<mbgl::style::RasterLayer>());
- } else if (coreLayer.is<mbgl::style::SymbolLayer>()) {
- return new SymbolLayer(map, *coreLayer.as<mbgl::style::SymbolLayer>());
- } else if (coreLayer.is<mbgl::style::CustomLayer>()) {
- return new CustomLayer(map, *coreLayer.as<mbgl::style::CustomLayer>());
- } else {
- return new UnknownLayer(map, coreLayer);
+// Mapping from style layers to peer classes
+template <class> struct PeerType {};
+template <> struct PeerType<style::BackgroundLayer> { using Type = android::BackgroundLayer; };
+template <> struct PeerType<style::CircleLayer> { using Type = android::CircleLayer; };
+template <> struct PeerType<style::FillExtrusionLayer> { using Type = android::FillExtrusionLayer; };
+template <> struct PeerType<style::FillLayer> { using Type = android::FillLayer; };
+template <> struct PeerType<style::LineLayer> { using Type = android::LineLayer; };
+template <> struct PeerType<style::RasterLayer> { using Type = android::RasterLayer; };
+template <> struct PeerType<style::SymbolLayer> { using Type = android::SymbolLayer; };
+template <> struct PeerType<style::CustomLayer> { using Type = android::CustomLayer; };
+
+// Inititalizes a non-owning peer
+struct LayerPeerIntitializer {
+ mbgl::Map& map;
+
+ template <class LayerType>
+ Layer* operator()(LayerType& layer) {
+ return new typename PeerType<LayerType>::Type(map, 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(mbgl::Map& map, mbgl::style::Layer& coreLayer) {
+ Layer* layer = coreLayer.accept(LayerPeerIntitializer {map});
+ return layer ? layer : new UnknownLayer(map, coreLayer);
}
-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::FillExtrusionLayer>()) {
- return createPeer<style::FillExtrusionLayer, FillExtrusionLayer>(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));
+// Initializes an owning peer
+// Only usable once since it needs to pass on ownership
+// of the given layer and thus enforced to be an rvalue
+struct UniqueLayerPeerIntitializer {
+ mbgl::Map& map;
+ std::unique_ptr<style::Layer> layer;
+
+ template <class LayerType>
+ Layer* operator()(LayerType&) && {
+ return new typename PeerType<LayerType>::Type(
+ map,
+ std::unique_ptr<LayerType>(layer.release()->as<LayerType>())
+ );
}
+};
+
+static Layer* initializeLayerPeer(Map& map, std::unique_ptr<mbgl::style::Layer> coreLayer) {
+ Layer* layer = coreLayer->accept(UniqueLayerPeerIntitializer {map, std::move(coreLayer)});
+ return layer ? layer : new UnknownLayer(map, std::move(coreLayer));
}
jni::jobject* createJavaLayerPeer(jni::JNIEnv& env, Map& map, style::Layer& coreLayer) {
diff --git a/platform/android/src/style/layers/symbol_layer.cpp b/platform/android/src/style/layers/symbol_layer.cpp
index 3a560a5deb..d44744a6cf 100644
--- a/platform/android/src/style/layers/symbol_layer.cpp
+++ b/platform/android/src/style/layers/symbol_layer.cpp
@@ -125,6 +125,18 @@ namespace android {
return jni::Object<jni::ObjectTag>(*converted);
}
+ jni::Object<jni::ObjectTag> SymbolLayer::getIconAnchor(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getIconAnchor());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getIconPitchAlignment(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getIconPitchAlignment());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
jni::Object<jni::ObjectTag> SymbolLayer::getTextPitchAlignment(jni::JNIEnv& env) {
using namespace mbgl::android::conversion;
Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getTextPitchAlignment());
@@ -514,6 +526,8 @@ namespace android {
METHOD(&SymbolLayer::getIconPadding, "nativeGetIconPadding"),
METHOD(&SymbolLayer::getIconKeepUpright, "nativeGetIconKeepUpright"),
METHOD(&SymbolLayer::getIconOffset, "nativeGetIconOffset"),
+ METHOD(&SymbolLayer::getIconAnchor, "nativeGetIconAnchor"),
+ METHOD(&SymbolLayer::getIconPitchAlignment, "nativeGetIconPitchAlignment"),
METHOD(&SymbolLayer::getTextPitchAlignment, "nativeGetTextPitchAlignment"),
METHOD(&SymbolLayer::getTextRotationAlignment, "nativeGetTextRotationAlignment"),
METHOD(&SymbolLayer::getTextField, "nativeGetTextField"),
diff --git a/platform/android/src/style/layers/symbol_layer.hpp b/platform/android/src/style/layers/symbol_layer.hpp
index 8366051c6e..417e5e143f 100644
--- a/platform/android/src/style/layers/symbol_layer.hpp
+++ b/platform/android/src/style/layers/symbol_layer.hpp
@@ -59,6 +59,10 @@ public:
jni::Object<jni::ObjectTag> getIconOffset(jni::JNIEnv&);
+ jni::Object<jni::ObjectTag> getIconAnchor(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getIconPitchAlignment(jni::JNIEnv&);
+
jni::Object<jni::ObjectTag> getTextPitchAlignment(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getTextRotationAlignment(jni::JNIEnv&);
diff --git a/platform/android/src/style/sources/geojson_source.cpp b/platform/android/src/style/sources/geojson_source.cpp
index 780cc4b6f6..90ef851eba 100644
--- a/platform/android/src/style/sources/geojson_source.cpp
+++ b/platform/android/src/style/sources/geojson_source.cpp
@@ -1,5 +1,7 @@
#include "geojson_source.hpp"
+#include <mbgl/renderer/query.hpp>
+
// Java -> C++ conversion
#include "../android_conversion.hpp"
#include "../conversion/filter.hpp"
@@ -41,8 +43,8 @@ namespace android {
) {
}
- GeoJSONSource::GeoJSONSource(mbgl::Map& map, mbgl::style::GeoJSONSource& coreSource)
- : Source(map, coreSource) {
+ GeoJSONSource::GeoJSONSource(mbgl::style::GeoJSONSource& coreSource)
+ : Source(coreSource) {
}
GeoJSONSource::~GeoJSONSource() = default;
@@ -108,8 +110,8 @@ namespace android {
using namespace mbgl::android::geojson;
std::vector<mbgl::Feature> features;
- if (map) {
- features = map->querySourceFeatures(source.getID(), { {}, toFilter(env, jfilter) });
+ if (rendererFrontend) {
+ features = rendererFrontend->querySourceFeatures(source.getID(), { {}, toFilter(env, jfilter) });
}
return *convert<jni::Array<jni::Object<Feature>>, std::vector<mbgl::Feature>>(env, features);
}
diff --git a/platform/android/src/style/sources/geojson_source.hpp b/platform/android/src/style/sources/geojson_source.hpp
index 938a20612c..52dd632bfa 100644
--- a/platform/android/src/style/sources/geojson_source.hpp
+++ b/platform/android/src/style/sources/geojson_source.hpp
@@ -21,7 +21,7 @@ public:
GeoJSONSource(jni::JNIEnv&, jni::String, jni::Object<>);
- GeoJSONSource(mbgl::Map&, mbgl::style::GeoJSONSource&);
+ GeoJSONSource(mbgl::style::GeoJSONSource&);
~GeoJSONSource();
diff --git a/platform/android/src/style/sources/image_source.cpp b/platform/android/src/style/sources/image_source.cpp
new file mode 100644
index 0000000000..d46b367c53
--- /dev/null
+++ b/platform/android/src/style/sources/image_source.cpp
@@ -0,0 +1,72 @@
+#include "image_source.hpp"
+
+// Java -> C++ conversion
+#include "../android_conversion.hpp"
+
+// C++ -> Java conversion
+#include "../../conversion/conversion.hpp"
+#include <mbgl/style/conversion.hpp>
+#include <mbgl/util/premultiply.hpp>
+
+#include "../../bitmap.hpp"
+#include <string>
+#include <array>
+
+namespace mbgl {
+namespace android {
+
+ ImageSource::ImageSource(jni::JNIEnv& env, jni::String sourceId, jni::Object<LatLngQuad> coordinatesObject)
+ : Source(env, std::make_unique<mbgl::style::ImageSource>(
+ jni::Make<std::string>(env, sourceId),
+ LatLngQuad::getLatLngArray(env, coordinatesObject)
+ )
+ ) {
+ }
+
+ ImageSource::ImageSource(mbgl::style::ImageSource& coreSource)
+ : Source(coreSource) {
+ }
+
+ ImageSource::~ImageSource() = default;
+
+ void ImageSource::setURL(jni::JNIEnv& env, jni::String url) {
+ // Update the core source
+ source.as<mbgl::style::ImageSource>()->ImageSource::setURL(jni::Make<std::string>(env, url));
+ }
+
+ jni::String ImageSource::getURL(jni::JNIEnv& env) {
+ optional<std::string> url = source.as<mbgl::style::ImageSource>()->ImageSource::getURL();
+ return url ? jni::Make<jni::String>(env, *url) : jni::String();
+ }
+
+ void ImageSource::setImage(jni::JNIEnv& env, jni::Object<Bitmap> bitmap) {
+ source.as<mbgl::style::ImageSource>()->setImage(Bitmap::GetImage(env, bitmap));
+ }
+
+ jni::Class<ImageSource> ImageSource::javaClass;
+
+ jni::jobject* ImageSource::createJavaPeer(jni::JNIEnv& env) {
+ static auto constructor = ImageSource::javaClass.template GetConstructor<jni::jlong>(env);
+ return ImageSource::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this));
+ }
+
+ void ImageSource::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ ImageSource::javaClass = *jni::Class<ImageSource>::Find(env).NewGlobalRef(env).release();
+
+ #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
+
+ // Register the peer
+ jni::RegisterNativePeer<ImageSource>(
+ env, ImageSource::javaClass, "nativePtr",
+ std::make_unique<ImageSource, JNIEnv&, jni::String, jni::Object<LatLngQuad>>,
+ "initialize",
+ "finalize",
+ METHOD(&ImageSource::setURL, "nativeSetUrl"),
+ METHOD(&ImageSource::getURL, "nativeGetUrl"),
+ METHOD(&ImageSource::setImage, "nativeSetImage")
+ );
+ }
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/sources/image_source.hpp b/platform/android/src/style/sources/image_source.hpp
new file mode 100644
index 0000000000..9787a7294f
--- /dev/null
+++ b/platform/android/src/style/sources/image_source.hpp
@@ -0,0 +1,38 @@
+#pragma once
+
+#include "source.hpp"
+#include "../../geometry/lat_lng_quad.hpp"
+#include <mbgl/style/sources/image_source.hpp>
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class Bitmap;
+
+class ImageSource : public Source {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/sources/ImageSource"; };
+
+ static jni::Class<ImageSource> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+ ImageSource(jni::JNIEnv&, jni::String, jni::Object<LatLngQuad>);
+
+ ImageSource(mbgl::style::ImageSource&);
+
+ ~ImageSource();
+
+ void setURL(jni::JNIEnv&, jni::String);
+ jni::String getURL(jni::JNIEnv&);
+
+ void setImage(jni::JNIEnv&, jni::Object<Bitmap>);
+
+ jni::jobject* createJavaPeer(jni::JNIEnv&);
+
+}; // class ImageSource
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/sources/raster_source.cpp b/platform/android/src/style/sources/raster_source.cpp
index 32fdb163b0..d45342a1ad 100644
--- a/platform/android/src/style/sources/raster_source.cpp
+++ b/platform/android/src/style/sources/raster_source.cpp
@@ -22,8 +22,8 @@ namespace android {
) {
}
- RasterSource::RasterSource(mbgl::Map& map, mbgl::style::RasterSource& coreSource)
- : Source(map, coreSource) {
+ RasterSource::RasterSource(mbgl::style::RasterSource& coreSource)
+ : Source(coreSource) {
}
RasterSource::~RasterSource() = default;
diff --git a/platform/android/src/style/sources/raster_source.hpp b/platform/android/src/style/sources/raster_source.hpp
index a79ccc10a4..84c49d7381 100644
--- a/platform/android/src/style/sources/raster_source.hpp
+++ b/platform/android/src/style/sources/raster_source.hpp
@@ -18,7 +18,7 @@ public:
RasterSource(jni::JNIEnv&, jni::String, jni::Object<>, jni::jint);
- RasterSource(mbgl::Map&, mbgl::style::RasterSource&);
+ RasterSource(mbgl::style::RasterSource&);
~RasterSource();
diff --git a/platform/android/src/style/sources/source.cpp b/platform/android/src/style/sources/source.cpp
index e0e9bb9870..447b13019d 100644
--- a/platform/android/src/style/sources/source.cpp
+++ b/platform/android/src/style/sources/source.cpp
@@ -3,6 +3,7 @@
#include <jni/jni.hpp>
+#include <mbgl/style/style.hpp>
#include <mbgl/util/logging.hpp>
// Java -> C++ conversion
@@ -25,11 +26,11 @@ namespace android {
, source(*ownedSource) {
}
- Source::Source(mbgl::Map& coreMap, mbgl::style::Source& coreSource) : source(coreSource) , map(&coreMap) {
+ Source::Source(mbgl::style::Source& coreSource)
+ : source(coreSource) {
}
- Source::~Source() {
- }
+ Source::~Source() = default;
style::Source& Source::get() {
return source;
@@ -55,10 +56,11 @@ namespace android {
}
// Add source to map
- _map.addSource(releaseCoreSource());
+ _map.getStyle().addSource(releaseCoreSource());
+ }
- // Save pointer to the map
- this->map = &_map;
+ void Source::setRendererFrontend(AndroidRendererFrontend& frontend_) {
+ rendererFrontend = &frontend_;
}
std::unique_ptr<mbgl::style::Source> Source::releaseCoreSource() {
diff --git a/platform/android/src/style/sources/source.hpp b/platform/android/src/style/sources/source.hpp
index 49fc50d754..383017b66f 100644
--- a/platform/android/src/style/sources/source.hpp
+++ b/platform/android/src/style/sources/source.hpp
@@ -5,6 +5,7 @@
#include <mbgl/style/source.hpp>
#include "../value.hpp"
+#include "../../android_renderer_frontend.hpp"
#include <jni/jni.hpp>
@@ -23,7 +24,7 @@ public:
/*
* Called when a Java object is created on the c++ side
*/
- Source(mbgl::Map&, mbgl::style::Source&);
+ Source(mbgl::style::Source&);
/*
* Called when a Java object was created from the jvm side
@@ -41,6 +42,8 @@ public:
void addToMap(mbgl::Map&);
+ void setRendererFrontend(AndroidRendererFrontend&);
+
virtual jni::jobject* createJavaPeer(jni::JNIEnv&) = 0;
jni::String getId(jni::JNIEnv&);
@@ -57,8 +60,9 @@ protected:
// 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
- mbgl::Map* map;
+ // RendererFrontend pointer is valid only when
+ // added to the map
+ AndroidRendererFrontend* rendererFrontend;
};
} // namespace android
diff --git a/platform/android/src/style/sources/sources.cpp b/platform/android/src/style/sources/sources.cpp
index b4e70202b4..9ab3ca8e84 100644
--- a/platform/android/src/style/sources/sources.cpp
+++ b/platform/android/src/style/sources/sources.cpp
@@ -2,35 +2,46 @@
#include <mbgl/style/source.hpp>
#include <mbgl/style/sources/geojson_source.hpp>
+#include <mbgl/style/sources/image_source.hpp>
#include <mbgl/style/sources/raster_source.hpp>
#include <mbgl/style/sources/vector_source.hpp>
#include "source.hpp"
#include "geojson_source.hpp"
+#include "image_source.hpp"
#include "raster_source.hpp"
#include "unknown_source.hpp"
#include "vector_source.hpp"
+namespace {
+
+ using namespace mbgl::android;
+
+ Source* initializeSourcePeer(mbgl::style::Source& coreSource) {
+ Source* source;
+ if (coreSource.is<mbgl::style::VectorSource>()) {
+ source = new VectorSource(*coreSource.as<mbgl::style::VectorSource>());
+ } else if (coreSource.is<mbgl::style::RasterSource>()) {
+ source = new RasterSource(*coreSource.as<mbgl::style::RasterSource>());
+ } else if (coreSource.is<mbgl::style::GeoJSONSource>()) {
+ source = new GeoJSONSource(*coreSource.as<mbgl::style::GeoJSONSource>());
+ } else if (coreSource.is<mbgl::style::ImageSource>()) {
+ source = new ImageSource(*coreSource.as<mbgl::style::ImageSource>());
+ } else {
+ source = new UnknownSource(coreSource);
+ }
+
+ return source;
+ }
+} // namespace
+
namespace mbgl {
namespace android {
-Source* initializeSourcePeer(mbgl::Map& map, mbgl::style::Source& coreSource) {
- Source* source;
- if (coreSource.is<mbgl::style::VectorSource>()) {
- source = new VectorSource(map, *coreSource.as<mbgl::style::VectorSource>());
- } else if (coreSource.is<mbgl::style::RasterSource>()) {
- source = new RasterSource(map, *coreSource.as<mbgl::style::RasterSource>());
- } else if (coreSource.is<mbgl::style::GeoJSONSource>()) {
- source = new GeoJSONSource(map, *coreSource.as<mbgl::style::GeoJSONSource>());
- } else {
- source = new UnknownSource(map, coreSource);
- }
-
- return source;
-}
-jni::jobject* createJavaSourcePeer(jni::JNIEnv& env, mbgl::Map& map, mbgl::style::Source& coreSource) {
- std::unique_ptr<Source> peerSource = std::unique_ptr<Source>(initializeSourcePeer(map, coreSource));
+jni::jobject* createJavaSourcePeer(jni::JNIEnv& env, AndroidRendererFrontend& frontend, mbgl::style::Source& coreSource) {
+ std::unique_ptr<Source> peerSource = std::unique_ptr<Source>(initializeSourcePeer(coreSource));
+ peerSource->setRendererFrontend(frontend);
jni::jobject* result = peerSource->createJavaPeer(env);
peerSource.release();
return result;
@@ -39,6 +50,7 @@ jni::jobject* createJavaSourcePeer(jni::JNIEnv& env, mbgl::Map& map, mbgl::style
void registerNativeSources(jni::JNIEnv& env) {
Source::registerNative(env);
GeoJSONSource::registerNative(env);
+ ImageSource::registerNative(env);
RasterSource::registerNative(env);
UnknownSource::registerNative(env);
VectorSource::registerNative(env);
diff --git a/platform/android/src/style/sources/sources.hpp b/platform/android/src/style/sources/sources.hpp
index 09a8b35067..c7b36818b2 100644
--- a/platform/android/src/style/sources/sources.hpp
+++ b/platform/android/src/style/sources/sources.hpp
@@ -1,20 +1,18 @@
#pragma once
-#include <mbgl/map/map.hpp>
#include <mbgl/style/source.hpp>
#include "source.hpp"
+#include "../../android_renderer_frontend.hpp"
#include <jni/jni.hpp>
namespace mbgl {
namespace android {
- mbgl::android::Source* initializeSourcePeer(mbgl::Map&, mbgl::style::Source&);
-
- jni::jobject* createJavaSourcePeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Source&);
+ jni::jobject* createJavaSourcePeer(jni::JNIEnv&, AndroidRendererFrontend&, mbgl::style::Source&);
void registerNativeSources(jni::JNIEnv&);
-}
-}
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/sources/unknown_source.cpp b/platform/android/src/style/sources/unknown_source.cpp
index 86736597c3..79f27bdfbf 100644
--- a/platform/android/src/style/sources/unknown_source.cpp
+++ b/platform/android/src/style/sources/unknown_source.cpp
@@ -12,8 +12,8 @@ namespace {
namespace mbgl {
namespace android {
- UnknownSource::UnknownSource(mbgl::Map& map, mbgl::style::Source& coreSource)
- : Source(map, coreSource) {
+ UnknownSource::UnknownSource(mbgl::style::Source& coreSource)
+ : Source(coreSource) {
}
jni::Class<UnknownSource> UnknownSource::javaClass;
diff --git a/platform/android/src/style/sources/unknown_source.hpp b/platform/android/src/style/sources/unknown_source.hpp
index 3c37239792..4a003c9a7f 100644
--- a/platform/android/src/style/sources/unknown_source.hpp
+++ b/platform/android/src/style/sources/unknown_source.hpp
@@ -16,7 +16,7 @@ public:
static void registerNative(jni::JNIEnv&);
- UnknownSource(mbgl::Map&, mbgl::style::Source&);
+ UnknownSource(mbgl::style::Source&);
~UnknownSource() = default;
diff --git a/platform/android/src/style/sources/vector_source.cpp b/platform/android/src/style/sources/vector_source.cpp
index e2d9f60dec..7fe45441bd 100644
--- a/platform/android/src/style/sources/vector_source.cpp
+++ b/platform/android/src/style/sources/vector_source.cpp
@@ -1,5 +1,7 @@
#include "vector_source.hpp"
+#include <mbgl/renderer/query.hpp>
+
// Java -> C++ conversion
#include "../android_conversion.hpp"
#include "../conversion/filter.hpp"
@@ -28,8 +30,8 @@ namespace android {
) {
}
- VectorSource::VectorSource(mbgl::Map& map, mbgl::style::VectorSource& coreSource)
- : Source(map, coreSource) {
+ VectorSource::VectorSource(mbgl::style::VectorSource& coreSource)
+ : Source(coreSource) {
}
VectorSource::~VectorSource() = default;
@@ -46,8 +48,8 @@ namespace android {
using namespace mbgl::android::geojson;
std::vector<mbgl::Feature> features;
- if (map) {
- features = map->querySourceFeatures(source.getID(), { toVector(env, jSourceLayerIds), toFilter(env, jfilter) });
+ if (rendererFrontend) {
+ features = rendererFrontend->querySourceFeatures(source.getID(), { toVector(env, jSourceLayerIds), toFilter(env, jfilter) });
}
return *convert<jni::Array<jni::Object<Feature>>, std::vector<mbgl::Feature>>(env, features);
}
diff --git a/platform/android/src/style/sources/vector_source.hpp b/platform/android/src/style/sources/vector_source.hpp
index 643b468338..509fe068d1 100644
--- a/platform/android/src/style/sources/vector_source.hpp
+++ b/platform/android/src/style/sources/vector_source.hpp
@@ -19,7 +19,7 @@ public:
VectorSource(jni::JNIEnv&, jni::String, jni::Object<>);
- VectorSource(mbgl::Map&, mbgl::style::VectorSource&);
+ VectorSource(mbgl::style::VectorSource&);
~VectorSource();