[android] #5610 - Initial Runtime Style Bindings

[android] #5610 - Adjusted public api after discussion

[android] #5610 - added jni binding for NativeMapView#getLayer

[android] #5610 - Added initial test Activity

[android] #5610 - Started on NativePeer implementation for Layer

[android] #5610 - replaced low-level jni code with high-level for native getLayer

[android] 5610 - completed basic layer peer class - constructible from java and c++

[android] #5610 - removed reference that was redundant and causing the finalizer exception

[android] #5610 - Added a property peer

[android] #5610 - added value type to do type conversions - wip

[android] #5610 - simplified property conversion approach - wrapped value with jenv

[android] #5610 - added some more value conversions

[android] #5610 - Finished conversion for basic types

[android] #5610 - allow color's to be set as either an android color int or a String to support all formats in the spec

[android] #5610 - encode color ints as rgba to retain alpha channel

[android] #5610 - recalculate classes after paint property

[android] #5610 - more examples

[android] #5610 - fixed the example

[android] #5610 - cleaned up example code before continueing

[android] #5610 - added layout property example

[android] #5610 - set visibility on layer

[android] #5610 - added removeLayer and example

[android] #5610 - added more type conversions

[android] #5610 - Started on peer classes for layer implementations - WIP

[android] #5610 - First complete layer subclass peer implementation

[android] #5610 - added a little bit of structure before adding the other layer types

[android] #5610 - generate the c++ headers from the style spec

[android] #5610 - make sure the visibility is set as a string

[android] #5610 - Generate c++ layer peer class implementations from the style spec

[android] #5610 - generate java layer peer classes

[android] #5610 - cleanup comments

[android] #5610 - register all c++ peer classes with jni

[android] #5610 - addLayer

[android] #5610 - comment out broken case

[android] #5610 - Sources api - very much WIP

[android] 5610 - GeoJson source implementation and geojson conversion

[android] #5610 - cleanup add source/layer example a bit

[android] #5610 - initial filter api

[android] #5610 - Added filter api on the relevant Layer classes

[android] #5610 - raster layer is not filterable

[android] #5610 - actually make it compile

[android] #5610 - completed filter implementation

[android] #5610 - Vector and Raster Source + examples

[android] #5610 - removed superfluous interface, moved filters to the correct package

[android] #5610 - fixed comments

[android] #5610 - moved tests to the right package

[android] #5610 - hide difference between paint and layout properties in public api, make more performant set method for proeprties

[android] #5610 - fix rebase issue
This commit is contained in:
Ivo van Dongen
2016-07-08 18:31:55 +02:00
parent b3c914fb3f
commit 9a3eadfd5b
60 changed files with 5510 additions and 2 deletions

View File

@@ -0,0 +1,114 @@
'use strict';
const fs = require('fs');
const ejs = require('ejs');
const spec = require('mapbox-gl-style-spec').latest;
const _ = require('lodash');
global.iff = function (condition, val) {
return condition() ? val : "";
}
global.camelize = function (str) {
return str.replace(/(?:^|-)(.)/g, function (_, x) {
return x.toUpperCase();
});
}
global.camelizeWithLeadingLowercase = function (str) {
return str.replace(/-(.)/g, function (_, x) {
return x.toUpperCase();
});
}
global.snakeCaseUpper = function (str) {
return str.replace(/-/g, "_").toUpperCase();
}
global.propertyType = function propertyType(property) {
//TODO: Doe we want these exceptions?
// if (/-translate-anchor$/.test(property.name)) {
// return 'TranslateAnchorType';
// }
// if (/-(rotation|pitch)-alignment$/.test(property.name)) {
// return 'AlignmentType';
// }
switch (property.type) {
case 'boolean':
return 'Boolean';
case 'number':
return 'Float';
case 'string':
return 'String';
case 'enum':
return `String`;
case 'color':
return `String`;
case 'array':
return `${propertyType({type:property.value})}[]`;
default:
throw new Error(`unknown type for ${property.name}`);
}
}
global.propertyTypeAnnotation = function propertyTypeAnnotation(property) {
switch (property.type) {
case 'enum':
return `@Property.${snakeCaseUpper(property.name)}`;
default:
return "";
}
};
//Process Layers
const layers = spec.layer.type.values.map((type) => {
const layoutProperties = Object.keys(spec[`layout_${type}`]).reduce((memo, name) => {
if (name !== 'visibility') {
spec[`layout_${type}`][name].name = name;
memo.push(spec[`layout_${type}`][name]);
}
return memo;
}, []);
const paintProperties = Object.keys(spec[`paint_${type}`]).reduce((memo, name) => {
spec[`paint_${type}`][name].name = name;
memo.push(spec[`paint_${type}`][name]);
return memo;
}, []);
return {
type: type,
layoutProperties: layoutProperties,
paintProperties: paintProperties,
};
});
const layerHpp = ejs.compile(fs.readFileSync('platform/android/scripts/layer.hpp.ejs', 'utf8'), {strict: true});
const layerCpp = ejs.compile(fs.readFileSync('platform/android/scripts/layer.cpp.ejs', 'utf8'), {strict: true});
const layerJava = ejs.compile(fs.readFileSync('platform/android/scripts/layer.java.ejs', 'utf8'), {strict: true});
for (const layer of layers) {
fs.writeFileSync(`platform/android/src/style/layers/${layer.type}_layer.hpp`, layerHpp(layer));
fs.writeFileSync(`platform/android/src/style/layers/${layer.type}_layer.cpp`, layerCpp(layer));
fs.writeFileSync(`platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/${camelize(layer.type)}Layer.java`, layerJava(layer));
}
//Process all layer properties
const layoutProperties = _(layers).map('layoutProperties').flatten().value();
const paintProperties = _(layers).map('paintProperties').flatten().value();
const propertiesTemplate = ejs.compile(fs.readFileSync('platform/android/scripts/layer_property_factory.java.ejs', 'utf8'), {strict: true});
fs.writeFileSync(
`platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java`,
propertiesTemplate({layoutProperties: layoutProperties, paintProperties: paintProperties})
);
//Create types for the enum properties
const enumProperties = _(layoutProperties).union(paintProperties).filter({'type': 'enum'}).value();
const enumPropertyTemplate = ejs.compile(fs.readFileSync('platform/android/scripts/layer_property.java.ejs', 'utf8'), {strict: true});
fs.writeFileSync(
`platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java`,
enumPropertyTemplate({properties: enumProperties})
);

