Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions platform/android/MapLibreAndroid/src/cpp/jni_native.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "native_map_options.hpp"
#include "rendering_stats.hpp"
#include "util/tile_server_options.hpp"
#include "plugin/plugin_file_source.hpp"
#ifndef MBGL_MODULE_OFFLINE_DISABLE
#include "offline/offline_manager.hpp"
#include "offline/offline_region.hpp"
Expand Down Expand Up @@ -107,6 +108,11 @@ void registerNatives(JavaVM* vm) {
Polygon::registerNative(env);
Polyline::registerNative(env);

// Plugins
PluginProtocolHandlerResource::registerNative(env);
PluginProtocolHandlerResponse::registerNative(env);
PluginFileSource::registerNative(env);

// Map
MapRenderer::registerNative(env);
MapRendererRunnable::registerNative(env);
Expand Down
103 changes: 102 additions & 1 deletion platform/android/MapLibreAndroid/src/cpp/native_map_view.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
#include <mbgl/style/image.hpp>
#include <mbgl/style/filter.hpp>
#include <mbgl/renderer/query.hpp>
#include <mbgl/plugin/plugin_file_source.hpp>
#include <mbgl/storage/file_source_manager.hpp>

// Java -> C++ conversion
#include "style/android_conversion.hpp"
Expand Down Expand Up @@ -1320,6 +1322,103 @@ void NativeMapView::enableRenderingStatsView(JNIEnv&, jni::jboolean value) {
map->enableRenderingStatsView(value);
}

// Plugins
void NativeMapView::addPluginFileSource(JNIEnv &jniEnv,
const jni::Object<PluginFileSource>& pluginFileSource) {

// TODO: Unclear if any of these options are needed for plugins
mbgl::ResourceOptions resourceOptions;

// TODO: Unclear if any of the properties on clientOptions need to be set
mbgl::ClientOptions clientOptions;

android::UniqueEnv _env = android::AttachEnv();

// Set when the source is added to a map.
jni::Global<jni::Object<PluginFileSource>> pluginPeer = jni::NewGlobal(*_env, pluginFileSource);
std::shared_ptr<PluginFileSourceContainer> fileSourceContainer = std::make_shared<PluginFileSourceContainer>();
fileSourceContainer->_fileSource = std::move(pluginPeer);
_pluginFileSources.push_back(fileSourceContainer);

std::shared_ptr<mbgl::PluginFileSource> pluginSource = std::make_shared<mbgl::PluginFileSource>(resourceOptions, clientOptions);
pluginSource->setOnRequestResourceFunction([fileSourceContainer](const mbgl::Resource &resource) -> mbgl::Response {
mbgl::Response tempResponse;

android::UniqueEnv env = android::AttachEnv();
static auto& javaClass = jni::Class<PluginFileSource>::Singleton(*env);
static auto requestResource = javaClass.GetMethod<jni::Object<PluginProtocolHandlerResponse>(jni::Object<PluginProtocolHandlerResource>)>(*env, "requestResource");
auto javaResource = PluginFileSource::createJavaResource(*env, resource);
auto tempResult = fileSourceContainer->_fileSource.Call(*env, requestResource, javaResource);
PluginProtocolHandlerResponse::Update(*env,
tempResult,
tempResponse);

return tempResponse;
});
pluginSource->setOnCanRequestFunction([fileSourceContainer](const mbgl::Resource &resource) -> bool {
android::UniqueEnv env = android::AttachEnv();
static auto& javaClass = jni::Class<PluginFileSource>::Singleton(*env);
static auto canRequestResource = javaClass.GetMethod<jboolean(jni::Object<PluginProtocolHandlerResource>)>(*env, "canRequestResource");
auto javaResource = PluginFileSource::createJavaResource(*env, resource);
auto tempResult = fileSourceContainer->_fileSource.Call(*env, canRequestResource, javaResource);
return tempResult;


/*
if (!renderingStats) {
renderingStats = jni::NewGlobal(*_env, RenderingStats::Create(*_env));
}

RenderingStats::Update(*_env, renderingStats, status.renderingStats);

weakReference.Call(*_env,
onDidFinishRenderingFrame,
(jboolean)(status.mode != MapObserver::RenderMode::Partial),
renderingStats);
*/
/*
static auto resourceURLField = javaClass.GetField<jni::Object<PluginProtocolHandlerResource>>(env, "resource");
auto str = jni::Make<jni::String>(env, resource.url); // wrap the jstring
javaObject.Set(env, resourceURLField, str);

fileSourceContainer->_fileSource.Set(env, )
*/




});
auto fileSourceManager = mbgl::FileSourceManager::get();
fileSourceManager->registerCustomFileSource(pluginSource);


/*
android::UniqueEnv _env = android::AttachEnv();
static auto& javaClass = jni::Class<NativeMapView>::Singleton(*_env);
static auto onDidFinishRenderingFrame = javaClass.GetMethod<void(jboolean, jni::Object<RenderingStats>)>(
*_env, "onDidFinishRenderingFrame");
auto weakReference = javaPeer.get(*_env);
if (weakReference) {
if (!renderingStats) {
renderingStats = jni::NewGlobal(*_env, RenderingStats::Create(*_env));
}

RenderingStats::Update(*_env, renderingStats, status.renderingStats);

weakReference.Call(*_env,
onDidFinishRenderingFrame,
(jboolean)(status.mode != MapObserver::RenderMode::Partial),
renderingStats);
}

*/



}



// Static methods //

void NativeMapView::registerNative(jni::JNIEnv& env) {
Expand Down Expand Up @@ -1442,7 +1541,9 @@ void NativeMapView::registerNative(jni::JNIEnv& env) {
METHOD(&NativeMapView::getTileLodZoomShift, "nativeGetTileLodZoomShift"),
METHOD(&NativeMapView::triggerRepaint, "nativeTriggerRepaint"),
METHOD(&NativeMapView::isRenderingStatsViewEnabled, "nativeIsRenderingStatsViewEnabled"),
METHOD(&NativeMapView::enableRenderingStatsView, "nativeEnableRenderingStatsView"));
METHOD(&NativeMapView::enableRenderingStatsView, "nativeEnableRenderingStatsView"),
METHOD(&NativeMapView::addPluginFileSource, "nativeAddPluginFileSource"));

}

