[android] Custom layer bindings
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
package com.mapbox.mapboxsdk.layers;
|
||||
|
||||
public class CustomLayer {
|
||||
public CustomLayer(String id,
|
||||
long context,
|
||||
long initializeFunction,
|
||||
long renderFunction,
|
||||
long deinitializeFunction) {
|
||||
this.mID = id;
|
||||
this.mContext = context;
|
||||
this.mInitializeFunction = initializeFunction;
|
||||
this.mRenderFunction = renderFunction;
|
||||
this.mDeinitializeFunction = deinitializeFunction;
|
||||
}
|
||||
|
||||
public String mID;
|
||||
public long mContext;
|
||||
public long mInitializeFunction;
|
||||
public long mRenderFunction;
|
||||
public long mDeinitializeFunction;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* This package contains classes to add and manage layers in your map.
|
||||
*/
|
||||
package com.mapbox.mapboxsdk.layers;
|
||||
@@ -74,6 +74,7 @@ import com.mapbox.mapboxsdk.geometry.BoundingBox;
|
||||
import com.mapbox.mapboxsdk.geometry.CoordinateBounds;
|
||||
import com.mapbox.mapboxsdk.geometry.LatLng;
|
||||
import com.mapbox.mapboxsdk.geometry.LatLngZoom;
|
||||
import com.mapbox.mapboxsdk.layers.CustomLayer;
|
||||
import com.mapbox.mapboxsdk.utils.ApiAccess;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
@@ -3782,6 +3783,11 @@ public final class MapView extends FrameLayout {
|
||||
mAttributionsView.setVisibility(visibility);
|
||||
}
|
||||
|
||||
@UiThread
|
||||
public void addCustomLayer(CustomLayer customLayer, String before) {
|
||||
mNativeMapView.addCustomLayer(customLayer, before);
|
||||
}
|
||||
|
||||
private void setWidgetGravity(@NonNull final View view, int gravity) {
|
||||
LayoutParams layoutParams = (LayoutParams) view.getLayoutParams();
|
||||
layoutParams.gravity = gravity;
|
||||
|
||||
@@ -11,6 +11,7 @@ import com.mapbox.mapboxsdk.geometry.BoundingBox;
|
||||
import com.mapbox.mapboxsdk.geometry.LatLng;
|
||||
import com.mapbox.mapboxsdk.geometry.LatLngZoom;
|
||||
import com.mapbox.mapboxsdk.geometry.ProjectedMeters;
|
||||
import com.mapbox.mapboxsdk.layers.CustomLayer;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.List;
|
||||
@@ -449,6 +450,10 @@ final class NativeMapView {
|
||||
return nativeGetTopOffsetPixelsForAnnotationSymbol(mNativeMapViewPtr, symbolName);
|
||||
}
|
||||
|
||||
public void addCustomLayer(CustomLayer customLayer, String before) {
|
||||
nativeAddCustomLayer(mNativeMapViewPtr, customLayer, before);
|
||||
}
|
||||
|
||||
//
|
||||
// Callbacks
|
||||
//
|
||||
@@ -629,4 +634,6 @@ final class NativeMapView {
|
||||
private native LatLng nativeLatLngForPixel(long nativeMapViewPtr, PointF pixel);
|
||||
|
||||
private native double nativeGetTopOffsetPixelsForAnnotationSymbol(long nativeMapViewPtr, String symbolName);
|
||||
|
||||
private native void nativeAddCustomLayer(long nativeMapViewPtr, CustomLayer customLayer, String before);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.mapbox.mapboxsdk.testapp;
|
||||
|
||||
public class ExampleCustomLayer {
|
||||
static {
|
||||
System.loadLibrary("example-custom-layer");
|
||||
}
|
||||
|
||||
public native static long createContext();
|
||||
public static long InitializeFunction;
|
||||
public static long RenderFunction;
|
||||
public static long DeinitializeFunction;
|
||||
}
|
||||
@@ -34,6 +34,7 @@ import com.mapbox.mapboxsdk.constants.MyBearingTracking;
|
||||
import com.mapbox.mapboxsdk.constants.MyLocationTracking;
|
||||
import com.mapbox.mapboxsdk.constants.Style;
|
||||
import com.mapbox.mapboxsdk.geometry.LatLng;
|
||||
import com.mapbox.mapboxsdk.layers.CustomLayer;
|
||||
import com.mapbox.mapboxsdk.testapp.utils.GeoParseUtil;
|
||||
import com.mapbox.mapboxsdk.utils.ApiAccess;
|
||||
import com.mapbox.mapboxsdk.views.MapView;
|
||||
@@ -395,6 +396,10 @@ public class MainActivity extends AppCompatActivity {
|
||||
startActivity(new Intent(getApplicationContext(), PolylineActivity.class));
|
||||
return true;
|
||||
|
||||
case R.id.action_custom_layer:
|
||||
addCustomLayer();
|
||||
return true;
|
||||
|
||||
default:
|
||||
return changeMapStyle(menuItem.getItemId());
|
||||
}
|
||||
@@ -570,6 +575,16 @@ public class MainActivity extends AppCompatActivity {
|
||||
mMapView.removeAllAnnotations();
|
||||
}
|
||||
|
||||
private void addCustomLayer() {
|
||||
mMapView.addCustomLayer(
|
||||
new CustomLayer("custom",
|
||||
ExampleCustomLayer.createContext(),
|
||||
ExampleCustomLayer.InitializeFunction,
|
||||
ExampleCustomLayer.RenderFunction,
|
||||
ExampleCustomLayer.DeinitializeFunction),
|
||||
null);
|
||||
}
|
||||
|
||||
// Called when FPS changes
|
||||
private class MyOnFpsChangedListener implements MapView.OnFpsChangedListener {
|
||||
|
||||
|
||||
@@ -138,6 +138,12 @@
|
||||
android:icon="@drawable/ic_trending_up_24dp"
|
||||
android:title="@string/activity_polyline" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_custom_layer"
|
||||
android:checkable="false"
|
||||
android:icon="@drawable/ic_trending_up_24dp"
|
||||
android:title="@string/activity_custom_layer" />
|
||||
|
||||
</menu>
|
||||
</item>
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
<string name="activity_user_tracking_mode">User tracking mode</string>
|
||||
<string name="activity_polyline">Polyline Activity</string>
|
||||
<string name="activity_animate_coordinate_change">Animate Coordinate Change</string>
|
||||
<string name="activity_custom_layer">Custom Layer</string>
|
||||
|
||||
<string name="navdrawer_menu_title_mainactivity_controls">Main Activity Controls</string>
|
||||
<string name="navdrawer_menu_title_mainactivity_styles">Main Activity Styles</string>
|
||||
|
||||
104
platform/android/example_custom_layer.cpp
Normal file
104
platform/android/example_custom_layer.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
#include <jni.h>
|
||||
#include <GLES2/gl2.h>
|
||||
|
||||
static const GLchar * vertexShaderSource = "attribute vec2 a_pos; void main() { gl_Position = vec4(a_pos, 0, 1); }";
|
||||
static const GLchar * fragmentShaderSource = "void main() { gl_FragColor = vec4(0, 1, 0, 1); }";
|
||||
|
||||
class ExampleCustomLayer {
|
||||
public:
|
||||
~ExampleCustomLayer() {
|
||||
if (program) {
|
||||
glDeleteBuffers(1, &buffer);
|
||||
glDetachShader(program, vertexShader);
|
||||
glDetachShader(program, fragmentShader);
|
||||
glDeleteShader(vertexShader);
|
||||
glDeleteShader(fragmentShader);
|
||||
glDeleteProgram(program);
|
||||
}
|
||||
}
|
||||
|
||||
void initialize() {
|
||||
program = glCreateProgram();
|
||||
vertexShader = glCreateShader(GL_VERTEX_SHADER);
|
||||
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
|
||||
glShaderSource(vertexShader, 1, &vertexShaderSource, nullptr);
|
||||
glCompileShader(vertexShader);
|
||||
glAttachShader(program, vertexShader);
|
||||
glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr);
|
||||
glCompileShader(fragmentShader);
|
||||
glAttachShader(program, fragmentShader);
|
||||
glLinkProgram(program);
|
||||
a_pos = glGetAttribLocation(program, "a_pos");
|
||||
|
||||
GLfloat background[] = { -1,-1, 1,-1, -1,1, 1,1 };
|
||||
glGenBuffers(1, &buffer);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, buffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(GLfloat), background, GL_STATIC_DRAW);
|
||||
}
|
||||
|
||||
void render() {
|
||||
glUseProgram(program);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, buffer);
|
||||
glEnableVertexAttribArray(a_pos);
|
||||
glVertexAttribPointer(a_pos, 2, GL_FLOAT, GL_FALSE, 0, NULL);
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
|
||||
GLuint program = 0;
|
||||
GLuint vertexShader = 0;
|
||||
GLuint fragmentShader = 0;
|
||||
GLuint buffer = 0;
|
||||
GLuint a_pos = 0;
|
||||
};
|
||||
|
||||
jlong JNICALL nativeCreateContext(JNIEnv*, jobject) {
|
||||
return reinterpret_cast<jlong>(new ExampleCustomLayer());
|
||||
}
|
||||
|
||||
void nativeInitialize(void *context) {
|
||||
reinterpret_cast<ExampleCustomLayer*>(context)->initialize();
|
||||
}
|
||||
|
||||
void nativeRender(void *context) {
|
||||
reinterpret_cast<ExampleCustomLayer*>(context)->render();
|
||||
}
|
||||
|
||||
void nativeDenitialize(void *context) {
|
||||
delete reinterpret_cast<ExampleCustomLayer*>(context);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) {
|
||||
JNIEnv *env = nullptr;
|
||||
vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6);
|
||||
|
||||
jclass customLayerClass = env->FindClass("com/mapbox/mapboxsdk/testapp/ExampleCustomLayer");
|
||||
|
||||
JNINativeMethod methods[] = {
|
||||
{"createContext", "()J", reinterpret_cast<void *>(&nativeCreateContext)}
|
||||
};
|
||||
|
||||
if (env->RegisterNatives(customLayerClass, methods, 1) < 0) {
|
||||
env->ExceptionDescribe();
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
env->SetStaticLongField(customLayerClass,
|
||||
env->GetStaticFieldID(customLayerClass, "InitializeFunction", "J"),
|
||||
reinterpret_cast<jlong>(nativeInitialize));
|
||||
|
||||
env->SetStaticLongField(customLayerClass,
|
||||
env->GetStaticFieldID(customLayerClass, "RenderFunction", "J"),
|
||||
reinterpret_cast<jlong>(nativeRender));
|
||||
|
||||
env->SetStaticLongField(customLayerClass,
|
||||
env->GetStaticFieldID(customLayerClass, "DeinitializeFunction", "J"),
|
||||
reinterpret_cast<jlong>(nativeDenitialize));
|
||||
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *, void *) {
|
||||
}
|
||||
@@ -111,6 +111,13 @@ jclass httpRequestClass = nullptr;
|
||||
jmethodID httpRequestStartId = nullptr;
|
||||
jmethodID httpRequestCancelId = nullptr;
|
||||
|
||||
jclass customLayerClass = nullptr;
|
||||
jfieldID customLayerIdId = nullptr;
|
||||
jfieldID customLayerContextId = nullptr;
|
||||
jfieldID customLayerInitializeFunctionId = nullptr;
|
||||
jfieldID customLayerRenderFunctionId = nullptr;
|
||||
jfieldID customLayerDeinitializeFunctionId = nullptr;
|
||||
|
||||
bool throw_jni_error(JNIEnv *env, const char *msg) {
|
||||
if (env->ThrowNew(runtimeExceptionClass, msg) < 0) {
|
||||
env->ExceptionDescribe();
|
||||
@@ -1471,6 +1478,19 @@ jdouble JNICALL nativeGetTopOffsetPixelsForAnnotationSymbol(JNIEnv *env, jobject
|
||||
return nativeMapView->getMap().getTopOffsetPixelsForAnnotationIcon(std_string_from_jstring(env, symbolName));
|
||||
}
|
||||
|
||||
void JNICALL nativeAddCustomLayer(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jobject customLayer, jstring before) {
|
||||
mbgl::Log::Debug(mbgl::Event::JNI, "nativeAddCustomLayer");
|
||||
assert(nativeMapViewPtr != 0);
|
||||
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
|
||||
nativeMapView->getMap().addCustomLayer(
|
||||
std_string_from_jstring(env, reinterpret_cast<jstring>(env->GetObjectField(customLayer, customLayerIdId))),
|
||||
reinterpret_cast<mbgl::CustomLayerInitializeFunction>(env->GetLongField(customLayer, customLayerInitializeFunctionId)),
|
||||
reinterpret_cast<mbgl::CustomLayerRenderFunction>(env->GetLongField(customLayer, customLayerRenderFunctionId)),
|
||||
reinterpret_cast<mbgl::CustomLayerDeinitializeFunction>(env->GetLongField(customLayer, customLayerDeinitializeFunctionId)),
|
||||
reinterpret_cast<void*>(env->GetLongField(customLayer, customLayerContextId)),
|
||||
before ? std_string_from_jstring(env, before).c_str() : nullptr);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1848,6 +1868,36 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||
env->ExceptionDescribe();
|
||||
}
|
||||
|
||||
customLayerClass = env->FindClass("com/mapbox/mapboxsdk/layers/CustomLayer");
|
||||
if (customLayerClass == nullptr) {
|
||||
env->ExceptionDescribe();
|
||||
}
|
||||
|
||||
customLayerIdId = env->GetFieldID(customLayerClass, "mID", "Ljava/lang/String;");
|
||||
if (customLayerIdId == nullptr) {
|
||||
env->ExceptionDescribe();
|
||||
}
|
||||
|
||||
customLayerContextId = env->GetFieldID(customLayerClass, "mContext", "J");
|
||||
if (customLayerContextId == nullptr) {
|
||||
env->ExceptionDescribe();
|
||||
}
|
||||
|
||||
customLayerInitializeFunctionId = env->GetFieldID(customLayerClass, "mInitializeFunction", "J");
|
||||
if (customLayerInitializeFunctionId == nullptr) {
|
||||
env->ExceptionDescribe();
|
||||
}
|
||||
|
||||
customLayerRenderFunctionId = env->GetFieldID(customLayerClass, "mRenderFunction", "J");
|
||||
if (customLayerRenderFunctionId == nullptr) {
|
||||
env->ExceptionDescribe();
|
||||
}
|
||||
|
||||
customLayerDeinitializeFunctionId = env->GetFieldID(customLayerClass, "mDeinitializeFunction", "J");
|
||||
if (customLayerDeinitializeFunctionId == nullptr) {
|
||||
env->ExceptionDescribe();
|
||||
}
|
||||
|
||||
const std::vector<JNINativeMethod> methods = {
|
||||
{"nativeCreate", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;FIJ)J",
|
||||
reinterpret_cast<void *>(&nativeCreate)},
|
||||
@@ -1965,6 +2015,8 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||
reinterpret_cast<void *>(&nativeLatLngForPixel)},
|
||||
{"nativeGetTopOffsetPixelsForAnnotationSymbol", "(JLjava/lang/String;)D",
|
||||
reinterpret_cast<void *>(&nativeGetTopOffsetPixelsForAnnotationSymbol)},
|
||||
{"nativeAddCustomLayer", "(JLcom/mapbox/mapboxsdk/layers/CustomLayer;Ljava/lang/String;)V",
|
||||
reinterpret_cast<void *>(&nativeAddCustomLayer)},
|
||||
};
|
||||
|
||||
if (env->RegisterNatives(nativeMapViewClass, methods.data(), methods.size()) < 0) {
|
||||
|
||||
@@ -59,11 +59,46 @@
|
||||
],
|
||||
},
|
||||
|
||||
{ 'target_name': 'example-custom-layer-lib',
|
||||
'product_name': 'example-custom-layer',
|
||||
'type': 'shared_library',
|
||||
'hard_dependency': 1,
|
||||
|
||||
'sources': [
|
||||
'./example_custom_layer.cpp',
|
||||
],
|
||||
|
||||
'variables': {
|
||||
'ldflags': [
|
||||
'-llog',
|
||||
'-landroid',
|
||||
'-lEGL',
|
||||
'-lGLESv2',
|
||||
'-lstdc++',
|
||||
'-latomic',
|
||||
],
|
||||
},
|
||||
|
||||
'conditions': [
|
||||
['OS == "mac"', {
|
||||
'xcode_settings': {
|
||||
'OTHER_LDFLAGS': [ '<@(ldflags)' ],
|
||||
}
|
||||
}, {
|
||||
'libraries': [ '<@(ldflags)' ],
|
||||
}]
|
||||
],
|
||||
},
|
||||
|
||||
{ 'target_name': 'androidapp',
|
||||
'type': 'none',
|
||||
'hard_dependency': 1,
|
||||
|
||||
'dependencies': [
|
||||
'android-lib',
|
||||
'example-custom-layer-lib',
|
||||
],
|
||||
|
||||
'variables': {
|
||||
'pwd': '<!(pwd)',
|
||||
},
|
||||
@@ -85,11 +120,17 @@
|
||||
|
||||
'actions': [
|
||||
{
|
||||
'action_name': 'Strip dynamic library',
|
||||
'action_name': 'Strip mapbox library',
|
||||
'inputs': [ '<(PRODUCT_DIR)/lib.target/libmapbox-gl.so' ],
|
||||
'outputs': [ '<(pwd)/../android/MapboxGLAndroidSDK/src/main/jniLibs/$(JNIDIR)/libmapbox-gl.so' ],
|
||||
'action': [ '$(STRIP)', '<@(_inputs)', '-o', '<@(_outputs)' ]
|
||||
},
|
||||
{
|
||||
'action_name': 'Strip example custom layer library',
|
||||
'inputs': [ '<(PRODUCT_DIR)/lib.target/libexample-custom-layer.so' ],
|
||||
'outputs': [ '<(pwd)/../android/MapboxGLAndroidSDKTestApp/src/main/jniLibs/$(JNIDIR)/libexample-custom-layer.so' ],
|
||||
'action': [ '$(STRIP)', '<@(_inputs)', '-o', '<@(_outputs)' ]
|
||||
}
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -285,6 +285,8 @@ double MapContext::getTopOffsetPixelsForAnnotationIcon(const std::string& name)
|
||||
|
||||
void MapContext::addLayer(std::unique_ptr<StyleLayer> layer, mapbox::util::optional<std::string> after) {
|
||||
style->addLayer(std::move(layer), after);
|
||||
updateFlags |= Update::Classes;
|
||||
asyncUpdate.send();
|
||||
}
|
||||
|
||||
void MapContext::setSourceTileCacheSize(size_t size) {
|
||||
|
||||
Reference in New Issue
Block a user