[android] Custom layer bindings

This commit is contained in:
John Firebaugh
2015-12-11 16:04:40 -08:00
parent e304033552
commit 8a17d30c50
12 changed files with 272 additions and 1 deletions

View File

@@ -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;
}

View File

@@ -0,0 +1,4 @@
/**
* This package contains classes to add and manage layers in your map.
*/
package com.mapbox.mapboxsdk.layers;

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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 {

View File

@@ -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>

View File

@@ -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>

View 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 *) {
}

View File

@@ -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) {

View File

@@ -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)' ]
}
],
},
],

View File

@@ -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) {