[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

@@ -301,6 +301,14 @@
android:value="@string/category_fragment" />
</activity>
<activity android:name=".activity.style.RuntimeStyleActivity"
android:description="@string/description_runtime_style"
android:label="@string/activity_runtime_style">
<meta-data
android:name="@string/category"
android:value="@string/category_style" />
</activity>
<!-- Configuration Settings -->
<meta-data
android:name="com.mapbox.TestEventsServer"

View File

@@ -0,0 +1,299 @@
package com.mapbox.mapboxsdk.testapp.activity.style;
import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.RawRes;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.style.layers.FillLayer;
import com.mapbox.mapboxsdk.style.layers.Layer;
import com.mapbox.mapboxsdk.style.layers.LineLayer;
import com.mapbox.mapboxsdk.style.layers.NoSuchLayerException;
import com.mapbox.mapboxsdk.style.layers.Property;
import com.mapbox.mapboxsdk.style.layers.RasterLayer;
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
import com.mapbox.mapboxsdk.style.sources.RasterSource;
import com.mapbox.mapboxsdk.style.sources.Source;
import com.mapbox.mapboxsdk.style.sources.VectorSource;
import com.mapbox.mapboxsdk.testapp.R;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import static com.mapbox.mapboxsdk.style.layers.Filter.*;
import static com.mapbox.mapboxsdk.style.layers.Property.*;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.*;
/**
* Sample Activity to show a typical location picker use case
*/
public class RuntimeStyleActivity extends AppCompatActivity {
private static final String TAG = RuntimeStyleActivity.class.getSimpleName();
private MapView mapView;
private MapboxMap mapboxMap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_runtime_style);
setupActionBar();
//Initialize map as normal
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(new OnMapReadyCallback() {
@Override
public void onMapReady(MapboxMap map) {
//Store for later
mapboxMap = map;
//Center and Zoom (Amsterdam, zoomed to streets)
mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(52.379189, 4.899431), 14));
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_runtime_style, menu);
return true;
}
@Override
public void onResume() {
super.onResume();
mapView.onResume();
}
@Override
public void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
onBackPressed();
return true;
case R.id.action_water_color:
setWaterColor();
return true;
case R.id.action_background_opacity:
setBackgroundOpacity();
return true;
case R.id.action_road_avoid_edges:
setRoadSymbolPlacement();
return true;
case R.id.action_layer_visibility:
setLayerInvisible();
return true;
case R.id.action_remove_layer:
removeBuildings();
return true;
case R.id.action_add_parks_layer:
addParksLayer();
return true;
case R.id.action_add_terrain_layer:
addTerrainLayer();
return true;
case R.id.action_add_satellite_layer:
addSatelliteLayer();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void setLayerInvisible() {
String[] roadLayers = new String[]{"water"};
for (String roadLayer : roadLayers) {
Layer layer = mapboxMap.getLayer(roadLayer);
if (layer != null) {
layer.set(visibility(false));
}
}
}
private void setRoadSymbolPlacement() {
//Zoom so that the labels are visible first
mapboxMap.animateCamera(CameraUpdateFactory.zoomTo(14), new DefaultCallback() {
@Override
public void onFinish() {
String[] roadLayers = new String[]{"road-label-small", "road-label-medium", "road-label-large"};
for (String roadLayer : roadLayers) {
Layer layer = mapboxMap.getLayer(roadLayer);
if (layer != null) {
layer.set(symbolPlacement(SYMBOL_PLACEMENT_POINT));
}
}
}
});
}
private void setBackgroundOpacity() {
Layer background = mapboxMap.getLayer("background");
if (background != null) {
background.set(backgroundOpacity(0.2f));
}
}
private void setWaterColor() {
Layer water = mapboxMap.getLayer("water");
if (water != null) {
water.set(
visibility(true),
fillColor(Color.RED)
);
} else {
Toast.makeText(RuntimeStyleActivity.this, "No water layer in this style", Toast.LENGTH_SHORT).show();
}
}
private void removeBuildings() {
//Zoom to see buildings first
try {
mapboxMap.removeLayer("building");
} catch (NoSuchLayerException e) {
Toast.makeText(RuntimeStyleActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
private void addParksLayer() {
//Add a source
Source source;
try {
source = new GeoJsonSource("amsterdam-spots", readRawResource(R.raw.amsterdam));
} catch (IOException e) {
Toast.makeText(RuntimeStyleActivity.this, "Couldn't add source: " + e.getMessage(), Toast.LENGTH_SHORT).show();
return;
}
mapboxMap.addSource(source);
FillLayer layer = new FillLayer("parksLayer", "amsterdam-spots");
layer.set(
fillColor(Color.RED),
fillOutlineColor(Color.BLUE),
fillOpacity(0.3f),
fillAntialias(true)
);
//Only show me parks
layer.setFilter(eq("type", "park"));
mapboxMap.addLayer(layer, "building");
//layer.setPaintProperty(fillColor(Color.RED)); //XXX But not after the object is attached
//Or get the object later and set it. It's all good.
mapboxMap.getLayer("parksLayer").set(fillColor(Color.RED));
//Get a good look at it all
mapboxMap.animateCamera(CameraUpdateFactory.zoomTo(12));
}
private void addTerrainLayer() {
//Add a source
Source source = new VectorSource("my-terrain-source", "mapbox://mapbox.mapbox-terrain-v2");
mapboxMap.addSource(source);
LineLayer layer = new LineLayer("terrainLayer", "my-terrain-source");
layer.setSourceLayer("contour");
layer.set(
lineJoin(Property.LINE_JOIN_ROUND),
lineCap(Property.LINE_CAP_ROUND),
lineColor(Color.RED),
lineWidth(20f)
);
mapboxMap.addLayer(layer);
}
private void addSatelliteLayer() {
//Add a source
Source source = new RasterSource("my-raster-source", "mapbox://mapbox.satellite");
mapboxMap.addSource(source);
//Add a layer
mapboxMap.addLayer(new RasterLayer("satellite-layer", "my-raster-source"));
}
private String readRawResource(@RawRes int rawResource) throws IOException {
InputStream is = getResources().openRawResource(rawResource);
Writer writer = new StringWriter();
char[] buffer = new char[1024];
try {
Reader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
int n;
while ((n = reader.read(buffer)) != -1) {
writer.write(buffer, 0, n);
}
} finally {
is.close();
}
return writer.toString();
}
private void setupActionBar() {
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setDisplayShowHomeEnabled(true);
}
}
private static class DefaultCallback implements MapboxMap.CancelableCallback {
@Override
public void onCancel() {
//noop
}
@Override
public void onFinish() {
//noop
}
}
}

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/primary"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
<com.mapbox.mapboxsdk.maps.MapView
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/toolbar"/>
</RelativeLayout>

View File

@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:mapbox="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_water_color"
android:title="Color the water"
mapbox:showAsAction="never"/>
<item
android:id="@+id/action_background_opacity"
android:title="Set background opacity"
mapbox:showAsAction="never"/>
<item
android:id="@+id/action_road_avoid_edges"
android:title="Set road symbol placement to Point"
mapbox:showAsAction="never"/>
<item
android:id="@+id/action_layer_visibility"
android:title="Set layer visibility to false"
mapbox:showAsAction="never"/>
<item
android:id="@+id/action_add_parks_layer"
android:title="Add a parks layer"
mapbox:showAsAction="never"/>
<item
android:id="@+id/action_remove_layer"
android:title="Remove buildings layer"
mapbox:showAsAction="never"/>
<item
android:id="@+id/action_add_terrain_layer"
android:title="Add a terrain layer"
mapbox:showAsAction="never"/>
<item
android:id="@+id/action_add_satellite_layer"
android:title="Add a satellite layer"
mapbox:showAsAction="never"/>
</menu>

File diff suppressed because it is too large Load Diff

View File

@@ -54,6 +54,7 @@
<string name="activity_minmax_zoom">Min/Max Zoom</string>
<string name="activity_viewpager">ViewPager</string>
<string name="title_activity_navigation_drawer">Navigation Drawer</string>
<string name="activity_runtime_style">Runtime Style</string>
<!-- Description -->
<string name="description_user_location_tracking">Tracks the location of the user</string>
@@ -92,6 +93,7 @@
<string name="description_location_picker">Use a fixed Marker to select your location</string>
<string name="description_viewpager">Use SupportMapFragments in a ViewPager</string>
<string name="description_navigation_drawer">Test for Navigation Drawer support</string>
<string name="description_runtime_style">Adopt the map style on the fly</string>
<string name="menuitem_title_concurrent_infowindow">Concurrent Open InfoWindows</string>
<string name="menuitem_title_deselect_markers_on_tap">Deselect Markers On Tap</string>
@@ -112,6 +114,7 @@
<string name="category_offline">Offline</string>
<string name="category_userlocation">User Location</string>
<string name="category_navigation">Navigation</string>
<string name="category_style">Styling</string>
<string name="action_visible_bounds_explanation">Center map around 2 markers</string>
<string name="action_remove_polylines">Remove polylines</string>

View File

@@ -0,0 +1,90 @@
package com.mapbox.mapboxsdk.style.layers;
import org.junit.Test;
import static org.junit.Assert.*;
import static com.mapbox.mapboxsdk.style.layers.Filter.*;
/**
* Tests for Filter
*/
public class FilterTest {
@Test
public void testAll() {
assertArrayEquals(all().toArray(), new Object[]{"all"});
assertArrayEquals(
all(eq("key", 2), neq("key", 3)).toArray(),
new Object[]{"all", new Object[]{"==", "key", 2}, new Object[]{"!=", "key", 3}}
);
}
@Test
public void testAny() {
assertArrayEquals(any().toArray(), new Object[]{"any"});
assertArrayEquals(
any(eq("key", 2), neq("key", 3)).toArray(),
new Object[]{"any", new Object[]{"==", "key", 2}, new Object[]{"!=", "key", 3}}
);
}
@Test
public void testNone() {
assertArrayEquals(none().toArray(), new Object[]{"none"});
assertArrayEquals(
none(eq("key", 2), neq("key", 3)).toArray(),
new Object[]{"none", new Object[]{"==", "key", 2}, new Object[]{"!=", "key", 3}}
);
}
@Test
public void testHas() {
assertArrayEquals(has("key").toArray(), new Object[]{"has", "key"});
}
@Test
public void testHasNot() {
assertArrayEquals(notHas("key").toArray(), new Object[]{"!has", "key"});
}
@Test
public void testEq() {
assertArrayEquals(eq("key", 1).toArray(), new Object[]{"==", "key", 1});
}
@Test
public void testNeq() {
assertArrayEquals(neq("key", 1).toArray(), new Object[]{"!=", "key", 1});
}
@Test
public void testGt() {
assertArrayEquals(gt("key", 1).toArray(), new Object[]{">", "key", 1});
}
@Test
public void testGte() {
assertArrayEquals(gte("key", 1).toArray(), new Object[]{">=", "key", 1});
}
@Test
public void testLt() {
assertArrayEquals(lt("key", 1).toArray(), new Object[]{"<", "key", 1});
}
@Test
public void testLte() {
assertArrayEquals(lte("key", 1).toArray(), new Object[]{"<=", "key", 1});
}
@Test
public void testIn() {
assertArrayEquals(in("key", 1, 2, "Aap").toArray(), new Object[]{"in", "key", 1, 2, "Aap"});
}
@Test
public void testNotIn() {
assertArrayEquals(notIn("key", 1, 2, "Noot").toArray(), new Object[]{"!in", "key", 1, 2, "Noot"});
}
}