View File

@@ -0,0 +1,64 @@
<%
const type = locals.type;
-%>
// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make style-code-android`.
#include "<%- type %>_layer.hpp"
#include <string>
//XXX
#include <mbgl/platform/log.hpp>
namespace mbgl {
namespace android {
<% if (type === 'background') { -%>
<%- camelize(type) %>Layer::<%- camelize(type) %>Layer(jni::JNIEnv& env, jni::String layerId)
: Layer(env, std::make_unique<mbgl::style::<%- camelize(type) %>Layer>(jni::Make<std::string>(env, layerId))) {
<% } else { -%>
<%- camelize(type) %>Layer::<%- camelize(type) %>Layer(jni::JNIEnv& env, jni::String layerId, jni::String sourceId)
: Layer(env, std::make_unique<mbgl::style::<%- camelize(type) %>Layer>(jni::Make<std::string>(env, layerId), jni::Make<std::string>(env, sourceId))) {
<% } -%>
mbgl::Log::Debug(mbgl::Event::JNI, "<%- camelize(type) %>Layer constructed, owning reference");
}
<%- camelize(type) %>Layer::<%- camelize(type) %>Layer(mbgl::Map& map, mbgl::style::<%- camelize(type) %>Layer& coreLayer)
: Layer(map, coreLayer) {
mbgl::Log::Debug(mbgl::Event::JNI, "<%- camelize(type) %>Layer Non-owning reference constructor");
}
<%- camelize(type) %>Layer::~<%- camelize(type) %>Layer() = default;
jni::Class<<%- camelize(type) %>Layer> <%- camelize(type) %>Layer::javaClass;
jni::jobject* <%- camelize(type) %>Layer::createJavaPeer(jni::JNIEnv& env) {
static auto constructor = <%- camelize(type) %>Layer::javaClass.template GetConstructor<jni::jlong>(env);
return <%- camelize(type) %>Layer::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this));
}
void <%- camelize(type) %>Layer::registerNative(jni::JNIEnv& env) {
mbgl::Log::Debug(mbgl::Event::JNI, "Registering native background layer");
//Lookup the class
<%- camelize(type) %>Layer::javaClass = *jni::Class<<%- camelize(type) %>Layer>::Find(env).NewGlobalRef(env).release();
#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
//Register the peer
jni::RegisterNativePeer<<%- camelize(type) %>Layer>(
env, <%- camelize(type) %>Layer::javaClass, "nativePtr",
<% if (type === 'background') { -%>
std::make_unique<<%- camelize(type) %>Layer, JNIEnv&, jni::String>,
<% } else { -%>
std::make_unique<<%- camelize(type) %>Layer, JNIEnv&, jni::String, jni::String>,
<% } -%>
"initialize",
"finalize"
);
}
} // namespace android
} // namespace mbgl

View File