void NativeMapView::onRegisterShaders(gfx::ShaderRegistry&) {};
Expand Down
11 changes: 9 additions & 2 deletions platform/android/MapLibreAndroid/src/cpp/native_map_view.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
#include "style/light.hpp"
#include "native_map_options.hpp"
#include "bitmap.hpp"

#include "plugin/plugin_file_source.hpp"
#include <exception>
#include <string>
#include <jni.h>
Expand Down Expand Up @@ -325,7 +325,11 @@ class NativeMapView : public MapObserver {
jni::jboolean isRenderingStatsViewEnabled(JNIEnv&);
void enableRenderingStatsView(JNIEnv&, jni::jboolean);

// Shader compilation
// Plugins
void addPluginFileSource(JNIEnv &,
const jni::Object<mbgl::android::PluginFileSource>& );

// Shader compilation
void onRegisterShaders(mbgl::gfx::ShaderRegistry&) override;
void onPreCompileShader(mbgl::shaders::BuiltIn, mbgl::gfx::Backend::Type, const std::string&) override;
void onPostCompileShader(mbgl::shaders::BuiltIn, mbgl::gfx::Backend::Type, const std::string&) override;
Expand Down Expand Up @@ -364,6 +368,9 @@ class NativeMapView : public MapObserver {

// Ensure these are initialised last
std::unique_ptr<mbgl::Map> map;

// List of plugin file source
std::vector<std::shared_ptr<mbgl::android::PluginFileSourceContainer>> _pluginFileSources;
};

} // namespace android
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@

#include "plugin_file_source.hpp"

using namespace mbgl::android;

// Putting these here (should probably move out to a more dedicated JNI place within
// the native repo at some point, but this means we don't have to update
// the jni.hpp dependency
namespace jni {

struct ByteBufferTag
{
static constexpr auto Name() { return "java/nio/ByteBuffer"; }
};

template <>
struct TagTraits< ByteBufferTag >
{
using SuperType = Object<ObjectTag>;
using UntaggedType = jobject;
};

}

void PluginFileSource::registerNative(jni::JNIEnv& env) {
jni::Class<PluginFileSource>::Singleton(env);
}

jni::Global<jni::Object<PluginProtocolHandlerResource>> PluginFileSource::createJavaResource(jni::JNIEnv& env,
const mbgl::Resource &resource) {
jni::Global<jni::Object<PluginProtocolHandlerResource>> tempResult = jni::NewGlobal(env, PluginProtocolHandlerResource::Create(env));
PluginProtocolHandlerResource::Update(env, tempResult, resource);
return tempResult;
}

void PluginProtocolHandlerResource::registerNative(jni::JNIEnv& env) {
jni::Class<PluginProtocolHandlerResource>::Singleton(env);
}

jni::Local<jni::Object<PluginProtocolHandlerResource>> PluginProtocolHandlerResource::Create(jni::JNIEnv& env) {
auto& javaClass = jni::Class<PluginProtocolHandlerResource>::Singleton(env);
auto constructor = javaClass.GetConstructor(env);
return javaClass.New(env, constructor);
}

void PluginProtocolHandlerResource::Update(jni::JNIEnv& env,
jni::Object<PluginProtocolHandlerResource>& javaObject,
const mbgl::Resource &resource) {

static auto &javaClass = jni::Class<PluginProtocolHandlerResource>::Singleton(env);

static auto resourceKindField = javaClass.GetField<jni::jint>(env, "kind");
javaObject.Set(env, resourceKindField, static_cast<jni::jint>(resource.kind));

static auto resourceURLField = javaClass.GetField<jni::String>(env, "resourceURL");
auto str = jni::Make<jni::String>(env, resource.url); // wrap the jstring
javaObject.Set(env, resourceURLField, str);

}


void PluginProtocolHandlerResponse::registerNative(jni::JNIEnv& env) {
jni::Class<PluginProtocolHandlerResponse>::Singleton(env);
}