@@ -0,0 +1,38 @@
<%
const type = locals.type;
-%>
// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make style-code-android`.
#pragma once
#include "layer.hpp"
#include <mbgl/style/layers/<%- type %>_layer.hpp>
#include <jni/jni.hpp>
namespace mbgl {
namespace android {
class <%- camelize(type) %>Layer : public Layer {
public:
static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/<%- camelize(type) %>Layer"; };
static jni::Class<<%- camelize(type) %>Layer> javaClass;
static void registerNative(jni::JNIEnv&);
<% if (type === 'background') { -%>
<%- camelize(type) %>Layer(jni::JNIEnv&, jni::String);
<% } else { -%>
<%- camelize(type) %>Layer(jni::JNIEnv&, jni::String, jni::String);
<% } -%>
<%- camelize(type) %>Layer(mbgl::Map&, mbgl::style::<%- camelize(type) %>Layer&);
~<%- camelize(type) %>Layer();
jni::jobject* createJavaPeer(jni::JNIEnv&);
};
} // namespace android
} // namespace mbgl

View File

@@ -0,0 +1,44 @@
<%
const type = locals.type;
-%>
// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make style-code-android`.
package com.mapbox.mapboxsdk.style.layers;
/**
* <%- camelize(type) %> Layer
*/
public class <%- camelize(type) %>Layer extends Layer {
public <%- camelize(type) %>Layer(long nativePtr) {
super(nativePtr);
}
<% if (type === 'background') { -%>
public <%- camelize(type) %>Layer(String layerId) {
initialize(layerId);
}
protected native void initialize(String layerId);
<% } else { -%>
public <%- camelize(type) %>Layer(String layerId, String sourceId) {
initialize(layerId, sourceId);
}
protected native void initialize(String layerId, String sourceId);
public void setSourceLayer(String sourceLayer) {
nativeSetSourceLayer(sourceLayer);
}
<% } -%>
<% if (type !== 'background' && type !== 'raster') { -%>
public void setFilter(Filter.Statement filter) {
this.setFilter(filter.toArray());
}
public void setFilter(Object[] filter) {
nativeSetFilter(filter);
}
<% } -%>
}

View File

@@ -0,0 +1,42 @@
<%
const properties = locals.properties;
-%>
// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make style-code-android`.
package com.mapbox.mapboxsdk.style.layers;
import android.support.annotation.StringDef;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Paint/Layout properties for Layer
*/
public abstract class Property<T> {
<% for (const property of properties) { -%>
//<%- property.name %>
<% for (const value of property.values) { -%>
public static final String <%- snakeCaseUpper(property.name) %>_<%- snakeCaseUpper(value) %> = "<%- value %>";
<% } -%>
@StringDef({
<% for (const value of property.values) { -%>
<%- snakeCaseUpper(property.name) %>_<%- snakeCaseUpper(value) %>,
<% } -%>
})
@Retention(RetentionPolicy.SOURCE)
public @interface <%- snakeCaseUpper(property.name) %> {}
<% } -%>
//Class definition
public final String name;
public final T value;
/* package */ Property(String name, T value) {
this.name = name;
this.value = value;
}
}

View File

@@ -0,0 +1,45 @@
<%
const paintProperties = locals.paintProperties;
const layoutProperties = locals.layoutProperties;
-%>
// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make style-code-android`.
package com.mapbox.mapboxsdk.style.layers;
import android.annotation.SuppressLint;
import android.support.annotation.ColorInt;
/**
* Constructs paint/layout properties for Layers
* @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layers>Layer style documentation</a>
*
*/
public class PropertyFactory {
public static Property<String> visibility(Boolean visible) {
return new LayoutProperty<>("visibility", visible? "visible": "none");
}
<% for (const property of paintProperties) { -%>
<% if (property.type == 'color') { -%>
public static Property<String> <%- camelizeWithLeadingLowercase(property.name) %>(@ColorInt int value) {
return new PaintProperty<>("<%- property.name %>", colorToRgbaString(value));
}
<% } -%>
public static Property<<%- propertyType(property) %>> <%- camelizeWithLeadingLowercase(property.name) %>(<%- propertyTypeAnnotation(property) %><%- iff(() => propertyTypeAnnotation(property), " ") %><%- propertyType(property) %> value) {
return new PaintProperty<>("<%- property.name %>", value);
}
<% } -%>
<% for (const property of layoutProperties) { -%>
public static Property<<%- propertyType(property) %>> <%- camelizeWithLeadingLowercase(property.name) %>(<%- propertyTypeAnnotation(property) %><%- iff(() => propertyTypeAnnotation(property), " ") %><%- propertyType(property) %> value) {
return new LayoutProperty<>("<%- property.name %>", value);
}
<% } -%>
@SuppressLint("DefaultLocale")
static String colorToRgbaString(@ColorInt int value) {
return String.format("rgba(%d, %d, %d, %d)", (value >> 16) & 0xFF, (value >> 8) & 0xFF, value & 0xFF, (value >> 24) & 0xFF);
}
}