jni::Local<jni::Object<PluginProtocolHandlerResponse>> PluginProtocolHandlerResponse::Create(jni::JNIEnv&env) {
auto& javaClass = jni::Class<PluginProtocolHandlerResponse>::Singleton(env);
auto constructor = javaClass.GetConstructor(env);
return javaClass.New(env, constructor);
}

void PluginProtocolHandlerResponse::Update(jni::JNIEnv & env,
[[maybe_unused]] jni::Object<PluginProtocolHandlerResponse>& javaObject,
[[maybe_unused]] mbgl::Response &response) {
static auto &javaClass = jni::Class<PluginProtocolHandlerResponse>::Singleton(env);
static auto dataField = javaClass.GetField<jni::Object<jni::ByteBufferTag>>(env, "data");
auto objectValue = javaObject.Get(env, dataField);
auto objectRef = jobject(objectValue.get());
void* bufPtr = env.GetDirectBufferAddress(objectRef);
jsize length = env.GetDirectBufferCapacity(objectRef);
response.data = std::make_shared<std::string>((const char*)bufPtr, length);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#pragma once

#include <jni/jni.hpp>
#include <mbgl/plugin/plugin_file_source.hpp>

namespace mbgl {
namespace android {

class PluginProtocolHandlerResource {
public:
static constexpr auto Name() { return "org/maplibre/android/plugin/PluginProtocolHandlerResource"; };
static void registerNative(jni::JNIEnv&);

static jni::Local<jni::Object<PluginProtocolHandlerResource>> Create(jni::JNIEnv&);
static void Update(jni::JNIEnv&, jni::Object<PluginProtocolHandlerResource>&, const mbgl::Resource &);
};

class PluginProtocolHandlerResponse {
public:
static constexpr auto Name() { return "org/maplibre/android/plugin/PluginProtocolHandlerResponse"; };
static void registerNative(jni::JNIEnv&);

static jni::Local<jni::Object<PluginProtocolHandlerResponse>> Create(jni::JNIEnv&);
static void Update(jni::JNIEnv&,
jni::Object<PluginProtocolHandlerResponse>&,
mbgl::Response &);

};

class PluginFileSource {
public:
static constexpr auto Name() { return "org/maplibre/android/plugin/PluginFileSource"; };

//static mbgl::PluginFileSource getFileSource(jni::JNIEnv&, const jni::Object<PluginFileSource>&);

static jni::Global<jni::Object<PluginProtocolHandlerResource>> createJavaResource(jni::JNIEnv& env,
const mbgl::Resource &resource);

static void registerNative(jni::JNIEnv&);
};

class PluginFileSourceContainer {
public:
jni::Global<jni::Object<PluginFileSource>> _fileSource;
};

}
}


Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.maplibre.android.gestures.RotateGestureDetector;
import org.maplibre.android.gestures.ShoveGestureDetector;
import org.maplibre.android.gestures.StandardScaleGestureDetector;
import org.maplibre.android.plugin.PluginProtocolHandler;
import org.maplibre.geojson.Feature;
import org.maplibre.geojson.Geometry;
import org.maplibre.android.MapStrictMode;
Expand Down Expand Up @@ -2694,4 +2695,19 @@ private void notifyDeveloperAnimationListeners() {
listener.onDeveloperAnimationStarted();
}
}



/**
* Adds a custom protocol handler to the map view
*/
ArrayList<PluginProtocolHandler> pluginProtocolHandlers = new ArrayList<PluginProtocolHandler>();
public void addPluginProtocolHandler(PluginProtocolHandler protocolHandler) {
pluginProtocolHandlers.add(protocolHandler);
nativeMapView.addPluginProtocolHandler(protocolHandler);

// nativeMapView.addPolygon()
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.maplibre.android.maps.renderer.MapRenderer;
import org.maplibre.android.maps.widgets.CompassView;
import org.maplibre.android.net.ConnectivityReceiver;
import org.maplibre.android.plugin.PluginProtocolHandler;
import org.maplibre.android.storage.FileSource;
import org.maplibre.android.utils.BitmapUtils;
import org.maplibre.android.tile.TileOperation;
Expand Down Expand Up @@ -1817,4 +1818,14 @@ private AttributionDialogManager getDialogManager() {
public static void setMapStrictModeEnabled(boolean strictModeEnabled) {
MapStrictMode.setStrictModeEnabled(strictModeEnabled);
}

/**
* Adds a custom protocol handler to the map view
*/
public void addPluginProtocolHandler(PluginProtocolHandler protocolHandler) {
if (maplibreMap != null) {
maplibreMap.addPluginProtocolHandler(protocolHandler);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import org.maplibre.android.plugin.PluginProtocolHandler;
import org.maplibre.geojson.Feature;
import org.maplibre.geojson.Geometry;
import org.maplibre.android.annotations.Marker;
Expand Down Expand Up @@ -270,6 +271,8 @@ List<Feature> queryRenderedFeatures(@NonNull RectF coordinates,

void enableRenderingStatsView(boolean value);

void addPluginProtocolHandler(PluginProtocolHandler protocolHandler);

void setSwapBehaviorFlush(boolean flush);

//
Expand Down
Loading