summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
Diffstat (limited to 'platform')
-rw-r--r--platform/android/CHANGELOG.md65
-rw-r--r--platform/android/MapboxGLAndroidSDK/gradle.properties4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/AndroidManifest.xml1
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/MapboxAccountManager.java12
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Annotation.java17
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerOptions.java16
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerViewOptions.java76
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java8
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java29
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java29
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerOptions.java5
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java140
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java336
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewOptions.java18
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MultiPoint.java11
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Polygon.java39
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Polyline.java26
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java12
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/Style.java189
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/ConversionException.java22
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidMarkerPositionException.java10
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/MapboxAccountManagerNotStartedException.java23
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java7
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/layers/CustomLayer.java23
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/layers/package-info.java4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationServices.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java470
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java230
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java101
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java121
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java45
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java224
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettings.java120
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java63
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java71
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/BackgroundLayer.java73
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java135
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CustomLayer.java30
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillLayer.java150
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Filter.java115
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Function.java85
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Layer.java112
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LayoutProperty.java9
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LineLayer.java191
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/NoSuchLayerException.java11
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PaintProperty.java9
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java237
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java1300
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyValue.java56
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/RasterLayer.java100
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/SymbolLayer.java508
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/layer.java.ejs107
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property.java.ejs53
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property_factory.java.ejs78
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java44
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterSource.java33
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java16
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/TileSet.java290
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/VectorSource.java45
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/GzipRequestInterceptor.java54
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/MapboxEvent.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/MapboxEventManager.java76
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java27
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/default_markerview.pngbin0 -> 1669 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/default_markerview.pngbin0 -> 1115 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/default_markerview.pngbin0 -> 2163 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/default_markerview.pngbin0 -> 3163 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/default_markerview.pngbin0 -> 4071 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapview_internal.xml18
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/layout/view_image_marker.xml5
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml1
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values/strings.xml7
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/resources/fabric/com.mapbox.mapboxsdk.mapbox-android-sdk.properties2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/build.gradle10
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/BaseMapboxMapTest.java36
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/BaseTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/BaseTest.java)4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/BulkMarkerActivityTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/BulkMarkerActivityTest.java)4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/DirectionsActivityTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/DirectionsActivityTest.java)4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/DynamicMarkerChangeActivityTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/DynamicMarkerChangeActivityTest.java)6
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/GeocoderActivityTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/GeocoderActivityTest.java)4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/InfoWindowActivityTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/InfoWindowActivityTest.java)4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/InfoWindowAdapterActivityTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/InfoWindowAdapterActivityTest.java)4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/LatLngBoundsActivityTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/LatLngBoundsActivityTest.java)4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/ManualZoomActivityTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/ManualZoomActivityTest.java)4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/MapFragmentActivityTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/MapFragmentActivityTest.java)4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/MapPaddingActivityTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/MapPaddingActivityTest.java)4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/MaxMinZoomActivityTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/MaxMinZoomActivityTest.java)4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/MyLocationTrackingModeActivityTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/MyLocationTrackingModeActivityTest.java)4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/PolylineActivityTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/PolylineActivityTest.java)4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/ScrollByActivityTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/ScrollByActivityTest.java)2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/SupportMapFragmentActivityTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/SupportMapFragmentActivityTest.java)2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/utils/DrawerUtils.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/utils/DrawerUtils.java)2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/utils/GestureUtils.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/utils/GestureUtils.java)2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/utils/OnMapReadyIdlingResource.java57
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/utils/ScreenshotUtil.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/utils/ScreenshotUtil.java)2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/utils/ViewUtils.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/utils/ViewUtils.java)2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/camera/RotateTest.java67
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/camera/TiltTest.java67
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/camera/ZoomTest.java74
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapUtils.java21
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/BackgroundLayerTest.java142
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/CircleLayerTest.java255
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/FillLayerTest.java287
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/LineLayerTest.java428
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/RasterLayerTest.java242
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/RuntimeStyleBackgroundLayerTest.java61
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/RuntimeStyleTests.java91
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/RuntimeStyleTimingTests.java45
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/SymbolLayerTest.java1283
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/layer.junit.ejs146
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/ScreenshotActivityTest.java124
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/robotium/BaseMainActivityTest.java46
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/robotium/CompassViewTest.java48
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/robotium/SimpleRotateTest.java29
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/robotium/SimpleZoomTest.java28
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/robotium/utils/ViewAssertion.java17
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml94
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/FeatureOverviewActivity.java41
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java176
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/BulkMarkerActivity.java56
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/DynamicMarkerChangeActivity.java51
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewActivity.java285
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewScaleActivity.java141
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PolygonActivity.java92
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PolylineActivity.java74
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PressForMarkerActivity.java6
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/LatLngBoundsActivity.java17
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/ManualZoomActivity.java5
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/customlayer/CustomLayerActivity.java13
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/directions/DirectionsActivity.java104
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MapFragmentActivity.java3
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/SupportMapFragmentActivity.java3
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/ViewPagerActivity.java111
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/geocoding/GeocoderActivity.java89
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/PrintActivity.java112
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/SnapshotActivity.java3
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/DynamicInfoWindowAdapterActivity.java169
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowActivity.java16
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DebugModeActivity.java13
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DoubleMapActivity.java5
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/NavigationDrawerActivity.java238
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/SurfaceViewMediaControlActivity.java142
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/navigation/LocationPickerActivity.java467
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java6
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleActivity.java366
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleTestActivity.java69
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleTimingTestActivity.java87
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationDrawableActivity.java68
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationTrackingModeActivity.java52
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/CountryMarkerViewOptions.java14
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/PulseMarkerView.java11
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/PulseMarkerViewOptions.java79
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/TextMarkerView.java18
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/TextMarkerViewOptions.java92
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/anim/pulse.xml24
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/ic_drawer.pngbin0 -> 2829 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/icon.pngbin1587 -> 19772 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/ic_drawer.pngbin0 -> 2820 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/icon.pngbin913 -> 11003 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/ic_drawer.pngbin0 -> 2836 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/icon.pngbin1587 -> 30669 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_drawer.pngbin0 -> 202 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/icon.pngbin2382 -> 58564 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/ic_car_top.pngbin0 -> 19879 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/ic_taxi_top.pngbin0 -> 11275 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/icon.pngbin3018 -> 93272 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_circle.xml12
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_clear_24dp.xml9
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_car_black_24dp.xml9
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_run_black_24dp.xml9
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_print_24dp.xml9
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_marker.xml7
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_infowindow_adapter_dynamic.xml24
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_picker.xml41
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_marker_view_scale.xml60
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_navigation_drawer.xml33
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_press_for_marker.xml14
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_print.xml45
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_runtime_style.xml19
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_snapshot.xml3
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_surfaceview_mediacontrols.xml31
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_viewpager.xml30
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/drawer_navigation_drawer.xml7
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/view_custom_marker.xml4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/view_pulse_marker.xml21
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_infowindow.xml6
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_polygon.xml20
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_polyline.xml16
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_runtime_style.xml45
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/amsterdam.geojson2283
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values-v21/attrs.xml6
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values-v21/dimens.xml4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values-v21/styles.xml19
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values-w820dp/dimens.xml6
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/dimens.xml7
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml56
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/styles.xml14
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/InfoWindowTest.java6
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerTest.java16
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerViewTest.java61
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/constants/StyleVersionTest.java1
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java21
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java44
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/StyleInitializerTest.java75
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettingsTest.java4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/style/layers/FilterTest.java90
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/style/layers/FunctionTest.java29
-rw-r--r--platform/android/bitrise.yml2
-rw-r--r--platform/android/build.gradle2
-rw-r--r--platform/android/platform.gyp17
-rw-r--r--platform/android/scripts/configure.sh7
-rwxr-xr-xplatform/android/scripts/debug.sh2
-rw-r--r--platform/android/scripts/generate-style-code.js206
-rw-r--r--platform/android/src/asset_file_source.cpp2
-rw-r--r--platform/android/src/async_task.cpp4
-rw-r--r--platform/android/src/conversion/constant.hpp95
-rw-r--r--platform/android/src/conversion/conversion.hpp50
-rw-r--r--platform/android/src/java_types.cpp37
-rw-r--r--platform/android/src/java_types.hpp35
-rwxr-xr-xplatform/android/src/jni.cpp273
-rw-r--r--platform/android/src/jni.hpp1
-rwxr-xr-xplatform/android/src/native_map_view.cpp33
-rwxr-xr-xplatform/android/src/native_map_view.hpp3
-rw-r--r--platform/android/src/run_loop.cpp70
-rw-r--r--platform/android/src/run_loop_impl.hpp13
-rw-r--r--platform/android/src/style/android_conversion.hpp91
-rw-r--r--platform/android/src/style/android_geojson.hpp48
-rw-r--r--platform/android/src/style/conversion/function.hpp52
-rw-r--r--platform/android/src/style/conversion/property_value.hpp38
-rw-r--r--platform/android/src/style/conversion/types.hpp98
-rw-r--r--platform/android/src/style/conversion/types.hpp.ejs40
-rw-r--r--platform/android/src/style/conversion/types_string_values.hpp209
-rw-r--r--platform/android/src/style/conversion/types_string_values.hpp.ejs48
-rw-r--r--platform/android/src/style/layers/background_layer.cpp67
-rw-r--r--platform/android/src/style/layers/background_layer.hpp39
-rw-r--r--platform/android/src/style/layers/circle_layer.cpp95
-rw-r--r--platform/android/src/style/layers/circle_layer.hpp47
-rw-r--r--platform/android/src/style/layers/custom_layer.cpp57
-rw-r--r--platform/android/src/style/layers/custom_layer.hpp32
-rw-r--r--platform/android/src/style/layers/fill_layer.cpp95
-rw-r--r--platform/android/src/style/layers/fill_layer.hpp47
-rw-r--r--platform/android/src/style/layers/layer.cpp171
-rw-r--r--platform/android/src/style/layers/layer.cpp.ejs69
-rw-r--r--platform/android/src/style/layers/layer.hpp80
-rw-r--r--platform/android/src/style/layers/layer.hpp.ejs45
-rw-r--r--platform/android/src/style/layers/layers.cpp64
-rw-r--r--platform/android/src/style/layers/layers.hpp20
-rw-r--r--platform/android/src/style/layers/line_layer.cpp144
-rw-r--r--platform/android/src/style/layers/line_layer.hpp61
-rw-r--r--platform/android/src/style/layers/raster_layer.cpp95
-rw-r--r--platform/android/src/style/layers/raster_layer.hpp47
-rw-r--r--platform/android/src/style/layers/symbol_layer.cpp382
-rw-r--r--platform/android/src/style/layers/symbol_layer.hpp129
-rw-r--r--platform/android/src/style/sources/sources.cpp28
-rw-r--r--platform/android/src/style/sources/sources.hpp14
-rw-r--r--platform/android/src/style/value.cpp67
-rw-r--r--platform/android/src/style/value.hpp35
-rw-r--r--platform/android/src/thread.cpp37
-rw-r--r--platform/android/src/timer.cpp5
-rw-r--r--platform/darwin/src/MGLFeature.h18
-rw-r--r--platform/darwin/src/MGLFeature.mm4
-rw-r--r--platform/darwin/src/MGLMultiPoint.mm4
-rw-r--r--platform/darwin/src/MGLPolygon.mm6
-rw-r--r--platform/darwin/src/MGLPolyline.mm6
-rw-r--r--platform/darwin/src/headless_view_cgl.cpp2
-rw-r--r--platform/darwin/src/log_nslog.mm3
-rw-r--r--platform/darwin/src/nsthread.mm13
-rw-r--r--platform/darwin/src/settings_nsuserdefaults.mm60
-rw-r--r--platform/darwin/test/MGLFeatureTests.mm19
-rw-r--r--platform/default/asset_file_source.cpp6
-rw-r--r--platform/default/glfw_view.cpp35
-rw-r--r--platform/default/headless_view_glx.cpp4
-rw-r--r--platform/default/http_file_source.cpp10
-rw-r--r--platform/default/image.cpp14
-rw-r--r--platform/default/jpeg_reader.cpp40
-rw-r--r--platform/default/log_stderr.cpp3
-rw-r--r--platform/default/mbgl/storage/offline.cpp20
-rw-r--r--platform/default/mbgl/storage/offline_database.cpp66
-rw-r--r--platform/default/mbgl/storage/offline_database.hpp7
-rw-r--r--platform/default/mbgl/storage/offline_download.cpp120
-rw-r--r--platform/default/mbgl/storage/offline_download.hpp2
-rw-r--r--platform/default/online_file_source.cpp8
-rw-r--r--platform/default/png_reader.cpp31
-rw-r--r--platform/default/run_loop.cpp6
-rw-r--r--platform/default/settings_json.cpp4
-rw-r--r--platform/default/sqlite3.hpp4
-rw-r--r--platform/default/string_stdlib.cpp19
-rw-r--r--platform/default/thread.cpp29
-rw-r--r--platform/ios/CHANGELOG.md58
-rw-r--r--platform/ios/DEVELOPING.md15
-rw-r--r--platform/ios/Mapbox.playground/Contents.swift115
-rw-r--r--platform/ios/app/MBXAppDelegate.h2
-rw-r--r--platform/ios/app/MBXViewController.m278
-rw-r--r--platform/ios/benchmark/MBXBenchAppDelegate.h2
-rw-r--r--platform/ios/docs/doc-README.md2
-rw-r--r--platform/ios/docs/pod-README.md2
-rw-r--r--platform/ios/ios.xcodeproj/project.pbxproj34
-rw-r--r--platform/ios/scripts/configure.sh7
-rwxr-xr-xplatform/ios/scripts/package.sh19
-rw-r--r--platform/ios/src/MGLAnnotationImage.h24
-rw-r--r--platform/ios/src/MGLCalloutView.h36
-rw-r--r--platform/ios/src/MGLCompactCalloutView.h5
-rw-r--r--platform/ios/src/MGLMapView.h59
-rw-r--r--platform/ios/src/MGLMapView.mm28
-rw-r--r--platform/ios/src/MGLMapViewDelegate.h8
-rw-r--r--platform/ios/src/MGLUserLocation.h18
-rw-r--r--platform/ios/src/MGLUserLocationAnnotationView.h2
-rw-r--r--platform/linux/scripts/configure.sh9
-rw-r--r--platform/macos/CHANGELOG.md28
-rw-r--r--platform/macos/DEVELOPING.md15
-rw-r--r--platform/macos/INSTALL.md18
-rw-r--r--platform/macos/app/AppDelegate.m18
-rw-r--r--platform/macos/app/Base.lproj/MainMenu.xib116
-rw-r--r--platform/macos/app/MapDocument.m42
-rw-r--r--platform/macos/app/wms.json21
-rw-r--r--platform/macos/docs/doc-README.md2
-rw-r--r--platform/macos/docs/pod-README.md2
-rw-r--r--platform/macos/macos.xcodeproj/project.pbxproj12
-rw-r--r--platform/macos/macos.xcworkspace/xcshareddata/xcschemes/test.xcscheme6
-rw-r--r--platform/macos/scripts/configure.sh7
-rwxr-xr-xplatform/macos/scripts/deploy-packages.sh83
-rwxr-xr-xplatform/macos/scripts/package.sh2
-rw-r--r--platform/macos/src/MGLMapView.h36
-rw-r--r--platform/macos/src/MGLMapView.mm56
-rw-r--r--platform/node/CHANGELOG.md63
-rw-r--r--platform/node/README.md16
-rwxr-xr-xplatform/node/scripts/after_script.sh26
-rw-r--r--platform/node/src/node_conversion.hpp113
-rw-r--r--platform/node/src/node_feature.cpp7
-rw-r--r--platform/node/src/node_feature.hpp2
-rw-r--r--platform/node/src/node_geojson.hpp14
-rw-r--r--platform/node/src/node_log.cpp8
-rw-r--r--platform/node/src/node_map.cpp323
-rw-r--r--platform/node/src/node_map.hpp37
-rw-r--r--platform/node/src/node_mapbox_gl_native.cpp12
-rw-r--r--platform/node/src/node_request.cpp140
-rw-r--r--platform/node/src/node_request.hpp30
-rw-r--r--platform/node/test/memory.test.js108
-rw-r--r--platform/node/test/suite_implementation.js42
-rw-r--r--platform/qt/app/mapwindow.cpp38
-rw-r--r--platform/qt/app/qmapboxgl.gypi3
-rw-r--r--platform/qt/app/source.geojson253
-rw-r--r--platform/qt/app/source.qrc5
-rw-r--r--platform/qt/bitrise-qt4.yml2
-rw-r--r--platform/qt/bitrise-qt5.yml2
-rw-r--r--platform/qt/include/QQuickMapboxGLStyleProperty1
-rw-r--r--platform/qt/include/qmapbox.hpp10
-rw-r--r--platform/qt/include/qmapboxgl.hpp14
-rw-r--r--platform/qt/include/qquickmapboxgl.hpp22
-rw-r--r--platform/qt/include/qquickmapboxglstyleproperty.hpp75
-rw-r--r--platform/qt/platform.gyp28
-rw-r--r--platform/qt/qmlapp/main.cpp5
-rw-r--r--platform/qt/qmlapp/main.qml121
-rw-r--r--platform/qt/scripts/configure.sh24
-rw-r--r--platform/qt/src/async_task_impl.hpp6
-rw-r--r--platform/qt/src/http_file_source.hpp8
-rw-r--r--platform/qt/src/http_request.cpp5
-rw-r--r--platform/qt/src/http_request.hpp4
-rw-r--r--platform/qt/src/qmapboxgl.cpp199
-rw-r--r--platform/qt/src/qmapboxgl_p.hpp15
-rw-r--r--platform/qt/src/qquickmapboxgl.cpp28
-rw-r--r--platform/qt/src/qquickmapboxglrenderer.cpp26
-rw-r--r--platform/qt/src/qquickmapboxglrenderer.hpp18
-rw-r--r--platform/qt/src/qquickmapboxglstyleproperty.cpp118
-rw-r--r--platform/qt/src/qt_conversion.hpp106
-rw-r--r--platform/qt/src/qt_geojson.hpp49
-rw-r--r--platform/qt/src/run_loop_impl.hpp4
-rw-r--r--platform/qt/src/string_stdlib.cpp24
-rw-r--r--platform/qt/src/timer_impl.hpp6
372 files changed, 21513 insertions, 2703 deletions
diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md
index f73c5ba198..b5524132f6 100644
--- a/platform/android/CHANGELOG.md
+++ b/platform/android/CHANGELOG.md
@@ -2,13 +2,56 @@
Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started.
-## 4.0.1
+## 4.1.1 - July 19, 2016
+
+Mapbox Android 4.1.1 is a patch release and is recommended to upgrade to it as soon as possible.
+
+* Default Styles Caching Crash ([#5722](https://github.com/mapbox/mapbox-gl-native/issues/5722))
+
+## 4.1.0 - June 29, 2016
+
+Mapbox Android 4.1.0 builds off our ambitious 4.0.0 version with 3 major new features being released.
+
+* View Based Annotations ([#3276](https://github.com/mapbox/mapbox-gl-native/issues/3276))
+* UserLocationView Refactor ([#4396](https://github.com/mapbox/mapbox-gl-native/issues/4396))
+* MapboxAccountManager ([#5004](https://github.com/mapbox/mapbox-gl-native/issues/5004))
+
+## 4.1.0-beta.3 - June 20, 2016
+
+* New samples:
+ * [Location picker](https://github.com/mapbox/mapbox-gl-native/pull/5391)
+ * [Animate and rotate multiple markers](https://github.com/mapbox/mapbox-gl-native/issues/5299)
+ * [Scaling marker activity](https://github.com/mapbox/mapbox-gl-native/issues/5409)
+* Marker improvements:
+ * [Expose MarkerView alpha](https://github.com/mapbox/mapbox-gl-native/pull/5329)
+ * [Icon should be optional for MarkerView](https://github.com/mapbox/mapbox-gl-native/pull/5328)
+ * [Expose an API to enable selection/deselection of markers on a map tap](https://github.com/mapbox/mapbox-gl-native/pull/5312)
+ * [Bring selected MarkerView to the front](https://github.com/mapbox/mapbox-gl-native/pull/5294)
+* [Make gesture focal point configurable](https://github.com/mapbox/mapbox-gl-native/pull/5332)
+
+## 4.1.0-beta.2 - June 8, 2016
+
+* Dynamically Update InfoWindow ([#5237](https://github.com/mapbox/mapbox-gl-native/issues/5237))
+* armeabi ABI Work On armv7 Devices ([#3985](https://github.com/mapbox/mapbox-gl-native/issues/3985))
+* Remove Adapter Requirement For MarkerView ([#5214](https://github.com/mapbox/mapbox-gl-native/issues/5214))
+* Always Current Version Style URL Constants ([#5193](https://github.com/mapbox/mapbox-gl-native/issues/5193))
+* Random NullPointerException On Telemetry ([#5186](https://github.com/mapbox/mapbox-gl-native/issues/5186))
+
+## 4.1.0-beta.1 - May 26, 2016
+
+Mapbox Android 4.1.0 builds off our ambitious 4.0.0 version with 3 major new features being released. To help us produce the highest quality SDK possible we're releasing an official Beta release first so that everyone has time to explore it and help hardened it before the official 4.1.0 Final Release.
+
+* View Based Annotations ([#3276](https://github.com/mapbox/mapbox-gl-native/issues/3276))
+* UserLocationView Refactor ([#4396](https://github.com/mapbox/mapbox-gl-native/issues/4396))
+* MapboxAccountManager ([#5004](https://github.com/mapbox/mapbox-gl-native/issues/5004))
+
+## 4.0.1 - May 12, 2016
Mapbox Android 4.0.1 is a patch release to make this bug fix available sooner.
* MapboxMap.removeAnnotations() doesn't remove markers ([#4553](https://github.com/mapbox/mapbox-gl-native/issues/4553))
-## 4.0.0
+## 4.0.0 - March 30, 2016
Mapbox Android 4.0.0 contains the following 3 major new features.
@@ -16,14 +59,14 @@ Mapbox Android 4.0.0 contains the following 3 major new features.
* Offline Maps ([#3891](https://github.com/mapbox/mapbox-gl-native/issues/3891))
* Telemetry ([#2421](https://github.com/mapbox/mapbox-gl-native/issues/2421))
-## 4.0.0-rc.1
+## 4.0.0-rc.1 - March 25, 2016
* Default Value Bug Fix for MapboxMapOptions ([#4398](https://github.com/mapbox/mapbox-gl-native/issues/4398))
* NullPointerException When Scrolling ([#4424](https://github.com/mapbox/mapbox-gl-native/issues/4424))
* Platform Specific CHANGELOGS ([#4432](https://github.com/mapbox/mapbox-gl-native/issues/4432))
* Introduce LatLng.wrap() ([#4475](https://github.com/mapbox/mapbox-gl-native/issues/4475))
-## 4.0.0-beta.2
+## 4.0.0-beta.2 - March 21, 2016
* arm64 ABI Support ([#3128](https://github.com/mapbox/mapbox-gl-native/issues/3128))
* Unify Offline And Cache Databases ([#4362](https://github.com/mapbox/mapbox-gl-native/issues/4362))
@@ -32,7 +75,7 @@ Mapbox Android 4.0.0 contains the following 3 major new features.
* OnCameraChange Bug Fix ([#4327](https://github.com/mapbox/mapbox-gl-native/issues/4327))
* OnCameraChangeListener vs getCameraPosition ([#4326](https://github.com/mapbox/mapbox-gl-native/issues/4326))
-## 4.0.0-beta.1
+## 4.0.0-beta.1 - March 15, 2016
Mapbox Android 4.0.0 is the most ambitious Android release to date with 3 major new features being released. To help us produce the highest quality SDK possible we're releasing an official Beta release first so that everyone has time to explore it and help hardened it before the official 4.0.0 Final Release.
@@ -40,27 +83,27 @@ Mapbox Android 4.0.0 is the most ambitious Android release to date with 3 major
* Offline Maps ([#3891](https://github.com/mapbox/mapbox-gl-native/issues/3891))
* Telemetry ([#2421](https://github.com/mapbox/mapbox-gl-native/issues/2421))
-## 3.2.0
+## 3.2.0 - January 28, 2016
* Fixed crash caused by annotation image with non-integer width or height ([#3031](https://github.com/mapbox/mapbox-gl-native/issues/3031))
* Tracking Mode Reverses Bearing Fix ([#3664](https://github.com/mapbox/mapbox-gl-native/issues/3664))
* GPS Extra Rotation Fix ([#3661](https://github.com/mapbox/mapbox-gl-native/issues/3661))
* Added new methods for getting and setting the min and max zoom levels: `getMinZoom`, `setMinZoom`, `getMaxZoom`, `setMaxZoom`. ([#509](https://github.com/mapbox/mapbox-gl-native/issues/509))
-## 3.1.0
+## 3.1.0 - January 20, 2016
* Camera API Callback Improvements ([#3412](https://github.com/mapbox/mapbox-gl-native/issues/3412))
* Coordinate Deprecated For LatLng ([#3309](https://github.com/mapbox/mapbox-gl-native/issues/3309))
* Responsive User Dot Location Tracking ([#2049](https://github.com/mapbox/mapbox-gl-native/issues/2049))
-## 3.0.0
+## 3.0.0 - December 21, 2015
* Added Camera API ([#3244](https://github.com/mapbox/mapbox-gl-native/issues/3244))
* Custom Layer Support ([#3248](https://github.com/mapbox/mapbox-gl-native/issues/3348))
* Reverse Tilt Gesutre Detection ([#3245](https://github.com/mapbox/mapbox-gl-native/issues/3245))
* Decoupled Location Provider ([#2954](https://github.com/mapbox/mapbox-gl-native/issues/2954))
-## 2.3.0
+## 2.3.0 - December 4, 2015
* Added Tilt / Pitch Support ([#2805](https://github.com/mapbox/mapbox-gl-native/issues/2805))
* Keep InfoWindow Open When Panning ([#3121](https://github.com/mapbox/mapbox-gl-native/issues/3121))
@@ -68,7 +111,7 @@ Mapbox Android 4.0.0 is the most ambitious Android release to date with 3 major
* OkHttp Replace curl ([#2856](https://github.com/mapbox/mapbox-gl-native/issues/2856))
* GPS and Compass Customization Support ([#2858](https://github.com/mapbox/mapbox-gl-native/issues/2858))
-## 2.2.0
+## 2.2.0 - October 28, 2015
- New User Dot location graphics ([#2732](https://github.com/mapbox/mapbox-gl-native/issues/2732))
- Custom Drawable Markers ([#2744](https://github.com/mapbox/mapbox-gl-native/issues/2744))
@@ -78,7 +121,7 @@ Mapbox Android 4.0.0 is the most ambitious Android release to date with 3 major
- **RESOLVED** Black Screen On Ice Cream Sandwich and Jelly Bean devices ([#2802](https://github.com/mapbox/mapbox-gl-native/issues/2802))
-## 2.1.0
+## 2.1.0 - October 21, 2015
- Initial Android release.
diff --git a/platform/android/MapboxGLAndroidSDK/gradle.properties b/platform/android/MapboxGLAndroidSDK/gradle.properties
index c2df63b0bb..6aab985298 100644
--- a/platform/android/MapboxGLAndroidSDK/gradle.properties
+++ b/platform/android/MapboxGLAndroidSDK/gradle.properties
@@ -1,5 +1,5 @@
GROUP=com.mapbox.mapboxsdk
-VERSION_NAME=4.1.0-SNAPSHOT
+VERSION_NAME=4.2.0-SNAPSHOT
POM_DESCRIPTION=Mapbox GL Android SDK
POM_URL=https://github.com/mapbox/mapbox-gl-native
@@ -17,6 +17,6 @@ ANDROID_BUILD_TARGET_SDK_VERSION=23
ANDROID_BUILD_TOOLS_VERSION=23.0.3
ANDROID_BUILD_SDK_VERSION=23
-POM_NAME=Mapbox GL Android SDK
+POM_NAME=Mapbox Android SDK
POM_ARTIFACT_ID=mapbox-android-sdk
POM_PACKAGING=aar
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/AndroidManifest.xml b/platform/android/MapboxGLAndroidSDK/src/main/AndroidManifest.xml
index 0307d462c8..c848e61e6c 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/AndroidManifest.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/AndroidManifest.xml
@@ -2,6 +2,7 @@
package="com.mapbox.mapboxsdk">
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
+ <uses-feature android:name="android.hardware.wifi" android:required="false" /> <!-- Implied by ACCESS_WIFI_STATE. -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/MapboxAccountManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/MapboxAccountManager.java
index 211590653a..8f2597c60a 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/MapboxAccountManager.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/MapboxAccountManager.java
@@ -2,8 +2,10 @@ package com.mapbox.mapboxsdk;
import android.content.Context;
import android.text.TextUtils;
+
import com.mapbox.mapboxsdk.constants.MapboxConstants;
import com.mapbox.mapboxsdk.exceptions.InvalidAccessTokenException;
+import com.mapbox.mapboxsdk.exceptions.MapboxAccountManagerNotStartedException;
import com.mapbox.mapboxsdk.telemetry.MapboxEventManager;
public class MapboxAccountManager {
@@ -16,8 +18,9 @@ public class MapboxAccountManager {
/**
* MapboxAccountManager should NOT be instantiated directly.
* Use @see MapboxAccountManager#getInstance() instead.
+ *
* @param applicationContext Context used to get ApplicationContext
- * @param accessToken Mapbox Access Token
+ * @param accessToken Mapbox Access Token
*/
private MapboxAccountManager(Context applicationContext, String accessToken) {
super();
@@ -29,7 +32,7 @@ public class MapboxAccountManager {
* Primary entry point to Mapbox for implementing developers.
* Must be configured in either Application.onCreate() or Launch Activity.onCreate()
*
- * @param context Context used to get Application Context
+ * @param context Context used to get Application Context
* @param accessToken Mapbox Access Token. You can get one on the Mapbox Web site.
* @return MapboxAccountManager instance for app
*/
@@ -49,11 +52,16 @@ public class MapboxAccountManager {
* @return MapboxAccountManager instance for app. May be NULL if not configured yet.
*/
public static MapboxAccountManager getInstance() {
+ if (mapboxAccountManager == null) {
+ throw new MapboxAccountManagerNotStartedException();
+ }
+
return mapboxAccountManager;
}
/**
* Access Token for this application
+ *
* @return Mapbox Access Token
*/
public String getAccessToken() {
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Annotation.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Annotation.java
index 36d56591c8..3c4868c84b 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Annotation.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Annotation.java
@@ -23,6 +23,7 @@ public abstract class Annotation implements Comparable<Annotation> {
*/
private long id = -1; // -1 unless added to a MapView
protected MapboxMap mapboxMap;
+ protected MapView mapView;
protected Annotation() {
}
@@ -68,6 +69,22 @@ public abstract class Annotation implements Comparable<Annotation> {
return mapboxMap;
}
+ /**
+ * Don not use this method. Used internally by the SDK.
+ */
+ public void setMapView(MapView mapView) {
+ this.mapView = mapView;
+ }
+
+ /**
+ * Gets the associated MapView
+ *
+ * @return The MapView
+ */
+ protected MapView getMapView() {
+ return mapView;
+ }
+
@Override
public int compareTo(@NonNull Annotation annotation) {
if (id < annotation.getId()) {
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerOptions.java
index fc2022f9e1..3adeb52ea7 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerOptions.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerOptions.java
@@ -39,6 +39,22 @@ public abstract class BaseMarkerOptions<U extends Marker, T extends BaseMarkerOp
return getThis();
}
+ public T setIcon(Icon icon) {
+ return icon(icon);
+ }
+
+ public T setPosition(LatLng position) {
+ return position(position);
+ }
+
+ public T setSnippet(String snippet) {
+ return snippet(snippet);
+ }
+
+ public T setTitle(String title) {
+ return title(title);
+ }
+
public abstract T getThis();
public abstract U getMarker();
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerViewOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerViewOptions.java
index 0cd54fc0f0..a5c6397b6f 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerViewOptions.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerViewOptions.java
@@ -1,7 +1,7 @@
package com.mapbox.mapboxsdk.annotations;
import android.os.Parcelable;
-import android.support.annotation.AnimatorRes;
+import android.support.annotation.FloatRange;
import android.support.annotation.NonNull;
import com.mapbox.mapboxsdk.geometry.LatLng;
@@ -26,10 +26,10 @@ public abstract class BaseMarkerViewOptions<U extends MarkerView, T extends Base
protected float anchorV = 1f;
protected float infoWindowAnchorU = 0.5f;
protected float infoWindowAnchorV = 0.0f;
- protected int selectAnimRes;
- protected int deselectAnimRes;
- protected int rotation;
+ protected float rotation;
protected boolean visible = true;
+ protected boolean selected;
+ protected float alpha = 1.0f;
/**
* Default constructor
@@ -99,7 +99,7 @@ public abstract class BaseMarkerViewOptions<U extends MarkerView, T extends Base
* @param v the v-value
* @return the object for which the method was called
*/
- public T anchor(float u, float v) {
+ public T anchor(@FloatRange(from = 0.0, to = 1.0) float u, @FloatRange(from = 0.0, to = 1.0) float v) {
this.anchorU = u;
this.anchorV = v;
return getThis();
@@ -112,53 +112,42 @@ public abstract class BaseMarkerViewOptions<U extends MarkerView, T extends Base
* @param v the v-values
* @return the object for which the method was called
*/
- public T infoWindowAnchor(float u, float v) {
+ public T infoWindowAnchor(@FloatRange(from = 0.0, to = 1.0) float u, @FloatRange(from = 0.0, to = 1.0) float v) {
this.infoWindowAnchorU = u;
this.infoWindowAnchorV = v;
return getThis();
}
/**
- * Set the animator resource to be used when an MarkerView is selected.
+ * Set the rotation of the MarkerView.
*
- * @param selectAnimRes the used animator resource
+ * @param rotation the rotation value
* @return the object for which the method was called
*/
- public T selectAnimatorResource(@AnimatorRes int selectAnimRes) {
- this.selectAnimRes = selectAnimRes;
+ public T rotation(float rotation) {
+ this.rotation = rotation;
return getThis();
}
/**
- * Set the animator resource to be used when an MarkerView is deselected.
+ * Set the visibility state of the MarkerView.
*
- * @param deselectAnimRes the used animator resource
+ * @param visible the visible state
* @return the object for which the method was called
*/
- public T deselectAnimatorResource(@AnimatorRes int deselectAnimRes) {
- this.deselectAnimRes = deselectAnimRes;
+ public T visible(boolean visible) {
+ this.visible = visible;
return getThis();
}
/**
- * Set the rotation of the MarkerView.
+ * Set the alpha of the MarkerView.
*
- * @param rotation the rotation value
+ * @param alpha the alpha value
* @return the object for which the method was called
*/
- public T rotation(int rotation) {
- this.rotation = rotation;
- return getThis();
- }
-
- /**
- * Set the visibility state of the MarkerView.
- *
- * @param visible the visible state
- * @return the object for which the method was calleds
- */
- public T visible(boolean visible) {
- this.visible = visible;
+ public T alpha(float alpha) {
+ this.alpha = alpha;
return getThis();
}
@@ -244,29 +233,11 @@ public abstract class BaseMarkerViewOptions<U extends MarkerView, T extends Base
}
/**
- * Get the animator resource used for selecting the MarkerView.
- *
- * @return the animator resource
- */
- public int getSelectAnimRes() {
- return selectAnimRes;
- }
-
- /**
- * Get the animator resource used for deselecting the MarkerView.
- *
- * @return the animator resource
- */
- public int getDeselectAnimRes() {
- return deselectAnimRes;
- }
-
- /**
* Get the rotation of the MarkerView.
*
* @return the rotation value
*/
- public int getRotation() {
+ public float getRotation() {
return rotation;
}
@@ -280,6 +251,15 @@ public abstract class BaseMarkerViewOptions<U extends MarkerView, T extends Base
}
/**
+ * Get the alpha of the MarkerView.
+ *
+ * @return the alpha value
+ */
+ public float getAlpha() {
+ return alpha;
+ }
+
+ /**
* Get the instance of the object for which this method was called.
*
* @return the object for which the this method was called
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java
index d7d41b98be..93c6deddc9 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java
@@ -33,6 +33,7 @@ public final class IconFactory {
private Context mContext;
private static IconFactory sInstance;
private Icon mDefaultMarker;
+ private Icon mDefaultMarkerView;
private BitmapFactory.Options mOptions;
private int mNextId = 0;
@@ -121,6 +122,13 @@ public final class IconFactory {
return mDefaultMarker;
}
+ public Icon defaultMarkerView() {
+ if (mDefaultMarkerView == null) {
+ mDefaultMarkerView = fromResource(R.drawable.default_markerview);
+ }
+ return mDefaultMarkerView;
+ }
+
private Icon fromInputStream(@NonNull InputStream is) {
Bitmap bitmap = BitmapFactory.decodeStream(is, null, mOptions);
return fromBitmap(bitmap);
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java
index 7452ab8fac..9af459e8a0 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java
@@ -3,6 +3,7 @@ package com.mapbox.mapboxsdk.annotations;
import android.content.res.Resources;
import android.graphics.PointF;
import android.support.annotation.LayoutRes;
+import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -222,9 +223,22 @@ public class InfoWindow {
}
mMapboxMap = new WeakReference<>(mapboxMap);
String title = overlayItem.getTitle();
- ((TextView) view.findViewById(R.id.infowindow_title)).setText(title);
+ TextView titleTextView = ((TextView) view.findViewById(R.id.infowindow_title));
+ if (!TextUtils.isEmpty(title)) {
+ titleTextView.setText(title);
+ titleTextView.setVisibility(View.VISIBLE);
+ } else {
+ titleTextView.setVisibility(View.GONE);
+ }
+
String snippet = overlayItem.getSnippet();
- ((TextView) view.findViewById(R.id.infowindow_description)).setText(snippet);
+ TextView snippetTextView = ((TextView) view.findViewById(R.id.infowindow_description));
+ if (!TextUtils.isEmpty(snippet)) {
+ snippetTextView.setText(snippet);
+ snippetTextView.setVisibility(View.VISIBLE);
+ } else {
+ snippetTextView.setVisibility(View.GONE);
+ }
}
InfoWindow setBoundMarker(Marker boundMarker) {
@@ -245,11 +259,20 @@ public class InfoWindow {
View view = mView.get();
if (mapboxMap != null && marker != null && view != null) {
mCoordinates = mapboxMap.getProjection().toScreenLocation(marker.getPosition());
- view.setX(mCoordinates.x + mViewWidthOffset - mMarkerWidthOffset);
+
+ if (view instanceof InfoWindowView) {
+ view.setX(mCoordinates.x + mViewWidthOffset - mMarkerWidthOffset);
+ } else {
+ view.setX(mCoordinates.x - (view.getMeasuredWidth() / 2) - mMarkerWidthOffset);
+ }
view.setY(mCoordinates.y + mMarkerHeightOffset);
}
}
+ public View getView() {
+ return mView != null ? mView.get() : null;
+ }
+
boolean isVisible() {
return mIsVisible;
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java
index 16b219684f..d24f020a18 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java
@@ -3,7 +3,6 @@ package com.mapbox.mapboxsdk.annotations;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.View;
-
import com.mapbox.mapboxsdk.R;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapView;
@@ -91,8 +90,9 @@ public class Marker extends Annotation {
}
}
- void setSnippet(String snippet) {
+ public void setSnippet(String snippet) {
this.snippet = snippet;
+ refreshInfoWindowContent();
}
/**
@@ -112,8 +112,30 @@ public class Marker extends Annotation {
return icon;
}
- void setTitle(String title) {
+ public void setTitle(String title) {
this.title = title;
+ refreshInfoWindowContent();
+ }
+
+ @Nullable
+ public InfoWindow getInfoWindow() {
+ return infoWindow;
+ }
+
+ /**
+ * Update only for default Marker's InfoWindow content for Title and Snippet
+ */
+ private void refreshInfoWindowContent() {
+ if (isInfoWindowShown() && mapView != null && mapboxMap != null && mapboxMap.getInfoWindowAdapter() == null) {
+ InfoWindow infoWindow = getInfoWindow(mapView);
+ if (mapView.getContext() != null) {
+ infoWindow.adaptDefaultMarker(this, mapboxMap, mapView);
+ }
+ MapboxMap map = getMapboxMap();
+ if (map != null) {
+ map.updateMarker(this);
+ }
+ }
}
/**
@@ -121,6 +143,7 @@ public class Marker extends Annotation {
*/
public InfoWindow showInfoWindow(@NonNull MapboxMap mapboxMap, @NonNull MapView mapView) {
setMapboxMap(mapboxMap);
+ setMapView(mapView);
MapboxMap.InfoWindowAdapter infoWindowAdapter = getMapboxMap().getInfoWindowAdapter();
if (infoWindowAdapter != null) {
// end developer is using a custom InfoWindowAdapter
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerOptions.java
index 7ca3687b0d..e0f3b86fc2 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerOptions.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerOptions.java
@@ -4,6 +4,7 @@ import android.graphics.Bitmap;
import android.os.Parcel;
import android.os.Parcelable;
+import com.mapbox.mapboxsdk.exceptions.InvalidMarkerPositionException;
import com.mapbox.mapboxsdk.geometry.LatLng;
@@ -70,6 +71,10 @@ public final class MarkerOptions extends BaseMarkerOptions<Marker, MarkerOptions
* @return Marker The build marker
*/
public Marker getMarker() {
+ if (position == null) {
+ throw new InvalidMarkerPositionException();
+ }
+
marker.setPosition(position);
marker.setSnippet(snippet);
marker.setTitle(title);
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java
index 3e51044643..a577550635 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java
@@ -1,6 +1,18 @@
package com.mapbox.mapboxsdk.annotations;
+import android.animation.AnimatorSet;
+import android.graphics.Bitmap;
+import android.graphics.PointF;
+import android.support.annotation.FloatRange;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.view.View;
+import android.view.animation.AnimationUtils;
+
+import com.mapbox.mapboxsdk.constants.MapboxConstants;
+import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.utils.AnimatorUtils;
/**
* MarkerView is an annotation that shows an View at a geographical location.
@@ -19,8 +31,8 @@ public class MarkerView extends Marker {
private float anchorU;
private float anchorV;
- private float offsetX;
- private float offsetY;
+ private float offsetX = -1;
+ private float offsetY = -1;
private float infoWindowAnchorU;
private float infoWindowAnchorV;
@@ -28,13 +40,14 @@ public class MarkerView extends Marker {
private boolean flat;
private boolean visible = true;
- private int selectAnimRes;
- private int deselectAnimRes;
-
private float tiltValue;
private float rotation;
private float alpha = 1;
+ private Icon markerViewIcon;
+
+ private boolean selected;
+
/**
* Publicly hidden default constructor
*/
@@ -53,12 +66,11 @@ public class MarkerView extends Marker {
this.infoWindowAnchorU = baseMarkerViewOptions.getInfoWindowAnchorU();
this.infoWindowAnchorV = baseMarkerViewOptions.getInfoWindowAnchorV();
this.flat = baseMarkerViewOptions.isFlat();
- this.selectAnimRes = baseMarkerViewOptions.getSelectAnimRes();
- this.deselectAnimRes = baseMarkerViewOptions.getDeselectAnimRes();
this.infoWindowAnchorU = baseMarkerViewOptions.infoWindowAnchorU;
this.infoWindowAnchorV = baseMarkerViewOptions.infoWindowAnchorV;
this.anchorU = baseMarkerViewOptions.anchorU;
this.anchorV = baseMarkerViewOptions.anchorV;
+ this.selected = baseMarkerViewOptions.selected;
}
/**
@@ -71,9 +83,10 @@ public class MarkerView extends Marker {
* @param u u-coordinate of the anchor, as a ratio of the image width (in the range [0, 1])
* @param v v-coordinate of the anchor, as a ratio of the image height (in the range [0, 1])
*/
- public void setAnchor(float u, float v) {
+ public void setAnchor(@FloatRange(from = 0.0, to = 1.0) float u, @FloatRange(from = 0.0, to = 1.0) float v) {
this.anchorU = u;
this.anchorV = v;
+ setOffset(-1, -1);
}
/**
@@ -95,26 +108,16 @@ public class MarkerView extends Marker {
}
/**
- * Internal method to set the horizontal calculated offset.
+ * Internal method to set the calculated offset.
* <p>
* These are calculated based on the View bounds and the provided anchor.
* </p>
*
* @param x the x-value of the offset
- */
- void setOffsetX(float x) {
- offsetX = x;
- }
-
- /**
- * Internal method to set the vertical calculated offset.
- * <p>
- * These are calculated based on the View bounds and the provided anchor.
- * </p>
- *
* @param y the y-value of the offset
*/
- void setOffsetY(float y) {
+ void setOffset(float x, float y) {
+ offsetX = x;
offsetY = y;
}
@@ -149,7 +152,7 @@ public class MarkerView extends Marker {
* @param v v-coordinate of the info window anchor, as a ratio of the image height (in the range [0, 1])
* @see #setAnchor(float, float) for more details.
*/
- public void setInfoWindowAnchor(float u, float v) {
+ public void setInfoWindowAnchor(@FloatRange(from = 0.0, to = 1.0) float u, @FloatRange(from = 0.0, to = 1.0) float v) {
this.infoWindowAnchorU = u;
this.infoWindowAnchorV = v;
}
@@ -191,42 +194,6 @@ public class MarkerView extends Marker {
}
/**
- * Get the animator resource used to animate to the selected state of a MarkerView.
- *
- * @return the animator resource used
- */
- public int getSelectAnimRes() {
- return selectAnimRes;
- }
-
- /**
- * Set the animator resource used to animate to the deselected state of a MarkerView.
- *
- * @param selectAnimRes the animator resource used
- */
- public void setSelectAnimRes(int selectAnimRes) {
- this.selectAnimRes = selectAnimRes;
- }
-
- /**
- * Get the animator resource used to animate to the deslected state of a MarkerView.
- *
- * @return the animator resource used
- */
- public int getDeselectAnimRes() {
- return deselectAnimRes;
- }
-
- /**
- * Set the animator resource used to animate to the selected state of a MarkerView.
- *
- * @param deselectAnimRes the animator resource used
- */
- public void setDeselectAnimRes(int deselectAnimRes) {
- this.deselectAnimRes = deselectAnimRes;
- }
-
- /**
* Internal method to get the current tilted value of a MarkerView.
*
* @return the tilted value
@@ -240,7 +207,7 @@ public class MarkerView extends Marker {
*
* @param tiltValue the tilted value to set
*/
- void setTilt(float tiltValue) {
+ void setTilt(@FloatRange(from = 0.0, to = MapboxConstants.MAXIMUM_TILT) float tiltValue) {
this.tiltValue = tiltValue;
}
@@ -308,7 +275,7 @@ public class MarkerView extends Marker {
*
* @param alpha the alpha value to animate to
*/
- public void setAlpha(float alpha) {
+ public void setAlpha(@FloatRange(from = 0.0, to = 255.0) float alpha) {
this.alpha = alpha;
if (markerViewManager != null) {
markerViewManager.animateAlpha(this, alpha);
@@ -316,6 +283,53 @@ public class MarkerView extends Marker {
}
/**
+ * Set the icon of the MarkerView.
+ *
+ * @param icon the icon to be used as Marker image
+ */
+ @Override
+ public void setIcon(@Nullable Icon icon) {
+ if (icon != null) {
+ markerViewIcon = IconFactory.recreate("icon", icon.getBitmap());
+ }
+ Bitmap bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
+ Icon transparentIcon = IconFactory.recreate("markerViewSettings", bitmap);
+ if (markerViewManager != null) {
+ markerViewManager.updateIcon(this);
+ }
+ super.setIcon(transparentIcon);
+ }
+
+ @Override
+ public void setPosition(LatLng position) {
+ super.setPosition(position);
+ if (markerViewManager != null) {
+ markerViewManager.update();
+ }
+ }
+
+ public boolean isSelected() {
+ return selected;
+ }
+
+ /**
+ * For internal use only, use {@link MapboxMap#selectMarker(Marker)} instead.
+ */
+ void setSelected(boolean selected) {
+ this.selected = selected;
+ }
+
+ /**
+ * Get the icon of the MarkerView.
+ *
+ * @return the icon use as Marker image
+ */
+ @Override
+ public Icon getIcon() {
+ return markerViewIcon;
+ }
+
+ /**
* Set the MapboxMap associated tot the MapView containing the MarkerView.
* <p>
* This method is used to instantiate the MarkerView and provide an instance of {@link com.mapbox.mapboxsdk.maps.MapboxMap.MarkerViewAdapter}
@@ -326,6 +340,12 @@ public class MarkerView extends Marker {
@Override
public void setMapboxMap(MapboxMap mapboxMap) {
super.setMapboxMap(mapboxMap);
+
+ if(isFlat()) {
+ // initial tilt value if MapboxMap is started with a tilt attribute
+ tiltValue = (float) mapboxMap.getCameraPosition().tilt;
+ }
+
markerViewManager = mapboxMap.getMarkerViewManager();
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java
index d9fc9e62ae..d138ded963 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java
@@ -1,12 +1,16 @@
package com.mapbox.mapboxsdk.annotations;
+import android.content.Context;
import android.graphics.PointF;
import android.os.SystemClock;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
-import android.support.v4.util.Pools;
+import android.view.LayoutInflater;
import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import com.mapbox.mapboxsdk.R;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.Projection;
@@ -26,12 +30,13 @@ import java.util.Map;
*/
public class MarkerViewManager {
- private Map<MarkerView, View> mMarkerViewMap;
+ private Map<MarkerView, View> markerViewMap;
private MapboxMap mapboxMap;
private MapView mapView;
private List<MapboxMap.MarkerViewAdapter> markerViewAdapters;
- private long mViewMarkerBoundsUpdateTime;
+ private long viewMarkerBoundsUpdateTime;
private MapboxMap.OnMarkerViewClickListener onMarkerViewClickListener;
+ private ImageMarkerViewAdapter defaultMarkerViewAdapter;
/**
* Creates an instance of MarkerViewManager.
@@ -43,7 +48,9 @@ public class MarkerViewManager {
this.mapboxMap = mapboxMap;
this.markerViewAdapters = new ArrayList<>();
this.mapView = mapView;
- mMarkerViewMap = new HashMap<>();
+ this.markerViewMap = new HashMap<>();
+ this.defaultMarkerViewAdapter = new ImageMarkerViewAdapter(mapView.getContext());
+ this.markerViewAdapters.add(defaultMarkerViewAdapter);
}
/**
@@ -56,7 +63,7 @@ public class MarkerViewManager {
* @param rotation the rotation value
*/
public void animateRotation(@NonNull MarkerView marker, float rotation) {
- View convertView = mMarkerViewMap.get(marker);
+ View convertView = markerViewMap.get(marker);
if (convertView != null) {
AnimatorUtils.rotate(convertView, rotation);
}
@@ -72,7 +79,7 @@ public class MarkerViewManager {
* @param alpha the alpha value
*/
public void animateAlpha(@NonNull MarkerView marker, float alpha) {
- View convertView = mMarkerViewMap.get(marker);
+ View convertView = markerViewMap.get(marker);
if (convertView != null) {
AnimatorUtils.alpha(convertView, alpha);
}
@@ -88,7 +95,7 @@ public class MarkerViewManager {
* @param visible the flag indicating if MarkerView is visible
*/
public void animateVisible(@NonNull MarkerView marker, boolean visible) {
- View convertView = mMarkerViewMap.get(marker);
+ View convertView = markerViewMap.get(marker);
if (convertView != null) {
convertView.setVisibility(visible ? View.VISIBLE : View.GONE);
}
@@ -103,20 +110,24 @@ public class MarkerViewManager {
* </p>
*/
public void update() {
- View convertView;
- for (MarkerView marker : mMarkerViewMap.keySet()) {
- convertView = mMarkerViewMap.get(marker);
+ for (final MarkerView marker : markerViewMap.keySet()) {
+ final View convertView = markerViewMap.get(marker);
if (convertView != null) {
PointF point = mapboxMap.getProjection().toScreenLocation(marker.getPosition());
- int x = (int) (marker.getAnchorU() * convertView.getMeasuredWidth());
- int y = (int) (marker.getAnchorV() * convertView.getMeasuredHeight());
-
- marker.setOffsetX(x);
- marker.setOffsetY(y);
+ if (marker.getOffsetX() == -1) {
+ // ensure view is measured first
+ if (convertView.getMeasuredWidth() == 0) {
+ convertView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
+ }
+ int x = (int) (marker.getAnchorU() * convertView.getMeasuredWidth());
+ int y = (int) (marker.getAnchorV() * convertView.getMeasuredHeight());
+ marker.setOffset(x, y);
+ }
- convertView.setX(point.x - x);
- convertView.setY(point.y - y);
+ convertView.setX(point.x - marker.getOffsetX());
+ convertView.setY(point.y - marker.getOffsetY());
+ // animate visibility
if (marker.isVisible() && convertView.getVisibility() == View.GONE) {
convertView.animate().cancel();
convertView.setAlpha(0);
@@ -133,9 +144,9 @@ public class MarkerViewManager {
*/
public void setTilt(float tilt) {
View convertView;
- for (MarkerView markerView : mMarkerViewMap.keySet()) {
+ for (MarkerView markerView : markerViewMap.keySet()) {
if (markerView.isFlat()) {
- convertView = mMarkerViewMap.get(markerView);
+ convertView = markerViewMap.get(markerView);
if (convertView != null) {
markerView.setTilt(tilt);
convertView.setRotationX(tilt);
@@ -145,69 +156,167 @@ public class MarkerViewManager {
}
/**
+ *
+ */
+ public void updateIcon(@NonNull MarkerView markerView) {
+ View convertView = markerViewMap.get(markerView);
+ if (convertView != null && convertView instanceof ImageView) {
+ ((ImageView) convertView).setImageBitmap(markerView.getIcon().getBitmap());
+ }
+ }
+
+ /**
* Animate a MarkerView to a deselected state.
* <p>
- * The {@link MarkerView#getDeselectAnimRes()} will be called to get the related animation.
- * If non are provided, no animation will be started.
+ * The {@link com.mapbox.mapboxsdk.maps.MapboxMap.MarkerViewAdapter#onDeselect(MarkerView, View)} will be called to execute an animation.
* </p>
*
* @param marker the MarkerView to deselect
*/
public void deselect(@NonNull MarkerView marker) {
- final View convertView = mMarkerViewMap.get(marker);
+ deselect(marker, true);
+ }
+
+ /**
+ * Animate a MarkerView to a deselected state.
+ * <p>
+ * The {@link com.mapbox.mapboxsdk.maps.MapboxMap.MarkerViewAdapter#onDeselect(MarkerView, View)} will be called to execute an animation.
+ * </p>
+ *
+ * @param marker the MarkerView to deselect
+ * @param callbackToMap indicates if deselect marker must be called on MapboxMap
+ */
+ public void deselect(@NonNull MarkerView marker, boolean callbackToMap) {
+ final View convertView = markerViewMap.get(marker);
+ if (convertView != null) {
+ for (MapboxMap.MarkerViewAdapter adapter : markerViewAdapters) {
+ if (adapter.getMarkerClass().equals(marker.getClass())) {
+ adapter.onDeselect(marker, convertView);
+ }
+ }
+ if (callbackToMap) {
+ mapboxMap.deselectMarker(marker);
+ }
+ marker.setSelected(false);
+ }
+ }
+
+ /**
+ * Animate a MarkerView to a selected state.
+ *
+ * @param marker the MarkerView object to select
+ */
+ public void select(@NonNull MarkerView marker) {
+ select(marker, true);
+ }
+
+ /**
+ * Animate a MarkerView to a selected state.
+ *
+ * @param marker the MarkerView object to select
+ * @param callbackToMap indicates if select marker must be called on MapboxMap
+ */
+ public void select(@NonNull MarkerView marker, boolean callbackToMap) {
+ final View convertView = markerViewMap.get(marker);
+ for (MapboxMap.MarkerViewAdapter adapter : markerViewAdapters) {
+ if (adapter.getMarkerClass().equals(marker.getClass())) {
+ select(marker, convertView, adapter, callbackToMap);
+ }
+ }
+ }
+
+ /**
+ * Animate a MarkerView to a selected state.
+ * <p>
+ * The {@link com.mapbox.mapboxsdk.maps.MapboxMap.MarkerViewAdapter#onSelect(MarkerView, View, boolean)} will be called to execute an animation.
+ * </p>
+ *
+ * @param marker the MarkerView object to select
+ * @param convertView the View presentation of the MarkerView
+ * @param adapter the adapter used to adapt the marker to the convertView
+ */
+ public void select(@NonNull MarkerView marker, View convertView, MapboxMap.MarkerViewAdapter adapter) {
+ select(marker, convertView, adapter, true);
+ }
+
+
+ /**
+ * Animate a MarkerView to a selected state.
+ * <p>
+ * The {@link com.mapbox.mapboxsdk.maps.MapboxMap.MarkerViewAdapter#onSelect(MarkerView, View, boolean)} will be called to execute an animation.
+ * </p>
+ *
+ * @param marker the MarkerView object to select
+ * @param convertView the View presentation of the MarkerView
+ * @param adapter the adapter used to adapt the marker to the convertView
+ * @param callbackToMap indicates if select marker must be called on MapboxMap
+ */
+ public void select(@NonNull MarkerView marker, View convertView, MapboxMap.MarkerViewAdapter adapter, boolean callbackToMap) {
if (convertView != null) {
- int deselectAnimatorRes = marker.getDeselectAnimRes();
- if (deselectAnimatorRes != 0) {
- AnimatorUtils.animate(convertView, deselectAnimatorRes);
+ if (adapter.onSelect(marker, convertView, false)) {
+ if (callbackToMap) {
+ mapboxMap.selectMarker(marker);
+ }
}
+ marker.setSelected(true);
+ convertView.bringToFront();
}
}
/**
+ * Get view representation from a MarkerView.
+ * <p>
+ * If marker is not found in current viewport, null is returned.
+ * </p>
+ *
+ * @param marker the marker to get the view for
+ * @return the android SDK View object
+ */
+ @Nullable
+ public View getView(MarkerView marker) {
+ return markerViewMap.get(marker);
+ }
+
+ /**
* Remove a MarkerView from a map.
* <p>
* The {@link MarkerView} will be removed using an alpha animation and related {@link View}
- * will be released to the {@link android.support.v4.util.Pools.SimplePool} from the related
+ * will be released to the android.support.v4.util.Pools.SimplePool from the related
* {@link com.mapbox.mapboxsdk.maps.MapboxMap.MarkerViewAdapter}. It's possible to remove
* the {@link MarkerView} from the underlying collection if needed.
* </p>
*
- * @param marker the MarkerView to remove
- * @param removeFromMap flag indicating if a MarkerView will be removed from the collection.
+ * @param marker the MarkerView to remove
*/
- public void removeMarkerView(MarkerView marker, boolean removeFromMap) {
- final View viewHolder = mMarkerViewMap.get(marker);
+ public void removeMarkerView(MarkerView marker) {
+ final View viewHolder = markerViewMap.get(marker);
if (viewHolder != null && marker != null) {
for (final MapboxMap.MarkerViewAdapter<?> adapter : markerViewAdapters) {
- if (adapter.getMarkerClass() == marker.getClass()) {
-
- // get pool of Views associated to an adapter
- final Pools.SimplePool<View> viewPool = adapter.getViewReusePool();
-
- // cancel ongoing animations
- viewHolder.animate().cancel();
- viewHolder.setAlpha(1);
- AnimatorUtils.alpha(viewHolder, 0, new AnimatorUtils.OnAnimationEndListener() {
- @Override
- public void onAnimationEnd() {
- viewHolder.setVisibility(View.GONE);
- viewPool.release(viewHolder);
- }
- });
+ if (adapter.getMarkerClass().equals(marker.getClass())) {
+ if (adapter.prepareViewForReuse(marker, viewHolder)) {
+ // reset offset for reuse
+ marker.setOffset(-1, -1);
+ adapter.releaseView(viewHolder);
+ }
}
}
}
- if (removeFromMap) {
- mMarkerViewMap.remove(marker);
- }
+ markerViewMap.remove(marker);
}
/**
- * Add a MarkerViewAdapter.
+ * Add a MarkerViewAdapter to the MarkerViewManager.
+ * <p>
+ * The provided MarkerViewAdapter must use supply a generic subclass of MarkerView.
+ * </p>
*
* @param markerViewAdapter the MarkerViewAdapter to add
*/
- public void addMarkerViewAdapter(@Nullable MapboxMap.MarkerViewAdapter markerViewAdapter) {
+ public void addMarkerViewAdapter(MapboxMap.MarkerViewAdapter markerViewAdapter) {
+ if (markerViewAdapter.getMarkerClass().equals(MarkerView.class)) {
+ throw new RuntimeException("Providing a custom MarkerViewAdapter requires subclassing MarkerView");
+ }
+
if (!markerViewAdapters.contains(markerViewAdapter)) {
markerViewAdapters.add(markerViewAdapter);
invalidateViewMarkersInBounds();
@@ -223,7 +332,6 @@ public class MarkerViewManager {
return markerViewAdapters;
}
-
/**
* Register a callback to be invoked when this view is clicked.
*
@@ -243,11 +351,11 @@ public class MarkerViewManager {
public void scheduleViewMarkerInvalidation() {
if (!markerViewAdapters.isEmpty()) {
long currentTime = SystemClock.elapsedRealtime();
- if (currentTime < mViewMarkerBoundsUpdateTime) {
+ if (currentTime < viewMarkerBoundsUpdateTime) {
return;
}
invalidateViewMarkersInBounds();
- mViewMarkerBoundsUpdateTime = currentTime + 250;
+ viewMarkerBoundsUpdateTime = currentTime + 250;
}
}
@@ -264,26 +372,27 @@ public class MarkerViewManager {
View convertView;
// remove old markers
- Iterator<MarkerView> iterator = mMarkerViewMap.keySet().iterator();
+ Iterator<MarkerView> iterator = markerViewMap.keySet().iterator();
while (iterator.hasNext()) {
MarkerView m = iterator.next();
if (!markers.contains(m)) {
// remove marker
- convertView = mMarkerViewMap.get(m);
- int deselectAnimRes = m.getDeselectAnimRes();
- if (deselectAnimRes != 0) {
- AnimatorUtils.animate(convertView, deselectAnimRes, 0);
+ convertView = markerViewMap.get(m);
+ for (MapboxMap.MarkerViewAdapter adapter : markerViewAdapters) {
+ if (adapter.getMarkerClass().equals(m.getClass())) {
+ adapter.prepareViewForReuse(m, convertView);
+ adapter.releaseView(convertView);
+ iterator.remove();
+ }
}
- removeMarkerView(m, false);
- iterator.remove();
}
}
// introduce new markers
for (final MarkerView marker : markers) {
- if (!mMarkerViewMap.containsKey(marker)) {
+ if (!markerViewMap.containsKey(marker)) {
for (final MapboxMap.MarkerViewAdapter adapter : markerViewAdapters) {
- if (adapter.getMarkerClass() == marker.getClass()) {
+ if (adapter.getMarkerClass().equals(marker.getClass())) {
convertView = (View) adapter.getViewReusePool().acquire();
final View adaptedView = adapter.getView(marker, convertView, mapView);
if (adaptedView != null) {
@@ -298,18 +407,16 @@ public class MarkerViewManager {
adaptedView.setAlpha(marker.getAlpha());
// visible
- adaptedView.setVisibility(marker.isVisible() ? View.VISIBLE : View.GONE);
+ adaptedView.setVisibility(View.GONE);
if (mapboxMap.getSelectedMarkers().contains(marker)) {
// if a marker to be shown was selected
// replay that animation with duration 0
- int selectAnimRes = marker.getSelectAnimRes();
- if (selectAnimRes != 0) {
- AnimatorUtils.animate(convertView, selectAnimRes, 0);
+ if (adapter.onSelect(marker, adaptedView, true)) {
+ mapboxMap.selectMarker(marker);
}
}
- final int animSelectRes = marker.getSelectAnimRes();
adaptedView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
@@ -319,34 +426,93 @@ public class MarkerViewManager {
}
if (!clickHandled) {
- // InfoWindow offset
- int infoWindowOffsetX = (int) ((adaptedView.getWidth() * marker.getInfoWindowAnchorU()) - marker.getOffsetX());
- int infoWindowOffsetY = (int) ((adaptedView.getHeight() * marker.getInfoWindowAnchorV()) - marker.getOffsetY());
- marker.setTopOffsetPixels(infoWindowOffsetY);
- marker.setRightOffsetPixels(infoWindowOffsetX);
-
- if (animSelectRes != 0) {
- AnimatorUtils.animate(v, animSelectRes, new AnimatorUtils.OnAnimationEndListener() {
- @Override
- public void onAnimationEnd() {
- mapboxMap.selectMarker(marker);
- }
- });
- } else {
- mapboxMap.selectMarker(marker);
- }
+ ensureInfoWindowOffset(marker);
+ select(marker, v, adapter);
}
}
});
- mMarkerViewMap.put(marker, adaptedView);
+ markerViewMap.put(marker, adaptedView);
if (convertView == null) {
- mapView.addView(adaptedView);
+ adaptedView.setVisibility(View.GONE);
+ mapView.getMarkerViewContainer().addView(adaptedView);
}
}
}
}
}
}
+ // trigger update to make newly added ViewMarker visible,
+ // these would only be updated when the map is moved.
+ update();
+ }
+
+ //TODO: This whole method is a stopgap for: https://github.com/mapbox/mapbox-gl-native/issues/5384
+ public void ensureInfoWindowOffset(MarkerView marker) {
+ View view = null;
+ if (markerViewMap.containsKey(marker)) {
+ view = markerViewMap.get(marker);
+ } else {
+ for (final MapboxMap.MarkerViewAdapter adapter : markerViewAdapters) {
+ if (adapter.getMarkerClass().equals(marker.getClass())) {
+ View convertView = (View) adapter.getViewReusePool().acquire();
+ view = adapter.getView(marker, convertView, mapView);
+ break;
+ }
+ }
+ }
+
+ if (view != null) {
+ //Ensure the marker's view is measured first
+ if (view.getMeasuredWidth() == 0) {
+ view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
+ }
+
+ // update position on map
+ if (marker.getOffsetX() == -1) {
+ int x = (int) (marker.getAnchorU() * view.getMeasuredWidth());
+ int y = (int) (marker.getAnchorV() * view.getMeasuredHeight());
+ marker.setOffset(x, y);
+ }
+
+ // InfoWindow offset
+ int infoWindowOffsetX = (int) ((view.getMeasuredWidth() * marker.getInfoWindowAnchorU()) - marker.getOffsetX());
+ int infoWindowOffsetY = (int) ((view.getMeasuredHeight() * marker.getInfoWindowAnchorV()) - marker.getOffsetY());
+ marker.setTopOffsetPixels(infoWindowOffsetY);
+ marker.setRightOffsetPixels(infoWindowOffsetX);
+ }
+ }
+
+ /**
+ * Default MarkerViewAdapter used for base class of MarkerView to adapt a MarkerView to an ImageView
+ */
+ public static class ImageMarkerViewAdapter extends MapboxMap.MarkerViewAdapter<MarkerView> {
+
+ private LayoutInflater inflater;
+
+ public ImageMarkerViewAdapter(Context context) {
+ super(context);
+ inflater = LayoutInflater.from(context);
+ }
+
+ @Nullable
+ @Override
+ public View getView(@NonNull MarkerView marker, @Nullable View convertView, @NonNull ViewGroup parent) {
+ ViewHolder viewHolder;
+ if (convertView == null) {
+ viewHolder = new ViewHolder();
+ convertView = inflater.inflate(R.layout.view_image_marker, parent, false);
+ viewHolder.imageView = (ImageView) convertView.findViewById(R.id.image);
+ convertView.setTag(viewHolder);
+ } else {
+ viewHolder = (ViewHolder) convertView.getTag();
+ }
+ viewHolder.imageView.setImageBitmap(marker.getIcon().getBitmap());
+ return convertView;
+ }
+
+ private static class ViewHolder {
+ ImageView imageView;
+ }
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewOptions.java
index 0c9faed355..86ad873347 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewOptions.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewOptions.java
@@ -4,6 +4,7 @@ import android.graphics.Bitmap;
import android.os.Parcel;
import android.os.Parcelable;
+import com.mapbox.mapboxsdk.exceptions.InvalidMarkerPositionException;
import com.mapbox.mapboxsdk.geometry.LatLng;
/**
@@ -28,10 +29,9 @@ public class MarkerViewOptions extends BaseMarkerViewOptions<MarkerView, MarkerV
flat(in.readByte() != 0);
anchor(in.readFloat(), in.readFloat());
infoWindowAnchor(in.readFloat(), in.readFloat());
- selectAnimatorResource(in.readInt());
- deselectAnimatorResource(in.readInt());
- rotation(in.readInt());
+ rotation(in.readFloat());
visible(in.readByte() != 0);
+ alpha(in.readFloat());
if (in.readByte() != 0) {
// this means we have an icon
String iconId = in.readString();
@@ -61,10 +61,9 @@ public class MarkerViewOptions extends BaseMarkerViewOptions<MarkerView, MarkerV
out.writeFloat(getAnchorV());
out.writeFloat(getInfoWindowAnchorU());
out.writeFloat(getInfoWindowAnchorV());
- out.writeInt(getSelectAnimRes());
- out.writeInt(getDeselectAnimRes());
- out.writeInt(getRotation());
+ out.writeFloat(getRotation());
out.writeByte((byte) (isVisible() ? 1 : 0));
+ out.writeFloat(alpha);
Icon icon = getIcon();
out.writeByte((byte) (icon != null ? 1 : 0));
if (icon != null) {
@@ -75,6 +74,10 @@ public class MarkerViewOptions extends BaseMarkerViewOptions<MarkerView, MarkerV
@Override
public MarkerView getMarker() {
+ if (position == null) {
+ throw new InvalidMarkerPositionException();
+ }
+
marker.setPosition(position);
marker.setSnippet(snippet);
marker.setTitle(title);
@@ -82,10 +85,9 @@ public class MarkerViewOptions extends BaseMarkerViewOptions<MarkerView, MarkerV
marker.setFlat(flat);
marker.setAnchor(anchorU, anchorV);
marker.setInfoWindowAnchor(infoWindowAnchorU, infoWindowAnchorV);
- marker.setSelectAnimRes(selectAnimRes);
- marker.setDeselectAnimRes(deselectAnimRes);
marker.setRotation(rotation);
marker.setVisible(visible);
+ marker.setAlpha(alpha);
return marker;
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MultiPoint.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MultiPoint.java
index d2aaea1d17..a76238fdcb 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MultiPoint.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MultiPoint.java
@@ -34,19 +34,24 @@ public abstract class MultiPoint extends Annotation {
*
* @param points the points of the polyline
*/
- void setPoints(List<LatLng> points) {
+ public void setPoints(List<LatLng> points) {
this.points = new ArrayList<>(points);
+ update();
}
- void addPoint(LatLng point) {
+ public void addPoint(LatLng point) {
points.add(point);
+ update();
}
public float getAlpha() {
return alpha;
}
- void setAlpha(float alpha) {
+ public void setAlpha(float alpha) {
this.alpha = alpha;
+ update();
}
+
+ abstract void update();
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Polygon.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Polygon.java
index 4a07b16827..78e3a99e96 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Polygon.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Polygon.java
@@ -2,10 +2,7 @@ package com.mapbox.mapboxsdk.annotations;
import android.graphics.Color;
-import com.mapbox.mapboxsdk.geometry.LatLng;
-
-import java.util.ArrayList;
-import java.util.List;
+import com.mapbox.mapboxsdk.maps.MapboxMap;
/**
* Polygon is a geometry annotation that's a closed loop of coordinates.
@@ -19,19 +16,49 @@ public final class Polygon extends MultiPoint {
super();
}
+ /**
+ * Get the color of the fill region of the polygon.
+ *
+ * @return the color of the fill
+ */
public int getFillColor() {
return fillColor;
}
+ /**
+ * Get the color fo the stroke of the polygon.
+ *
+ * @return the color of the stroke
+ */
public int getStrokeColor() {
return strokeColor;
}
- void setFillColor(int color) {
+ /**
+ * Sets the color of the fill region of the polygon.
+ *
+ * @param color - the color in ARGB format
+ */
+ public void setFillColor(int color) {
fillColor = color;
+ update();
}
- void setStrokeColor(int color) {
+ /**
+ * Sets the color of the stroke of the polygon.
+ *
+ * @param color - the color in ARGB format
+ */
+ public void setStrokeColor(int color) {
strokeColor = color;
+ update();
+ }
+
+ @Override
+ void update() {
+ MapboxMap mapboxMap = getMapboxMap();
+ if (mapboxMap != null) {
+ mapboxMap.updatePolygon(this);
+ }
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Polyline.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Polyline.java
index cfaf0d21d9..4bf3242d57 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Polyline.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Polyline.java
@@ -2,6 +2,8 @@ package com.mapbox.mapboxsdk.annotations;
import android.graphics.Color;
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+
/**
* Polyline is a geometry feature with an unclosed list of coordinates drawn as a line
*/
@@ -14,10 +16,20 @@ public final class Polyline extends MultiPoint {
super();
}
+ /**
+ * Returns the Polyline tint color.
+ *
+ * @return the tint color
+ */
public int getColor() {
return color;
}
+ /**
+ * Returns the Polyline width.
+ *
+ * @return the width
+ */
public float getWidth() {
return width;
}
@@ -27,8 +39,9 @@ public final class Polyline extends MultiPoint {
*
* @param color - the color in ARGB format
*/
- void setColor(int color) {
+ public void setColor(int color) {
this.color = color;
+ update();
}
/**
@@ -36,7 +49,16 @@ public final class Polyline extends MultiPoint {
*
* @param width in pixels
*/
- void setWidth(float width) {
+ public void setWidth(float width) {
this.width = width;
+ update();
+ }
+
+ @Override
+ void update() {
+ MapboxMap mapboxMap = getMapboxMap();
+ if (mapboxMap != null) {
+ mapboxMap.updatePolyline(this);
+ }
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java
index ece992ad54..3993615eb9 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java
@@ -31,6 +31,16 @@ public class MapboxConstants {
public static final String KEY_META_DATA_STAGING_ACCESS_TOKEN = "com.mapbox.TestEventsAccessToken";
/**
+ * Key used to switch storage to external in AndroidManifest.xml
+ */
+ public final static String KEY_META_DATA_SET_STORAGE_EXTERNAL = "com.mapbox.SetStorageExternal";
+
+ /**
+ * Default value for KEY_META_DATA_SET_STORAGE_EXTERNAL (default is internal storage)
+ */
+ public final static boolean DEFAULT_SET_STORAGE_EXTERNAL = false;
+
+ /**
* Default animation time
*/
public static final int ANIMATION_DURATION = 300;
@@ -116,4 +126,6 @@ public class MapboxConstants {
public static final String MAPBOX_SHARED_PREFERENCES_FILE = "MapboxSharedPreferences";
public static final String MAPBOX_SHARED_PREFERENCE_KEY_VENDORID = "mapboxVendorId";
public static final String MAPBOX_SHARED_PREFERENCE_KEY_TELEMETRY_ENABLED = "mapboxTelemetryEnabled";
+ public static final String MAPBOX_SHARED_PREFERENCE_KEY_TELEMETRY_STAGING_URL = "mapboxTelemetryStagingUrl";
+ public static final String MAPBOX_SHARED_PREFERENCE_KEY_TELEMETRY_STAGING_ACCESS_TOKEN = "mapboxTelemetryStagingAccessToken";
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/Style.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/Style.java
index aa24d58656..51eb038052 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/Style.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/Style.java
@@ -1,7 +1,9 @@
package com.mapbox.mapboxsdk.constants;
import android.support.annotation.StringDef;
+
import com.mapbox.mapboxsdk.maps.MapView;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -15,169 +17,33 @@ import java.lang.annotation.RetentionPolicy;
*/
public class Style {
- /**
- * Mapbox Streets: A complete basemap, perfect for incorporating your own data.
- */
- private static final String MAPBOX_STREETS_BASE = "mapbox://styles/mapbox/streets-v%d";
- /**
- * Outdoors: A general-purpose style tailored to outdoor activities.
- */
- private static final String OUTDOORS_BASE = "mapbox://styles/mapbox/outdoors-v%d";
- /**
- * Light: Subtle light backdrop for data visualizations.
- */
- private static final String LIGHT_BASE = "mapbox://styles/mapbox/light-v%d";
- /**
- * Dark: Subtle dark backdrop for data visualizations.
- */
- private static final String DARK_BASE = "mapbox://styles/mapbox/dark-v%d";
- /**
- * Satellite: A beautiful global satellite and aerial imagery layer.
- */
- private static final String SATELLITE_BASE = "mapbox://styles/mapbox/satellite-v%d";
- /**
- * Satellite Streets: Global satellite and aerial imagery with unobtrusive labels.
- */
- private static final String SATELLITE_STREETS_BASE = "mapbox://styles/mapbox/satellite-streets-v%d";
-
- /**
- * Satellite Streets: Global satellite and aerial imagery with unobtrusive labels (Version 8).
- */
- private static final String SATELLITE_STREETS_V8 = "mapbox://styles/mapbox/satellite-hybrid-v8";
-
- /**
- * Get versioned url of Mapbox streets style.
- * <p>
- * <ul>
- * <li>Current default version is 9.</li>
- * </ul
- * </p>
- * <p>
- * More information on the Mapbox styles API can be found on https://www.mapbox.com/api-documentation/#styles
- * </p>
- *
- * @param version the version of the style.
- * @return uri to load style from
- */
- public static String getMapboxStreetsUrl(int version) {
- return String.format(MapboxConstants.MAPBOX_LOCALE, MAPBOX_STREETS_BASE, version);
- }
-
- /**
- * Get versioned url of Outdoors streets style.
- * <p>
- * <ul>
- * <li>Current version is 9.</li>
- * </ul>
- * </p>
- * <p>
- * More information on the Mapbox styles API can be found on https://www.mapbox.com/api-documentation/#styles
- * </p>
- *
- * @param version the version of the style.
- * @return uri to load style from
- */
- public static String getOutdoorsStyleUrl(int version) {
- return String.format(MapboxConstants.MAPBOX_LOCALE, OUTDOORS_BASE, version);
- }
-
- /**
- * Get versioned url of Light style.
- * <p>
- * <ul>
- * <li>Current default version is 9.</li>
- * </ul>
- * </p>
- * <p>
- * More information on the Mapbox styles API can be found on https://www.mapbox.com/api-documentation/#styles
- * </p>
- *
- * @param version the version of the style.
- * @return uri to load style from
- */
- public static String getLightStyleUrl(int version) {
- return String.format(MapboxConstants.MAPBOX_LOCALE, LIGHT_BASE, version);
- }
-
- /**
- * Get versioned url of Dark style.
- * <p>
- * <ul>
- * <li>Current default version is 9.</li>
- * </ul>
- * </p>
- * <p>
- * More information on the Mapbox styles API can be found on https://www.mapbox.com/api-documentation/#styles
- * </p>
- *
- * @param version the version of the style.
- * @return uri to load style from
- */
- public static String getDarkStyleUrl(int version) {
- return String.format(MapboxConstants.MAPBOX_LOCALE, DARK_BASE, version);
- }
-
- /**
- * Get versioned url of Satellite style.
- * <p>
- * <ul>
- * <li>Current version is 9.</li>
- * </ul>
- * </p>
- * <p>
- * More information on the Mapbox styles API can be found on https://www.mapbox.com/api-documentation/#styles
- * </p>
- *
- * @param version the version of the style.
- * @return uri to load style from
- */
- public static String getSatelliteStyleUrl(int version) {
- return String.format(MapboxConstants.MAPBOX_LOCALE, SATELLITE_BASE, version);
- }
/**
- * Get versioned url of Satellite streets style.
- * <p>
- * <ul>
- * <li>Current version is 9.</li>
- * </ul>
- * </p>
- * <p>
- * More information on the Mapbox styles API can be found on https://www.mapbox.com/api-documentation/#styles
- * </p>
- *
- * @param version the version of the style.
- * @return uri to load style from
+ * Indicates the parameter accepts one of the values from {@link Style}. Using one of these
+ * constants means your map style will always use the latest version and may change as we
+ * improve the style
*/
- public static String getSatelliteStreetsStyleUrl(int version) {
- if (version == 8) {
- return SATELLITE_STREETS_V8;
- }
- return String.format(MapboxConstants.MAPBOX_LOCALE, SATELLITE_STREETS_BASE, version);
- }
-
- /**
- * Indicates the parameter accepts one of the values from {@link Style}.
- *
- * @deprecated use dedicated versioned methods in {@link Style} instead.
- */
- @StringDef({MAPBOX_STREETS, EMERALD, LIGHT, DARK, SATELLITE, SATELLITE_STREETS})
+ @StringDef({MAPBOX_STREETS, OUTDOORS, EMERALD, LIGHT, DARK, SATELLITE, SATELLITE_STREETS})
@Retention(RetentionPolicy.SOURCE)
- @Deprecated
public @interface StyleUrl {
}
// IMPORTANT: If you change any of these you also need to edit them in strings.xml
/**
- * Mapbox Streets: A complete basemap, perfect for incorporating your own data.
- *
- * @deprecated use {@link #getMapboxStreetsUrl(int)} instead.
+ * Mapbox Streets: A complete basemap, perfect for incorporating your own data. Using this
+ * constant means your map style will always use the latest version and may change as we
+ * improve the style.
*/
- @Deprecated
public static final String MAPBOX_STREETS = "mapbox://styles/mapbox/streets-v9";
/**
+ * Outdoors: A general-purpose style tailored to outdoor activities. Using this constant means
+ * your map style will always use the latest version and may change as we improve the style.
+ */
+ public static final String OUTDOORS = "mapbox://styles/mapbox/outdoors-v9";
+
+ /**
* Emerald: A versatile style, with emphasis on road networks and public transit.
*
* @deprecated this style has been deprecated and will be removed in future versions.
@@ -186,34 +52,27 @@ public class Style {
public static final String EMERALD = "mapbox://styles/mapbox/emerald-v8";
/**
- * Light: Subtle light backdrop for data visualizations.
- *
- * @deprecated use {@link #getLightStyleUrl(int)} instead.
+ * Light: Subtle light backdrop for data visualizations. Using this constant means your map
+ * style will always use the latest version and may change as we improve the style.
*/
- @Deprecated
public static final String LIGHT = "mapbox://styles/mapbox/light-v9";
/**
- * Dark: Subtle dark backdrop for data visualizations.
- *
- * @deprecated use {@link #getDarkStyleUrl(int)} (int)} instead.
+ * Dark: Subtle dark backdrop for data visualizations. Using this constant means your map style
+ * will always use the latest version and may change as we improve the style.
*/
- @Deprecated
public static final String DARK = "mapbox://styles/mapbox/dark-v9";
/**
- * Satellite: A beautiful global satellite and aerial imagery layer.
- *
- * @deprecated use {@link #getSatelliteStyleUrl(int)} instead.
+ * Satellite: A beautiful global satellite and aerial imagery layer. Using this constant means
+ * your map style will always use the latest version and may change as we improve the style.
*/
- @Deprecated
public static final String SATELLITE = "mapbox://styles/mapbox/satellite-v9";
/**
- * Satellite Streets: Global satellite and aerial imagery with unobtrusive labels.
- *
- * @deprecated use {@link #getSatelliteStreetsStyleUrl(int)} (int)} instead.
+ * Satellite Streets: Global satellite and aerial imagery with unobtrusive labels. Using this
+ * constant means your map style will always use the latest version and may change as we
+ * improve the style.
*/
- @Deprecated
public static final String SATELLITE_STREETS = "mapbox://styles/mapbox/satellite-streets-v9";
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/ConversionException.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/ConversionException.java
new file mode 100644
index 0000000000..87656db2a9
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/ConversionException.java
@@ -0,0 +1,22 @@
+package com.mapbox.mapboxsdk.exceptions;
+
+/**
+ * Thrown on conversion errors
+ */
+public class ConversionException extends RuntimeException {
+
+ public ConversionException() {
+ }
+
+ public ConversionException(String detailMessage) {
+ super(detailMessage);
+ }
+
+ public ConversionException(String detailMessage, Throwable throwable) {
+ super(detailMessage, throwable);
+ }
+
+ public ConversionException(Throwable throwable) {
+ super(throwable);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidMarkerPositionException.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidMarkerPositionException.java
new file mode 100644
index 0000000000..8dc98118b1
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidMarkerPositionException.java
@@ -0,0 +1,10 @@
+package com.mapbox.mapboxsdk.exceptions;
+
+public class InvalidMarkerPositionException extends RuntimeException {
+
+ public InvalidMarkerPositionException() {
+ super("Adding an invalid Marker to a Map. " +
+ "Missing the required position field. " +
+ "Provide a non null LatLng as position to the Marker.");
+ }
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/MapboxAccountManagerNotStartedException.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/MapboxAccountManagerNotStartedException.java
new file mode 100644
index 0000000000..4954098f15
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/MapboxAccountManagerNotStartedException.java
@@ -0,0 +1,23 @@
+package com.mapbox.mapboxsdk.exceptions;
+
+
+import android.content.Context;
+import android.os.Bundle;
+
+import com.mapbox.mapboxsdk.MapboxAccountManager;
+import com.mapbox.mapboxsdk.maps.MapView;
+
+/**
+ * A MapboxAccountManagerNotStartedException is thrown by {@link com.mapbox.mapboxsdk.maps.MapView}
+ * when {@link MapboxAccountManager} is not started before {@link MapView#onCreate(Bundle)}.
+ *
+ * @see MapView#onCreate(Bundle)
+ * @see MapboxAccountManager#start(Context, String)
+ */
+public class MapboxAccountManagerNotStartedException extends RuntimeException {
+
+ public MapboxAccountManagerNotStartedException() {
+ super("\nMapboxAccountManager was not started correctly. Use MapboxAccountManager#start(Context, String) to initialise. " +
+ "\nMore information in this guide https://www.mapbox.com/help/first-steps-android-sdk/#access-tokens.");
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java
index 5251ab4d6d..2fd28202af 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java
@@ -290,6 +290,13 @@ public class LatLngBounds implements Parcelable {
return LatLngBounds.fromLatLngs(mLatLngList);
}
+ public Builder includes(List<LatLng> latLngs){
+ for (LatLng point : latLngs) {
+ mLatLngList.add(point);
+ }
+ return this;
+ }
+
public Builder include(@NonNull LatLng latLng) {
mLatLngList.add(latLng);
return this;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/layers/CustomLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/layers/CustomLayer.java
deleted file mode 100644
index 30efd59a6e..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/layers/CustomLayer.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.mapbox.mapboxsdk.layers;
-
-public class CustomLayer {
-
- public String mID;
- public long mContext;
- public long mInitializeFunction;
- public long mRenderFunction;
- public long mDeinitializeFunction;
-
- 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;
- }
-
-}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/layers/package-info.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/layers/package-info.java
deleted file mode 100644
index 4c58308c47..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/layers/package-info.java
+++ /dev/null
@@ -1,4 +0,0 @@
-/**
- * Do not use this package. Experimental feature.
- */
-package com.mapbox.mapboxsdk.layers;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationServices.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationServices.java
index 08f18892d2..4fade484b4 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationServices.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationServices.java
@@ -18,12 +18,10 @@ import java.util.concurrent.CopyOnWriteArrayList;
/**
* Manages locational updates. Contains methods to register and unregister location listeners.
- * <p>
* <ul>
* <li>You can register a {@link LocationListener} with {@link #addLocationListener(LocationListener)} to receive location updates.</li>
* <li> You can unregister a {@link LocationListener} with {@link #removeLocationListener(LocationListener)}.</li>
* </ul>
- * <p/>
* <p>
* Note: If registering a listener in your Activity.onResume() implementation, you should unregister it in Activity.onPause().
* (You won't receive location updates when paused, and this will cut down on unnecessary system overhead).
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java
index b34b947a2a..6b0c207a1a 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java
@@ -13,11 +13,10 @@ import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
import android.graphics.Canvas;
-import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.RectF;
-import android.graphics.SurfaceTexture;
import android.graphics.drawable.ColorDrawable;
import android.location.Location;
import android.net.ConnectivityManager;
@@ -45,9 +44,11 @@ import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.Surface;
-import android.view.TextureView;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
import android.view.View;
import android.view.ViewConfiguration;
+import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.FrameLayout;
@@ -77,7 +78,6 @@ import com.mapbox.mapboxsdk.constants.Style;
import com.mapbox.mapboxsdk.exceptions.IconBitmapChangedException;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
-import com.mapbox.mapboxsdk.layers.CustomLayer;
import com.mapbox.mapboxsdk.location.LocationListener;
import com.mapbox.mapboxsdk.location.LocationServices;
import com.mapbox.mapboxsdk.maps.widgets.CompassView;
@@ -124,6 +124,7 @@ public class MapView extends FrameLayout {
private NativeMapView mNativeMapView;
private boolean mHasSurface = false;
+ private ViewGroup mMarkerViewContainer;
private CompassView mCompassView;
private ImageView mLogoView;
private ImageView mAttributionsView;
@@ -142,6 +143,7 @@ public class MapView extends FrameLayout {
private ShoveGestureDetector mShoveGestureDetector;
private boolean mTwoTap = false;
private boolean mZoomStarted = false;
+ private boolean mDragStarted = false;
private boolean mQuickZoom = false;
private boolean mScrollInProgress = false;
@@ -150,9 +152,13 @@ public class MapView extends FrameLayout {
private int mContentPaddingRight;
private int mContentPaddingBottom;
- private StyleInitializer mStyleInitializer;
+ private PointF mFocalPoint;
+
+ private String mStyleUrl;
+ private String mInitalStyle;
private List<OnMapReadyCallback> mOnMapReadyCallbackList;
+ private SnapshotRequest mSnapshotRequest;
@UiThread
public MapView(@NonNull Context context) {
@@ -184,7 +190,6 @@ public class MapView extends FrameLayout {
mOnMapChangedListener = new CopyOnWriteArrayList<>();
mMapboxMap = new MapboxMap(this);
mIcons = new ArrayList<>();
- mStyleInitializer = new StyleInitializer(context);
View view = LayoutInflater.from(context).inflate(R.layout.mapview_internal, this);
if (!isInEditMode()) {
@@ -192,8 +197,7 @@ public class MapView extends FrameLayout {
}
// Reference the TextureView
- TextureView textureView = (TextureView) view.findViewById(R.id.textureView);
- textureView.setSurfaceTextureListener(new SurfaceTextureListener());
+ SurfaceView surfaceView = (SurfaceView) view.findViewById(R.id.surfaceView);
// Check if we are in Android Studio UI editor to avoid error in layout preview
if (isInEditMode()) {
@@ -209,6 +213,8 @@ public class MapView extends FrameLayout {
setFocusableInTouchMode(true);
requestFocus();
+ surfaceView.getHolder().addCallback(new SurfaceCallback());
+
// Touch gesture detectors
mGestureDetector = new GestureDetectorCompat(context, new GestureListener());
mGestureDetector.setIsLongpressEnabled(true);
@@ -224,6 +230,8 @@ public class MapView extends FrameLayout {
// Connectivity
onConnectivityChanged(isConnected());
+ mMarkerViewContainer = (ViewGroup) view.findViewById(R.id.markerViewContainer);
+
mMyLocationView = (MyLocationView) view.findViewById(R.id.userLocationView);
mMyLocationView.setMapboxMap(mMapboxMap);
@@ -252,23 +260,19 @@ public class MapView extends FrameLayout {
CameraPosition position = options.getCamera();
if (position != null) {
mMapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition(position));
+ mMyLocationView.setTilt(position.tilt);
}
- String accessToken = null;
- if (MapboxAccountManager.getInstance() != null) {
- accessToken = MapboxAccountManager.getInstance().getAccessToken();
- } else {
- accessToken = options.getAccessToken();
+ // access token
+ String accessToken = options.getAccessToken();
+ if (!TextUtils.isEmpty(accessToken)) {
+ mMapboxMap.setAccessToken(accessToken);
}
+ // style url
String style = options.getStyle();
- if (!TextUtils.isEmpty(accessToken)) {
- mMapboxMap.setAccessToken(accessToken);
- if (style != null) {
- setStyleUrl(style);
- }
- } else {
- mStyleInitializer.setStyle(style, true);
+ if (!TextUtils.isEmpty(style)) {
+ mInitalStyle = style;
}
// MyLocationView
@@ -356,8 +360,17 @@ public class MapView extends FrameLayout {
*/
@UiThread
public void onCreate(@Nullable Bundle savedInstanceState) {
+ String accessToken = mMapboxMap.getAccessToken();
+ if (TextUtils.isEmpty(accessToken)) {
+ accessToken = MapboxAccountManager.getInstance().getAccessToken();
+ mMapboxMap.setAccessToken(accessToken);
+ } else {
+ // user provided access token through xml attributes, need to start MapboxAccountManager
+ MapboxAccountManager.start(getContext(), accessToken);
+ }
+
// Force a check for an access token
- MapboxAccountManager.validateAccessToken(getAccessToken());
+ MapboxAccountManager.validateAccessToken(accessToken);
if (savedInstanceState != null && savedInstanceState.getBoolean(MapboxConstants.STATE_HAS_SAVED_STATE)) {
@@ -407,7 +420,6 @@ public class MapView extends FrameLayout {
// User location
try {
- //noinspection ResourceType
mMapboxMap.setMyLocationEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_MY_LOCATION_ENABLED));
} catch (SecurityException ignore) {
// User did not accept location permissions
@@ -445,10 +457,20 @@ public class MapView extends FrameLayout {
callback.onMapReady(mMapboxMap);
iterator.remove();
}
+ mMapboxMap.getMarkerViewManager().scheduleViewMarkerInvalidation();
}
} else if (change == REGION_IS_CHANGING || change == REGION_DID_CHANGE || change == DID_FINISH_LOADING_MAP) {
mMapboxMap.getMarkerViewManager().scheduleViewMarkerInvalidation();
+
+ mCompassView.update(getDirection());
+ mMyLocationView.update();
+ mMapboxMap.getMarkerViewManager().update();
+
+ for (InfoWindow infoWindow : mMapboxMap.getInfoWindows()) {
+ infoWindow.update();
+ }
}
+
}
});
@@ -473,7 +495,7 @@ public class MapView extends FrameLayout {
outState.putBoolean(MapboxConstants.STATE_HAS_SAVED_STATE, true);
outState.putParcelable(MapboxConstants.STATE_CAMERA_POSITION, mMapboxMap.getCameraPosition());
outState.putBoolean(MapboxConstants.STATE_DEBUG_ACTIVE, mMapboxMap.isDebugActive());
- outState.putString(MapboxConstants.STATE_STYLE_URL, mStyleInitializer.getStyle());
+ outState.putString(MapboxConstants.STATE_STYLE_URL, mStyleUrl);
outState.putBoolean(MapboxConstants.STATE_MY_LOCATION_ENABLED, mMapboxMap.isMyLocationEnabled());
// TrackingSettings
@@ -504,7 +526,7 @@ public class MapView extends FrameLayout {
// UiSettings - Logo
outState.putInt(MapboxConstants.STATE_LOGO_GRAVITY, uiSettings.getLogoGravity());
outState.putInt(MapboxConstants.STATE_LOGO_MARGIN_LEFT, uiSettings.getLogoMarginLeft());
- outState.putInt(MapboxConstants.STATE_LOGO_MARGIN_TOP, uiSettings.getCompassMarginTop());
+ outState.putInt(MapboxConstants.STATE_LOGO_MARGIN_TOP, uiSettings.getLogoMarginTop());
outState.putInt(MapboxConstants.STATE_LOGO_MARGIN_RIGHT, uiSettings.getLogoMarginRight());
outState.putInt(MapboxConstants.STATE_LOGO_MARGIN_BOTTOM, uiSettings.getLogoMarginBottom());
outState.putBoolean(MapboxConstants.STATE_LOGO_ENABLED, uiSettings.isLogoEnabled());
@@ -555,10 +577,23 @@ public class MapView extends FrameLayout {
mNativeMapView.update();
mMyLocationView.onResume();
- if (mStyleInitializer.isDefaultStyle()) {
+ if (mStyleUrl == null) {
+ // user supplied style through xml
// user has failed to supply a style url
- setStyleUrl(mStyleInitializer.getStyle());
+ setStyleUrl(mInitalStyle == null ? Style.MAPBOX_STREETS : mInitalStyle);
+ }
+ }
+
+ void setFocalPoint(PointF focalPoint) {
+ if (focalPoint == null) {
+ // resetting focal point,
+ UiSettings uiSettings = mMapboxMap.getUiSettings();
+ // need to validate if we need to reset focal point with user provided one
+ if (uiSettings.getFocalPoint() != null) {
+ focalPoint = uiSettings.getFocalPoint();
+ }
}
+ mFocalPoint = focalPoint;
}
/**
@@ -648,6 +683,7 @@ public class MapView extends FrameLayout {
if (mDestroyed) {
return;
}
+ mMyLocationView.setBearing(0);
mNativeMapView.cancelTransitions();
mNativeMapView.resetNorth();
}
@@ -672,11 +708,11 @@ public class MapView extends FrameLayout {
return mContentPaddingBottom;
}
- int getContentWidth(){
+ int getContentWidth() {
return getWidth() - mContentPaddingLeft - mContentPaddingRight;
}
- int getContentHeight(){
+ int getContentHeight() {
return getHeight() - mContentPaddingBottom - mContentPaddingTop;
}
@@ -783,7 +819,7 @@ public class MapView extends FrameLayout {
* <li>{@code asset://...}:
* reads the style from the APK {@code assets/} directory.
* This is used to load a style bundled with your app.</li>
- * <li>{@code null}: loads the default {@link Style#getMapboxStreetsUrl(int)} style.</li>
+ * <li>{@code null}: loads the default {@link Style#MAPBOX_STREETS} style.</li>
* </ul>
* <p>
* This method is asynchronous and will return immediately before the style finishes loading.
@@ -799,7 +835,7 @@ public class MapView extends FrameLayout {
if (mDestroyed) {
return;
}
- mStyleInitializer.setStyle(url);
+ mStyleUrl = url;
mNativeMapView.setStyleUrl(url);
}
@@ -833,7 +869,7 @@ public class MapView extends FrameLayout {
@UiThread
@NonNull
public String getStyleUrl() {
- return mStyleInitializer.getStyle();
+ return mStyleUrl;
}
//
@@ -874,7 +910,7 @@ public class MapView extends FrameLayout {
* <p>
* DEPRECATED @see MapboxAccountManager#getAccessToken()
* </p>
- * <p/>
+ * <p>
* Returns the current Mapbox access token used to load map styles and tiles.
* </p>
*
@@ -991,12 +1027,53 @@ public class MapView extends FrameLayout {
if (updatedMarker.getId() == -1) {
Log.w(MapboxConstants.TAG, "marker has an id of -1, possibly was not added yet, doing nothing");
+ return;
+ }
+
+ if (!(updatedMarker instanceof MarkerView)) {
+ ensureIconLoaded(updatedMarker);
}
- ensureIconLoaded(updatedMarker);
mNativeMapView.updateMarker(updatedMarker);
}
+
+ void updatePolygon(Polygon polygon) {
+ if (mDestroyed) {
+ return;
+ }
+
+ if (polygon == null) {
+ Log.w(MapboxConstants.TAG, "polygon was null, doing nothing");
+ return;
+ }
+
+ if (polygon.getId() == -1) {
+ Log.w(MapboxConstants.TAG, "polygon has an id of -1, indicating the polygon was not added to the map yet.");
+ return;
+ }
+
+ mNativeMapView.updatePolygon(polygon);
+ }
+
+ void updatePolyline(Polyline polyline) {
+ if (mDestroyed) {
+ return;
+ }
+
+ if (polyline == null) {
+ Log.w(MapboxConstants.TAG, "polygon was null, doing nothing");
+ return;
+ }
+
+ if (polyline.getId() == -1) {
+ Log.w(MapboxConstants.TAG, "polygon has an id of -1, indicating the polygon was not added to the map yet.");
+ return;
+ }
+
+ mNativeMapView.updatePolyline(polyline);
+ }
+
private void ensureIconLoaded(Marker marker) {
Icon icon = marker.getIcon();
if (icon == null) {
@@ -1021,7 +1098,7 @@ public class MapView extends FrameLayout {
}
long addMarker(@NonNull Marker marker) {
- if(mDestroyed){
+ if (mDestroyed) {
return 0l;
}
return mNativeMapView.addMarker(marker);
@@ -1120,7 +1197,7 @@ public class MapView extends FrameLayout {
int count = annotationList.size();
for (int i = 0; i < count; i++) {
Annotation annotation = annotationList.get(i);
- if (annotation instanceof MarkerView && idsList.contains(annotation.getId())) {
+ if (annotation instanceof MarkerView) {
annotations.add((MarkerView) annotation);
}
}
@@ -1128,6 +1205,13 @@ public class MapView extends FrameLayout {
return new ArrayList<>(annotations);
}
+ /**
+ * @return the ViewGroup containing the marker views
+ */
+ public ViewGroup getMarkerViewContainer() {
+ return mMarkerViewContainer;
+ }
+
int getTopOffsetPixelsForIcon(Icon icon) {
if (mDestroyed) {
@@ -1317,93 +1401,66 @@ public class MapView extends FrameLayout {
return mNativeMapView.getScale();
}
- // This class handles TextureView callbacks
- private class SurfaceTextureListener implements TextureView.SurfaceTextureListener {
+ private class SurfaceCallback implements SurfaceHolder.Callback {
private Surface mSurface;
- private View mViewHolder;
-
- private static final int VIEW_MARKERS_POOL_SIZE = 20;
-
- // Called when the native surface texture has been created
- // Must do all EGL/GL ES initialization here
@Override
- public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
- mNativeMapView.createSurface(mSurface = new Surface(surface));
- mNativeMapView.resizeFramebuffer(width, height);
+ public void surfaceCreated(SurfaceHolder holder) {
+ mNativeMapView.createSurface(mSurface = holder.getSurface());
mHasSurface = true;
}
- // Called when the native surface texture has been destroyed
- // Must do all EGL/GL ES destruction here
- @Override
- public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
- mHasSurface = false;
-
- if (mNativeMapView != null) {
- mNativeMapView.destroySurface();
- }
- mSurface.release();
- return true;
- }
-
- // Called when the format or size of the native surface texture has been changed
- // Must handle window resizing here.
@Override
- public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (mDestroyed) {
return;
}
-
mNativeMapView.resizeFramebuffer(width, height);
}
- // Called when the SurfaceTexure frame is drawn to screen
- // Must sync with UI here
@Override
- public void onSurfaceTextureUpdated(SurfaceTexture surface) {
- if (mDestroyed) {
- return;
- }
-
- mCompassView.update(getDirection());
- mMyLocationView.update();
- mMapboxMap.getMarkerViewManager().update();
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ mHasSurface = false;
- for (InfoWindow infoWindow : mMapboxMap.getInfoWindows()) {
- infoWindow.update();
+ if (mNativeMapView != null) {
+ mNativeMapView.destroySurface();
}
+ mSurface.release();
}
}
- // Used by UserLocationView
- void update() {
- if (mDestroyed) {
- return;
- }
-
- mNativeMapView.update();
- }
-
CameraPosition invalidateCameraPosition() {
if (mDestroyed) {
return new CameraPosition.Builder().build();
}
- return new CameraPosition.Builder(mNativeMapView.getCameraValues()).build();
+ CameraPosition position = new CameraPosition.Builder(mNativeMapView.getCameraValues()).build();
+ mMyLocationView.setCameraPosition(position);
+ return position;
}
double getBearing() {
if (mDestroyed) {
return 0;
}
- return mNativeMapView.getBearing();
+
+ double direction = -mNativeMapView.getBearing();
+
+ while (direction > 360) {
+ direction -= 360;
+ }
+ while (direction < 0) {
+ direction += 360;
+ }
+
+ return direction;
}
void setBearing(float bearing) {
if (mDestroyed) {
return;
}
+ mMyLocationView.setBearing(bearing);
mNativeMapView.setBearing(bearing);
}
@@ -1411,9 +1468,18 @@ public class MapView extends FrameLayout {
if (mDestroyed) {
return;
}
+ mMyLocationView.setBearing(bearing);
mNativeMapView.setBearing(bearing, duration);
}
+ void setBearing(double bearing, float focalX, float focalY) {
+ if (mDestroyed) {
+ return;
+ }
+ mMyLocationView.setBearing(bearing);
+ mNativeMapView.setBearing(bearing, focalX, focalY);
+ }
+
//
// View events
//
@@ -1455,6 +1521,17 @@ public class MapView extends FrameLayout {
private void trackGestureEvent(@NonNull String gestureId, @NonNull float xCoordinate, @NonNull float yCoordinate) {
LatLng tapLatLng = fromScreenLocation(new PointF(xCoordinate, yCoordinate));
+ // NaN and Infinite checks to prevent JSON errors at send to server time
+ if (Double.isNaN(tapLatLng.getLatitude()) || Double.isNaN(tapLatLng.getLongitude())) {
+ Log.d(MapView.class.getSimpleName(), "trackGestureEvent() has a NaN lat or lon. Returning.");
+ return;
+ }
+
+ if (Double.isInfinite(tapLatLng.getLatitude()) || Double.isInfinite(tapLatLng.getLongitude())) {
+ Log.d(MapView.class.getSimpleName(), "trackGestureEvent() has an Infinite lat or lon. Returning.");
+ return;
+ }
+
Hashtable<String, Object> evt = new Hashtable<>();
evt.put(MapboxEvent.ATTRIBUTE_EVENT, MapboxEvent.TYPE_MAP_CLICK);
evt.put(MapboxEvent.ATTRIBUTE_CREATED, MapboxEventManager.generateCreateDate());
@@ -1476,6 +1553,17 @@ public class MapView extends FrameLayout {
private void trackGestureDragEndEvent(@NonNull float xCoordinate, @NonNull float yCoordinate) {
LatLng tapLatLng = fromScreenLocation(new PointF(xCoordinate, yCoordinate));
+ // NaN and Infinite checks to prevent JSON errors at send to server time
+ if (Double.isNaN(tapLatLng.getLatitude()) || Double.isNaN(tapLatLng.getLongitude())) {
+ Log.d(MapView.class.getSimpleName(), "trackGestureDragEndEvent() has a NaN lat or lon. Returning.");
+ return;
+ }
+
+ if (Double.isInfinite(tapLatLng.getLatitude()) || Double.isInfinite(tapLatLng.getLongitude())) {
+ Log.d(MapView.class.getSimpleName(), "trackGestureDragEndEvent() has an Infinite lat or lon. Returning.");
+ return;
+ }
+
Hashtable<String, Object> evt = new Hashtable<>();
evt.put(MapboxEvent.ATTRIBUTE_EVENT, MapboxEvent.TYPE_MAP_DRAGEND);
evt.put(MapboxEvent.ATTRIBUTE_CREATED, MapboxEventManager.generateCreateDate());
@@ -1533,8 +1621,12 @@ public class MapView extends FrameLayout {
|| mShoveGestureDetector.isInProgress();
if (mTwoTap && isTap && !inProgress) {
- PointF focalPoint = TwoFingerGestureDetector.determineFocalPoint(event);
- zoom(false, focalPoint.x, focalPoint.y);
+ if (mFocalPoint != null) {
+ zoom(false, mFocalPoint.x / mScreenDensity, mFocalPoint.y / mScreenDensity);
+ } else {
+ PointF focalPoint = TwoFingerGestureDetector.determineFocalPoint(event);
+ zoom(false, focalPoint.x, focalPoint.y);
+ }
mTwoTap = false;
return true;
}
@@ -1593,12 +1685,12 @@ public class MapView extends FrameLayout {
}
// Single finger double tap
- if (mMapboxMap.getTrackingSettings().isLocationTrackingDisabled()) {
+ if (mFocalPoint != null) {
+ // User provided focal point
+ zoom(true, mFocalPoint.x, mFocalPoint.y);
+ } else {
// Zoom in on gesture
zoom(true, e.getX(), e.getY());
- } else {
- // Zoom in on user location view
- zoom(true, mMyLocationView.getCenterX(), mMyLocationView.getCenterY());
}
break;
}
@@ -1673,8 +1765,10 @@ public class MapView extends FrameLayout {
}
}
} else {
- // deselect any selected marker
- mMapboxMap.deselectMarkers();
+ if (mMapboxMap.getUiSettings().isDeselectMarkersOnTap()) {
+ // deselect any selected marker
+ mMapboxMap.deselectMarkers();
+ }
// notify app of map click
MapboxMap.OnMapClickListener listener = mMapboxMap.getOnMapClickListener();
@@ -1742,10 +1836,15 @@ public class MapView extends FrameLayout {
return false;
}
+ if (mDragStarted) {
+ return false;
+ }
+
+ requestDisallowInterceptTouchEvent(true);
+
// reset tracking modes if gesture occurs
resetTrackingModesIfRequired();
-
// Cancel any animation
mNativeMapView.cancelTransitions();
@@ -1816,29 +1915,28 @@ public class MapView extends FrameLayout {
return false;
}
+ if (mDragStarted) {
+ return false;
+ }
+
// Cancel any animation
mNativeMapView.cancelTransitions();
// Gesture is a quickzoom if there aren't two fingers
mQuickZoom = !mTwoTap;
- TrackingSettings trackingSettings = mMapboxMap.getTrackingSettings();
-
// Scale the map
- if (uiSettings.isScrollGesturesEnabled() && !mQuickZoom && trackingSettings.isLocationTrackingDisabled()) {
+ if (mFocalPoint != null) {
+ // arround user provided focal point
+ mNativeMapView.scaleBy(detector.getScaleFactor(), mFocalPoint.x / mScreenDensity, mFocalPoint.y / mScreenDensity);
+ } else if (mQuickZoom) {
+ // around center map
+ mNativeMapView.scaleBy(detector.getScaleFactor(), (getWidth() / 2) / mScreenDensity, (getHeight() / 2) / mScreenDensity);
+ } else {
// around gesture
mNativeMapView.scaleBy(detector.getScaleFactor(), detector.getFocusX() / mScreenDensity, detector.getFocusY() / mScreenDensity);
- } else {
- if (trackingSettings.isLocationTrackingDisabled()) {
- // around center map
- mNativeMapView.scaleBy(detector.getScaleFactor(), (getWidth() / 2) / mScreenDensity, (getHeight() / 2) / mScreenDensity);
- } else {
- // around user location view
- float x = mMyLocationView.getX() + mMyLocationView.getWidth() / 2;
- float y = mMyLocationView.getY() + mMyLocationView.getHeight() / 2;
- mNativeMapView.scaleBy(detector.getScaleFactor(), x / mScreenDensity, y / mScreenDensity);
- }
}
+
return true;
}
}
@@ -1881,10 +1979,14 @@ public class MapView extends FrameLayout {
return false;
}
+ if (mDragStarted) {
+ return false;
+ }
+
// If rotate is large enough ignore a tap
// Also is zoom already started, don't rotate
mTotalAngle += detector.getRotationDegreesDelta();
- if (!mZoomStarted && ((mTotalAngle > 10.0f) || (mTotalAngle < -10.0f))) {
+ if (!mZoomStarted && ((mTotalAngle > 20.0f) || (mTotalAngle < -20.0f))) {
mStarted = true;
}
@@ -1908,16 +2010,12 @@ public class MapView extends FrameLayout {
bearing += detector.getRotationDegreesDelta();
// Rotate the map
- if (mMapboxMap.getTrackingSettings().isLocationTrackingDisabled()) {
- // around gesture
- mNativeMapView.setBearing(bearing,
- detector.getFocusX() / mScreenDensity,
- detector.getFocusY() / mScreenDensity);
+ if (mFocalPoint != null) {
+ // User provided focal point
+ setBearing(bearing, mFocalPoint.x / mScreenDensity, mFocalPoint.y / mScreenDensity);
} else {
- // around center userlocation
- float x = mMyLocationView.getX() + mMyLocationView.getWidth() / 2;
- float y = mMyLocationView.getY() + mMyLocationView.getHeight() / 2;
- mNativeMapView.setBearing(bearing, x / mScreenDensity, y / mScreenDensity);
+ // around gesture
+ setBearing(bearing, detector.getFocusX() / mScreenDensity, detector.getFocusY() / mScreenDensity);
}
return true;
}
@@ -1950,6 +2048,7 @@ public class MapView extends FrameLayout {
mBeginTime = 0;
mTotalDelta = 0.0f;
mStarted = false;
+ mDragStarted = false;
}
@Override
@@ -1988,6 +2087,8 @@ public class MapView extends FrameLayout {
// Tilt the map
mMapboxMap.setTilt(pitch);
+ mDragStarted = true;
+
return true;
}
}
@@ -2409,6 +2510,13 @@ public class MapView extends FrameLayout {
mMapboxMap.setMyLocationEnabled(true);
}
mMyLocationView.setMyLocationTrackingMode(myLocationTrackingMode);
+
+ if (myLocationTrackingMode == MyLocationTracking.TRACKING_FOLLOW) {
+ setFocalPoint(new PointF(mMyLocationView.getCenterX(), mMyLocationView.getCenterY()));
+ } else {
+ setFocalPoint(null);
+ }
+
MapboxMap.OnMyLocationTrackingModeChangeListener listener = mMapboxMap.getOnMyLocationTrackingModeChangeListener();
if (listener != null) {
listener.onMyLocationTrackingModeChange(myLocationTrackingMode);
@@ -2514,45 +2622,19 @@ public class MapView extends FrameLayout {
return mMapboxMap.getUiSettings().getAttributionTintColor();
}
- //
- // Custom layer
- //
-
- @UiThread
- void addCustomLayer(CustomLayer customLayer, String before) {
- if (mDestroyed) {
- return;
- }
- mNativeMapView.addCustomLayer(customLayer, before);
- }
-
- @UiThread
- void removeCustomLayer(String id) {
- if (mDestroyed) {
- return;
- }
- mNativeMapView.removeCustomLayer(id);
- }
-
- @UiThread
- void invalidateCustomLayers() {
- if (mDestroyed) {
- return;
- }
- mNativeMapView.update();
- }
-
/**
* Sets a callback object which will be triggered when the {@link MapboxMap} instance is ready to be used.
*
* @param callback The callback object that will be triggered when the map is ready to be used.
*/
@UiThread
- public void getMapAsync(@NonNull final OnMapReadyCallback callback) {
- if (!mInitialLoad) {
+ public void getMapAsync(final OnMapReadyCallback callback) {
+ if (!mInitialLoad && callback != null) {
callback.onMapReady(mMapboxMap);
} else {
- mOnMapReadyCallbackList.add(callback);
+ if (callback != null) {
+ mOnMapReadyCallbackList.add(callback);
+ }
}
}
@@ -2568,20 +2650,55 @@ public class MapView extends FrameLayout {
return mMyLocationView;
}
+ NativeMapView getNativeMapView() {
+ return mNativeMapView;
+ }
+
+ //
+ // Snapshot API
+ //
+
@UiThread
void snapshot(@NonNull final MapboxMap.SnapshotReadyCallback callback, @Nullable final Bitmap bitmap) {
- TextureView textureView = (TextureView) findViewById(R.id.textureView);
- final boolean canUseBitmap = bitmap != null && textureView.getWidth() == bitmap.getWidth() && textureView.getHeight() == bitmap.getHeight();
+ mSnapshotRequest = new SnapshotRequest(bitmap, callback);
+ mNativeMapView.scheduleTakeSnapshot();
+ mNativeMapView.render();
+ }
- setDrawingCacheEnabled(true);
- Bitmap content = Bitmap.createBitmap(getDrawingCache());
- setDrawingCacheEnabled(false);
+ // Called when the snapshot method was executed
+ // Called via JNI from NativeMapView
+ // Forward to any listeners
+ protected void onSnapshotReady(byte[] bytes) {
+ if (mSnapshotRequest != null && bytes != null) {
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inBitmap = mSnapshotRequest.getBitmap(); // the old Bitmap to be reused
+ options.inMutable = true;
+ options.inSampleSize = 1;
+ Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
+
+ MapboxMap.SnapshotReadyCallback callback = mSnapshotRequest.getCallback();
+ if (callback != null) {
+ callback.onSnapshotReady(bitmap);
+ }
+ }
+ }
+
+ private class SnapshotRequest {
+ private Bitmap bitmap;
+ private MapboxMap.SnapshotReadyCallback callback;
+
+ public SnapshotRequest(Bitmap bitmap, MapboxMap.SnapshotReadyCallback callback) {
+ this.bitmap = bitmap;
+ this.callback = callback;
+ }
+
+ public Bitmap getBitmap() {
+ return bitmap;
+ }
- Bitmap output = Bitmap.createBitmap(content.getWidth(), content.getHeight(), Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(output);
- canvas.drawBitmap(canUseBitmap ? textureView.getBitmap(bitmap) : textureView.getBitmap(), 0, 0, null);
- canvas.drawBitmap(content, new Matrix(), null);
- callback.onSnapshotReady(output);
+ public MapboxMap.SnapshotReadyCallback getCallback() {
+ return callback;
+ }
}
//
@@ -2700,41 +2817,6 @@ public class MapView extends FrameLayout {
}
/**
- * Class responsible for managing state of Style loading.
- */
- static class StyleInitializer {
-
- private String mStyle;
- private boolean mDefaultStyle;
-
- StyleInitializer(@NonNull Context context) {
- mStyle = Style.getMapboxStreetsUrl(context.getResources().getInteger(R.integer.style_version));
- mDefaultStyle = true;
- }
-
- void setStyle(@NonNull String style) {
- setStyle(style, false);
- }
-
- void setStyle(@NonNull String style, boolean defaultStyle) {
- if (style == null) {
- // don't override default style
- return;
- }
- mStyle = style;
- mDefaultStyle = defaultStyle;
- }
-
- public String getStyle() {
- return mStyle;
- }
-
- boolean isDefaultStyle() {
- return mDefaultStyle;
- }
- }
-
- /**
* Definition of a map change event.
*
* @see MapView.OnMapChangedListener#onMapChanged(int)
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java
index fbe6a31f6a..26f13ed353 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java
@@ -38,9 +38,10 @@ 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.location.LocationListener;
import com.mapbox.mapboxsdk.maps.widgets.MyLocationViewSettings;
+import com.mapbox.mapboxsdk.style.layers.Layer;
+import com.mapbox.mapboxsdk.style.layers.NoSuchLayerException;
+import com.mapbox.mapboxsdk.style.sources.Source;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
@@ -53,10 +54,11 @@ import java.util.concurrent.TimeUnit;
* you must obtain one from the getMapAsync() method on a MapFragment or MapView that you have
* added to your application.
* <p>
- * Note: Similar to a View object, a GoogleMap should only be read and modified from the main thread.
+ * Note: Similar to a View object, a MapboxMap should only be read and modified from the main thread.
* </p>
*/
public class MapboxMap {
+ private static final String TAG = MapboxMap.class.getSimpleName();
private MapView mMapView;
private UiSettings mUiSettings;
@@ -72,7 +74,6 @@ public class MapboxMap {
private List<InfoWindow> mInfoWindows;
private MapboxMap.InfoWindowAdapter mInfoWindowAdapter;
- private Bitmap mViewMarkerBitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
private boolean mMyLocationEnabled;
private boolean mAllowConcurrentMultipleInfoWindows;
@@ -105,6 +106,54 @@ public class MapboxMap {
mMarkerViewManager = new MarkerViewManager(this, mapView);
}
+ // Style
+
+ @Nullable
+ @UiThread
+ public Layer getLayer(@NonNull String layerId) {
+ return getMapView().getNativeMapView().getLayer(layerId);
+ }
+
+ /**
+ * Tries to cast the Layer to T, returns null if it's another type
+ */
+ @Nullable
+ @UiThread
+ public <T extends Layer> T getLayerAs(@NonNull String layerId) {
+ try {
+ //noinspection unchecked
+ return (T) getMapView().getNativeMapView().getLayer(layerId);
+ } catch (ClassCastException e) {
+ Log.e(TAG, String.format("Layer: %s is a different type: %s", layerId, e.getMessage()));
+ return null;
+ }
+ }
+
+ @UiThread
+ public void addLayer(@NonNull Layer layer) {
+ addLayer(layer, null);
+ }
+
+ @UiThread
+ public void addLayer(@NonNull Layer layer, String before) {
+ getMapView().getNativeMapView().addLayer(layer, before);
+ }
+
+ @UiThread
+ public void removeLayer(@NonNull String layerId) throws NoSuchLayerException {
+ getMapView().getNativeMapView().removeLayer(layerId);
+ }
+
+ @UiThread
+ public void addSource(@NonNull Source source) {
+ getMapView().getNativeMapView().addSource(source);
+ }
+
+ @UiThread
+ public void removeSource(@NonNull String sourceId) {
+ getMapView().getNativeMapView().removeSource(sourceId);
+ }
+
//
// MinZoom
//
@@ -291,7 +340,7 @@ public class MapboxMap {
* it will return the current location of the camera in flight.
*
* @param update The change that should be applied to the camera.
- * @see {@link CameraUpdateFactory} for a set of updates.
+ * @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates.
*/
@UiThread
public final void easeCamera(CameraUpdate update) {
@@ -306,7 +355,7 @@ public class MapboxMap {
* @param update The change that should be applied to the camera.
* @param durationMs The duration of the animation in milliseconds. This must be strictly
* positive, otherwise an IllegalArgumentException will be thrown.
- * @see {@link CameraUpdateFactory} for a set of updates.
+ * @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates.
*/
@UiThread
public final void easeCamera(CameraUpdate update, int durationMs) {
@@ -327,7 +376,7 @@ public class MapboxMap {
* will be notified with onFinish(). If the animation stops due to interruption
* by a later camera movement or a user gesture, onCancel() will be called.
* Do not update or ease the camera from within onCancel().
- * @see {@link CameraUpdateFactory} for a set of camera updates.
+ * @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates.
*/
@UiThread
public final void easeCamera(CameraUpdate update, int durationMs, final MapboxMap.CancelableCallback callback) {
@@ -368,7 +417,7 @@ public class MapboxMap {
* of the camera in flight.
*
* @param update The change that should be applied to the camera.
- * @see {@link CameraUpdateFactory} for a set of updates.
+ * @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates.
*/
@UiThread
public final void animateCamera(CameraUpdate update) {
@@ -385,7 +434,7 @@ public class MapboxMap {
* @param callback The callback to invoke from the main thread when the animation stops. If the
* animation completes normally, onFinish() is called; otherwise, onCancel() is
* called. Do not update or animate the camera from within onCancel().
- * @see {@link CameraUpdateFactory} for a set of updates.
+ * @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates.
*/
@UiThread
public final void animateCamera(CameraUpdate update, MapboxMap.CancelableCallback callback) {
@@ -401,7 +450,7 @@ public class MapboxMap {
* @param update The change that should be applied to the camera.
* @param durationMs The duration of the animation in milliseconds. This must be strictly
* positive, otherwise an IllegalArgumentException will be thrown.
- * @see {@link CameraUpdateFactory} for a set of updates.
+ * @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates.
*/
@UiThread
public final void animateCamera(CameraUpdate update, int durationMs) {
@@ -424,7 +473,7 @@ public class MapboxMap {
* by a later camera movement or a user gesture, onCancel() will be called.
* Do not update or animate the camera from within onCancel(). If a callback
* isn't required, leave it as null.
- * @see {@link CameraUpdateFactory} for a set of updates.
+ * @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates.
*/
@UiThread
public final void animateCamera(CameraUpdate update, int durationMs, final MapboxMap.CancelableCallback callback) {
@@ -550,7 +599,7 @@ public class MapboxMap {
* <li>{@code asset://...}:
* reads the style from the APK {@code assets/} directory.
* This is used to load a style bundled with your app.</li>
- * <li>{@code null}: loads the default {@link Style#getMapboxStreetsUrl(int)} style.</li>
+ * <li>{@code null}: loads the default {@link Style#MAPBOX_STREETS} style.</li>
* </ul>
* <p>
* This method is asynchronous and will return immediately before the style finishes loading.
@@ -703,10 +752,11 @@ public class MapboxMap {
@NonNull
public MarkerView addMarker(@NonNull BaseMarkerViewOptions markerOptions) {
MarkerView marker = prepareViewMarker(markerOptions);
- long id = mMapView.addMarker(marker);
marker.setMapboxMap(this);
+ long id = mMapView.addMarker(marker);
marker.setId(id);
mAnnotations.put(id, marker);
+ mMarkerViewManager.invalidateViewMarkersInBounds();
return marker;
}
@@ -777,6 +827,36 @@ public class MapboxMap {
}
/**
+ * Update a polygon on this map.
+ *
+ * @param polygon An updated polygon object.
+ */
+ @UiThread
+ public void updatePolygon(Polygon polygon) {
+ mMapView.updatePolygon(polygon);
+
+ int index = mAnnotations.indexOfKey(polygon.getId());
+ if (index > -1) {
+ mAnnotations.setValueAt(index, polygon);
+ }
+ }
+
+ /**
+ * Update a polyline on this map.
+ *
+ * @param polyline An updated polyline object.
+ */
+ @UiThread
+ public void updatePolyline(Polyline polyline) {
+ mMapView.updatePolyline(polyline);
+
+ int index = mAnnotations.indexOfKey(polyline.getId());
+ if (index > -1) {
+ mAnnotations.setValueAt(index, polyline);
+ }
+ }
+
+ /**
* Adds a polyline to this map.
*
* @param polylineOptions A polyline options object that defines how to render the polyline.
@@ -952,7 +1032,7 @@ public class MapboxMap {
Marker marker = (Marker) annotation;
marker.hideInfoWindow();
if (marker instanceof MarkerView) {
- mMarkerViewManager.removeMarkerView((MarkerView) marker, true);
+ mMarkerViewManager.removeMarkerView((MarkerView) marker);
}
}
long id = annotation.getId();
@@ -986,7 +1066,7 @@ public class MapboxMap {
Marker marker = (Marker) annotation;
marker.hideInfoWindow();
if (marker instanceof MarkerView) {
- mMarkerViewManager.removeMarkerView((MarkerView) marker, true);
+ mMarkerViewManager.removeMarkerView((MarkerView) marker);
}
}
ids[i] = annotationList.get(i).getId();
@@ -1012,7 +1092,7 @@ public class MapboxMap {
Marker marker = (Marker) annotation;
marker.hideInfoWindow();
if (marker instanceof MarkerView) {
- mMarkerViewManager.removeMarkerView((MarkerView) marker, true);
+ mMarkerViewManager.removeMarkerView((MarkerView) marker);
}
}
}
@@ -1143,6 +1223,11 @@ public class MapboxMap {
}
if (!handledDefaultClick) {
+ if (marker instanceof MarkerView) {
+ mMarkerViewManager.select((MarkerView) marker, false);
+ mMarkerViewManager.ensureInfoWindowOffset((MarkerView) marker);
+ }
+
if (isInfoWindowValidForMarker(marker) || getInfoWindowAdapter() != null) {
mInfoWindows.add(marker.showInfoWindow(this, mMapView));
}
@@ -1166,7 +1251,7 @@ public class MapboxMap {
}
if (marker instanceof MarkerView) {
- mMarkerViewManager.deselect((MarkerView) marker);
+ mMarkerViewManager.deselect((MarkerView) marker, false);
}
}
@@ -1187,6 +1272,10 @@ public class MapboxMap {
marker.hideInfoWindow();
}
+ if (marker instanceof MarkerView) {
+ mMarkerViewManager.deselect((MarkerView) marker, false);
+ }
+
mSelectedMarkers.remove(marker);
}
@@ -1209,7 +1298,11 @@ public class MapboxMap {
private MarkerView prepareViewMarker(BaseMarkerViewOptions markerViewOptions) {
MarkerView marker = markerViewOptions.getMarker();
- Icon icon = IconFactory.recreate("markerViewSettings", mViewMarkerBitmap);
+
+ Icon icon = markerViewOptions.getIcon();
+ if (icon == null) {
+ icon = IconFactory.getInstance(mMapView.getContext()).defaultMarkerView();
+ }
marker.setIcon(icon);
return marker;
}
@@ -1287,9 +1380,11 @@ public class MapboxMap {
//
/**
+ * <p>
* Sets the distance from the edges of the map view’s frame to the edges of the map
* view’s logical viewport.
- * <p/>
+ * </p>
+ * <p>
* When the value of this property is equal to {0,0,0,0}, viewport
* properties such as `centerCoordinate` assume a viewport that matches the map
* view’s frame. Otherwise, those properties are inset, excluding part of the
@@ -1533,10 +1628,8 @@ public class MapboxMap {
*
* @param listener The callback that's invoked when the user clicks on a marker.
* To unset the callback, use null.
- * @deprecated As of release 4.1.0, replaced by {@link com.mapbox.mapboxsdk.location.LocationServices#addLocationListener(LocationListener)})}
*/
@UiThread
- @Deprecated
public void setOnMyLocationChangeListener(@Nullable MapboxMap.OnMyLocationChangeListener listener) {
mMapView.setOnMyLocationChangeListener(listener);
}
@@ -1573,34 +1666,6 @@ public class MapboxMap {
return mOnMyBearingTrackingModeChangeListener;
}
- //
- // Custom layer
- //
-
- /**
- * Do not use this method, experimental feature.
- */
- @UiThread
- public void addCustomLayer(CustomLayer customLayer, String before) {
- mMapView.addCustomLayer(customLayer, before);
- }
-
- /**
- * Do not use this method, experimental feature.
- */
- @UiThread
- public void removeCustomLayer(String id) {
- mMapView.removeCustomLayer(id);
- }
-
- /**
- * Do not use this method, experimental feature.
- */
- @UiThread
- public void invalidateCustomLayers() {
- mMapView.invalidateCustomLayers();
- }
-
MapView getMapView() {
return mMapView;
}
@@ -1621,7 +1686,7 @@ public class MapboxMap {
* Triggers an invalidation of the map view.
*/
public void invalidate() {
- mMapView.update();
+ mMapView.invalidate();
}
/**
@@ -1826,7 +1891,7 @@ public class MapboxMap {
public MarkerViewAdapter(Context context) {
this.context = context;
persistentClass = (Class<U>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
- mViewReusePool = new Pools.SimplePool<>(20);
+ mViewReusePool = new Pools.SimplePool<>(10000);
}
/**
@@ -1841,11 +1906,56 @@ public class MapboxMap {
public abstract View getView(@NonNull U marker, @NonNull View convertView, @NonNull ViewGroup parent);
/**
+ * Called when an MarkerView is removed from the MapView or the View object is going to be reused.
+ * <p>
+ * <p>
+ * This method should be used to reset an animated view back to it's original state for view reuse.
+ * </p>
+ * <p>
+ * Returning true indicates you want to the view reuse to be handled automatically.
+ * Returning false indicates you want to perform an animation and you are required calling {@link #releaseView(View)} yourself.
+ * </p>
+ *
+ * @param marker the model representing the MarkerView
+ * @param convertView the reusable view
+ * @return true if you want reuse to occur automatically, false if you want to manage this yourself.
+ */
+ public boolean prepareViewForReuse(@NonNull MarkerView marker, @NonNull View convertView) {
+ return true;
+ }
+
+ /**
+ * Called when a MarkerView is selected from the MapView.
+ * <p>
+ * Returning true from this method indicates you want to move the MarkerView to the selected state.
+ * Returning false indicates you want to animate the View first an manually select the MarkerView when appropriate.
+ * </p>
+ *
+ * @param marker the model representing the MarkerView
+ * @param convertView the reusable view
+ * @param reselectionFromRecycling indicates if the onSelect callback is the initial selection
+ * callback or that selection occurs due to recreation of selected marker
+ * @return true if you want to select the Marker immediately, false if you want to manage this yourself.
+ */
+ public boolean onSelect(@NonNull U marker, @NonNull View convertView, boolean reselectionFromRecycling) {
+ return true;
+ }
+
+ /**
+ * Called when a MarkerView is deselected from the MapView.
+ *
+ * @param marker the model representing the MarkerView
+ * @param convertView the reusable view
+ */
+ public void onDeselect(@NonNull U marker, @NonNull View convertView) {
+ }
+
+ /**
* Returns the generic type of the used MarkerView.
*
* @return the generic type
*/
- public Class<U> getMarkerClass() {
+ public final Class<U> getMarkerClass() {
return persistentClass;
}
@@ -1854,7 +1964,7 @@ public class MapboxMap {
*
* @return the pool associated to this adapter
*/
- public Pools.SimplePool<View> getViewReusePool() {
+ public final Pools.SimplePool<View> getViewReusePool() {
return mViewReusePool;
}
@@ -1863,9 +1973,19 @@ public class MapboxMap {
*
* @return the context used
*/
- public Context getContext() {
+ public final Context getContext() {
return context;
}
+
+ /**
+ * Release a View to the ViewPool.
+ *
+ * @param view the view to be released
+ */
+ public final void releaseView(View view) {
+ view.setVisibility(View.GONE);
+ mViewReusePool.release(view);
+ }
}
/**
@@ -1890,9 +2010,7 @@ public class MapboxMap {
* Interface definition for a callback to be invoked when the the My Location view changes location.
*
* @see MapboxMap#setOnMyLocationChangeListener(OnMyLocationChangeListener)
- * @deprecated As of release 4.1.0, replaced by {@link com.mapbox.mapboxsdk.location.LocationListener}
*/
- @Deprecated
public interface OnMyLocationChangeListener {
/**
* Called when the location of the My Location view has changed
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java
index 17593129e7..0fd6b1390d 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java
@@ -13,10 +13,12 @@ import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.view.Gravity;
+
import com.mapbox.mapboxsdk.R;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
import com.mapbox.mapboxsdk.utils.ColorUtils;
+
import java.util.Arrays;
/**
@@ -176,17 +178,17 @@ public class MapboxMapOptions implements Parcelable {
mapboxMapOptions.myLocationBackgroundTintColor(typedArray.getColor(R.styleable.MapView_my_location_background_tint, Color.TRANSPARENT));
Drawable foregroundDrawable = typedArray.getDrawable(R.styleable.MapView_my_location_foreground);
- if(foregroundDrawable==null){
- foregroundDrawable = ContextCompat.getDrawable(context,R.drawable.ic_mylocationview_normal);
+ if (foregroundDrawable == null) {
+ foregroundDrawable = ContextCompat.getDrawable(context, R.drawable.ic_mylocationview_normal);
}
Drawable foregroundBearingDrawable = typedArray.getDrawable(R.styleable.MapView_my_location_foreground_bearing);
- if(foregroundBearingDrawable==null){
- foregroundBearingDrawable = ContextCompat.getDrawable(context,R.drawable.ic_mylocationview_bearing);
+ if (foregroundBearingDrawable == null) {
+ foregroundBearingDrawable = ContextCompat.getDrawable(context, R.drawable.ic_mylocationview_bearing);
}
Drawable backgroundDrawable = typedArray.getDrawable(R.styleable.MapView_my_location_background);
- if(backgroundDrawable==null){
+ if (backgroundDrawable == null) {
backgroundDrawable = ContextCompat.getDrawable(context, R.drawable.ic_mylocationview_background);
}
@@ -223,6 +225,7 @@ public class MapboxMapOptions implements Parcelable {
*
* @param accessToken Token to be used to access the service
* @return This
+ * @deprecated As of release 4.1.0, replaced by {@link com.mapbox.mapboxsdk.MapboxAccountManager#start(Context, String)}
*/
@Deprecated
public MapboxMapOptions accessToken(String accessToken) {
@@ -451,19 +454,39 @@ public class MapboxMapOptions implements Parcelable {
}
/**
+ * Set the foreground drawables of the MyLocationView.
*
- * @param myLocationForegroundDrawable
- * @param myLocationBearingDrawable
+ * @param myLocationForegroundDrawable the drawable to show as foreground without bearing
+ * @param myLocationBearingDrawable the drawable to show as foreground when bearing is disabled
* @return This
*/
- public MapboxMapOptions myLocationForegroundDrawables(Drawable myLocationForegroundDrawable, Drawable myLocationBearingDrawable ) {
+ public MapboxMapOptions myLocationForegroundDrawables(Drawable myLocationForegroundDrawable, Drawable myLocationBearingDrawable) {
this.myLocationForegroundDrawable = myLocationForegroundDrawable;
this.myLocationForegroundBearingDrawable = myLocationBearingDrawable;
return this;
}
/**
- * @param myLocationBackgroundDrawable
+ * Set the foreground drawable of the MyLocationView.
+ * <p>
+ * The same drawable will be used for both bearing as non bearing modes.
+ * </p>
+ *
+ * @param myLocationForegroundDrawable the drawable to show as foreground
+ * @return This
+ */
+ public MapboxMapOptions myLocationForegroundDrawable(Drawable myLocationForegroundDrawable) {
+ this.myLocationForegroundDrawable = myLocationForegroundDrawable;
+ return this;
+ }
+
+ /**
+ * Set the background drawable of MyLocationView.
+ * <p>
+ * Padding can be added to provide an offset to the background.
+ * </p>
+ *
+ * @param myLocationBackgroundDrawable the drawable to show as background
* @return This
*/
public MapboxMapOptions myLocationBackgroundDrawable(Drawable myLocationBackgroundDrawable) {
@@ -472,7 +495,12 @@ public class MapboxMapOptions implements Parcelable {
}
/**
- * @param myLocationForegroundTintColor
+ * Set the foreground tint color of MyLocationView.
+ * <p>
+ * The color will tint both the foreground and the bearing foreground drawable.
+ * </p>
+ *
+ * @param myLocationForegroundTintColor the color to tint the foreground drawable
* @return This
*/
public MapboxMapOptions myLocationForegroundTintColor(@ColorInt int myLocationForegroundTintColor) {
@@ -481,7 +509,9 @@ public class MapboxMapOptions implements Parcelable {
}
/**
- * @param myLocationBackgroundTintColor
+ * Set the background tint color of MyLocationView.
+ *
+ * @param myLocationBackgroundTintColor the color to tint the background
* @return This
*/
public MapboxMapOptions myLocationBackgroundTintColor(@ColorInt int myLocationBackgroundTintColor) {
@@ -490,7 +520,9 @@ public class MapboxMapOptions implements Parcelable {
}
/**
- * @param myLocationBackgroundPadding
+ * Set the MyLocationView padding.
+ *
+ * @param myLocationBackgroundPadding the color to tint the background
* @return This
*/
public MapboxMapOptions myLocationBackgroundPadding(int[] myLocationBackgroundPadding) {
@@ -499,7 +531,9 @@ public class MapboxMapOptions implements Parcelable {
}
/**
- * @param myLocationAccuracyTintColor
+ * Set the MyLocationView accuracy circle tint color.
+ *
+ * @param myLocationAccuracyTintColor the color to tint the accuracy circle
* @return This
*/
public MapboxMapOptions myLocationAccuracyTint(@ColorInt int myLocationAccuracyTintColor) {
@@ -508,7 +542,9 @@ public class MapboxMapOptions implements Parcelable {
}
/**
- * @param alpha
+ * Set the MyLocationView accuracy alpha value.
+ *
+ * @param alpha the alpha value
* @return This
*/
public MapboxMapOptions myLocationAccuracyAlpha(@IntRange(from = 0, to = 255) int alpha) {
@@ -691,6 +727,11 @@ public class MapboxMapOptions implements Parcelable {
return attributionMargins;
}
+ /**
+ * Get the current configured tint color for attribution for a map view.
+ *
+ * @return the tint color
+ */
@ColorInt
public int getAttributionTintColor() {
return attributionTintColor;
@@ -706,56 +747,72 @@ public class MapboxMapOptions implements Parcelable {
}
/**
- * @return
+ * Get the current configured MyLocationView foreground drawable.
+ *
+ * @return the drawable used as foreground
*/
public Drawable getMyLocationForegroundDrawable() {
return myLocationForegroundDrawable;
}
/**
- * @return
+ * Get the current configured MyLocationView foreground bearing drawable.
+ *
+ * @return the drawable used as foreground when bearing is enabled
*/
public Drawable getMyLocationForegroundBearingDrawable() {
return myLocationForegroundBearingDrawable;
}
/**
- * @return
+ * Get the current configured MyLocationView background drawable.
+ *
+ * @return the drawable used as background
*/
public Drawable getMyLocationBackgroundDrawable() {
return myLocationBackgroundDrawable;
}
/**
- * @return
+ * Get the current configured MyLocationView foreground tint color.
+ *
+ * @return the tint color
*/
public int getMyLocationForegroundTintColor() {
return myLocationForegroundTintColor;
}
/**
- * @return
+ * Get the current configured MyLocationView background tint color.
+ *
+ * @return the tint color
*/
public int getMyLocationBackgroundTintColor() {
return myLocationBackgroundTintColor;
}
/**
- * @return
+ * Get the current configured MyLocationView background padding.
+ *
+ * @return an array describing the padding in a LTRB manner
*/
public int[] getMyLocationBackgroundPadding() {
return myLocationBackgroundPadding;
}
/**
- * @return
+ * Get the current configured MyLocationView accuracy circle color tint value.
+ *
+ * @return the tint color
*/
public int getMyLocationAccuracyTintColor() {
return myLocationAccuracyTintColor;
}
/**
- * @return
+ * Get the current configured MyLocationView accuracy circle alpha value.
+ *
+ * @return the alpha value
*/
public int getMyLocationAccuracyAlpha() {
return myLocationAccuracyAlpha;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java
index 6c092ee0c8..929f515d8d 100755
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java
@@ -5,15 +5,21 @@ import android.content.Context;
import android.graphics.PointF;
import android.graphics.RectF;
import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.view.Surface;
+import com.mapbox.mapboxsdk.annotations.Icon;
import com.mapbox.mapboxsdk.annotations.Marker;
import com.mapbox.mapboxsdk.annotations.Polygon;
import com.mapbox.mapboxsdk.annotations.Polyline;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
import com.mapbox.mapboxsdk.geometry.ProjectedMeters;
-import com.mapbox.mapboxsdk.layers.CustomLayer;
+import com.mapbox.mapboxsdk.offline.OfflineManager;
+import com.mapbox.mapboxsdk.style.layers.Layer;
+import com.mapbox.mapboxsdk.style.layers.NoSuchLayerException;
+import com.mapbox.mapboxsdk.style.sources.Source;
import java.util.List;
@@ -50,7 +56,7 @@ final class NativeMapView {
public NativeMapView(MapView mapView) {
Context context = mapView.getContext();
- String dataPath = context.getFilesDir().getAbsolutePath();
+ String dataPath = OfflineManager.getDatabasePath(context);
// With the availability of offline, we're unifying the ambient (cache) and the offline
// databases to be in the same folder, outside cache, to avoid automatic deletion from
@@ -230,7 +236,7 @@ final class NativeMapView {
}
public void setLatLng(LatLng latLng, long duration) {
- nativeSetLatLng(mNativeMapViewPtr, latLng, duration);
+ nativeSetLatLng(mNativeMapViewPtr, latLng.getLatitude(), latLng.getLongitude(), duration);
}
public LatLng getLatLng() {
@@ -343,7 +349,7 @@ final class NativeMapView {
}
public long addMarker(Marker marker) {
- Marker[] markers = { marker };
+ Marker[] markers = {marker};
return nativeAddMarkers(mNativeMapViewPtr, markers)[0];
}
@@ -352,7 +358,7 @@ final class NativeMapView {
}
public long addPolyline(Polyline polyline) {
- Polyline[] polylines = { polyline };
+ Polyline[] polylines = {polyline};
return nativeAddPolylines(mNativeMapViewPtr, polylines)[0];
}
@@ -361,7 +367,7 @@ final class NativeMapView {
}
public long addPolygon(Polygon polygon) {
- Polygon[] polygons = { polygon };
+ Polygon[] polygons = {polygon};
return nativeAddPolygons(mNativeMapViewPtr, polygons)[0];
}
@@ -370,11 +376,25 @@ final class NativeMapView {
}
public void updateMarker(Marker marker) {
- nativeUpdateMarker(mNativeMapViewPtr, marker);
+ LatLng position = marker.getPosition();
+ Icon icon = marker.getIcon();
+ nativeUpdateMarker(mNativeMapViewPtr, marker.getId(), position.getLatitude(), position.getLongitude(), icon.getId());
+ }
+
+ public void updatePolygon(Polygon polygon) {
+ //TODO remove new id assignment, https://github.com/mapbox/mapbox-gl-native/issues/5844
+ long newId = nativeUpdatePolygon(mNativeMapViewPtr, polygon.getId(), polygon);
+ polygon.setId(newId);
+ }
+
+ public void updatePolyline(Polyline polyline) {
+ //TODO remove new id assignment, https://github.com/mapbox/mapbox-gl-native/issues/5844
+ long newId = nativeUpdatePolyline(mNativeMapViewPtr, polyline.getId(), polyline);
+ polyline.setId(newId);
}
public void removeAnnotation(long id) {
- long[] ids = { id };
+ long[] ids = {id};
removeAnnotations(ids);
}
@@ -423,19 +443,19 @@ final class NativeMapView {
}
public ProjectedMeters projectedMetersForLatLng(LatLng latLng) {
- return nativeProjectedMetersForLatLng(mNativeMapViewPtr, latLng);
+ return nativeProjectedMetersForLatLng(mNativeMapViewPtr, latLng.getLatitude(), latLng.getLongitude());
}
public LatLng latLngForProjectedMeters(ProjectedMeters projectedMeters) {
- return nativeLatLngForProjectedMeters(mNativeMapViewPtr, projectedMeters);
+ return nativeLatLngForProjectedMeters(mNativeMapViewPtr, projectedMeters.getNorthing(), projectedMeters.getEasting());
}
public PointF pixelForLatLng(LatLng latLng) {
- return nativePixelForLatLng(mNativeMapViewPtr, latLng);
+ return nativePixelForLatLng(mNativeMapViewPtr, latLng.getLatitude(), latLng.getLongitude());
}
public LatLng latLngForPixel(PointF pixel) {
- return nativeLatLngForPixel(mNativeMapViewPtr, pixel);
+ return nativeLatLngForPixel(mNativeMapViewPtr, pixel.x, pixel.y);
}
public double getTopOffsetPixelsForAnnotationSymbol(String symbolName) {
@@ -443,27 +463,46 @@ final class NativeMapView {
}
public void jumpTo(double angle, LatLng center, double pitch, double zoom) {
- nativeJumpTo(mNativeMapViewPtr, angle, center, pitch, zoom);
+ nativeJumpTo(mNativeMapViewPtr, angle, center.getLatitude(), center.getLongitude(), pitch, zoom);
}
public void easeTo(double angle, LatLng center, long duration, double pitch, double zoom, boolean easingInterpolator) {
- nativeEaseTo(mNativeMapViewPtr, angle, center, duration, pitch, zoom, easingInterpolator);
+ nativeEaseTo(mNativeMapViewPtr, angle, center.getLatitude(), center.getLongitude(), duration, pitch, zoom, easingInterpolator);
}
public void flyTo(double angle, LatLng center, long duration, double pitch, double zoom) {
- nativeFlyTo(mNativeMapViewPtr, angle, center, duration, pitch, zoom);
+ nativeFlyTo(mNativeMapViewPtr, angle, center.getLatitude(), center.getLongitude(), duration, pitch, zoom);
}
- public void addCustomLayer(CustomLayer customLayer, String before) {
- nativeAddCustomLayer(mNativeMapViewPtr, customLayer, before);
+ public double[] getCameraValues() {
+ return nativeGetCameraValues(mNativeMapViewPtr);
}
- public void removeCustomLayer(String id) {
- nativeRemoveCustomLayer(mNativeMapViewPtr, id);
+ // Runtime style Api
+
+ public Layer getLayer(String layerId) {
+ return nativeGetLayer(mNativeMapViewPtr, layerId);
}
- public double[] getCameraValues(){
- return nativeGetCameraValues(mNativeMapViewPtr);
+ public void addLayer(@NonNull Layer layer, @Nullable String before) {
+ nativeAddLayer(mNativeMapViewPtr, layer.getNativePtr(), before);
+ layer.invalidate();
+ }
+
+ public void removeLayer(@NonNull String layerId) throws NoSuchLayerException {
+ nativeRemoveLayer(mNativeMapViewPtr, layerId);
+ }
+
+ public void addSource(@NonNull Source source) {
+ nativeAddSource(mNativeMapViewPtr, source.getId(), source);
+ }
+
+ public void removeSource(@NonNull String sourceId) {
+ nativeRemoveSource(mNativeMapViewPtr, sourceId);
+ }
+
+ public void scheduleTakeSnapshot() {
+ nativeScheduleTakeSnapshot(mNativeMapViewPtr);
}
//
@@ -482,6 +521,10 @@ final class NativeMapView {
mMapView.onFpsChanged(fps);
}
+ protected void onSnapshotReady(byte[] bytes) {
+ mMapView.onSnapshotReady(bytes);
+ }
+
//
// JNI methods
//
@@ -539,7 +582,7 @@ final class NativeMapView {
private native void nativeMoveBy(long nativeMapViewPtr, double dx,
double dy, long duration);
- private native void nativeSetLatLng(long nativeMapViewPtr, LatLng latLng,
+ private native void nativeSetLatLng(long nativeMapViewPtr, double latitude, double longitude,
long duration);
private native LatLng nativeGetLatLng(long nativeMapViewPtr);
@@ -588,7 +631,7 @@ final class NativeMapView {
private native void nativeResetNorth(long nativeMapViewPtr);
- private native void nativeUpdateMarker(long nativeMapViewPtr, Marker marker);
+ private native void nativeUpdateMarker(long nativeMapViewPtr, long markerId, double lat, double lon, String iconId);
private native long[] nativeAddMarkers(long nativeMapViewPtr, Marker[] markers);
@@ -620,25 +663,37 @@ final class NativeMapView {
private native double nativeGetMetersPerPixelAtLatitude(long nativeMapViewPtr, double lat, double zoom);
- private native ProjectedMeters nativeProjectedMetersForLatLng(long nativeMapViewPtr, LatLng latLng);
+ private native ProjectedMeters nativeProjectedMetersForLatLng(long nativeMapViewPtr, double latitude, double longitude);
- private native LatLng nativeLatLngForProjectedMeters(long nativeMapViewPtr, ProjectedMeters projectedMeters);
+ private native LatLng nativeLatLngForProjectedMeters(long nativeMapViewPtr, double northing, double easting);
- private native PointF nativePixelForLatLng(long nativeMapViewPtr, LatLng latLng);
+ private native PointF nativePixelForLatLng(long nativeMapViewPtr, double lat, double lon);
- private native LatLng nativeLatLngForPixel(long nativeMapViewPtr, PointF pixel);
+ private native LatLng nativeLatLngForPixel(long nativeMapViewPtr, float x, float y);
private native double nativeGetTopOffsetPixelsForAnnotationSymbol(long nativeMapViewPtr, String symbolName);
- private native void nativeJumpTo(long nativeMapViewPtr, double angle, LatLng center, double pitch, double zoom);
+ private native void nativeJumpTo(long nativeMapViewPtr, double angle, double latitude, double longitude, double pitch, double zoom);
- private native void nativeEaseTo(long nativeMapViewPtr, double angle, LatLng center, long duration, double pitch, double zoom, boolean easingInterpolator);
+ private native void nativeEaseTo(long nativeMapViewPtr, double angle, double latitude, double longitude, long duration, double pitch, double zoom, boolean easingInterpolator);
- private native void nativeFlyTo(long nativeMapViewPtr, double angle, LatLng center, long duration, double pitch, double zoom);
+ private native void nativeFlyTo(long nativeMapViewPtr, double angle, double latitude, double longitude, long duration, double pitch, double zoom);
- private native void nativeAddCustomLayer(long nativeMapViewPtr, CustomLayer customLayer, String before);
+ private native double[] nativeGetCameraValues(long mNativeMapViewPtr);
- private native void nativeRemoveCustomLayer(long nativeMapViewPtr, String id);
+ private native Layer nativeGetLayer(long nativeMapViewPtr, String layerId);
- private native double[] nativeGetCameraValues(long mNativeMapViewPtr);
+ private native void nativeAddLayer(long nativeMapViewPtr, long layerPtr, String before);
+
+ private native void nativeRemoveLayer(long nativeMapViewPtr, String layerId) throws NoSuchLayerException;
+
+ private native void nativeAddSource(long mNativeMapViewPtr, String id, Source source);
+
+ private native void nativeRemoveSource(long mNativeMapViewPtr, String sourceId);
+
+ private native long nativeUpdatePolygon(long nativeMapViewPtr, long polygonId, Polygon polygon);
+
+ private native long nativeUpdatePolyline(long nativeMapviewPtr, long polylineId, Polyline polyline);
+
+ private native void nativeScheduleTakeSnapshot(long nativeMapViewPtr);
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java
index d37c3a02ea..a41b2606a5 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java
@@ -31,7 +31,7 @@ public class Projection {
* @param latitude The latitude for which to return the value.
* @return The distance measured in meters.
*/
- public double getMetersPerPixelAtLatitude(@FloatRange(from = -180, to = 180) double latitude) {
+ public double getMetersPerPixelAtLatitude(@FloatRange(from = -90, to = 90) double latitude) {
return mMapView.getMetersPerPixelAtLatitude(latitude);
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java
index 30492bc421..f2a49f102b 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java
@@ -101,7 +101,7 @@ public class TrackingSettings {
*
* @return True to indicate the tracking modes will be dismissed.
* @deprecated use @link #isAllDismissTrackingOnGestureinstead
- */
+ */
@Deprecated
public boolean isDismissTrackingOnGesture() {
return dismissLocationTrackingOnGesture && dismissBearingTrackingOnGesture;
@@ -215,7 +215,7 @@ public class TrackingSettings {
private void validateGesturesForBearingTrackingMode() {
int myBearingTrackingMode = getMyBearingTrackingMode();
if (!dismissBearingTrackingOnGesture) {
- if (myBearingTrackingMode == MyBearingTracking.NONE) {
+ if (myBearingTrackingMode == MyBearingTracking.NONE || myLocationTrackingMode == MyLocationTracking.TRACKING_NONE) {
uiSettings.setRotateGesturesEnabled(true);
} else {
uiSettings.setRotateGesturesEnabled(false);
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java
index 3cd9efb13e..4ce631fc3e 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java
@@ -1,7 +1,9 @@
package com.mapbox.mapboxsdk.maps;
+import android.graphics.PointF;
import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
import android.view.Gravity;
import android.view.View;
@@ -33,6 +35,10 @@ public class UiSettings {
private boolean zoomControlsEnabled;
+ private boolean deselectMarkersOnTap = true;
+
+ private PointF focalPoint;
+
UiSettings(@NonNull MapView mapView) {
this.mapView = mapView;
this.compassSettings = new ViewSettings();
@@ -484,6 +490,26 @@ public class UiSettings {
}
/**
+ * Gets whether the markers are automatically deselected (and therefore, their infowindows
+ * closed) when a map tap is detected.
+
+ * @return If true, markers are deselected on a map tap.
+ */
+ public boolean isDeselectMarkersOnTap() {
+ return deselectMarkersOnTap;
+ }
+
+ /**
+ * Sets whether the markers are automatically deselected (and therefore, their infowindows
+ * closed) when a map tap is detected.
+ *
+ * @param deselectMarkersOnTap
+ */
+ public void setDeselectMarkersOnTap(boolean deselectMarkersOnTap) {
+ this.deselectMarkersOnTap = deselectMarkersOnTap;
+ }
+
+ /**
* <p>
* Changes whether the user may scroll around the map.
* </p>
@@ -542,6 +568,25 @@ public class UiSettings {
}
/**
+ * Sets the focal point used as center for a gesture
+ *
+ * @param focalPoint the focal point to be used.
+ */
+ public void setFocalPoint(@Nullable PointF focalPoint) {
+ this.focalPoint = focalPoint;
+ mapView.setFocalPoint(focalPoint);
+ }
+
+ /**
+ * Returns the gesture focal point
+ *
+ * @return The focal point
+ */
+ public PointF getFocalPoint() {
+ return focalPoint;
+ }
+
+ /**
* Returns the measured height of the MapView
*
* @return height in pixels
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java
index aed4e87c07..a37a717482 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java
@@ -1,10 +1,11 @@
package com.mapbox.mapboxsdk.maps.widgets;
-import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
+import android.graphics.Camera;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.PorterDuff;
@@ -15,6 +16,8 @@ import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.location.Location;
+import android.os.Bundle;
+import android.os.Parcelable;
import android.os.SystemClock;
import android.support.annotation.ColorInt;
import android.support.annotation.FloatRange;
@@ -22,8 +25,8 @@ import android.support.annotation.IntRange;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.view.View;
+import android.view.ViewGroup;
-import com.mapbox.mapboxsdk.R;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.constants.MyBearingTracking;
@@ -33,7 +36,6 @@ import com.mapbox.mapboxsdk.location.LocationListener;
import com.mapbox.mapboxsdk.location.LocationServices;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.Projection;
-import com.mapbox.mapboxsdk.maps.UiSettings;
import java.lang.ref.WeakReference;
@@ -45,7 +47,6 @@ public class MyLocationView extends View {
private MyLocationBehavior myLocationBehavior;
private MapboxMap mapboxMap;
private Projection projection;
- private int maxSize;
private int[] contentPadding = new int[4];
private Location location;
@@ -57,12 +58,20 @@ public class MyLocationView extends View {
private float gpsDirection;
private float previousDirection;
- private float accuracy = 0;
- private Paint accuracyPaint = new Paint();
+ private float accuracy;
+ private Paint accuracyPaint;
private ValueAnimator locationChangeAnimator;
private ValueAnimator accuracyAnimator;
- private ObjectAnimator directionAnimator;
+ private ValueAnimator directionAnimator;
+
+ private ValueAnimator.AnimatorUpdateListener invalidateSelfOnUpdateListener =
+ new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ invalidate();
+ }
+ };
private Drawable foregroundDrawable;
private Drawable foregroundBearingDrawable;
@@ -79,6 +88,14 @@ public class MyLocationView extends View {
private int backgroundOffsetRight;
private int backgroundOffsetBottom;
+ private Matrix matrix;
+ private Camera camera;
+ private PointF screenLocation;
+
+ // camera vars
+ private float bearing;
+ private float tilt;
+
@MyLocationTracking.Mode
private int myLocationTrackingMode;
@@ -104,16 +121,44 @@ public class MyLocationView extends View {
}
private void init(Context context) {
+ if(isInEditMode()){
+ return;
+ }
+
setEnabled(false);
+
+ // setup LayoutParams
+ ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT);
+ setLayoutParams(lp);
+
+ matrix = new Matrix();
+ camera = new Camera();
+ camera.setLocation(0, 0, -1000);
+ accuracyPaint = new Paint();
+
myLocationBehavior = new MyLocationBehaviorFactory().getBehavioralModel(MyLocationTracking.TRACKING_NONE);
compassListener = new CompassListener(context);
- maxSize = (int) context.getResources().getDimension(R.dimen.my_locationview_size);
}
public final void setForegroundDrawables(Drawable defaultDrawable, Drawable bearingDrawable) {
- if (defaultDrawable == null || bearingDrawable == null) {
+ if (defaultDrawable == null) {
return;
}
+
+ if (bearingDrawable == null) {
+ // if user only provided one resource
+ // use same for bearing mode
+ bearingDrawable = defaultDrawable.getConstantState().newDrawable();
+ }
+
+ if (backgroundDrawable == null) {
+ // if the user didn't provide a background resource we will use the foreground resource instead,
+ // we need to create a new drawable to handle tinting correctly
+ backgroundDrawable = defaultDrawable.getConstantState().newDrawable();
+ }
+
if (defaultDrawable.getIntrinsicWidth() != bearingDrawable.getIntrinsicWidth() || defaultDrawable.getIntrinsicHeight() != bearingDrawable.getIntrinsicHeight()) {
throw new RuntimeException("The dimensions from location and bearing drawables should be match");
}
@@ -151,7 +196,6 @@ public class MyLocationView extends View {
backgroundOffsetTop = top;
backgroundOffsetRight = right;
backgroundOffsetBottom = bottom;
-
setShadowDrawableTint(backgroundTintColor);
invalidateBounds();
@@ -187,19 +231,18 @@ public class MyLocationView extends View {
int backgroundWidth = backgroundDrawable.getIntrinsicWidth();
int backgroundHeight = backgroundDrawable.getIntrinsicHeight();
-
- int foregroundWidth = foregroundDrawable.getIntrinsicWidth();
- int foregroundHeight = foregroundDrawable.getIntrinsicHeight();
-
int horizontalOffset = backgroundOffsetLeft - backgroundOffsetRight;
int verticalOffset = backgroundOffsetTop - backgroundOffsetBottom;
+ backgroundBounds = new Rect(-backgroundWidth / 2 + horizontalOffset, -backgroundHeight / 2 + verticalOffset, backgroundWidth / 2 + horizontalOffset, backgroundHeight / 2 + verticalOffset);
+ backgroundDrawable.setBounds(backgroundBounds);
- int accuracyWidth = 2 * maxSize;
-
- backgroundBounds = new Rect(accuracyWidth - (backgroundWidth / 2) + horizontalOffset, accuracyWidth + verticalOffset - (backgroundWidth / 2), accuracyWidth + (backgroundWidth / 2) + horizontalOffset, accuracyWidth + (backgroundHeight / 2) + verticalOffset);
- foregroundBounds = new Rect(accuracyWidth - (foregroundWidth / 2), accuracyWidth - (foregroundHeight / 2), accuracyWidth + (foregroundWidth / 2), accuracyWidth + (foregroundHeight / 2));
+ int foregroundWidth = foregroundDrawable.getIntrinsicWidth();
+ int foregroundHeight = foregroundDrawable.getIntrinsicHeight();
+ foregroundBounds = new Rect(-foregroundWidth / 2, -foregroundHeight / 2, foregroundWidth / 2, foregroundHeight / 2);
+ foregroundDrawable.setBounds(foregroundBounds);
+ foregroundBearingDrawable.setBounds(foregroundBounds);
- // invoke a new measure
+ // invoke a new draw
invalidate();
}
@@ -207,23 +250,51 @@ public class MyLocationView extends View {
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
- if (location == null || foregroundBounds == null || backgroundBounds == null || accuracyAnimator == null) {
+ if (location == null || foregroundBounds == null || backgroundBounds == null || accuracyAnimator == null || screenLocation == null) {
// Not ready yet
return;
}
- // Draw circle
+ final PointF pointF = screenLocation;
+
float metersPerPixel = (float) projection.getMetersPerPixelAtLatitude(location.getLatitude());
- float accuracyPixels = (Float) accuracyAnimator.getAnimatedValue() / metersPerPixel;
+ float accuracyPixels = (Float) accuracyAnimator.getAnimatedValue() / metersPerPixel / 2;
float maxRadius = getWidth() / 2;
- canvas.drawCircle(foregroundBounds.centerX(), foregroundBounds.centerY(), accuracyPixels <= maxRadius ? accuracyPixels : maxRadius, accuracyPaint);
+ accuracyPixels = accuracyPixels <= maxRadius ? accuracyPixels : maxRadius;
+
+ // put matrix in origin
+ matrix.reset();
+
+ // apply tilt to camera
+ camera.save();
+ camera.rotate(tilt, 0, bearing);
+
+ // map camera matrix on our matrix
+ camera.getMatrix(matrix);
+
+ //
+ if (myBearingTrackingMode != MyBearingTracking.NONE && directionAnimator != null) {
+ matrix.preRotate((Float) directionAnimator.getAnimatedValue());
+ }
+
+ // put matrix at location of MyLocationView
+ matrix.postTranslate(pointF.x, pointF.y);
+
+ // concat our matrix on canvas
+ canvas.concat(matrix);
- // Draw shadow
+ // restore orientation from camera
+ camera.restore();
+
+ // draw circle
+ canvas.drawCircle(0, 0, accuracyPixels, accuracyPaint);
+
+ // draw shadow
if (backgroundDrawable != null) {
backgroundDrawable.draw(canvas);
}
- // Draw foreground
+ // draw foreground
if (myBearingTrackingMode == MyBearingTracking.NONE) {
if (foregroundDrawable != null) {
foregroundDrawable.draw(canvas);
@@ -233,31 +304,17 @@ public class MyLocationView extends View {
}
}
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
- if (foregroundDrawable != null && foregroundBounds != null) {
- foregroundDrawable.setBounds(foregroundBounds);
- }
-
- if (foregroundBearingDrawable != null && foregroundBounds != null) {
- foregroundBearingDrawable.setBounds(foregroundBounds);
- }
-
- if (backgroundDrawable != null && backgroundBounds != null) {
- backgroundDrawable.setBounds(backgroundBounds);
- }
-
- setMeasuredDimension(4 * maxSize, 4 * maxSize);
+ public void setTilt(@FloatRange(from = 0, to = 60.0f) double tilt) {
+ this.tilt = (float) tilt;
}
- public void setTilt(@FloatRange(from = 0, to = 60.0f) double tilt) {
- setRotationX((float) tilt);
+ public void setBearing(double bearing) {
+ this.bearing = (float) bearing;
}
- void updateOnNextFrame() {
- mapboxMap.invalidate();
+ public void setCameraPosition(CameraPosition position) {
+ setTilt(position.tilt);
+ setBearing(position.bearing);
}
public void onPause() {
@@ -294,6 +351,24 @@ public class MyLocationView extends View {
toggleGps(enabled);
}
+ @Override
+ protected Parcelable onSaveInstanceState() {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable("superState", super.onSaveInstanceState());
+ bundle.putFloat("tilt", tilt);
+ return bundle;
+ }
+
+ @Override
+ public void onRestoreInstanceState(Parcelable state){
+ if (state instanceof Bundle){
+ Bundle bundle = (Bundle) state;
+ tilt = bundle.getFloat("tilt");
+ state = bundle.getParcelable("superState");
+ }
+ super.onRestoreInstanceState(state);
+ }
+
/**
* Enabled / Disable GPS location updates along with updating the UI
*
@@ -345,7 +420,7 @@ public class MyLocationView extends View {
compassListener.onPause();
if (myLocationTrackingMode == MyLocationTracking.TRACKING_FOLLOW) {
// always face north
- gpsDirection = 0;
+ gpsDirection = bearing;
setCompass(gpsDirection);
}
}
@@ -385,8 +460,9 @@ public class MyLocationView extends View {
}
previousDirection = newDir;
- directionAnimator = ObjectAnimator.ofFloat(this, View.ROTATION, oldDir, newDir);
- directionAnimator.setDuration(1000);
+ directionAnimator = ValueAnimator.ofFloat(oldDir, newDir);
+ directionAnimator.setDuration(375);
+ directionAnimator.addUpdateListener(invalidateSelfOnUpdateListener);
directionAnimator.start();
}
@@ -469,29 +545,24 @@ public class MyLocationView extends View {
return;
}
- long currentTime = SystemClock.elapsedRealtime();
- if (currentTime < mCompassUpdateNextTimestamp) {
- return;
- }
-
int type = event.sensor.getType();
- float[] data;
if (type == Sensor.TYPE_ACCELEROMETER) {
- data = mGData;
+ System.arraycopy(event.values, 0, mGData, 0, 3);
} else if (type == Sensor.TYPE_MAGNETIC_FIELD) {
- data = mMData;
+ System.arraycopy(event.values, 0, mMData, 0, 3);
} else {
// we should not be here.
return;
}
- for (int i = 0; i < 3; i++) {
- data[i] = event.values[i];
+ long currentTime = SystemClock.elapsedRealtime();
+ if (currentTime < mCompassUpdateNextTimestamp) {
+ return;
}
SensorManager.getRotationMatrix(mR, mI, mGData, mMData);
SensorManager.getOrientation(mR, mOrientation);
- setCompass((int) (mOrientation[0] * 180.0f / Math.PI));
+ setCompass(mCurrentDegree = (int) (mOrientation[0] * 180.0f / Math.PI));
mCompassUpdateNextTimestamp = currentTime + UPDATE_RATE_MS;
}
@@ -530,7 +601,7 @@ public class MyLocationView extends View {
double latitude = fromLat + (toLat - fromLat) * frac;
double longitude = fromLng + (toLng - fromLng) * frac;
behavior.updateLatLng(latitude, longitude);
- updateOnNextFrame();
+ update();
}
}
@@ -607,7 +678,7 @@ public class MyLocationView extends View {
if (location.hasBearing()) {
builder.bearing(location.getBearing());
}
- gpsDirection = 0;
+ gpsDirection = location.getBearing();
setCompass(gpsDirection);
} else if (myBearingTrackingMode == MyBearingTracking.COMPASS) {
if (!compassListener.isPaused()) {
@@ -626,9 +697,9 @@ public class MyLocationView extends View {
@Override
void invalidate() {
int[] mapPadding = mapboxMap.getPadding();
- UiSettings uiSettings = mapboxMap.getUiSettings();
- setX((uiSettings.getWidth() - getWidth() + mapPadding[0] - mapPadding[2]) / 2 + (contentPadding[0] - contentPadding[2]) / 2);
- setY((uiSettings.getHeight() - getHeight() - mapPadding[3] + mapPadding[1]) / 2 + (contentPadding[1] - contentPadding[3]) / 2);
+ float x = (getWidth() + mapPadding[0] - mapPadding[2]) / 2 + (contentPadding[0] - contentPadding[2]) / 2;
+ float y = (getHeight() - mapPadding[3] + mapPadding[1]) / 2 + (contentPadding[1] - contentPadding[3]) / 2;
+ screenLocation = new PointF(x, y);
MyLocationView.this.invalidate();
}
}
@@ -648,8 +719,8 @@ public class MyLocationView extends View {
latLng = new LatLng(location);
// update LatLng direction
- if (location.hasBearing()) {
- gpsDirection = clamp(location.getBearing() - (float) mapboxMap.getCameraPosition().bearing);
+ if (myBearingTrackingMode == MyBearingTracking.GPS && location.hasBearing()) {
+ gpsDirection = location.getBearing();
setCompass(gpsDirection);
}
@@ -659,7 +730,7 @@ public class MyLocationView extends View {
// calculate updateLatLng time + add some extra offset to improve animation
long previousUpdateTimeStamp = locationUpdateTimestamp;
locationUpdateTimestamp = SystemClock.elapsedRealtime();
- long locationUpdateDuration = (long) ((locationUpdateTimestamp - previousUpdateTimeStamp) * 1.1);
+ long locationUpdateDuration = (long) ((locationUpdateTimestamp - previousUpdateTimeStamp) * 1.3);
// calculate interpolated entity
interpolatedLocation = new LatLng((latLng.getLatitude() + previousLocation.getLatitude()) / 2, (latLng.getLongitude() + previousLocation.getLongitude()) / 2);
@@ -681,24 +752,9 @@ public class MyLocationView extends View {
latLng = interpolatedLocation;
}
- private float clamp(float direction) {
- float diff = previousDirection - direction;
- if (diff > 180.0f) {
- direction += 360.0f;
- } else if (diff < -180.0f) {
- direction -= 360.f;
- }
- previousDirection = direction;
- return direction;
- }
-
@Override
void invalidate() {
- PointF screenLocation = projection.toScreenLocation(latLng);
- if (screenLocation != null) {
- setX((screenLocation.x - getWidth() / 2));
- setY((screenLocation.y - getHeight() / 2));
- }
+ screenLocation = projection.toScreenLocation(latLng);
MyLocationView.this.invalidate();
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettings.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettings.java
index 9ae96ebf7b..80bd1b3bef 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettings.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettings.java
@@ -6,6 +6,9 @@ import android.support.annotation.IntRange;
import com.mapbox.mapboxsdk.maps.MapView;
+/**
+ * Settings to configure the visual appearance of the MyLocationView.
+ */
public class MyLocationViewSettings {
private MapView mapView;
@@ -52,43 +55,101 @@ public class MyLocationViewSettings {
private int[] padding = new int[4];
+ /**
+ * Creates an instance of MyLocationViewSettings
+ *
+ * @param mapView the MapView that hosts the MyLocationView
+ * @param myLocationView the MyLocationView to apply the settings to
+ * @see MyLocationView
+ */
public MyLocationViewSettings(MapView mapView, MyLocationView myLocationView) {
this.mapView = mapView;
this.myLocationView = myLocationView;
}
+ /**
+ * Returns if the MyLocationView is enabled
+ *
+ * @return true if MyLocationView is enabled,
+ */
public boolean isEnabled() {
return enabled;
}
+ /**
+ * Set the enabled state of MyLocationView
+ *
+ * @param enabled true shows the MyLocationView on the map
+ */
public void setEnabled(boolean enabled) {
this.enabled = enabled;
myLocationView.setEnabled(enabled);
}
+ /**
+ * Set the foreground drawable of the MyLocationView
+ * <p>
+ * The foreground drawable is the image visible on screen
+ * </p>
+ *
+ * @param foregroundDrawable the drawable to show as foreground without bearing
+ * @param foregroundBearingDrawable the drawable to show as foreground when bearing is enabled
+ */
public void setForegroundDrawable(Drawable foregroundDrawable, Drawable foregroundBearingDrawable) {
this.foregroundDrawable = foregroundDrawable;
this.foregroundBearingDrawable = foregroundBearingDrawable;
myLocationView.setForegroundDrawables(foregroundDrawable, foregroundBearingDrawable);
}
+ /**
+ * Get the foreground drawable when bearing is disabled.
+ *
+ * @return the drawable used as foreground
+ */
public Drawable getForegroundDrawable() {
return foregroundDrawable;
}
+ /**
+ * Get the foreground drawable when bearing is enabled.
+ *
+ * @return the bearing drawable used as foreground
+ */
public Drawable getForegroundBearingDrawable() {
return foregroundBearingDrawable;
}
+ /**
+ * Set the foreground tint color.
+ * <p>
+ * The color will tint both the foreground and the bearing foreground drawable.
+ * </p>
+ *
+ * @param foregroundTintColor the color to tint the foreground drawable
+ */
public void setForegroundTintColor(@ColorInt int foregroundTintColor) {
this.foregroundTintColor = foregroundTintColor;
myLocationView.setForegroundDrawableTint(foregroundTintColor);
}
+ /**
+ * Get the foreground tint color.
+ *
+ * @return the foreground tint color
+ */
public int getForegroundTintColor() {
return foregroundTintColor;
}
+ /**
+ * Set the background drawable of MyLocationView
+ * <p>
+ * Padding can be added to provide an offset to the background
+ * </p>
+ *
+ * @param backgroundDrawable the drawable to show as background
+ * @param padding the padding added to the background
+ */
public void setBackgroundDrawable(Drawable backgroundDrawable, int[] padding) {
this.backgroundDrawable = backgroundDrawable;
this.backgroundOffset = padding;
@@ -99,46 +160,99 @@ public class MyLocationViewSettings {
}
}
+ /**
+ * Get the background drawable of MyLocationView.
+ *
+ * @return the drawable used as background
+ */
public Drawable getBackgroundDrawable() {
return backgroundDrawable;
}
+ /**
+ * Set the background tint color.
+ *
+ * @param backgroundTintColor the color to tint the background
+ */
public void setBackgroundTintColor(@ColorInt int backgroundTintColor) {
this.backgroundTintColor = backgroundTintColor;
myLocationView.setShadowDrawableTint(backgroundTintColor);
}
+ /**
+ * Get the background tint color.
+ *
+ * @return the background tint color
+ */
public int getBackgroundTintColor() {
return backgroundTintColor;
}
+ /**
+ * Get the background offset.
+ *
+ * @return the background offset
+ */
public int[] getBackgroundOffset() {
return backgroundOffset;
}
+ /**
+ * Set the MyLocationView padding.
+ *
+ * @param left the padding left of MyLocationView
+ * @param top the padding top of MyLocationView
+ * @param right the padding right of MyLocationView
+ * @param bottom the padding bottom of MyLocaionView
+ */
public void setPadding(int left, int top, int right, int bottom) {
padding = new int[]{left, top, right, bottom};
myLocationView.setContentPadding(padding);
mapView.invalidateContentPadding();
}
+ /**
+ * Get the MyLocationView padding.
+ *
+ * @return an array describing the padding in a LTRB manner
+ */
public int[] getPadding() {
return padding;
}
+ /**
+ * Get the alpha value of the accuracy circle of MyLocationView
+ *
+ * @return the alpha value
+ */
public int getAccuracyAlpha() {
return accuracyAlpha;
}
- public void setAccuracyAlpha(@IntRange(from = 0, to = 255) int arruracyAlpha) {
- this.accuracyAlpha = arruracyAlpha;
- myLocationView.setAccuracyAlpha(arruracyAlpha);
+ /**
+ * Set the alpha value of the accuracy circle of MyLocationView
+ *
+ * @param accuracyAlpha the alpha value to set
+ */
+ public void setAccuracyAlpha(@IntRange(from = 0, to = 255) int accuracyAlpha) {
+ this.accuracyAlpha = accuracyAlpha;
+ myLocationView.setAccuracyAlpha(accuracyAlpha);
}
+ /**
+ * Get the accuracy tint color of MyLocationView.
+ *
+ * @return the tint color used for accuracy
+ */
public int getAccuracyTintColor() {
return accuracyTintColor;
}
+ /**
+ * Set the accuracy tint color of MyLocationView.
+ *
+ * @param accuracyTintColor the accuracy tint color
+ */
public void setAccuracyTintColor(@ColorInt int accuracyTintColor) {
this.accuracyTintColor = accuracyTintColor;
myLocationView.setAccuracyTint(accuracyTintColor);
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java
index e81c366dba..ba6434e06d 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java
@@ -1,11 +1,17 @@
package com.mapbox.mapboxsdk.offline;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.util.Log;
+
import com.mapbox.mapboxsdk.MapboxAccountManager;
+import com.mapbox.mapboxsdk.constants.MapboxConstants;
+
import java.io.File;
/**
@@ -88,7 +94,7 @@ public class OfflineManager {
private OfflineManager(Context context) {
// Get a pointer to the DefaultFileSource instance
- String assetRoot = context.getFilesDir().getAbsolutePath();
+ String assetRoot = getDatabasePath(context);
String cachePath = assetRoot + File.separator + DATABASE_NAME;
mDefaultFileSourcePtr = createDefaultFileSource(cachePath, assetRoot, DEFAULT_MAX_CACHE_SIZE);
@@ -100,6 +106,61 @@ public class OfflineManager {
deleteAmbientDatabase(context);
}
+ public static String getDatabasePath(Context context) {
+ // Default value
+ boolean setStorageExternal = MapboxConstants.DEFAULT_SET_STORAGE_EXTERNAL;
+
+ try {
+ // Try getting a custom value from the app Manifest
+ ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(
+ context.getPackageName(), PackageManager.GET_META_DATA);
+ setStorageExternal = appInfo.metaData.getBoolean(
+ MapboxConstants.KEY_META_DATA_SET_STORAGE_EXTERNAL,
+ MapboxConstants.DEFAULT_SET_STORAGE_EXTERNAL);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(LOG_TAG, "Failed to read the package metadata: " + e.getMessage());
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "Failed to read the storage key: " + e.getMessage());
+ }
+
+ String databasePath = null;
+ if (setStorageExternal && isExternalStorageReadable()) {
+ try {
+ // Try getting the external storage path
+ databasePath = context.getExternalFilesDir(null).getAbsolutePath();
+ } catch (NullPointerException e) {
+ Log.e(LOG_TAG, "Failed to obtain the external storage path: " + e.getMessage());
+ }
+ }
+
+ if (databasePath == null) {
+ // Default to internal storage
+ databasePath = context.getFilesDir().getAbsolutePath();
+ }
+
+ return databasePath;
+ }
+
+ /**
+ * Checks if external storage is available to at least read. In order for this to work, make
+ * sure you include <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ * (or WRITE_EXTERNAL_STORAGE) for API level < 18 in your app Manifest.
+ *
+ * Code from https://developer.android.com/guide/topics/data/data-storage.html#filesExternal
+ */
+ public static boolean isExternalStorageReadable() {
+ String state = Environment.getExternalStorageState();
+ if (Environment.MEDIA_MOUNTED.equals(state) || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
+ return true;
+ }
+
+ Log.w(LOG_TAG, "External storage was requested but it isn't readable. For API level < 18"
+ + " make sure you've requested READ_EXTERNAL_STORAGE or WRITE_EXTERNAL_STORAGE"
+ + " permissions in your app Manifest (defaulting to internal storage).");
+
+ return false;
+ }
+
private void deleteAmbientDatabase(final Context context) {
// Delete the file in a separate thread to avoid affecting the UI
new Thread(new Runnable() {
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java
index 7f066e74d1..3756c93df2 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java
@@ -140,6 +140,34 @@ public class OfflineRegion {
public static final int STATE_INACTIVE = 0;
public static final int STATE_ACTIVE = 1;
+ // Keep track of the region state
+ private int state = STATE_INACTIVE;
+
+ private boolean deliverInactiveMessages = false;
+
+ /**
+ * Gets whether or not the `OfflineRegionObserver` will continue to deliver messages even if
+ * the region state has been set as STATE_INACTIVE.
+ */
+ public boolean isDeliveringInactiveMessages() {
+ return deliverInactiveMessages;
+ }
+
+ /**
+ * When set true, the `OfflineRegionObserver` will continue to deliver messages even if
+ * the region state has been set as STATE_INACTIVE (operations happen asynchronously). If set
+ * false, the client won't be notified of further messages.
+ */
+ public void setDeliverInactiveMessages(boolean deliverInactiveMessages) {
+ this.deliverInactiveMessages = deliverInactiveMessages;
+ }
+
+ private boolean deliverMessages() {
+ if (state == STATE_ACTIVE) return true;
+ if (isDeliveringInactiveMessages()) return true;
+ return false;
+ }
+
/*
* Constructor
*/
@@ -180,32 +208,38 @@ public class OfflineRegion {
setOfflineRegionObserver(new OfflineRegionObserver() {
@Override
public void onStatusChanged(final OfflineRegionStatus status) {
- getHandler().post(new Runnable() {
- @Override
- public void run() {
- observer.onStatusChanged(status);
- }
- });
+ if (deliverMessages()) {
+ getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ observer.onStatusChanged(status);
+ }
+ });
+ }
}
@Override
public void onError(final OfflineRegionError error) {
- getHandler().post(new Runnable() {
- @Override
- public void run() {
- observer.onError(error);
- }
- });
+ if (deliverMessages()) {
+ getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ observer.onError(error);
+ }
+ });
+ }
}
@Override
public void mapboxTileCountLimitExceeded(final long limit) {
- getHandler().post(new Runnable() {
- @Override
- public void run() {
- observer.mapboxTileCountLimitExceeded(limit);
- }
- });
+ if (deliverMessages()) {
+ getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ observer.mapboxTileCountLimitExceeded(limit);
+ }
+ });
+ }
}
});
}
@@ -214,6 +248,7 @@ public class OfflineRegion {
* Pause or resume downloading of regional resources.
*/
public void setDownloadState(@DownloadState int state) {
+ this.state = state;
setOfflineRegionDownloadState(state);
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/BackgroundLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/BackgroundLayer.java
new file mode 100644
index 0000000000..fae68c518e
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/BackgroundLayer.java
@@ -0,0 +1,73 @@
+// 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 com.mapbox.mapboxsdk.exceptions.ConversionException;
+
+import android.support.annotation.ColorInt;
+import android.support.annotation.NonNull;
+
+import static com.mapbox.mapboxsdk.utils.ColorUtils.*;
+
+/**
+ * Background Layer
+ */
+public class BackgroundLayer extends Layer {
+
+ public BackgroundLayer(long nativePtr) {
+ super(nativePtr);
+ }
+
+ public BackgroundLayer(String layerId) {
+ initialize(layerId);
+ }
+
+ protected native void initialize(String layerId);
+
+
+ public BackgroundLayer withProperties(@NonNull Property<?>... properties) {
+ setProperties(properties);
+ return this;
+ }
+
+ // Property getters
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getBackgroundColor() {
+ checkValidity();
+ return (PropertyValue<String>) new PropertyValue(nativeGetBackgroundColor());
+ }
+ /**
+ * The color with which the background will be drawn.
+ * @throws RuntimeException
+ */
+ @ColorInt
+ public int getBackgroundColorAsInt() {
+ checkValidity();
+ PropertyValue<String> value = getBackgroundColor();
+ if (value.isValue()) {
+ return rgbaToColor(value.getValue());
+ } else {
+ throw new RuntimeException("background-color was set as a Function");
+ }
+ }
+
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getBackgroundPattern() {
+ checkValidity();
+ return (PropertyValue<String>) new PropertyValue(nativeGetBackgroundPattern());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getBackgroundOpacity() {
+ checkValidity();
+ return (PropertyValue<Float>) new PropertyValue(nativeGetBackgroundOpacity());
+ }
+
+ private native Object nativeGetBackgroundColor();
+
+ private native Object nativeGetBackgroundPattern();
+
+ private native Object nativeGetBackgroundOpacity();
+
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java
new file mode 100644
index 0000000000..ce0e9fd5bd
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java
@@ -0,0 +1,135 @@
+// 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 com.mapbox.mapboxsdk.exceptions.ConversionException;
+
+import android.support.annotation.ColorInt;
+import android.support.annotation.NonNull;
+
+import static com.mapbox.mapboxsdk.utils.ColorUtils.*;
+
+/**
+ * Circle Layer
+ */
+public class CircleLayer extends Layer {
+
+ public CircleLayer(long nativePtr) {
+ super(nativePtr);
+ }
+
+ public CircleLayer(String layerId, String sourceId) {
+ initialize(layerId, sourceId);
+ }
+
+ protected native void initialize(String layerId, String sourceId);
+
+ public void setSourceLayer(String sourceLayer) {
+ checkValidity();
+ nativeSetSourceLayer(sourceLayer);
+ }
+
+ public CircleLayer withSourceLayer(String sourceLayer) {
+ setSourceLayer(sourceLayer);
+ return this;
+ }
+
+ public void setFilter(Filter.Statement filter) {
+ checkValidity();
+ this.setFilter(filter.toArray());
+ }
+
+ public void setFilter(Object[] filter) {
+ checkValidity();
+ nativeSetFilter(filter);
+ }
+
+ public CircleLayer withFilter(Object[] filter) {
+ setFilter(filter);
+ return this;
+ }
+
+ public CircleLayer withFilter(Filter.Statement filter) {
+ setFilter(filter);
+ return this;
+ }
+
+
+ public CircleLayer withProperties(@NonNull Property<?>... properties) {
+ setProperties(properties);
+ return this;
+ }
+
+ // Property getters
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getCircleRadius() {
+ checkValidity();
+ return (PropertyValue<Float>) new PropertyValue(nativeGetCircleRadius());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getCircleColor() {
+ checkValidity();
+ return (PropertyValue<String>) new PropertyValue(nativeGetCircleColor());
+ }
+ /**
+ * The color of the circle.
+ * @throws RuntimeException
+ */
+ @ColorInt
+ public int getCircleColorAsInt() {
+ checkValidity();
+ PropertyValue<String> value = getCircleColor();
+ if (value.isValue()) {
+ return rgbaToColor(value.getValue());
+ } else {
+ throw new RuntimeException("circle-color was set as a Function");
+ }
+ }
+
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getCircleBlur() {
+ checkValidity();
+ return (PropertyValue<Float>) new PropertyValue(nativeGetCircleBlur());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getCircleOpacity() {
+ checkValidity();
+ return (PropertyValue<Float>) new PropertyValue(nativeGetCircleOpacity());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float[]> getCircleTranslate() {
+ checkValidity();
+ return (PropertyValue<Float[]>) new PropertyValue(nativeGetCircleTranslate());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getCircleTranslateAnchor() {
+ checkValidity();
+ return (PropertyValue<String>) new PropertyValue(nativeGetCircleTranslateAnchor());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getCirclePitchScale() {
+ checkValidity();
+ return (PropertyValue<String>) new PropertyValue(nativeGetCirclePitchScale());
+ }
+
+ private native Object nativeGetCircleRadius();
+
+ private native Object nativeGetCircleColor();
+
+ private native Object nativeGetCircleBlur();
+
+ private native Object nativeGetCircleOpacity();
+
+ private native Object nativeGetCircleTranslate();
+
+ private native Object nativeGetCircleTranslateAnchor();
+
+ private native Object nativeGetCirclePitchScale();
+
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CustomLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CustomLayer.java
new file mode 100644
index 0000000000..f25d46dba9
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CustomLayer.java
@@ -0,0 +1,30 @@
+package com.mapbox.mapboxsdk.style.layers;
+
+/**
+ * Custom layer.
+ * <p/>
+ * Experimental feature. Do not use.
+ */
+public class CustomLayer extends Layer {
+
+ public CustomLayer(String id,
+ long context,
+ long initializeFunction,
+ long renderFunction,
+ long deinitializeFunction) {
+ initialize(id, initializeFunction, renderFunction, deinitializeFunction, context);
+ }
+
+ public CustomLayer(long nativePtr) {
+ super(nativePtr);
+ }
+
+ public void invalidate() {
+ nativeUpdate();
+ }
+
+ protected native void initialize(String id, long initializeFunction, long renderFunction, long deinitializeFunction, long context);
+
+ protected native void nativeUpdate();
+
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillLayer.java
new file mode 100644
index 0000000000..d188129e2a
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillLayer.java
@@ -0,0 +1,150 @@
+// 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 com.mapbox.mapboxsdk.exceptions.ConversionException;
+
+import android.support.annotation.ColorInt;
+import android.support.annotation.NonNull;
+
+import static com.mapbox.mapboxsdk.utils.ColorUtils.*;
+
+/**
+ * Fill Layer
+ */
+public class FillLayer extends Layer {
+
+ public FillLayer(long nativePtr) {
+ super(nativePtr);
+ }
+
+ public FillLayer(String layerId, String sourceId) {
+ initialize(layerId, sourceId);
+ }
+
+ protected native void initialize(String layerId, String sourceId);
+
+ public void setSourceLayer(String sourceLayer) {
+ checkValidity();
+ nativeSetSourceLayer(sourceLayer);
+ }
+
+ public FillLayer withSourceLayer(String sourceLayer) {
+ setSourceLayer(sourceLayer);
+ return this;
+ }
+
+ public void setFilter(Filter.Statement filter) {
+ checkValidity();
+ this.setFilter(filter.toArray());
+ }
+
+ public void setFilter(Object[] filter) {
+ checkValidity();
+ nativeSetFilter(filter);
+ }
+
+ public FillLayer withFilter(Object[] filter) {
+ setFilter(filter);
+ return this;
+ }
+
+ public FillLayer withFilter(Filter.Statement filter) {
+ setFilter(filter);
+ return this;
+ }
+
+
+ public FillLayer withProperties(@NonNull Property<?>... properties) {
+ setProperties(properties);
+ return this;
+ }
+
+ // Property getters
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Boolean> getFillAntialias() {
+ checkValidity();
+ return (PropertyValue<Boolean>) new PropertyValue(nativeGetFillAntialias());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getFillOpacity() {
+ checkValidity();
+ return (PropertyValue<Float>) new PropertyValue(nativeGetFillOpacity());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getFillColor() {
+ checkValidity();
+ return (PropertyValue<String>) new PropertyValue(nativeGetFillColor());
+ }
+ /**
+ * The color of the filled part of this layer. This color can be specified as rgba with an alpha component and the color's opacity will not affect the opacity of the 1px stroke, if it is used.
+ * @throws RuntimeException
+ */
+ @ColorInt
+ public int getFillColorAsInt() {
+ checkValidity();
+ PropertyValue<String> value = getFillColor();
+ if (value.isValue()) {
+ return rgbaToColor(value.getValue());
+ } else {
+ throw new RuntimeException("fill-color was set as a Function");
+ }
+ }
+
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getFillOutlineColor() {
+ checkValidity();
+ return (PropertyValue<String>) new PropertyValue(nativeGetFillOutlineColor());
+ }
+ /**
+ * The outline color of the fill. Matches the value of `fill-color` if unspecified.
+ * @throws RuntimeException
+ */
+ @ColorInt
+ public int getFillOutlineColorAsInt() {
+ checkValidity();
+ PropertyValue<String> value = getFillOutlineColor();
+ if (value.isValue()) {
+ return rgbaToColor(value.getValue());
+ } else {
+ throw new RuntimeException("fill-outline-color was set as a Function");
+ }
+ }
+
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float[]> getFillTranslate() {
+ checkValidity();
+ return (PropertyValue<Float[]>) new PropertyValue(nativeGetFillTranslate());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getFillTranslateAnchor() {
+ checkValidity();
+ return (PropertyValue<String>) new PropertyValue(nativeGetFillTranslateAnchor());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getFillPattern() {
+ checkValidity();
+ return (PropertyValue<String>) new PropertyValue(nativeGetFillPattern());
+ }
+
+ private native Object nativeGetFillAntialias();
+
+ private native Object nativeGetFillOpacity();
+
+ private native Object nativeGetFillColor();
+
+ private native Object nativeGetFillOutlineColor();
+
+ private native Object nativeGetFillTranslate();
+
+ private native Object nativeGetFillTranslateAnchor();
+
+ private native Object nativeGetFillPattern();
+
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Filter.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Filter.java
new file mode 100644
index 0000000000..04da4da0cb
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Filter.java
@@ -0,0 +1,115 @@
+package com.mapbox.mapboxsdk.style.layers;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * Utility to build filter expressions more easily:
+ *
+ * @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#types-filter">Style spec</a>
+ */
+public class Filter {
+
+ public abstract static class Statement {
+ protected final String operator;
+
+ public Statement(String operator) {
+ this.operator = operator;
+ }
+
+ public abstract Object[] toArray();
+ }
+
+ public static class SimpleStatement extends Statement {
+ private final String key;
+ private final Object[] values;
+
+ public SimpleStatement(String operator, String key, Object... values) {
+ super(operator);
+ this.key = key;
+ this.values = values;
+ }
+
+
+ @Override
+ public Object[] toArray() {
+ ArrayList<Object> array = new ArrayList<>(2 + values.length);
+ array.add(operator);
+ array.add(key);
+ array.addAll(Arrays.asList(values));
+ return array.toArray();
+ }
+ }
+
+ public static class CompoundStatement extends Statement {
+ private final Statement[] statements;
+
+ public CompoundStatement(String operator, Statement... statements) {
+ super(operator);
+ this.statements = statements;
+ }
+
+ @Override
+ public Object[] toArray() {
+ ArrayList<Object> array = new ArrayList<>(1 + statements.length);
+ array.add(operator);
+ for (Statement statement : statements) {
+ array.add(statement.toArray());
+ }
+ return array.toArray();
+ }
+ }
+
+ public static Statement all(Statement... statements) {
+ return new CompoundStatement("all", statements);
+ }
+
+ public static Statement any(Statement... statements) {
+ return new CompoundStatement("any", statements);
+ }
+
+ public static Statement none(Statement... statements) {
+ return new CompoundStatement("none", statements);
+ }
+
+ public static Statement has(String key) {
+ return new SimpleStatement("has", key);
+ }
+
+ public static Statement notHas(String key) {
+ return new SimpleStatement("!has", key);
+ }
+
+ public static Statement eq(String key, Object value) {
+ return new SimpleStatement("==", key, value);
+ }
+
+ public static Statement neq(String key, Object value) {
+ return new SimpleStatement("!=", key, value);
+ }
+
+ public static Statement gt(String key, Object value) {
+ return new SimpleStatement(">", key, value);
+ }
+
+ public static Statement gte(String key, Object value) {
+ return new SimpleStatement(">=", key, value);
+ }
+
+ public static Statement lt(String key, Object value) {
+ return new SimpleStatement("<", key, value);
+ }
+
+ public static Statement lte(String key, Object value) {
+ return new SimpleStatement("<=", key, value);
+ }
+
+ public static Statement in(String key, Object... values) {
+ return new SimpleStatement("in", key, values);
+ }
+
+ public static Statement notIn(String key, Object... values) {
+ return new SimpleStatement("!in", key, values);
+ }
+
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Function.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Function.java
new file mode 100644
index 0000000000..c776f9ff23
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Function.java
@@ -0,0 +1,85 @@
+package com.mapbox.mapboxsdk.style.layers;
+
+import android.support.annotation.FloatRange;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.Size;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Representation of <a href="https://www.mapbox.com/mapbox-gl-style-spec/#types-function">Function</a> in the Mapbox style specification
+ *
+ * @param <T> the target property's value type. Make sure it matches.
+ */
+public class Function<T> {
+
+ public static class Stop<I, O> {
+ public final I in;
+ public final O out;
+
+ Stop(I in, O out) {
+ this.in = in;
+ this.out = out;
+ }
+
+ Object[] toValueObject() {
+ return new Object[]{in, out};
+ }
+ }
+
+ @SafeVarargs
+ public static <T> Function<T> zoom(@NonNull @Size(min = 1) Stop<Float, T>... stops) {
+ return new Function<T>(stops);
+ }
+
+ @SafeVarargs
+ public static <T> Function<T> zoom(
+ @FloatRange(from = 0, to = 1, fromInclusive = false, toInclusive = false) float base,
+ @NonNull @Size(min = 1) Stop<Float, T>... stops) {
+ return new Function<T>(stops)
+ .withBase(base);
+ }
+
+ public static <T> Stop<Float, T> stop(float in, Property<T> output) {
+ return new Stop<>(in, output.value);
+ }
+
+ private final Stop<Float, T>[] stops;
+ private Float base;
+
+ Function(@NonNull @Size(min = 1) Stop<Float, T>[] stops) {
+ this.stops = stops;
+ }
+
+ Function<T> withBase(float base) {
+ this.base = base;
+ return this;
+ }
+
+ @Nullable
+ public Float getBase() {
+ return base;
+ }
+
+ public Stop<Float, T>[] getStops() {
+ return stops;
+ }
+
+ Map<String, Object> toValueObject() {
+ Object[] stopsValue = new Object[stops.length];
+
+ for (int i = 0; i < stopsValue.length; i++) {
+ Stop stop = stops[i];
+ stopsValue[i] = stop.toValueObject();
+ }
+
+ Map<String, Object> value = new HashMap<>();
+ if (base != null) {
+ value.put("base", base);
+ }
+ value.put("stops", stopsValue);
+ return value;
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Layer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Layer.java
new file mode 100644
index 0000000000..387cedbd6c
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Layer.java
@@ -0,0 +1,112 @@
+package com.mapbox.mapboxsdk.style.layers;
+
+import android.support.annotation.NonNull;
+
+/**
+ * Base class for the different Layer types
+ */
+public abstract class Layer {
+
+ private long nativePtr;
+ private boolean invalidated;
+
+ public Layer(long nativePtr) {
+ this.nativePtr = nativePtr;
+ }
+
+ public Layer() {
+ }
+
+ public void setProperties(@NonNull Property<?>... properties) {
+ checkValidity();
+
+ if (properties.length == 0) {
+ return;
+ }
+
+ boolean updateClasses = false;
+ for (Property<?> property : properties) {
+ if (property instanceof PaintProperty) {
+ updateClasses = true;
+ nativeSetPaintProperty(property.name, convertValue(property.value));
+ } else {
+ nativeSetLayoutProperty(property.name, convertValue(property.value));
+ }
+ }
+
+ nativeUpdateStyle(updateClasses);
+ }
+
+ public String getId() {
+ checkValidity();
+ return nativeGetId();
+ }
+
+ public PropertyValue<String> getVisibility() {
+ checkValidity();
+ return new PropertyValue<>(nativeGetVisibility());
+ }
+
+ public float getMinZoom() {
+ checkValidity();
+ return nativeGetMinZoom();
+ }
+
+ public float getMaxZoom() {
+ checkValidity();
+ return nativeGetMaxZoom();
+ }
+
+ public void setMinZoom(float zoom) {
+ checkValidity();
+ nativeSetMinZoom(zoom);
+ }
+
+ public void setMaxZoom(float zoom) {
+ checkValidity();
+ nativeSetMaxZoom(zoom);
+ }
+
+ @Override
+ protected native void finalize() throws Throwable;
+
+ protected native String nativeGetId();
+
+ protected native Object nativeGetVisibility();
+
+ protected native void nativeSetLayoutProperty(String name, Object value);
+
+ protected native void nativeSetPaintProperty(String name, Object value);
+
+ protected native void nativeSetFilter(Object[] filter);
+
+ protected native void nativeSetSourceLayer(String sourceLayer);
+
+ protected native void nativeUpdateStyle(boolean updateClasses);
+
+ protected native float nativeGetMinZoom();
+
+ protected native float nativeGetMaxZoom();
+
+ protected native void nativeSetMinZoom(float zoom);
+
+ protected native void nativeSetMaxZoom(float zoom);
+
+ public long getNativePtr() {
+ return nativePtr;
+ }
+
+ private Object convertValue(Object value) {
+ return value != null && value instanceof Function ? ((Function) value).toValueObject() : value;
+ }
+
+ protected void checkValidity() {
+ if (invalidated) {
+ throw new RuntimeException("Layer has been invalidated. Request a new reference after adding");
+ }
+ }
+
+ public void invalidate() {
+ this.invalidated = true;
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LayoutProperty.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LayoutProperty.java
new file mode 100644
index 0000000000..553554270e
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LayoutProperty.java
@@ -0,0 +1,9 @@
+package com.mapbox.mapboxsdk.style.layers;
+
+class LayoutProperty<T> extends Property<T> {
+
+ LayoutProperty(String name, T value) {
+ super(name, value);
+ }
+
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LineLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LineLayer.java
new file mode 100644
index 0000000000..ab5dd0815e
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LineLayer.java
@@ -0,0 +1,191 @@
+// 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 com.mapbox.mapboxsdk.exceptions.ConversionException;
+
+import android.support.annotation.ColorInt;
+import android.support.annotation.NonNull;
+
+import static com.mapbox.mapboxsdk.utils.ColorUtils.*;
+
+/**
+ * Line Layer
+ */
+public class LineLayer extends Layer {
+
+ public LineLayer(long nativePtr) {
+ super(nativePtr);
+ }
+
+ public LineLayer(String layerId, String sourceId) {
+ initialize(layerId, sourceId);
+ }
+
+ protected native void initialize(String layerId, String sourceId);
+
+ public void setSourceLayer(String sourceLayer) {
+ checkValidity();
+ nativeSetSourceLayer(sourceLayer);
+ }
+
+ public LineLayer withSourceLayer(String sourceLayer) {
+ setSourceLayer(sourceLayer);
+ return this;
+ }
+
+ public void setFilter(Filter.Statement filter) {
+ checkValidity();
+ this.setFilter(filter.toArray());
+ }
+
+ public void setFilter(Object[] filter) {
+ checkValidity();
+ nativeSetFilter(filter);
+ }
+
+ public LineLayer withFilter(Object[] filter) {
+ setFilter(filter);
+ return this;
+ }
+
+ public LineLayer withFilter(Filter.Statement filter) {
+ setFilter(filter);
+ return this;
+ }
+
+
+ public LineLayer withProperties(@NonNull Property<?>... properties) {
+ setProperties(properties);
+ return this;
+ }
+
+ // Property getters
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getLineCap() {
+ checkValidity();
+ return (PropertyValue<String>) new PropertyValue(nativeGetLineCap());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getLineJoin() {
+ checkValidity();
+ return (PropertyValue<String>) new PropertyValue(nativeGetLineJoin());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getLineMiterLimit() {
+ checkValidity();
+ return (PropertyValue<Float>) new PropertyValue(nativeGetLineMiterLimit());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getLineRoundLimit() {
+ checkValidity();
+ return (PropertyValue<Float>) new PropertyValue(nativeGetLineRoundLimit());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getLineOpacity() {
+ checkValidity();
+ return (PropertyValue<Float>) new PropertyValue(nativeGetLineOpacity());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getLineColor() {
+ checkValidity();
+ return (PropertyValue<String>) new PropertyValue(nativeGetLineColor());
+ }
+ /**
+ * The color with which the line will be drawn.
+ * @throws RuntimeException
+ */
+ @ColorInt
+ public int getLineColorAsInt() {
+ checkValidity();
+ PropertyValue<String> value = getLineColor();
+ if (value.isValue()) {
+ return rgbaToColor(value.getValue());
+ } else {
+ throw new RuntimeException("line-color was set as a Function");
+ }
+ }
+
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float[]> getLineTranslate() {
+ checkValidity();
+ return (PropertyValue<Float[]>) new PropertyValue(nativeGetLineTranslate());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getLineTranslateAnchor() {
+ checkValidity();
+ return (PropertyValue<String>) new PropertyValue(nativeGetLineTranslateAnchor());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getLineWidth() {
+ checkValidity();
+ return (PropertyValue<Float>) new PropertyValue(nativeGetLineWidth());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getLineGapWidth() {
+ checkValidity();
+ return (PropertyValue<Float>) new PropertyValue(nativeGetLineGapWidth());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getLineOffset() {
+ checkValidity();
+ return (PropertyValue<Float>) new PropertyValue(nativeGetLineOffset());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getLineBlur() {
+ checkValidity();
+ return (PropertyValue<Float>) new PropertyValue(nativeGetLineBlur());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float[]> getLineDasharray() {
+ checkValidity();
+ return (PropertyValue<Float[]>) new PropertyValue(nativeGetLineDasharray());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getLinePattern() {
+ checkValidity();
+ return (PropertyValue<String>) new PropertyValue(nativeGetLinePattern());
+ }
+
+ private native Object nativeGetLineCap();
+
+ private native Object nativeGetLineJoin();
+
+ private native Object nativeGetLineMiterLimit();
+
+ private native Object nativeGetLineRoundLimit();
+
+ private native Object nativeGetLineOpacity();
+
+ private native Object nativeGetLineColor();
+
+ private native Object nativeGetLineTranslate();
+
+ private native Object nativeGetLineTranslateAnchor();
+
+ private native Object nativeGetLineWidth();
+
+ private native Object nativeGetLineGapWidth();
+
+ private native Object nativeGetLineOffset();
+
+ private native Object nativeGetLineBlur();
+
+ private native Object nativeGetLineDasharray();
+
+ private native Object nativeGetLinePattern();
+
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/NoSuchLayerException.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/NoSuchLayerException.java
new file mode 100644
index 0000000000..d6ef4f8824
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/NoSuchLayerException.java
@@ -0,0 +1,11 @@
+package com.mapbox.mapboxsdk.style.layers;
+
+/**
+ * No such layer.
+ */
+public class NoSuchLayerException extends Exception {
+
+ public NoSuchLayerException(String message) {
+ super(message);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PaintProperty.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PaintProperty.java
new file mode 100644
index 0000000000..6f1a9a0a16
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PaintProperty.java
@@ -0,0 +1,9 @@
+package com.mapbox.mapboxsdk.style.layers;
+
+class PaintProperty<T> extends Property<T> {
+
+ PaintProperty(String name, T value) {
+ super(name, value);
+ }
+
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java
new file mode 100644
index 0000000000..a31f1adb54
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java
@@ -0,0 +1,237 @@
+// 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> {
+
+ //visibility
+ public static final String VISIBLE = "visible";
+ public static final String NONE = "none";
+
+ @StringDef({
+ VISIBLE,
+ NONE
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface VISIBILITY {}
+
+ //line-cap
+ public static final String LINE_CAP_BUTT = "butt";
+ public static final String LINE_CAP_ROUND = "round";
+ public static final String LINE_CAP_SQUARE = "square";
+
+ @StringDef({
+ LINE_CAP_BUTT,
+ LINE_CAP_ROUND,
+ LINE_CAP_SQUARE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface LINE_CAP {}
+
+ //line-join
+ public static final String LINE_JOIN_BEVEL = "bevel";
+ public static final String LINE_JOIN_ROUND = "round";
+ public static final String LINE_JOIN_MITER = "miter";
+
+ @StringDef({
+ LINE_JOIN_BEVEL,
+ LINE_JOIN_ROUND,
+ LINE_JOIN_MITER,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface LINE_JOIN {}
+
+ //symbol-placement
+ public static final String SYMBOL_PLACEMENT_POINT = "point";
+ public static final String SYMBOL_PLACEMENT_LINE = "line";
+
+ @StringDef({
+ SYMBOL_PLACEMENT_POINT,
+ SYMBOL_PLACEMENT_LINE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SYMBOL_PLACEMENT {}
+
+ //icon-rotation-alignment
+ public static final String ICON_ROTATION_ALIGNMENT_MAP = "map";
+ public static final String ICON_ROTATION_ALIGNMENT_VIEWPORT = "viewport";
+
+ @StringDef({
+ ICON_ROTATION_ALIGNMENT_MAP,
+ ICON_ROTATION_ALIGNMENT_VIEWPORT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ICON_ROTATION_ALIGNMENT {}
+
+ //icon-text-fit
+ public static final String ICON_TEXT_FIT_NONE = "none";
+ public static final String ICON_TEXT_FIT_BOTH = "both";
+ public static final String ICON_TEXT_FIT_WIDTH = "width";
+ public static final String ICON_TEXT_FIT_HEIGHT = "height";
+
+ @StringDef({
+ ICON_TEXT_FIT_NONE,
+ ICON_TEXT_FIT_BOTH,
+ ICON_TEXT_FIT_WIDTH,
+ ICON_TEXT_FIT_HEIGHT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ICON_TEXT_FIT {}
+
+ //text-pitch-alignment
+ public static final String TEXT_PITCH_ALIGNMENT_MAP = "map";
+ public static final String TEXT_PITCH_ALIGNMENT_VIEWPORT = "viewport";
+
+ @StringDef({
+ TEXT_PITCH_ALIGNMENT_MAP,
+ TEXT_PITCH_ALIGNMENT_VIEWPORT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface TEXT_PITCH_ALIGNMENT {}
+
+ //text-rotation-alignment
+ public static final String TEXT_ROTATION_ALIGNMENT_MAP = "map";
+ public static final String TEXT_ROTATION_ALIGNMENT_VIEWPORT = "viewport";
+
+ @StringDef({
+ TEXT_ROTATION_ALIGNMENT_MAP,
+ TEXT_ROTATION_ALIGNMENT_VIEWPORT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface TEXT_ROTATION_ALIGNMENT {}
+
+ //text-justify
+ public static final String TEXT_JUSTIFY_LEFT = "left";
+ public static final String TEXT_JUSTIFY_CENTER = "center";
+ public static final String TEXT_JUSTIFY_RIGHT = "right";
+
+ @StringDef({
+ TEXT_JUSTIFY_LEFT,
+ TEXT_JUSTIFY_CENTER,
+ TEXT_JUSTIFY_RIGHT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface TEXT_JUSTIFY {}
+
+ //text-anchor
+ public static final String TEXT_ANCHOR_CENTER = "center";
+ public static final String TEXT_ANCHOR_LEFT = "left";
+ public static final String TEXT_ANCHOR_RIGHT = "right";
+ public static final String TEXT_ANCHOR_TOP = "top";
+ public static final String TEXT_ANCHOR_BOTTOM = "bottom";
+ public static final String TEXT_ANCHOR_TOP_LEFT = "top-left";
+ public static final String TEXT_ANCHOR_TOP_RIGHT = "top-right";
+ public static final String TEXT_ANCHOR_BOTTOM_LEFT = "bottom-left";
+ public static final String TEXT_ANCHOR_BOTTOM_RIGHT = "bottom-right";
+
+ @StringDef({
+ TEXT_ANCHOR_CENTER,
+ TEXT_ANCHOR_LEFT,
+ TEXT_ANCHOR_RIGHT,
+ TEXT_ANCHOR_TOP,
+ TEXT_ANCHOR_BOTTOM,
+ TEXT_ANCHOR_TOP_LEFT,
+ TEXT_ANCHOR_TOP_RIGHT,
+ TEXT_ANCHOR_BOTTOM_LEFT,
+ TEXT_ANCHOR_BOTTOM_RIGHT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface TEXT_ANCHOR {}
+
+ //text-transform
+ public static final String TEXT_TRANSFORM_NONE = "none";
+ public static final String TEXT_TRANSFORM_UPPERCASE = "uppercase";
+ public static final String TEXT_TRANSFORM_LOWERCASE = "lowercase";
+
+ @StringDef({
+ TEXT_TRANSFORM_NONE,
+ TEXT_TRANSFORM_UPPERCASE,
+ TEXT_TRANSFORM_LOWERCASE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface TEXT_TRANSFORM {}
+
+ //fill-translate-anchor
+ public static final String FILL_TRANSLATE_ANCHOR_MAP = "map";
+ public static final String FILL_TRANSLATE_ANCHOR_VIEWPORT = "viewport";
+
+ @StringDef({
+ FILL_TRANSLATE_ANCHOR_MAP,
+ FILL_TRANSLATE_ANCHOR_VIEWPORT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface FILL_TRANSLATE_ANCHOR {}
+
+ //line-translate-anchor
+ public static final String LINE_TRANSLATE_ANCHOR_MAP = "map";
+ public static final String LINE_TRANSLATE_ANCHOR_VIEWPORT = "viewport";
+
+ @StringDef({
+ LINE_TRANSLATE_ANCHOR_MAP,
+ LINE_TRANSLATE_ANCHOR_VIEWPORT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface LINE_TRANSLATE_ANCHOR {}
+
+ //icon-translate-anchor
+ public static final String ICON_TRANSLATE_ANCHOR_MAP = "map";
+ public static final String ICON_TRANSLATE_ANCHOR_VIEWPORT = "viewport";
+
+ @StringDef({
+ ICON_TRANSLATE_ANCHOR_MAP,
+ ICON_TRANSLATE_ANCHOR_VIEWPORT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ICON_TRANSLATE_ANCHOR {}
+
+ //text-translate-anchor
+ public static final String TEXT_TRANSLATE_ANCHOR_MAP = "map";
+ public static final String TEXT_TRANSLATE_ANCHOR_VIEWPORT = "viewport";
+
+ @StringDef({
+ TEXT_TRANSLATE_ANCHOR_MAP,
+ TEXT_TRANSLATE_ANCHOR_VIEWPORT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface TEXT_TRANSLATE_ANCHOR {}
+
+ //circle-translate-anchor
+ public static final String CIRCLE_TRANSLATE_ANCHOR_MAP = "map";
+ public static final String CIRCLE_TRANSLATE_ANCHOR_VIEWPORT = "viewport";
+
+ @StringDef({
+ CIRCLE_TRANSLATE_ANCHOR_MAP,
+ CIRCLE_TRANSLATE_ANCHOR_VIEWPORT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface CIRCLE_TRANSLATE_ANCHOR {}
+
+ //circle-pitch-scale
+ public static final String CIRCLE_PITCH_SCALE_MAP = "map";
+ public static final String CIRCLE_PITCH_SCALE_VIEWPORT = "viewport";
+
+ @StringDef({
+ CIRCLE_PITCH_SCALE_MAP,
+ CIRCLE_PITCH_SCALE_VIEWPORT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface CIRCLE_PITCH_SCALE {}
+
+
+ //Class definition
+ public final String name;
+ public final T value;
+
+ /* package */ Property(String name, T value) {
+ this.name = name;
+ this.value = value;
+ }
+
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java
new file mode 100644
index 0000000000..88587dbb5b
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java
@@ -0,0 +1,1300 @@
+// 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 {
+
+ /**
+ * Set visibility
+ */
+ public static Property<String> visibility(@Property.VISIBILITY String value) {
+ return new LayoutProperty<>("visibility", value);
+ }
+
+ /**
+ * Set visibility
+ */
+ public static Property<Function<String>> visibility(Function<String> function) {
+ return new LayoutProperty<>("visibility", function);
+ }
+
+ /**
+ * Whether or not the fill should be antialiased.
+ */
+ public static Property<Boolean> fillAntialias(Boolean value) {
+ return new PaintProperty<>("fill-antialias", value);
+ }
+
+ /**
+ * Whether or not the fill should be antialiased.
+ */
+ public static Property<Function<Boolean>> fillAntialias(Function<Boolean> function) {
+ return new PaintProperty<>("fill-antialias", function);
+ }
+
+ /**
+ * The opacity of the entire fill layer. In contrast to the fill-color, this value will also affect the 1px stroke around the fill, if the stroke is used.
+ */
+ public static Property<Float> fillOpacity(Float value) {
+ return new PaintProperty<>("fill-opacity", value);
+ }
+
+ /**
+ * The opacity of the entire fill layer. In contrast to the fill-color, this value will also affect the 1px stroke around the fill, if the stroke is used.
+ */
+ public static Property<Function<Float>> fillOpacity(Function<Float> function) {
+ return new PaintProperty<>("fill-opacity", function);
+ }
+
+ /**
+ * The color of the filled part of this layer. This color can be specified as rgba with an alpha component and the color's opacity will not affect the opacity of the 1px stroke, if it is used.
+ */
+ public static Property<String> fillColor(@ColorInt int value) {
+ return new PaintProperty<>("fill-color", colorToRgbaString(value));
+ }
+
+ /**
+ * The color of the filled part of this layer. This color can be specified as rgba with an alpha component and the color's opacity will not affect the opacity of the 1px stroke, if it is used.
+ */
+ public static Property<String> fillColor(String value) {
+ return new PaintProperty<>("fill-color", value);
+ }
+
+ /**
+ * The color of the filled part of this layer. This color can be specified as rgba with an alpha component and the color's opacity will not affect the opacity of the 1px stroke, if it is used.
+ */
+ public static Property<Function<String>> fillColor(Function<String> function) {
+ return new PaintProperty<>("fill-color", function);
+ }
+
+ /**
+ * The outline color of the fill. Matches the value of `fill-color` if unspecified.
+ */
+ public static Property<String> fillOutlineColor(@ColorInt int value) {
+ return new PaintProperty<>("fill-outline-color", colorToRgbaString(value));
+ }
+
+ /**
+ * The outline color of the fill. Matches the value of `fill-color` if unspecified.
+ */
+ public static Property<String> fillOutlineColor(String value) {
+ return new PaintProperty<>("fill-outline-color", value);
+ }
+
+ /**
+ * The outline color of the fill. Matches the value of `fill-color` if unspecified.
+ */
+ public static Property<Function<String>> fillOutlineColor(Function<String> function) {
+ return new PaintProperty<>("fill-outline-color", function);
+ }
+
+ /**
+ * The geometry's offset. Values are [x, y] where negatives indicate left and up, respectively.
+ */
+ public static Property<Float[]> fillTranslate(Float[] value) {
+ return new PaintProperty<>("fill-translate", value);
+ }
+
+ /**
+ * The geometry's offset. Values are [x, y] where negatives indicate left and up, respectively.
+ */
+ public static Property<Function<Float[]>> fillTranslate(Function<Float[]> function) {
+ return new PaintProperty<>("fill-translate", function);
+ }
+
+ /**
+ * Control whether the translation is relative to the map (north) or viewport (screen)
+ */
+ public static Property<String> fillTranslateAnchor(@Property.FILL_TRANSLATE_ANCHOR String value) {
+ return new PaintProperty<>("fill-translate-anchor", value);
+ }
+
+ /**
+ * Control whether the translation is relative to the map (north) or viewport (screen)
+ */
+ public static Property<Function<String>> fillTranslateAnchor(Function<String> function) {
+ return new PaintProperty<>("fill-translate-anchor", function);
+ }
+
+ /**
+ * Name of image in sprite to use for drawing image fills. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512).
+ */
+ public static Property<String> fillPattern(String value) {
+ return new PaintProperty<>("fill-pattern", value);
+ }
+
+ /**
+ * Name of image in sprite to use for drawing image fills. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512).
+ */
+ public static Property<Function<String>> fillPattern(Function<String> function) {
+ return new PaintProperty<>("fill-pattern", function);
+ }
+
+ /**
+ * The opacity at which the line will be drawn.
+ */
+ public static Property<Float> lineOpacity(Float value) {
+ return new PaintProperty<>("line-opacity", value);
+ }
+
+ /**
+ * The opacity at which the line will be drawn.
+ */
+ public static Property<Function<Float>> lineOpacity(Function<Float> function) {
+ return new PaintProperty<>("line-opacity", function);
+ }
+
+ /**
+ * The color with which the line will be drawn.
+ */
+ public static Property<String> lineColor(@ColorInt int value) {
+ return new PaintProperty<>("line-color", colorToRgbaString(value));
+ }
+
+ /**
+ * The color with which the line will be drawn.
+ */
+ public static Property<String> lineColor(String value) {
+ return new PaintProperty<>("line-color", value);
+ }
+
+ /**
+ * The color with which the line will be drawn.
+ */
+ public static Property<Function<String>> lineColor(Function<String> function) {
+ return new PaintProperty<>("line-color", function);
+ }
+
+ /**
+ * The geometry's offset. Values are [x, y] where negatives indicate left and up, respectively.
+ */
+ public static Property<Float[]> lineTranslate(Float[] value) {
+ return new PaintProperty<>("line-translate", value);
+ }
+
+ /**
+ * The geometry's offset. Values are [x, y] where negatives indicate left and up, respectively.
+ */
+ public static Property<Function<Float[]>> lineTranslate(Function<Float[]> function) {
+ return new PaintProperty<>("line-translate", function);
+ }
+
+ /**
+ * Control whether the translation is relative to the map (north) or viewport (screen)
+ */
+ public static Property<String> lineTranslateAnchor(@Property.LINE_TRANSLATE_ANCHOR String value) {
+ return new PaintProperty<>("line-translate-anchor", value);
+ }
+
+ /**
+ * Control whether the translation is relative to the map (north) or viewport (screen)
+ */
+ public static Property<Function<String>> lineTranslateAnchor(Function<String> function) {
+ return new PaintProperty<>("line-translate-anchor", function);
+ }
+
+ /**
+ * Stroke thickness.
+ */
+ public static Property<Float> lineWidth(Float value) {
+ return new PaintProperty<>("line-width", value);
+ }
+
+ /**
+ * Stroke thickness.
+ */
+ public static Property<Function<Float>> lineWidth(Function<Float> function) {
+ return new PaintProperty<>("line-width", function);
+ }
+
+ /**
+ * Draws a line casing outside of a line's actual path. Value indicates the width of the inner gap.
+ */
+ public static Property<Float> lineGapWidth(Float value) {
+ return new PaintProperty<>("line-gap-width", value);
+ }
+
+ /**
+ * Draws a line casing outside of a line's actual path. Value indicates the width of the inner gap.
+ */
+ public static Property<Function<Float>> lineGapWidth(Function<Float> function) {
+ return new PaintProperty<>("line-gap-width", function);
+ }
+
+ /**
+ * The line's offset perpendicular to its direction. Values may be positive or negative, where positive indicates "rightwards" (if you were moving in the direction of the line) and negative indicates "leftwards."
+ */
+ public static Property<Float> lineOffset(Float value) {
+ return new PaintProperty<>("line-offset", value);
+ }
+
+ /**
+ * The line's offset perpendicular to its direction. Values may be positive or negative, where positive indicates "rightwards" (if you were moving in the direction of the line) and negative indicates "leftwards."
+ */
+ public static Property<Function<Float>> lineOffset(Function<Float> function) {
+ return new PaintProperty<>("line-offset", function);
+ }
+
+ /**
+ * Blur applied to the line, in pixels.
+ */
+ public static Property<Float> lineBlur(Float value) {
+ return new PaintProperty<>("line-blur", value);
+ }
+
+ /**
+ * Blur applied to the line, in pixels.
+ */
+ public static Property<Function<Float>> lineBlur(Function<Float> function) {
+ return new PaintProperty<>("line-blur", function);
+ }
+
+ /**
+ * Specifies the lengths of the alternating dashes and gaps that form the dash pattern. The lengths are later scaled by the line width. To convert a dash length to pixels, multiply the length by the current line width.
+ */
+ public static Property<Float[]> lineDasharray(Float[] value) {
+ return new PaintProperty<>("line-dasharray", value);
+ }
+
+ /**
+ * Specifies the lengths of the alternating dashes and gaps that form the dash pattern. The lengths are later scaled by the line width. To convert a dash length to pixels, multiply the length by the current line width.
+ */
+ public static Property<Function<Float[]>> lineDasharray(Function<Float[]> function) {
+ return new PaintProperty<>("line-dasharray", function);
+ }
+
+ /**
+ * Name of image in sprite to use for drawing image lines. For seamless patterns, image width must be a factor of two (2, 4, 8, ..., 512).
+ */
+ public static Property<String> linePattern(String value) {
+ return new PaintProperty<>("line-pattern", value);
+ }
+
+ /**
+ * Name of image in sprite to use for drawing image lines. For seamless patterns, image width must be a factor of two (2, 4, 8, ..., 512).
+ */
+ public static Property<Function<String>> linePattern(Function<String> function) {
+ return new PaintProperty<>("line-pattern", function);
+ }
+
+ /**
+ * The opacity at which the icon will be drawn.
+ */
+ public static Property<Float> iconOpacity(Float value) {
+ return new PaintProperty<>("icon-opacity", value);
+ }
+
+ /**
+ * The opacity at which the icon will be drawn.
+ */
+ public static Property<Function<Float>> iconOpacity(Function<Float> function) {
+ return new PaintProperty<>("icon-opacity", function);
+ }
+
+ /**
+ * The color of the icon. This can only be used with sdf icons.
+ */
+ public static Property<String> iconColor(@ColorInt int value) {
+ return new PaintProperty<>("icon-color", colorToRgbaString(value));
+ }
+
+ /**
+ * The color of the icon. This can only be used with sdf icons.
+ */
+ public static Property<String> iconColor(String value) {
+ return new PaintProperty<>("icon-color", value);
+ }
+
+ /**
+ * The color of the icon. This can only be used with sdf icons.
+ */
+ public static Property<Function<String>> iconColor(Function<String> function) {
+ return new PaintProperty<>("icon-color", function);
+ }
+
+ /**
+ * The color of the icon's halo. Icon halos can only be used with sdf icons.
+ */
+ public static Property<String> iconHaloColor(@ColorInt int value) {
+ return new PaintProperty<>("icon-halo-color", colorToRgbaString(value));
+ }
+
+ /**
+ * The color of the icon's halo. Icon halos can only be used with sdf icons.
+ */
+ public static Property<String> iconHaloColor(String value) {
+ return new PaintProperty<>("icon-halo-color", value);
+ }
+
+ /**
+ * The color of the icon's halo. Icon halos can only be used with sdf icons.
+ */
+ public static Property<Function<String>> iconHaloColor(Function<String> function) {
+ return new PaintProperty<>("icon-halo-color", function);
+ }
+
+ /**
+ * Distance of halo to the icon outline.
+ */
+ public static Property<Float> iconHaloWidth(Float value) {
+ return new PaintProperty<>("icon-halo-width", value);
+ }
+
+ /**
+ * Distance of halo to the icon outline.
+ */
+ public static Property<Function<Float>> iconHaloWidth(Function<Float> function) {
+ return new PaintProperty<>("icon-halo-width", function);
+ }
+
+ /**
+ * Fade out the halo towards the outside.
+ */
+ public static Property<Float> iconHaloBlur(Float value) {
+ return new PaintProperty<>("icon-halo-blur", value);
+ }
+
+ /**
+ * Fade out the halo towards the outside.
+ */
+ public static Property<Function<Float>> iconHaloBlur(Function<Float> function) {
+ return new PaintProperty<>("icon-halo-blur", function);
+ }
+
+ /**
+ * Distance that the icon's anchor is moved from its original placement. Positive values indicate right and down, while negative values indicate left and up.
+ */
+ public static Property<Float[]> iconTranslate(Float[] value) {
+ return new PaintProperty<>("icon-translate", value);
+ }
+
+ /**
+ * Distance that the icon's anchor is moved from its original placement. Positive values indicate right and down, while negative values indicate left and up.
+ */
+ public static Property<Function<Float[]>> iconTranslate(Function<Float[]> function) {
+ return new PaintProperty<>("icon-translate", function);
+ }
+
+ /**
+ * Control whether the translation is relative to the map (north) or viewport (screen).
+ */
+ public static Property<String> iconTranslateAnchor(@Property.ICON_TRANSLATE_ANCHOR String value) {
+ return new PaintProperty<>("icon-translate-anchor", value);
+ }
+
+ /**
+ * Control whether the translation is relative to the map (north) or viewport (screen).
+ */
+ public static Property<Function<String>> iconTranslateAnchor(Function<String> function) {
+ return new PaintProperty<>("icon-translate-anchor", function);
+ }
+
+ /**
+ * The opacity at which the text will be drawn.
+ */
+ public static Property<Float> textOpacity(Float value) {
+ return new PaintProperty<>("text-opacity", value);
+ }
+
+ /**
+ * The opacity at which the text will be drawn.
+ */
+ public static Property<Function<Float>> textOpacity(Function<Float> function) {
+ return new PaintProperty<>("text-opacity", function);
+ }
+
+ /**
+ * The color with which the text will be drawn.
+ */
+ public static Property<String> textColor(@ColorInt int value) {
+ return new PaintProperty<>("text-color", colorToRgbaString(value));
+ }
+
+ /**
+ * The color with which the text will be drawn.
+ */
+ public static Property<String> textColor(String value) {
+ return new PaintProperty<>("text-color", value);
+ }
+
+ /**
+ * The color with which the text will be drawn.
+ */
+ public static Property<Function<String>> textColor(Function<String> function) {
+ return new PaintProperty<>("text-color", function);
+ }
+
+ /**
+ * The color of the text's halo, which helps it stand out from backgrounds.
+ */
+ public static Property<String> textHaloColor(@ColorInt int value) {
+ return new PaintProperty<>("text-halo-color", colorToRgbaString(value));
+ }
+
+ /**
+ * The color of the text's halo, which helps it stand out from backgrounds.
+ */
+ public static Property<String> textHaloColor(String value) {
+ return new PaintProperty<>("text-halo-color", value);
+ }
+
+ /**
+ * The color of the text's halo, which helps it stand out from backgrounds.
+ */
+ public static Property<Function<String>> textHaloColor(Function<String> function) {
+ return new PaintProperty<>("text-halo-color", function);
+ }
+
+ /**
+ * Distance of halo to the font outline. Max text halo width is 1/4 of the font-size.
+ */
+ public static Property<Float> textHaloWidth(Float value) {
+ return new PaintProperty<>("text-halo-width", value);
+ }
+
+ /**
+ * Distance of halo to the font outline. Max text halo width is 1/4 of the font-size.
+ */
+ public static Property<Function<Float>> textHaloWidth(Function<Float> function) {
+ return new PaintProperty<>("text-halo-width", function);
+ }
+
+ /**
+ * The halo's fadeout distance towards the outside.
+ */
+ public static Property<Float> textHaloBlur(Float value) {
+ return new PaintProperty<>("text-halo-blur", value);
+ }
+
+ /**
+ * The halo's fadeout distance towards the outside.
+ */
+ public static Property<Function<Float>> textHaloBlur(Function<Float> function) {
+ return new PaintProperty<>("text-halo-blur", function);
+ }
+
+ /**
+ * Distance that the text's anchor is moved from its original placement. Positive values indicate right and down, while negative values indicate left and up.
+ */
+ public static Property<Float[]> textTranslate(Float[] value) {
+ return new PaintProperty<>("text-translate", value);
+ }
+
+ /**
+ * Distance that the text's anchor is moved from its original placement. Positive values indicate right and down, while negative values indicate left and up.
+ */
+ public static Property<Function<Float[]>> textTranslate(Function<Float[]> function) {
+ return new PaintProperty<>("text-translate", function);
+ }
+
+ /**
+ * Control whether the translation is relative to the map (north) or viewport (screen).
+ */
+ public static Property<String> textTranslateAnchor(@Property.TEXT_TRANSLATE_ANCHOR String value) {
+ return new PaintProperty<>("text-translate-anchor", value);
+ }
+
+ /**
+ * Control whether the translation is relative to the map (north) or viewport (screen).
+ */
+ public static Property<Function<String>> textTranslateAnchor(Function<String> function) {
+ return new PaintProperty<>("text-translate-anchor", function);
+ }
+
+ /**
+ * Circle radius.
+ */
+ public static Property<Float> circleRadius(Float value) {
+ return new PaintProperty<>("circle-radius", value);
+ }
+
+ /**
+ * Circle radius.
+ */
+ public static Property<Function<Float>> circleRadius(Function<Float> function) {
+ return new PaintProperty<>("circle-radius", function);
+ }
+
+ /**
+ * The color of the circle.
+ */
+ public static Property<String> circleColor(@ColorInt int value) {
+ return new PaintProperty<>("circle-color", colorToRgbaString(value));
+ }
+
+ /**
+ * The color of the circle.
+ */
+ public static Property<String> circleColor(String value) {
+ return new PaintProperty<>("circle-color", value);
+ }
+
+ /**
+ * The color of the circle.
+ */
+ public static Property<Function<String>> circleColor(Function<String> function) {
+ return new PaintProperty<>("circle-color", function);
+ }
+
+ /**
+ * Amount to blur the circle. 1 blurs the circle such that only the centerpoint is full opacity.
+ */
+ public static Property<Float> circleBlur(Float value) {
+ return new PaintProperty<>("circle-blur", value);
+ }
+
+ /**
+ * Amount to blur the circle. 1 blurs the circle such that only the centerpoint is full opacity.
+ */
+ public static Property<Function<Float>> circleBlur(Function<Float> function) {
+ return new PaintProperty<>("circle-blur", function);
+ }
+
+ /**
+ * The opacity at which the circle will be drawn.
+ */
+ public static Property<Float> circleOpacity(Float value) {
+ return new PaintProperty<>("circle-opacity", value);
+ }
+
+ /**
+ * The opacity at which the circle will be drawn.
+ */
+ public static Property<Function<Float>> circleOpacity(Function<Float> function) {
+ return new PaintProperty<>("circle-opacity", function);
+ }
+
+ /**
+ * The geometry's offset. Values are [x, y] where negatives indicate left and up, respectively.
+ */
+ public static Property<Float[]> circleTranslate(Float[] value) {
+ return new PaintProperty<>("circle-translate", value);
+ }
+
+ /**
+ * The geometry's offset. Values are [x, y] where negatives indicate left and up, respectively.
+ */
+ public static Property<Function<Float[]>> circleTranslate(Function<Float[]> function) {
+ return new PaintProperty<>("circle-translate", function);
+ }
+
+ /**
+ * Control whether the translation is relative to the map (north) or viewport (screen)
+ */
+ public static Property<String> circleTranslateAnchor(@Property.CIRCLE_TRANSLATE_ANCHOR String value) {
+ return new PaintProperty<>("circle-translate-anchor", value);
+ }
+
+ /**
+ * Control whether the translation is relative to the map (north) or viewport (screen)
+ */
+ public static Property<Function<String>> circleTranslateAnchor(Function<String> function) {
+ return new PaintProperty<>("circle-translate-anchor", function);
+ }
+
+ /**
+ * Controls the scaling behavior of the circle when the map is pitched. The value `map` scales circles according to their apparent distance to the camera. The value `viewport` results in no pitch-related scaling.
+ */
+ public static Property<String> circlePitchScale(@Property.CIRCLE_PITCH_SCALE String value) {
+ return new PaintProperty<>("circle-pitch-scale", value);
+ }
+
+ /**
+ * Controls the scaling behavior of the circle when the map is pitched. The value `map` scales circles according to their apparent distance to the camera. The value `viewport` results in no pitch-related scaling.
+ */
+ public static Property<Function<String>> circlePitchScale(Function<String> function) {
+ return new PaintProperty<>("circle-pitch-scale", function);
+ }
+
+ /**
+ * The opacity at which the image will be drawn.
+ */
+ public static Property<Float> rasterOpacity(Float value) {
+ return new PaintProperty<>("raster-opacity", value);
+ }
+
+ /**
+ * The opacity at which the image will be drawn.
+ */
+ public static Property<Function<Float>> rasterOpacity(Function<Float> function) {
+ return new PaintProperty<>("raster-opacity", function);
+ }
+
+ /**
+ * Rotates hues around the color wheel.
+ */
+ public static Property<Float> rasterHueRotate(Float value) {
+ return new PaintProperty<>("raster-hue-rotate", value);
+ }
+
+ /**
+ * Rotates hues around the color wheel.
+ */
+ public static Property<Function<Float>> rasterHueRotate(Function<Float> function) {
+ return new PaintProperty<>("raster-hue-rotate", function);
+ }
+
+ /**
+ * Increase or reduce the brightness of the image. The value is the minimum brightness.
+ */
+ public static Property<Float> rasterBrightnessMin(Float value) {
+ return new PaintProperty<>("raster-brightness-min", value);
+ }
+
+ /**
+ * Increase or reduce the brightness of the image. The value is the minimum brightness.
+ */
+ public static Property<Function<Float>> rasterBrightnessMin(Function<Float> function) {
+ return new PaintProperty<>("raster-brightness-min", function);
+ }
+
+ /**
+ * Increase or reduce the brightness of the image. The value is the maximum brightness.
+ */
+ public static Property<Float> rasterBrightnessMax(Float value) {
+ return new PaintProperty<>("raster-brightness-max", value);
+ }
+
+ /**
+ * Increase or reduce the brightness of the image. The value is the maximum brightness.
+ */
+ public static Property<Function<Float>> rasterBrightnessMax(Function<Float> function) {
+ return new PaintProperty<>("raster-brightness-max", function);
+ }
+
+ /**
+ * Increase or reduce the saturation of the image.
+ */
+ public static Property<Float> rasterSaturation(Float value) {
+ return new PaintProperty<>("raster-saturation", value);
+ }
+
+ /**
+ * Increase or reduce the saturation of the image.
+ */
+ public static Property<Function<Float>> rasterSaturation(Function<Float> function) {
+ return new PaintProperty<>("raster-saturation", function);
+ }
+
+ /**
+ * Increase or reduce the contrast of the image.
+ */
+ public static Property<Float> rasterContrast(Float value) {
+ return new PaintProperty<>("raster-contrast", value);
+ }
+
+ /**
+ * Increase or reduce the contrast of the image.
+ */
+ public static Property<Function<Float>> rasterContrast(Function<Float> function) {
+ return new PaintProperty<>("raster-contrast", function);
+ }
+
+ /**
+ * Fade duration when a new tile is added.
+ */
+ public static Property<Float> rasterFadeDuration(Float value) {
+ return new PaintProperty<>("raster-fade-duration", value);
+ }
+
+ /**
+ * Fade duration when a new tile is added.
+ */
+ public static Property<Function<Float>> rasterFadeDuration(Function<Float> function) {
+ return new PaintProperty<>("raster-fade-duration", function);
+ }
+
+ /**
+ * The color with which the background will be drawn.
+ */
+ public static Property<String> backgroundColor(@ColorInt int value) {
+ return new PaintProperty<>("background-color", colorToRgbaString(value));
+ }
+
+ /**
+ * The color with which the background will be drawn.
+ */
+ public static Property<String> backgroundColor(String value) {
+ return new PaintProperty<>("background-color", value);
+ }
+
+ /**
+ * The color with which the background will be drawn.
+ */
+ public static Property<Function<String>> backgroundColor(Function<String> function) {
+ return new PaintProperty<>("background-color", function);
+ }
+
+ /**
+ * Name of image in sprite to use for drawing an image background. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512).
+ */
+ public static Property<String> backgroundPattern(String value) {
+ return new PaintProperty<>("background-pattern", value);
+ }
+
+ /**
+ * Name of image in sprite to use for drawing an image background. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512).
+ */
+ public static Property<Function<String>> backgroundPattern(Function<String> function) {
+ return new PaintProperty<>("background-pattern", function);
+ }
+
+ /**
+ * The opacity at which the background will be drawn.
+ */
+ public static Property<Float> backgroundOpacity(Float value) {
+ return new PaintProperty<>("background-opacity", value);
+ }
+
+ /**
+ * The opacity at which the background will be drawn.
+ */
+ public static Property<Function<Float>> backgroundOpacity(Function<Float> function) {
+ return new PaintProperty<>("background-opacity", function);
+ }
+
+ /**
+ * The display of line endings.
+ */
+ public static Property<String> lineCap(@Property.LINE_CAP String value) {
+ return new LayoutProperty<>("line-cap", value);
+ }
+
+ /**
+ * The display of line endings.
+ */
+ public static Property<Function<String>> lineCap(Function<String> function) {
+ return new LayoutProperty<>("line-cap", function);
+ }
+
+ /**
+ * The display of lines when joining.
+ */
+ public static Property<String> lineJoin(@Property.LINE_JOIN String value) {
+ return new LayoutProperty<>("line-join", value);
+ }
+
+ /**
+ * The display of lines when joining.
+ */
+ public static Property<Function<String>> lineJoin(Function<String> function) {
+ return new LayoutProperty<>("line-join", function);
+ }
+
+ /**
+ * Used to automatically convert miter joins to bevel joins for sharp angles.
+ */
+ public static Property<Float> lineMiterLimit(Float value) {
+ return new LayoutProperty<>("line-miter-limit", value);
+ }
+
+ /**
+ * Used to automatically convert miter joins to bevel joins for sharp angles.
+ */
+ public static Property<Function<Float>> lineMiterLimit(Function<Float> function) {
+ return new LayoutProperty<>("line-miter-limit", function);
+ }
+
+ /**
+ * Used to automatically convert round joins to miter joins for shallow angles.
+ */
+ public static Property<Float> lineRoundLimit(Float value) {
+ return new LayoutProperty<>("line-round-limit", value);
+ }
+
+ /**
+ * Used to automatically convert round joins to miter joins for shallow angles.
+ */
+ public static Property<Function<Float>> lineRoundLimit(Function<Float> function) {
+ return new LayoutProperty<>("line-round-limit", function);
+ }
+
+ /**
+ * Label placement relative to its geometry. `line` can only be used on LineStrings and Polygons.
+ */
+ public static Property<String> symbolPlacement(@Property.SYMBOL_PLACEMENT String value) {
+ return new LayoutProperty<>("symbol-placement", value);
+ }
+
+ /**
+ * Label placement relative to its geometry. `line` can only be used on LineStrings and Polygons.
+ */
+ public static Property<Function<String>> symbolPlacement(Function<String> function) {
+ return new LayoutProperty<>("symbol-placement", function);
+ }
+
+ /**
+ * Distance between two symbol anchors.
+ */
+ public static Property<Float> symbolSpacing(Float value) {
+ return new LayoutProperty<>("symbol-spacing", value);
+ }
+
+ /**
+ * Distance between two symbol anchors.
+ */
+ public static Property<Function<Float>> symbolSpacing(Function<Float> function) {
+ return new LayoutProperty<>("symbol-spacing", function);
+ }
+
+ /**
+ * If true, the symbols will not cross tile edges to avoid mutual collisions. Recommended in layers that don't have enough padding in the vector tile to prevent collisions, or if it is a point symbol layer placed after a line symbol layer.
+ */
+ public static Property<Boolean> symbolAvoidEdges(Boolean value) {
+ return new LayoutProperty<>("symbol-avoid-edges", value);
+ }
+
+ /**
+ * If true, the symbols will not cross tile edges to avoid mutual collisions. Recommended in layers that don't have enough padding in the vector tile to prevent collisions, or if it is a point symbol layer placed after a line symbol layer.
+ */
+ public static Property<Function<Boolean>> symbolAvoidEdges(Function<Boolean> function) {
+ return new LayoutProperty<>("symbol-avoid-edges", function);
+ }
+
+ /**
+ * If true, the icon will be visible even if it collides with other previously drawn symbols.
+ */
+ public static Property<Boolean> iconAllowOverlap(Boolean value) {
+ return new LayoutProperty<>("icon-allow-overlap", value);
+ }
+
+ /**
+ * If true, the icon will be visible even if it collides with other previously drawn symbols.
+ */
+ public static Property<Function<Boolean>> iconAllowOverlap(Function<Boolean> function) {
+ return new LayoutProperty<>("icon-allow-overlap", function);
+ }
+
+ /**
+ * If true, other symbols can be visible even if they collide with the icon.
+ */
+ public static Property<Boolean> iconIgnorePlacement(Boolean value) {
+ return new LayoutProperty<>("icon-ignore-placement", value);
+ }
+
+ /**
+ * If true, other symbols can be visible even if they collide with the icon.
+ */
+ public static Property<Function<Boolean>> iconIgnorePlacement(Function<Boolean> function) {
+ return new LayoutProperty<>("icon-ignore-placement", function);
+ }
+
+ /**
+ * If true, text will display without their corresponding icons when the icon collides with other symbols and the text does not.
+ */
+ public static Property<Boolean> iconOptional(Boolean value) {
+ return new LayoutProperty<>("icon-optional", value);
+ }
+
+ /**
+ * If true, text will display without their corresponding icons when the icon collides with other symbols and the text does not.
+ */
+ public static Property<Function<Boolean>> iconOptional(Function<Boolean> function) {
+ return new LayoutProperty<>("icon-optional", function);
+ }
+
+ /**
+ * Orientation of icon when map is rotated.
+ */
+ public static Property<String> iconRotationAlignment(@Property.ICON_ROTATION_ALIGNMENT String value) {
+ return new LayoutProperty<>("icon-rotation-alignment", value);
+ }
+
+ /**
+ * Orientation of icon when map is rotated.
+ */
+ public static Property<Function<String>> iconRotationAlignment(Function<String> function) {
+ return new LayoutProperty<>("icon-rotation-alignment", function);
+ }
+
+ /**
+ * Scale factor for icon. 1 is original size, 3 triples the size.
+ */
+ public static Property<Float> iconSize(Float value) {
+ return new LayoutProperty<>("icon-size", value);
+ }
+
+ /**
+ * Scale factor for icon. 1 is original size, 3 triples the size.
+ */
+ public static Property<Function<Float>> iconSize(Function<Float> function) {
+ return new LayoutProperty<>("icon-size", function);
+ }
+
+ /**
+ * Position and scale an icon by the its corresponding text.
+ */
+ public static Property<String> iconTextFit(@Property.ICON_TEXT_FIT String value) {
+ return new LayoutProperty<>("icon-text-fit", value);
+ }
+
+ /**
+ * Position and scale an icon by the its corresponding text.
+ */
+ public static Property<Function<String>> iconTextFit(Function<String> function) {
+ return new LayoutProperty<>("icon-text-fit", function);
+ }
+
+ /**
+ * Size of padding area around the text-fit size in clockwise order: top, right, bottom, left.
+ */
+ public static Property<Float[]> iconTextFitPadding(Float[] value) {
+ return new LayoutProperty<>("icon-text-fit-padding", value);
+ }
+
+ /**
+ * Size of padding area around the text-fit size in clockwise order: top, right, bottom, left.
+ */
+ public static Property<Function<Float[]>> iconTextFitPadding(Function<Float[]> function) {
+ return new LayoutProperty<>("icon-text-fit-padding", function);
+ }
+
+ /**
+ * A string with {tokens} replaced, referencing the data property to pull from.
+ */
+ public static Property<String> iconImage(String value) {
+ return new LayoutProperty<>("icon-image", value);
+ }
+
+ /**
+ * A string with {tokens} replaced, referencing the data property to pull from.
+ */
+ public static Property<Function<String>> iconImage(Function<String> function) {
+ return new LayoutProperty<>("icon-image", function);
+ }
+
+ /**
+ * Rotates the icon clockwise.
+ */
+ public static Property<Float> iconRotate(Float value) {
+ return new LayoutProperty<>("icon-rotate", value);
+ }
+
+ /**
+ * Rotates the icon clockwise.
+ */
+ public static Property<Function<Float>> iconRotate(Function<Float> function) {
+ return new LayoutProperty<>("icon-rotate", function);
+ }
+
+ /**
+ * Size of the additional area around the icon bounding box used for detecting symbol collisions.
+ */
+ public static Property<Float> iconPadding(Float value) {
+ return new LayoutProperty<>("icon-padding", value);
+ }
+
+ /**
+ * Size of the additional area around the icon bounding box used for detecting symbol collisions.
+ */
+ public static Property<Function<Float>> iconPadding(Function<Float> function) {
+ return new LayoutProperty<>("icon-padding", function);
+ }
+
+ /**
+ * If true, the icon may be flipped to prevent it from being rendered upside-down.
+ */
+ public static Property<Boolean> iconKeepUpright(Boolean value) {
+ return new LayoutProperty<>("icon-keep-upright", value);
+ }
+
+ /**
+ * If true, the icon may be flipped to prevent it from being rendered upside-down.
+ */
+ public static Property<Function<Boolean>> iconKeepUpright(Function<Boolean> function) {
+ return new LayoutProperty<>("icon-keep-upright", function);
+ }
+
+ /**
+ * Offset distance of icon from its anchor. Positive values indicate right and down, while negative values indicate left and up.
+ */
+ public static Property<Float[]> iconOffset(Float[] value) {
+ return new LayoutProperty<>("icon-offset", value);
+ }
+
+ /**
+ * Offset distance of icon from its anchor. Positive values indicate right and down, while negative values indicate left and up.
+ */
+ public static Property<Function<Float[]>> iconOffset(Function<Float[]> function) {
+ return new LayoutProperty<>("icon-offset", function);
+ }
+
+ /**
+ * Aligns text to the plane of the `viewport` or the `map` when the map is pitched. Matches `text-rotation-alignment` if unspecified.
+ */
+ public static Property<String> textPitchAlignment(@Property.TEXT_PITCH_ALIGNMENT String value) {
+ return new LayoutProperty<>("text-pitch-alignment", value);
+ }
+
+ /**
+ * Aligns text to the plane of the `viewport` or the `map` when the map is pitched. Matches `text-rotation-alignment` if unspecified.
+ */
+ public static Property<Function<String>> textPitchAlignment(Function<String> function) {
+ return new LayoutProperty<>("text-pitch-alignment", function);
+ }
+
+ /**
+ * Orientation of text when map is rotated.
+ */
+ public static Property<String> textRotationAlignment(@Property.TEXT_ROTATION_ALIGNMENT String value) {
+ return new LayoutProperty<>("text-rotation-alignment", value);
+ }
+
+ /**
+ * Orientation of text when map is rotated.
+ */
+ public static Property<Function<String>> textRotationAlignment(Function<String> function) {
+ return new LayoutProperty<>("text-rotation-alignment", function);
+ }
+
+ /**
+ * Value to use for a text label. Feature properties are specified using tokens like {field_name}.
+ */
+ public static Property<String> textField(String value) {
+ return new LayoutProperty<>("text-field", value);
+ }
+
+ /**
+ * Value to use for a text label. Feature properties are specified using tokens like {field_name}.
+ */
+ public static Property<Function<String>> textField(Function<String> function) {
+ return new LayoutProperty<>("text-field", function);
+ }
+
+ /**
+ * Font stack to use for displaying text.
+ */
+ public static Property<String[]> textFont(String[] value) {
+ return new LayoutProperty<>("text-font", value);
+ }
+
+ /**
+ * Font stack to use for displaying text.
+ */
+ public static Property<Function<String[]>> textFont(Function<String[]> function) {
+ return new LayoutProperty<>("text-font", function);
+ }
+
+ /**
+ * Font size.
+ */
+ public static Property<Float> textSize(Float value) {
+ return new LayoutProperty<>("text-size", value);
+ }
+
+ /**
+ * Font size.
+ */
+ public static Property<Function<Float>> textSize(Function<Float> function) {
+ return new LayoutProperty<>("text-size", function);
+ }
+
+ /**
+ * The maximum line width for text wrapping.
+ */
+ public static Property<Float> textMaxWidth(Float value) {
+ return new LayoutProperty<>("text-max-width", value);
+ }
+
+ /**
+ * The maximum line width for text wrapping.
+ */
+ public static Property<Function<Float>> textMaxWidth(Function<Float> function) {
+ return new LayoutProperty<>("text-max-width", function);
+ }
+
+ /**
+ * Text leading value for multi-line text.
+ */
+ public static Property<Float> textLineHeight(Float value) {
+ return new LayoutProperty<>("text-line-height", value);
+ }
+
+ /**
+ * Text leading value for multi-line text.
+ */
+ public static Property<Function<Float>> textLineHeight(Function<Float> function) {
+ return new LayoutProperty<>("text-line-height", function);
+ }
+
+ /**
+ * Text tracking amount.
+ */
+ public static Property<Float> textLetterSpacing(Float value) {
+ return new LayoutProperty<>("text-letter-spacing", value);
+ }
+
+ /**
+ * Text tracking amount.
+ */
+ public static Property<Function<Float>> textLetterSpacing(Function<Float> function) {
+ return new LayoutProperty<>("text-letter-spacing", function);
+ }
+
+ /**
+ * Text justification options.
+ */
+ public static Property<String> textJustify(@Property.TEXT_JUSTIFY String value) {
+ return new LayoutProperty<>("text-justify", value);
+ }
+
+ /**
+ * Text justification options.
+ */
+ public static Property<Function<String>> textJustify(Function<String> function) {
+ return new LayoutProperty<>("text-justify", function);
+ }
+
+ /**
+ * Part of the text placed closest to the anchor.
+ */
+ public static Property<String> textAnchor(@Property.TEXT_ANCHOR String value) {
+ return new LayoutProperty<>("text-anchor", value);
+ }
+
+ /**
+ * Part of the text placed closest to the anchor.
+ */
+ public static Property<Function<String>> textAnchor(Function<String> function) {
+ return new LayoutProperty<>("text-anchor", function);
+ }
+
+ /**
+ * Maximum angle change between adjacent characters.
+ */
+ public static Property<Float> textMaxAngle(Float value) {
+ return new LayoutProperty<>("text-max-angle", value);
+ }
+
+ /**
+ * Maximum angle change between adjacent characters.
+ */
+ public static Property<Function<Float>> textMaxAngle(Function<Float> function) {
+ return new LayoutProperty<>("text-max-angle", function);
+ }
+
+ /**
+ * Rotates the text clockwise.
+ */
+ public static Property<Float> textRotate(Float value) {
+ return new LayoutProperty<>("text-rotate", value);
+ }
+
+ /**
+ * Rotates the text clockwise.
+ */
+ public static Property<Function<Float>> textRotate(Function<Float> function) {
+ return new LayoutProperty<>("text-rotate", function);
+ }
+
+ /**
+ * Size of the additional area around the text bounding box used for detecting symbol collisions.
+ */
+ public static Property<Float> textPadding(Float value) {
+ return new LayoutProperty<>("text-padding", value);
+ }
+
+ /**
+ * Size of the additional area around the text bounding box used for detecting symbol collisions.
+ */
+ public static Property<Function<Float>> textPadding(Function<Float> function) {
+ return new LayoutProperty<>("text-padding", function);
+ }
+
+ /**
+ * If true, the text may be flipped vertically to prevent it from being rendered upside-down.
+ */
+ public static Property<Boolean> textKeepUpright(Boolean value) {
+ return new LayoutProperty<>("text-keep-upright", value);
+ }
+
+ /**
+ * If true, the text may be flipped vertically to prevent it from being rendered upside-down.
+ */
+ public static Property<Function<Boolean>> textKeepUpright(Function<Boolean> function) {
+ return new LayoutProperty<>("text-keep-upright", function);
+ }
+
+ /**
+ * Specifies how to capitalize text, similar to the CSS `text-transform` property.
+ */
+ public static Property<String> textTransform(@Property.TEXT_TRANSFORM String value) {
+ return new LayoutProperty<>("text-transform", value);
+ }
+
+ /**
+ * Specifies how to capitalize text, similar to the CSS `text-transform` property.
+ */
+ public static Property<Function<String>> textTransform(Function<String> function) {
+ return new LayoutProperty<>("text-transform", function);
+ }
+
+ /**
+ * Offset distance of text from its anchor. Positive values indicate right and down, while negative values indicate left and up.
+ */
+ public static Property<Float[]> textOffset(Float[] value) {
+ return new LayoutProperty<>("text-offset", value);
+ }
+
+ /**
+ * Offset distance of text from its anchor. Positive values indicate right and down, while negative values indicate left and up.
+ */
+ public static Property<Function<Float[]>> textOffset(Function<Float[]> function) {
+ return new LayoutProperty<>("text-offset", function);
+ }
+
+ /**
+ * If true, the text will be visible even if it collides with other previously drawn symbols.
+ */
+ public static Property<Boolean> textAllowOverlap(Boolean value) {
+ return new LayoutProperty<>("text-allow-overlap", value);
+ }
+
+ /**
+ * If true, the text will be visible even if it collides with other previously drawn symbols.
+ */
+ public static Property<Function<Boolean>> textAllowOverlap(Function<Boolean> function) {
+ return new LayoutProperty<>("text-allow-overlap", function);
+ }
+
+ /**
+ * If true, other symbols can be visible even if they collide with the text.
+ */
+ public static Property<Boolean> textIgnorePlacement(Boolean value) {
+ return new LayoutProperty<>("text-ignore-placement", value);
+ }
+
+ /**
+ * If true, other symbols can be visible even if they collide with the text.
+ */
+ public static Property<Function<Boolean>> textIgnorePlacement(Function<Boolean> function) {
+ return new LayoutProperty<>("text-ignore-placement", function);
+ }
+
+ /**
+ * If true, icons will display without their corresponding text when the text collides with other symbols and the icon does not.
+ */
+ public static Property<Boolean> textOptional(Boolean value) {
+ return new LayoutProperty<>("text-optional", value);
+ }
+
+ /**
+ * If true, icons will display without their corresponding text when the text collides with other symbols and the icon does not.
+ */
+ public static Property<Function<Boolean>> textOptional(Function<Boolean> function) {
+ return new LayoutProperty<>("text-optional", function);
+ }
+
+ @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);
+ }
+
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyValue.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyValue.java
new file mode 100644
index 0000000000..204c154743
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyValue.java
@@ -0,0 +1,56 @@
+package com.mapbox.mapboxsdk.style.layers;
+
+import android.support.annotation.Nullable;
+import android.util.Log;
+
+/**
+ * Properties for Layer
+ */
+public class PropertyValue<T> {
+ private static final String TAG = PropertyValue.class.getSimpleName();
+
+ private final Object value;
+
+ /* package */ PropertyValue(Object value) {
+ this.value = value;
+ }
+
+ public boolean isNull() {
+ return value == null;
+ }
+
+ public boolean isFunction() {
+ return !isNull() && value instanceof Function;
+ }
+
+ public boolean isValue() {
+ return !isNull() && !isFunction();
+ }
+
+ @Nullable
+ public Function<T> getFunction() {
+ if (isFunction()) {
+ //noinspection unchecked
+ return (Function<T>) value;
+ } else {
+ Log.w(TAG, "not a function, try value");
+ return null;
+ }
+ }
+
+ @Nullable
+ public T getValue() {
+ if (isValue()) {
+ //noinspection unchecked
+ return (T) value;
+ } else {
+ Log.w(TAG, "not a value, try function");
+ return null;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s (%s)", getClass().getSimpleName(), value != null ? value.getClass().getSimpleName() : null);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/RasterLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/RasterLayer.java
new file mode 100644
index 0000000000..a6872cef0f
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/RasterLayer.java
@@ -0,0 +1,100 @@
+// 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 com.mapbox.mapboxsdk.exceptions.ConversionException;
+
+import android.support.annotation.ColorInt;
+import android.support.annotation.NonNull;
+
+import static com.mapbox.mapboxsdk.utils.ColorUtils.*;
+
+/**
+ * Raster Layer
+ */
+public class RasterLayer extends Layer {
+
+ public RasterLayer(long nativePtr) {
+ super(nativePtr);
+ }
+
+ public RasterLayer(String layerId, String sourceId) {
+ initialize(layerId, sourceId);
+ }
+
+ protected native void initialize(String layerId, String sourceId);
+
+ public void setSourceLayer(String sourceLayer) {
+ checkValidity();
+ nativeSetSourceLayer(sourceLayer);
+ }
+
+ public RasterLayer withSourceLayer(String sourceLayer) {
+ setSourceLayer(sourceLayer);
+ return this;
+ }
+
+
+ public RasterLayer withProperties(@NonNull Property<?>... properties) {
+ setProperties(properties);
+ return this;
+ }
+
+ // Property getters
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getRasterOpacity() {
+ checkValidity();
+ return (PropertyValue<Float>) new PropertyValue(nativeGetRasterOpacity());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getRasterHueRotate() {
+ checkValidity();
+ return (PropertyValue<Float>) new PropertyValue(nativeGetRasterHueRotate());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getRasterBrightnessMin() {
+ checkValidity();
+ return (PropertyValue<Float>) new PropertyValue(nativeGetRasterBrightnessMin());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getRasterBrightnessMax() {
+ checkValidity();
+ return (PropertyValue<Float>) new PropertyValue(nativeGetRasterBrightnessMax());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getRasterSaturation() {
+ checkValidity();
+ return (PropertyValue<Float>) new PropertyValue(nativeGetRasterSaturation());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getRasterContrast() {
+ checkValidity();
+ return (PropertyValue<Float>) new PropertyValue(nativeGetRasterContrast());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getRasterFadeDuration() {
+ checkValidity();
+ return (PropertyValue<Float>) new PropertyValue(nativeGetRasterFadeDuration());
+ }
+
+ private native Object nativeGetRasterOpacity();
+
+ private native Object nativeGetRasterHueRotate();
+
+ private native Object nativeGetRasterBrightnessMin();
+
+ private native Object nativeGetRasterBrightnessMax();
+
+ private native Object nativeGetRasterSaturation();
+
+ private native Object nativeGetRasterContrast();
+
+ private native Object nativeGetRasterFadeDuration();
+
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/SymbolLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/SymbolLayer.java
new file mode 100644
index 0000000000..ccbfdb411f
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/SymbolLayer.java
@@ -0,0 +1,508 @@
+// 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 com.mapbox.mapboxsdk.exceptions.ConversionException;
+
+import android.support.annotation.ColorInt;
+import android.support.annotation.NonNull;
+
+import static com.mapbox.mapboxsdk.utils.ColorUtils.*;
+
+/**
+ * Symbol Layer
+ */
+public class SymbolLayer extends Layer {
+
+ public SymbolLayer(long nativePtr) {
+ super(nativePtr);
+ }
+
+ public SymbolLayer(String layerId, String sourceId) {
+ initialize(layerId, sourceId);
+ }
+
+ protected native void initialize(String layerId, String sourceId);
+
+ public void setSourceLayer(String sourceLayer) {
+ checkValidity();
+ nativeSetSourceLayer(sourceLayer);
+ }
+
+ public SymbolLayer withSourceLayer(String sourceLayer) {
+ setSourceLayer(sourceLayer);
+ return this;
+ }
+
+ public void setFilter(Filter.Statement filter) {
+ checkValidity();
+ this.setFilter(filter.toArray());
+ }
+
+ public void setFilter(Object[] filter) {
+ checkValidity();
+ nativeSetFilter(filter);
+ }
+
+ public SymbolLayer withFilter(Object[] filter) {
+ setFilter(filter);
+ return this;
+ }
+
+ public SymbolLayer withFilter(Filter.Statement filter) {
+ setFilter(filter);
+ return this;
+ }
+
+
+ public SymbolLayer withProperties(@NonNull Property<?>... properties) {
+ setProperties(properties);
+ return this;
+ }
+
+ // Property getters
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getSymbolPlacement() {
+ checkValidity();
+ return (PropertyValue<String>) new PropertyValue(nativeGetSymbolPlacement());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getSymbolSpacing() {
+ checkValidity();
+ return (PropertyValue<Float>) new PropertyValue(nativeGetSymbolSpacing());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Boolean> getSymbolAvoidEdges() {
+ checkValidity();
+ return (PropertyValue<Boolean>) new PropertyValue(nativeGetSymbolAvoidEdges());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Boolean> getIconAllowOverlap() {
+ checkValidity();
+ return (PropertyValue<Boolean>) new PropertyValue(nativeGetIconAllowOverlap());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Boolean> getIconIgnorePlacement() {
+ checkValidity();
+ return (PropertyValue<Boolean>) new PropertyValue(nativeGetIconIgnorePlacement());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Boolean> getIconOptional() {
+ checkValidity();
+ return (PropertyValue<Boolean>) new PropertyValue(nativeGetIconOptional());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getIconRotationAlignment() {
+ checkValidity();
+ return (PropertyValue<String>) new PropertyValue(nativeGetIconRotationAlignment());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getIconSize() {
+ checkValidity();
+ return (PropertyValue<Float>) new PropertyValue(nativeGetIconSize());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getIconTextFit() {
+ checkValidity();
+ return (PropertyValue<String>) new PropertyValue(nativeGetIconTextFit());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float[]> getIconTextFitPadding() {
+ checkValidity();
+ return (PropertyValue<Float[]>) new PropertyValue(nativeGetIconTextFitPadding());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getIconImage() {
+ checkValidity();
+ return (PropertyValue<String>) new PropertyValue(nativeGetIconImage());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getIconRotate() {
+ checkValidity();
+ return (PropertyValue<Float>) new PropertyValue(nativeGetIconRotate());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getIconPadding() {
+ checkValidity();
+ return (PropertyValue<Float>) new PropertyValue(nativeGetIconPadding());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Boolean> getIconKeepUpright() {
+ checkValidity();
+ return (PropertyValue<Boolean>) new PropertyValue(nativeGetIconKeepUpright());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float[]> getIconOffset() {
+ checkValidity();
+ return (PropertyValue<Float[]>) new PropertyValue(nativeGetIconOffset());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getTextPitchAlignment() {
+ checkValidity();
+ return (PropertyValue<String>) new PropertyValue(nativeGetTextPitchAlignment());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getTextRotationAlignment() {
+ checkValidity();
+ return (PropertyValue<String>) new PropertyValue(nativeGetTextRotationAlignment());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getTextField() {
+ checkValidity();
+ return (PropertyValue<String>) new PropertyValue(nativeGetTextField());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String[]> getTextFont() {
+ checkValidity();
+ return (PropertyValue<String[]>) new PropertyValue(nativeGetTextFont());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getTextSize() {
+ checkValidity();
+ return (PropertyValue<Float>) new PropertyValue(nativeGetTextSize());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getTextMaxWidth() {
+ checkValidity();
+ return (PropertyValue<Float>) new PropertyValue(nativeGetTextMaxWidth());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getTextLineHeight() {
+ checkValidity();
+ return (PropertyValue<Float>) new PropertyValue(nativeGetTextLineHeight());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getTextLetterSpacing() {
+ checkValidity();
+ return (PropertyValue<Float>) new PropertyValue(nativeGetTextLetterSpacing());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getTextJustify() {
+ checkValidity();
+ return (PropertyValue<String>) new PropertyValue(nativeGetTextJustify());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getTextAnchor() {
+ checkValidity();
+ return (PropertyValue<String>) new PropertyValue(nativeGetTextAnchor());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getTextMaxAngle() {
+ checkValidity();
+ return (PropertyValue<Float>) new PropertyValue(nativeGetTextMaxAngle());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getTextRotate() {
+ checkValidity();
+ return (PropertyValue<Float>) new PropertyValue(nativeGetTextRotate());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getTextPadding() {
+ checkValidity();
+ return (PropertyValue<Float>) new PropertyValue(nativeGetTextPadding());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Boolean> getTextKeepUpright() {
+ checkValidity();
+ return (PropertyValue<Boolean>) new PropertyValue(nativeGetTextKeepUpright());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getTextTransform() {
+ checkValidity();
+ return (PropertyValue<String>) new PropertyValue(nativeGetTextTransform());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float[]> getTextOffset() {
+ checkValidity();
+ return (PropertyValue<Float[]>) new PropertyValue(nativeGetTextOffset());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Boolean> getTextAllowOverlap() {
+ checkValidity();
+ return (PropertyValue<Boolean>) new PropertyValue(nativeGetTextAllowOverlap());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Boolean> getTextIgnorePlacement() {
+ checkValidity();
+ return (PropertyValue<Boolean>) new PropertyValue(nativeGetTextIgnorePlacement());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Boolean> getTextOptional() {
+ checkValidity();
+ return (PropertyValue<Boolean>) new PropertyValue(nativeGetTextOptional());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getIconOpacity() {
+ checkValidity();
+ return (PropertyValue<Float>) new PropertyValue(nativeGetIconOpacity());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getIconColor() {
+ checkValidity();
+ return (PropertyValue<String>) new PropertyValue(nativeGetIconColor());
+ }
+ /**
+ * The color of the icon. This can only be used with sdf icons.
+ * @throws RuntimeException
+ */
+ @ColorInt
+ public int getIconColorAsInt() {
+ checkValidity();
+ PropertyValue<String> value = getIconColor();
+ if (value.isValue()) {
+ return rgbaToColor(value.getValue());
+ } else {
+ throw new RuntimeException("icon-color was set as a Function");
+ }
+ }
+
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getIconHaloColor() {
+ checkValidity();
+ return (PropertyValue<String>) new PropertyValue(nativeGetIconHaloColor());
+ }
+ /**
+ * The color of the icon's halo. Icon halos can only be used with sdf icons.
+ * @throws RuntimeException
+ */
+ @ColorInt
+ public int getIconHaloColorAsInt() {
+ checkValidity();
+ PropertyValue<String> value = getIconHaloColor();
+ if (value.isValue()) {
+ return rgbaToColor(value.getValue());
+ } else {
+ throw new RuntimeException("icon-halo-color was set as a Function");
+ }
+ }
+
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getIconHaloWidth() {
+ checkValidity();
+ return (PropertyValue<Float>) new PropertyValue(nativeGetIconHaloWidth());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getIconHaloBlur() {
+ checkValidity();
+ return (PropertyValue<Float>) new PropertyValue(nativeGetIconHaloBlur());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float[]> getIconTranslate() {
+ checkValidity();
+ return (PropertyValue<Float[]>) new PropertyValue(nativeGetIconTranslate());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getIconTranslateAnchor() {
+ checkValidity();
+ return (PropertyValue<String>) new PropertyValue(nativeGetIconTranslateAnchor());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getTextOpacity() {
+ checkValidity();
+ return (PropertyValue<Float>) new PropertyValue(nativeGetTextOpacity());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getTextColor() {
+ checkValidity();
+ return (PropertyValue<String>) new PropertyValue(nativeGetTextColor());
+ }
+ /**
+ * The color with which the text will be drawn.
+ * @throws RuntimeException
+ */
+ @ColorInt
+ public int getTextColorAsInt() {
+ checkValidity();
+ PropertyValue<String> value = getTextColor();
+ if (value.isValue()) {
+ return rgbaToColor(value.getValue());
+ } else {
+ throw new RuntimeException("text-color was set as a Function");
+ }
+ }
+
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getTextHaloColor() {
+ checkValidity();
+ return (PropertyValue<String>) new PropertyValue(nativeGetTextHaloColor());
+ }
+ /**
+ * The color of the text's halo, which helps it stand out from backgrounds.
+ * @throws RuntimeException
+ */
+ @ColorInt
+ public int getTextHaloColorAsInt() {
+ checkValidity();
+ PropertyValue<String> value = getTextHaloColor();
+ if (value.isValue()) {
+ return rgbaToColor(value.getValue());
+ } else {
+ throw new RuntimeException("text-halo-color was set as a Function");
+ }
+ }
+
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getTextHaloWidth() {
+ checkValidity();
+ return (PropertyValue<Float>) new PropertyValue(nativeGetTextHaloWidth());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getTextHaloBlur() {
+ checkValidity();
+ return (PropertyValue<Float>) new PropertyValue(nativeGetTextHaloBlur());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float[]> getTextTranslate() {
+ checkValidity();
+ return (PropertyValue<Float[]>) new PropertyValue(nativeGetTextTranslate());
+ }
+
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getTextTranslateAnchor() {
+ checkValidity();
+ return (PropertyValue<String>) new PropertyValue(nativeGetTextTranslateAnchor());
+ }
+
+ private native Object nativeGetSymbolPlacement();
+
+ private native Object nativeGetSymbolSpacing();
+
+ private native Object nativeGetSymbolAvoidEdges();
+
+ private native Object nativeGetIconAllowOverlap();
+
+ private native Object nativeGetIconIgnorePlacement();
+
+ private native Object nativeGetIconOptional();
+
+ private native Object nativeGetIconRotationAlignment();
+
+ private native Object nativeGetIconSize();
+
+ private native Object nativeGetIconTextFit();
+
+ private native Object nativeGetIconTextFitPadding();
+
+ private native Object nativeGetIconImage();
+
+ private native Object nativeGetIconRotate();
+
+ private native Object nativeGetIconPadding();
+
+ private native Object nativeGetIconKeepUpright();
+
+ private native Object nativeGetIconOffset();
+
+ private native Object nativeGetTextPitchAlignment();
+
+ private native Object nativeGetTextRotationAlignment();
+
+ private native Object nativeGetTextField();
+
+ private native Object nativeGetTextFont();
+
+ private native Object nativeGetTextSize();
+
+ private native Object nativeGetTextMaxWidth();
+
+ private native Object nativeGetTextLineHeight();
+
+ private native Object nativeGetTextLetterSpacing();
+
+ private native Object nativeGetTextJustify();
+
+ private native Object nativeGetTextAnchor();
+
+ private native Object nativeGetTextMaxAngle();
+
+ private native Object nativeGetTextRotate();
+
+ private native Object nativeGetTextPadding();
+
+ private native Object nativeGetTextKeepUpright();
+
+ private native Object nativeGetTextTransform();
+
+ private native Object nativeGetTextOffset();
+
+ private native Object nativeGetTextAllowOverlap();
+
+ private native Object nativeGetTextIgnorePlacement();
+
+ private native Object nativeGetTextOptional();
+
+ private native Object nativeGetIconOpacity();
+
+ private native Object nativeGetIconColor();
+
+ private native Object nativeGetIconHaloColor();
+
+ private native Object nativeGetIconHaloWidth();
+
+ private native Object nativeGetIconHaloBlur();
+
+ private native Object nativeGetIconTranslate();
+
+ private native Object nativeGetIconTranslateAnchor();
+
+ private native Object nativeGetTextOpacity();
+
+ private native Object nativeGetTextColor();
+
+ private native Object nativeGetTextHaloColor();
+
+ private native Object nativeGetTextHaloWidth();
+
+ private native Object nativeGetTextHaloBlur();
+
+ private native Object nativeGetTextTranslate();
+
+ private native Object nativeGetTextTranslateAnchor();
+
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/layer.java.ejs b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/layer.java.ejs
new file mode 100644
index 0000000000..00d9f09124
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/layer.java.ejs
@@ -0,0 +1,107 @@
+<%
+ const type = locals.type;
+ 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 com.mapbox.mapboxsdk.exceptions.ConversionException;
+
+import android.support.annotation.ColorInt;
+import android.support.annotation.NonNull;
+
+import static com.mapbox.mapboxsdk.utils.ColorUtils.*;
+
+/**
+ * <%- 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) {
+ checkValidity();
+ nativeSetSourceLayer(sourceLayer);
+ }
+
+ public <%- camelize(type) %>Layer withSourceLayer(String sourceLayer) {
+ setSourceLayer(sourceLayer);
+ return this;
+ }
+<% } -%>
+
+<% if (type !== 'background' && type !== 'raster') { -%>
+ public void setFilter(Filter.Statement filter) {
+ checkValidity();
+ this.setFilter(filter.toArray());
+ }
+
+ public void setFilter(Object[] filter) {
+ checkValidity();
+ nativeSetFilter(filter);
+ }
+
+ public <%- camelize(type) %>Layer withFilter(Object[] filter) {
+ setFilter(filter);
+ return this;
+ }
+
+ public <%- camelize(type) %>Layer withFilter(Filter.Statement filter) {
+ setFilter(filter);
+ return this;
+ }
+
+<% } -%>
+
+ public <%- camelize(type) %>Layer withProperties(@NonNull Property<?>... properties) {
+ setProperties(properties);
+ return this;
+ }
+
+ // Property getters
+
+<% for (const property of properties) { -%>
+ @SuppressWarnings("unchecked")
+ public PropertyValue<<%- propertyType(property) %>> get<%- camelize(property.name) %>() {
+ checkValidity();
+ return (PropertyValue<<%- propertyType(property) %>>) new PropertyValue(nativeGet<%- camelize(property.name) %>());
+ }
+ <% if (property.type == 'color') { -%>
+ /**
+ * <%- property.doc %>
+ * @throws RuntimeException
+ */
+ @ColorInt
+ public int get<%- camelize(property.name) %>AsInt() {
+ checkValidity();
+ PropertyValue<<%- propertyType(property) %>> value = get<%- camelize(property.name) %>();
+ if (value.isValue()) {
+ return rgbaToColor(value.getValue());
+ } else {
+ throw new RuntimeException("<%- property.name %> was set as a Function");
+ }
+ }
+
+ <% } -%>
+
+<% } -%>
+<% for (const property of properties) { -%>
+ private native Object nativeGet<%- camelize(property.name) %>();
+
+<% } -%>
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property.java.ejs b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property.java.ejs
new file mode 100644
index 0000000000..e734a9ff11
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property.java.ejs
@@ -0,0 +1,53 @@
+<%
+ 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> {
+
+ //visibility
+ public static final String VISIBLE = "visible";
+ public static final String NONE = "none";
+
+ @StringDef({
+ VISIBLE,
+ NONE
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface VISIBILITY {}
+
+<% 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;
+ }
+
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property_factory.java.ejs b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property_factory.java.ejs
new file mode 100644
index 0000000000..c7424bc31e
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property_factory.java.ejs
@@ -0,0 +1,78 @@
+<%
+ 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 {
+
+ /**
+ * Set visibility
+ */
+ public static Property<String> visibility(@Property.VISIBILITY String value) {
+ return new LayoutProperty<>("visibility", value);
+ }
+
+ /**
+ * Set visibility
+ */
+ public static Property<Function<String>> visibility(Function<String> function) {
+ return new LayoutProperty<>("visibility", function);
+ }
+
+<% for (const property of paintProperties) { -%>
+<% if (property.type == 'color') { -%>
+ /**
+ * <%- property.doc %>
+ */
+ public static Property<String> <%- camelizeWithLeadingLowercase(property.name) %>(@ColorInt int value) {
+ return new PaintProperty<>("<%- property.name %>", colorToRgbaString(value));
+ }
+
+<% } -%>
+ /**
+ * <%- property.doc %>
+ */
+ public static Property<<%- propertyType(property) %>> <%- camelizeWithLeadingLowercase(property.name) %>(<%- propertyTypeAnnotation(property) %><%- iff(() => propertyTypeAnnotation(property), " ") %><%- propertyType(property) %> value) {
+ return new PaintProperty<>("<%- property.name %>", value);
+ }
+
+ /**
+ * <%- property.doc %>
+ */
+ public static Property<Function<<%- propertyType(property) %>>> <%- camelizeWithLeadingLowercase(property.name) %>(Function<<%- propertyType(property) %>> function) {
+ return new PaintProperty<>("<%- property.name %>", function);
+ }
+
+<% } -%>
+<% for (const property of layoutProperties) { -%>
+ /**
+ * <%- property.doc %>
+ */
+ public static Property<<%- propertyType(property) %>> <%- camelizeWithLeadingLowercase(property.name) %>(<%- propertyTypeAnnotation(property) %><%- iff(() => propertyTypeAnnotation(property), " ") %><%- propertyType(property) %> value) {
+ return new LayoutProperty<>("<%- property.name %>", value);
+ }
+
+ /**
+ * <%- property.doc %>
+ */
+ public static Property<Function<<%- propertyType(property) %>>> <%- camelizeWithLeadingLowercase(property.name) %>(Function<<%- propertyType(property) %>> function) {
+ return new LayoutProperty<>("<%- property.name %>", function);
+ }
+
+<% } -%>
+ @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);
+ }
+
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java
new file mode 100644
index 0000000000..fc7928015e
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java
@@ -0,0 +1,44 @@
+package com.mapbox.mapboxsdk.style.sources;
+
+import java.net.URL;
+import java.util.HashMap;
+
+/**
+ * A GeoJson source.
+ *
+ * @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson">the style specification</a>
+ */
+public class GeoJsonSource extends Source {
+ public static final String TYPE = "geojson";
+ private static final String DATA_KEY = "data";
+
+ /**
+ * Create a GeoJsonSource from a raw json string
+ *
+ * @param id the source id
+ * @param geoJson raw Json body
+ */
+ public GeoJsonSource(String id, String geoJson) {
+ super(id, TYPE);
+ if (geoJson == null || geoJson.startsWith("http")) {
+ throw new IllegalArgumentException("Expected a raw json body");
+ }
+
+ //Wrap the String in a map as an Object is expected by the
+ //style conversion template
+ HashMap<String, String> wrapper = new HashMap<>();
+ wrapper.put(DATA_KEY, geoJson);
+ this.put(DATA_KEY, wrapper);
+ }
+
+ /**
+ * Create a GeoJsonSource from a remote geo json file
+ *
+ * @param id the source id
+ * @param url remote json file
+ */
+ public GeoJsonSource(String id, URL url) {
+ super(id, TYPE);
+ this.put(DATA_KEY, url.toExternalForm());
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterSource.java
new file mode 100644
index 0000000000..f5db6f2a37
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterSource.java
@@ -0,0 +1,33 @@
+package com.mapbox.mapboxsdk.style.sources;
+
+import java.net.URL;
+
+/**
+ * Construct a Raster Source.
+ *
+ * @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-raster">The style specificition</a>
+ */
+public class RasterSource extends Source {
+ public static final String TYPE = "raster";
+ private static final String URL_KEY = "url";
+ private static final String TILE_SIZE_KEY = "tileSize";
+
+ public RasterSource(String id, URL url) {
+ this(id, url.toExternalForm());
+ }
+
+ public RasterSource(String id, String url) {
+ super(id, TYPE);
+ this.put(URL_KEY, url);
+ }
+
+ public RasterSource(String id, TileSet tileSet) {
+ super(id, TYPE);
+ this.putAll(tileSet.toValueObject());
+ }
+
+ public RasterSource withTileSize(int tileSize) {
+ this.put(TILE_SIZE_KEY, (float) tileSize);
+ return this;
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java
new file mode 100644
index 0000000000..d9aacdc80d
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java
@@ -0,0 +1,16 @@
+package com.mapbox.mapboxsdk.style.sources;
+
+import java.util.HashMap;
+
+public abstract class Source extends HashMap<String, Object> {
+ private final String id;
+
+ protected Source(String id, String type) {
+ this.put("type", type);
+ this.id = id;
+ }
+
+ public String getId() {
+ return id;
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/TileSet.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/TileSet.java
new file mode 100644
index 0000000000..1da8827d72
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/TileSet.java
@@ -0,0 +1,290 @@
+package com.mapbox.mapboxsdk.style.sources;
+
+import android.support.annotation.Size;
+
+import com.mapbox.mapboxsdk.geometry.LatLng;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Tile set
+ *
+ * @see <a href="https://github.com/mapbox/tilejson-spec/tree/master/2.1.0">The tileset specification</a>
+ */
+public class TileSet {
+ private final String tilejson;
+ private String name;
+ private String description;
+ private String version;
+ private String attribution;
+ private String template;
+ private String legend;
+ private String scheme;
+ private final String[] tiles;
+ private String[] grids;
+ private String[] data;
+ private Float minZoom;
+ private Float maxZoom;
+ private Float[] bounds;
+ private Float[] center;
+
+ /**
+ * @param tilejson A semver.org style version number. Describes the version of the TileJSON spec that is implemented by this JSON object.
+ * @param tiles An array of tile endpoints. {z}, {x} and {y}, if present, are replaced with the corresponding integers.
+ * If multiple endpoints are specified, clients may use any combination of endpoints. All endpoints MUST return the same
+ * content for the same URL. The array MUST contain at least one endpoint.
+ * Example: "http:localhost:8888/admin/1.0.0/world-light,broadband/{z}/{x}/{y}.png"
+ */
+ public TileSet(String tilejson, String... tiles) {
+ this.tilejson = tilejson;
+ this.tiles = tiles;
+ }
+
+ public String getTilejson() {
+ return tilejson;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * A name describing the tileset. The name can
+ * contain any legal character. Implementations SHOULD NOT interpret the
+ * name as HTML.
+ * "name": "compositing",
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * A text description of the tileset. The
+ * description can contain any legal character.
+ * Implementations SHOULD NOT
+ * interpret the description as HTML.
+ * "description": "A simple, light grey world."
+ */
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public void setVersion(String version) {
+ this.version = version;
+ }
+
+ public String getAttribution() {
+ return attribution;
+ }
+
+ /**
+ * Default: null. Contains an attribution to be displayed
+ * when the map is shown to a user. Implementations MAY decide to treat this
+ * as HTML or literal text. For security reasons, make absolutely sure that
+ * this field can't be abused as a vector for XSS or beacon tracking.
+ * "attribution": "<a href='http:openstreetmap.org'>OSM contributors</a>",
+ */
+ public void setAttribution(String attribution) {
+ this.attribution = attribution;
+ }
+
+ public String getTemplate() {
+ return template;
+ }
+
+ /**
+ * Contains a mustache template to be used to
+ * format data from grids for interaction.
+ * See https:github.com/mapbox/utfgrid-spec/tree/master/1.2
+ * for the interactivity specification.
+ * "template": "{{#__teaser__}}{{NAME}}{{/__teaser__}}"
+ */
+ public void setTemplate(String template) {
+ this.template = template;
+ }
+
+ public String getLegend() {
+ return legend;
+ }
+
+ /**
+ * Contains a legend to be displayed with the map.
+ * Implementations MAY decide to treat this as HTML or literal text.
+ * For security reasons, make absolutely sure that this field can't be
+ * abused as a vector for XSS or beacon tracking.
+ * "legend": "Dangerous zones are red, safe zones are green"
+ */
+ public void setLegend(String legend) {
+ this.legend = legend;
+ }
+
+ public String getScheme() {
+ return scheme;
+ }
+
+ /**
+ * Default: "xyz". Either "xyz" or "tms". Influences the y
+ * direction of the tile coordinates.
+ * The global-mercator (aka Spherical Mercator) profile is assumed.
+ * "scheme": "xyz"
+ */
+ public void setScheme(String scheme) {
+ this.scheme = scheme;
+ }
+
+ public String[] getTiles() {
+ return tiles;
+ }
+
+ public String[] getGrids() {
+ return grids;
+ }
+
+ /**
+ * An array of interactivity endpoints. {z}, {x}
+ * and {y}, if present, are replaced with the corresponding integers. If multiple
+ * endpoints are specified, clients may use any combination of endpoints.
+ * All endpoints MUST return the same content for the same URL.
+ * If the array doesn't contain any entries, interactivity is not supported
+ * for this tileset. See https:github.com/mapbox/utfgrid-spec/tree/master/1.2
+ * for the interactivity specification.
+ * <p/>
+ * Example: "http:localhost:8888/admin/1.0.0/broadband/{z}/{x}/{y}.grid.json"
+ */
+ public void setGrids(String... grids) {
+ this.grids = grids;
+ }
+
+ public String[] getData() {
+ return data;
+ }
+
+ /**
+ * An array of data files in GeoJSON format.
+ * {z}, {x} and {y}, if present,
+ * are replaced with the corresponding integers. If multiple
+ * endpoints are specified, clients may use any combination of endpoints.
+ * All endpoints MUST return the same content for the same URL.
+ * If the array doesn't contain any entries, then no data is present in
+ * the map.
+ * <p/>
+ * "http:localhost:8888/admin/data.geojson"
+ */
+ public void setData(String... data) {
+ this.data = data;
+ }
+
+ public float getMinZoom() {
+ return minZoom;
+ }
+
+ /**
+ * 0. >= 0, <= 22. An integer specifying the minimum zoom level.
+ */
+ public void setMinZoom(float minZoom) {
+ this.minZoom = minZoom;
+ }
+
+ public float getMaxZoom() {
+ return maxZoom;
+ }
+
+ /**
+ * 0. >= 0, <= 22. An integer specifying the maximum zoom level.
+ */
+ public void setMaxZoom(float maxZoom) {
+ this.maxZoom = maxZoom;
+ }
+
+ public Float[] getBounds() {
+ return bounds;
+ }
+
+ /**
+ * Default: [-180, -90, 180, 90]. The maximum extent of available map tiles. Bounds MUST define an area
+ * covered by all zoom levels. The bounds are represented in WGS:84
+ * latitude and longitude values, in the order left, bottom, right, top.
+ * Values may be integers or floating point numbers.
+ */
+ public void setBounds(@Size(value = 4) Float... bounds) {
+ this.bounds = bounds;
+ }
+
+ public Float[] getCenter() {
+ return center;
+ }
+
+ /**
+ * The first value is the longitude, the second is latitude (both in
+ * WGS:84 values), the third value is the zoom level as an integer.
+ * Longitude and latitude MUST be within the specified bounds.
+ * The zoom level MUST be between minzoom and maxzoom.
+ * Implementations can use this value to set the default location. If the
+ * value is null, implementations may use their own algorithm for
+ * determining a default location.
+ */
+ public void setCenter(@Size(value = 2) Float... center) {
+ this.center = center;
+ }
+
+ public void setCenter(LatLng center) {
+ this.center = new Float[]{(float) center.getLongitude(), (float) center.getLatitude()};
+ }
+
+ Map<String, Object> toValueObject() {
+ Map<String, Object> result = new HashMap<>();
+ result.put("tilejson", tilejson);
+ result.put("tiles", tiles);
+
+ if (name != null) {
+ result.put("name", name);
+ }
+ if (description != null) {
+ result.put("description", description);
+ }
+ if (version != null) {
+ result.put("version", version);
+ }
+ if (attribution != null) {
+ result.put("attribution", attribution);
+ }
+ if (template != null) {
+ result.put("template", template);
+ }
+ if (legend != null) {
+ result.put("legend", legend);
+ }
+ if (scheme != null) {
+ result.put("scheme", scheme);
+ }
+ if (grids != null) {
+ result.put("grids", grids);
+ }
+ if (data != null) {
+ result.put("data", data);
+ }
+ if (minZoom != null) {
+ result.put("minzoom", minZoom);
+ }
+ if (maxZoom != null) {
+ result.put("maxzoom", maxZoom);
+ }
+ if (bounds != null) {
+ result.put("bounds", bounds);
+ }
+ if (center != null) {
+ result.put("center", center);
+ }
+
+ return result;
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/VectorSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/VectorSource.java
new file mode 100644
index 0000000000..381294083a
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/VectorSource.java
@@ -0,0 +1,45 @@
+package com.mapbox.mapboxsdk.style.sources;
+
+import java.net.URL;
+
+/**
+ * A vector source.
+ *
+ * @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-vector">the style specification</a>
+ */
+public class VectorSource extends Source {
+ public static final String TYPE = "vector";
+ private static final String URL_KEY = "url";
+
+ /**
+ * Create a vector source from a remote url
+ *
+ * @param id the source id
+ * @param url the url
+ */
+ public VectorSource(String id, URL url) {
+ this(id, url.toExternalForm());
+ }
+
+ /**
+ * Create a vector source from a remote url
+ *
+ * @param id the source id
+ * @param url the url
+ */
+ public VectorSource(String id, String url) {
+ super(id, TYPE);
+ this.put(URL_KEY, url);
+ }
+
+ /**
+ * Create a vector source from a tilset
+ *
+ * @param id the source id
+ * @param tileSet the tileset
+ */
+ public VectorSource(String id, TileSet tileSet) {
+ super(id, TYPE);
+ this.putAll(tileSet.toValueObject());
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/GzipRequestInterceptor.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/GzipRequestInterceptor.java
new file mode 100644
index 0000000000..1b13e9502f
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/GzipRequestInterceptor.java
@@ -0,0 +1,54 @@
+package com.mapbox.mapboxsdk.telemetry;
+
+import android.util.Log;
+import java.io.IOException;
+import okhttp3.Interceptor;
+import okhttp3.MediaType;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okhttp3.Response;
+import okio.BufferedSink;
+import okio.GzipSink;
+import okio.Okio;
+
+/**
+ * OkHttp Interceptor for Gzipping Telemetry Data requests to the server.
+ * Based on: https://github.com/square/okhttp/wiki/Interceptors
+ */
+public final class GzipRequestInterceptor implements Interceptor {
+
+ private static final String TAG = "GzipRequestInterceptor";
+
+ @Override public Response intercept(Interceptor.Chain chain) throws IOException {
+ Request originalRequest = chain.request();
+ if (originalRequest.body() == null || originalRequest.header("Content-Encoding") != null) {
+ Log.d(TAG, "Not compressing");
+ return chain.proceed(originalRequest);
+ }
+
+ Log.d(TAG, "Compressing");
+ Request compressedRequest = originalRequest.newBuilder()
+ .header("Content-Encoding", "gzip")
+ .method(originalRequest.method(), gzip(originalRequest.body()))
+ .build();
+ return chain.proceed(compressedRequest);
+ }
+
+ private RequestBody gzip(final RequestBody body) {
+ return new RequestBody() {
+ @Override public MediaType contentType() {
+ return body.contentType();
+ }
+
+ @Override public long contentLength() {
+ return -1; // We don't know the compressed length in advance!
+ }
+
+ @Override public void writeTo(BufferedSink sink) throws IOException {
+ BufferedSink gzipSink = Okio.buffer(new GzipSink(sink));
+ body.writeTo(gzipSink);
+ gzipSink.close();
+ }
+ };
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/MapboxEvent.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/MapboxEvent.java
index 41dec08ee9..22e37ec539 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/MapboxEvent.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/MapboxEvent.java
@@ -7,7 +7,7 @@ import java.io.Serializable;
*/
public class MapboxEvent implements Serializable {
public static final int VERSION_NUMBER = 2;
- public static final String MAPBOX_EVENTS_BASE_URL = "https://api.mapbox.com";
+ public static final String MAPBOX_EVENTS_BASE_URL = "https://events.mapbox.com";
public static final String SOURCE_MAPBOX = "mapbox";
// Event Types
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/MapboxEventManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/MapboxEventManager.java
index b386ed6549..84df822ce9 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/MapboxEventManager.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/MapboxEventManager.java
@@ -88,8 +88,12 @@ public class MapboxEventManager {
private static long flushDelayInMillis = 1000 * 60 * 3; // 3 Minutes
private static final int SESSION_ID_ROTATION_HOURS = 24;
+ private static final int FLUSH_EVENTS_CAP = 1000;
+
private static MessageDigest messageDigest = null;
+ private static final double locationEventAccuracy = 10000000;
+
private Timer timer = null;
/**
@@ -159,10 +163,12 @@ public class MapboxEventManager {
ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);
String stagingURL = appInfo.metaData.getString(MapboxConstants.KEY_META_DATA_STAGING_SERVER);
String stagingAccessToken = appInfo.metaData.getString(MapboxConstants.KEY_META_DATA_STAGING_ACCESS_TOKEN);
- String appName = context.getPackageManager().getApplicationLabel(appInfo).toString();
- PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
- String versionName = packageInfo.versionName;
- int versionCode = packageInfo.versionCode;
+
+ if (TextUtils.isEmpty(stagingURL) || TextUtils.isEmpty(stagingAccessToken)) {
+ Log.d(TAG, "Looking in SharedPreferences for Staging Credentials");
+ stagingURL = prefs.getString(MapboxConstants.MAPBOX_SHARED_PREFERENCE_KEY_TELEMETRY_STAGING_URL, null);
+ stagingAccessToken = prefs.getString(MapboxConstants.MAPBOX_SHARED_PREFERENCE_KEY_TELEMETRY_STAGING_ACCESS_TOKEN, null);
+ }
if (!TextUtils.isEmpty(stagingURL)) {
eventsURL = stagingURL;
@@ -172,6 +178,11 @@ public class MapboxEventManager {
this.accessToken = stagingAccessToken;
}
+ String appName = context.getPackageManager().getApplicationLabel(appInfo).toString();
+ PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
+ String versionName = packageInfo.versionName;
+ int versionCode = packageInfo.versionCode;
+
// Build User Agent
if (TextUtils.equals(userAgent, BuildConfig.MAPBOX_EVENTS_USER_AGENT_BASE) && !TextUtils.isEmpty(appName) && !TextUtils.isEmpty(versionName)) {
userAgent = appName + "/" + versionName + "/" + versionCode + " " + userAgent;
@@ -309,23 +320,48 @@ public class MapboxEventManager {
}
/**
+ * Centralized method for adding populated event to the queue allowing for cap size checking
+ * @param event Event to add to the Events Queue
+ */
+ private void putEventOnQueue(@NonNull Hashtable<String, Object> event) {
+ if (event == null) {
+ return;
+ }
+ events.add(event);
+ if (events.size() == FLUSH_EVENTS_CAP) {
+ Log.d(TAG, "eventsSize == flushCap so send data.");
+ flushEventsQueueImmediately();
+ }
+ }
+
+ /**
* Adds a Location Event to the system for processing
* @param location Location event
*/
public void addLocationEvent(Location location) {
+
+ // NaN and Infinite checks to prevent JSON errors at send to server time
+ if (Double.isNaN(location.getLatitude()) || Double.isNaN(location.getLongitude()) || Double.isNaN(location.getAltitude())) {
+ return;
+ }
+
+ if (Double.isInfinite(location.getLatitude()) || Double.isInfinite(location.getLongitude()) || Double.isInfinite(location.getAltitude())) {
+ return;
+ }
+
// Add Location even to queue
Hashtable<String, Object> event = new Hashtable<>();
event.put(MapboxEvent.ATTRIBUTE_EVENT, MapboxEvent.TYPE_LOCATION);
event.put(MapboxEvent.ATTRIBUTE_CREATED, generateCreateDate());
event.put(MapboxEvent.ATTRIBUTE_SOURCE, MapboxEvent.SOURCE_MAPBOX);
event.put(MapboxEvent.ATTRIBUTE_SESSION_ID, encodeString(mapboxSessionId));
- event.put(MapboxEvent.KEY_LATITUDE, location.getLatitude());
- event.put(MapboxEvent.KEY_LONGITUDE, location.getLongitude());
+ event.put(MapboxEvent.KEY_LATITUDE, Math.floor(location.getLatitude() * locationEventAccuracy) / locationEventAccuracy);
+ event.put(MapboxEvent.KEY_LONGITUDE, Math.floor(location.getLongitude() * locationEventAccuracy) / locationEventAccuracy);
event.put(MapboxEvent.KEY_ALTITUDE, location.getAltitude());
event.put(MapboxEvent.ATTRIBUTE_OPERATING_SYSTEM, operatingSystem);
event.put(MapboxEvent.ATTRIBUTE_APPLICATION_STATE, getApplicationState());
- events.add(event);
+ putEventOnQueue(event);
rotateSessionId();
}
@@ -364,7 +400,7 @@ public class MapboxEventManager {
eventWithAttributes.put(MapboxEvent.ATTRIBUTE_WIFI, getConnectedToWifi());
// Put Map Load on events before Turnstile clears it
- events.add(eventWithAttributes);
+ putEventOnQueue(eventWithAttributes);
// Turnstile
pushTurnstileEvent();
@@ -391,7 +427,7 @@ public class MapboxEventManager {
return;
}
- events.add(eventWithAttributes);
+ putEventOnQueue(eventWithAttributes);
}
/**
@@ -608,7 +644,9 @@ public class MapboxEventManager {
// =========
JSONArray jsonArray = new JSONArray();
- for (Hashtable<String, Object> evt : events) {
+ Vector<Hashtable<String, Object>> eventsClone = (Vector<Hashtable<String, Object>>) events.clone();
+
+ for (Hashtable<String, Object> evt : eventsClone) {
JSONObject jsonObject = new JSONObject();
// Build the JSON but only if there's a value for it in the evt
@@ -686,19 +724,23 @@ public class MapboxEventManager {
.add("cloudfront-staging.tilestream.net", "sha256/sPbNCVpVasMJxps3IqFfLTRKkVnRCLrTlZVc5kspqlkw=")
.add("cloudfront-staging.tilestream.net", "sha256/h6801m+z8v3zbgkRHpq6L29Esgfzhj89C1SyUCOQmqU=")
// Prod - Geotrust
- .add("api.mapbox.com", "sha256/svaiYM/ZVIfxC+CMDe4kj1KsviQmzyZ9To8nQqUJwFI=")
- .add("api.mapbox.com", "sha256/owrR9U9FWDWtrFF+myoRIu75JwU4sJwzvhCNLZoY37g=")
- .add("api.mapbox.com", "sha256/SQVGZiOrQXi+kqxcvWWE96HhfydlLVqFr4lQTqI5qqo=")
+ .add("events.mapbox.com", "sha256/BhynraKizavqoC5U26qgYuxLZst6pCu9J5stfL6RSYY=")
+ .add("events.mapbox.com", "sha256/owrR9U9FWDWtrFF+myoRIu75JwU4sJwzvhCNLZoY37g=")
+ .add("events.mapbox.com", "sha256/SQVGZiOrQXi+kqxcvWWE96HhfydlLVqFr4lQTqI5qqo=")
// Prod - DigiCert
- .add("api.mapbox.com", "sha256/JL+uwAwpA2U1UVl/AFdZy1ZnvkZJ1P1hRfmfPaPVSLU=")
- .add("api.mapbox.com", "sha256/RRM1dGqnDFsCJXBTHky16vi1obOlCgFFn/yOhI/y+ho=")
- .add("api.mapbox.com", "sha256/WoiWRyIOVNa9ihaBciRSC7XHjliYS9VwUGOIud4PB18=")
+ .add("events.mapbox.com", "sha256/Tb0uHZ/KQjWh8N9+CZFLc4zx36LONQ55l6laDi1qtT4=")
+ .add("events.mapbox.com", "sha256/RRM1dGqnDFsCJXBTHky16vi1obOlCgFFn/yOhI/y+ho=")
+ .add("events.mapbox.com", "sha256/WoiWRyIOVNa9ihaBciRSC7XHjliYS9VwUGOIud4PB18=")
.build();
- OkHttpClient client = new OkHttpClient.Builder().certificatePinner(certificatePinner).build();
+ OkHttpClient client = new OkHttpClient.Builder()
+ .certificatePinner(certificatePinner)
+ .addInterceptor(new GzipRequestInterceptor())
+ .build();
RequestBody body = RequestBody.create(JSON, jsonArray.toString());
String url = eventsURL + "/events/v2?access_token=" + accessToken;
+// Log.d(TAG, "Events URL = " + url);
Request request = new Request.Builder()
.url(url)
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java
index a0de07c5f1..ef404840e8 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java
@@ -3,6 +3,7 @@ package com.mapbox.mapboxsdk.utils;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
+import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
@@ -11,6 +12,10 @@ import android.util.TypedValue;
import android.widget.ImageView;
import com.mapbox.mapboxsdk.R;
+import com.mapbox.mapboxsdk.exceptions.ConversionException;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
public class ColorUtils {
@@ -87,4 +92,26 @@ public class ColorUtils {
Drawable wrappedDrawable = DrawableCompat.wrap(originalDrawable);
DrawableCompat.setTintList(wrappedDrawable, getSelector(tintColor));
}
+
+ static int normalizeColorComponent(String value) {
+ return (int) (Float.parseFloat(value) * 255);
+ }
+
+ /**
+ * Convert an rgba string to a Color int
+ *
+ * @throws ConversionException on illegal input
+ */
+ @ColorInt
+ public static int rgbaToColor(String value) {
+ Pattern c = Pattern.compile("rgba?\\s*\\(\\s*(\\d+\\.?\\d*)\\s*,\\s*(\\d+\\.?\\d*)\\s*,\\s*(\\d+\\.?\\d*)\\s*,?\\s*(\\d+\\.?\\d*)?\\s*\\)");
+ Matcher m = c.matcher(value);
+ if (m.matches() && m.groupCount() == 3) {
+ return Color.rgb(normalizeColorComponent(m.group(1)), normalizeColorComponent(m.group(2)), normalizeColorComponent(m.group(3)));
+ } else if (m.matches() && m.groupCount() == 4) {
+ return Color.argb(normalizeColorComponent(m.group(4)), normalizeColorComponent(m.group(1)), normalizeColorComponent(m.group(2)), normalizeColorComponent(m.group(3)));
+ } else {
+ throw new ConversionException("Not a valid rgb/rgba value");
+ }
+ }
} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/default_markerview.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/default_markerview.png
new file mode 100644
index 0000000000..651482f3ee
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/default_markerview.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/default_markerview.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/default_markerview.png
new file mode 100644
index 0000000000..63cb7b5f4b
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/default_markerview.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/default_markerview.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/default_markerview.png
new file mode 100644
index 0000000000..175f88ff88
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/default_markerview.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/default_markerview.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/default_markerview.png
new file mode 100644
index 0000000000..be782e1d4b
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/default_markerview.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/default_markerview.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/default_markerview.png
new file mode 100644
index 0000000000..fe1c486518
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/default_markerview.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapview_internal.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapview_internal.xml
index 9799487f12..2616724865 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapview_internal.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapview_internal.xml
@@ -1,11 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
- <TextureView
- android:id="@+id/textureView"
+ <SurfaceView
+ android:id="@+id/surfaceView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
+ <FrameLayout
+ android:id="@+id/markerViewContainer"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@android:color/transparent"/>
+
<com.mapbox.mapboxsdk.maps.widgets.CompassView
android:id="@+id/compassView"
android:layout_width="wrap_content"
@@ -23,15 +29,15 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
+ android:background="@drawable/bg_default_selector"
android:clickable="true"
android:contentDescription="@string/attributionsIconContentDescription"
android:padding="7dp"
- android:src="@drawable/ic_info_outline_24dp_selector"
- android:background="@drawable/bg_default_selector"/>
+ android:src="@drawable/ic_info_outline_24dp_selector" />
<com.mapbox.mapboxsdk.maps.widgets.MyLocationView
android:id="@+id/userLocationView"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
</merge> \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/view_image_marker.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/view_image_marker.xml
new file mode 100644
index 0000000000..7e4a079063
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/view_image_marker.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/image"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml
index d6cca7090f..fd0f4b98e7 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml
@@ -9,6 +9,5 @@
<dimen name="ten_dp">10dp</dimen>
<dimen name="sixteen_dp">16dp</dimen>
<dimen name="seventy_six_dp">76dp</dimen>
- <dimen name="my_locationview_size">64dp</dimen>
<dimen name="my_locationview_outer_circle">18dp</dimen>
</resources>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values/strings.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values/strings.xml
index becbcce0b0..687b85b2d8 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/values/strings.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values/strings.xml
@@ -11,11 +11,14 @@
<string name="infoWindowAddress">Address</string>
<!-- these are public -->
- <!-- {@deprecated Use Style.getXStyleUrl(int version) instead.} -->
+ <!-- Using one of these constants means your map style will always use the latest version and
+ may change as we improve the style. -->
<string name="style_mapbox_streets">mapbox://styles/mapbox/streets-v9</string>
+ <string name="style_outdoors">mapbox://styles/mapbox/outdoors-v9</string>
+ <!-- Note: Emerald style has been deprecated and will be removed in a future release-->
<string name="style_emerald">mapbox://styles/mapbox/emerald-v8</string>
<string name="style_light">mapbox://styles/mapbox/light-v9</string>
<string name="style_dark">mapbox://styles/mapbox/dark-v9</string>
<string name="style_satellite">mapbox://styles/mapbox/satellite-v9</string>
- <string name="style_satellite_streets">mapbox://styles/mapbox/satellite-hybrid-v9</string>
+ <string name="style_satellite_streets">mapbox://styles/mapbox/satellite-streets-v9</string>
</resources>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/resources/fabric/com.mapbox.mapboxsdk.mapbox-android-sdk.properties b/platform/android/MapboxGLAndroidSDK/src/main/resources/fabric/com.mapbox.mapboxsdk.mapbox-android-sdk.properties
index 8c1dcc38ce..63cccc00ef 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/resources/fabric/com.mapbox.mapboxsdk.mapbox-android-sdk.properties
+++ b/platform/android/MapboxGLAndroidSDK/src/main/resources/fabric/com.mapbox.mapboxsdk.mapbox-android-sdk.properties
@@ -1,3 +1,3 @@
fabric-identifier=com.mapbox.mapboxsdk.mapbox-android-sdk
-fabric-version=4.0.0
+fabric-version=4.1.1
fabric-build-type=binary
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle
index 5c6265c725..93def53b5c 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle
+++ b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle
@@ -90,13 +90,8 @@ dependencies {
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.4-beta1'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.4-beta1'
- // Directions SDK
- compile('com.mapbox.mapboxsdk:mapbox-android-directions:1.0.0@aar') {
- transitive = true
- }
-
- // Geocoder SDK
- compile('com.mapbox.mapboxsdk:mapbox-android-geocoder:1.0.0@aar') {
+ // Mapbox Android Services
+ compile('com.mapbox.mapboxsdk:mapbox-android-services:1.1.0@aar') {
transitive = true
}
@@ -107,7 +102,6 @@ dependencies {
androidTestCompile 'com.android.support.test:runner:0.4.1'
androidTestCompile 'com.android.support.test:rules:0.4.1'
androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.1'
- androidTestCompile 'com.jayway.android.robotium:robotium-solo:5.5.4'
}
checkstyle {
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/BaseMapboxMapTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/BaseMapboxMapTest.java
new file mode 100644
index 0000000000..1b1211b94c
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/BaseMapboxMapTest.java
@@ -0,0 +1,36 @@
+package com.mapbox.mapboxsdk.activity;
+
+import android.app.Activity;
+import android.support.test.espresso.Espresso;
+import android.util.Log;
+
+import com.mapbox.mapboxsdk.activity.utils.OnMapReadyIdlingResource;
+import com.mapbox.mapboxsdk.constants.MapboxConstants;
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.testapp.R;
+
+import org.junit.After;
+import org.junit.Before;
+
+public abstract class BaseMapboxMapTest extends BaseTest {
+
+ private OnMapReadyIdlingResource idlingResource;
+ protected MapboxMap mapboxMap;
+
+ @Before
+ public void registerIdlingResource() {
+ Log.e(MapboxConstants.TAG, "@Before test");
+ idlingResource = new OnMapReadyIdlingResource(getActivity());
+ Espresso.registerIdlingResources(idlingResource);
+ checkViewIsDisplayed(R.id.mapView);
+ mapboxMap = idlingResource.getMapboxMap();
+ }
+
+ public abstract Activity getActivity();
+
+ @After
+ public void unregisterIdlingResource() {
+ Log.e(MapboxConstants.TAG, "@After test");
+ Espresso.unregisterIdlingResources(idlingResource);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/BaseTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/BaseTest.java
index e9292332d5..ac2816cba4 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/BaseTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/BaseTest.java
@@ -1,8 +1,8 @@
-package com.mapbox.mapboxsdk.testapp.espresso;
+package com.mapbox.mapboxsdk.activity;
import android.app.Activity;
-import com.mapbox.mapboxsdk.testapp.espresso.utils.ScreenshotUtil;
+import com.mapbox.mapboxsdk.activity.utils.ScreenshotUtil;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/BulkMarkerActivityTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/BulkMarkerActivityTest.java
index b85fe41243..8fc3d2b2ed 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/BulkMarkerActivityTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/BulkMarkerActivityTest.java
@@ -1,11 +1,11 @@
-package com.mapbox.mapboxsdk.testapp.espresso;
+package com.mapbox.mapboxsdk.activity;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;
-import com.mapbox.mapboxsdk.testapp.activity.annotation.BulkMarkerActivity;
import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.annotation.BulkMarkerActivity;
import org.junit.Before;
import org.junit.Rule;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/DirectionsActivityTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/DirectionsActivityTest.java
index a84345b14d..4c5b3e1f3d 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/DirectionsActivityTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/DirectionsActivityTest.java
@@ -1,12 +1,12 @@
-package com.mapbox.mapboxsdk.testapp.espresso;
+package com.mapbox.mapboxsdk.activity;
import android.app.Activity;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;
-import com.mapbox.mapboxsdk.testapp.activity.directions.DirectionsActivity;
import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.directions.DirectionsActivity;
import org.junit.Before;
import org.junit.Rule;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/DynamicMarkerChangeActivityTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/DynamicMarkerChangeActivityTest.java
index 700da5e3bc..07b1489f34 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/DynamicMarkerChangeActivityTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/DynamicMarkerChangeActivityTest.java
@@ -1,12 +1,12 @@
-package com.mapbox.mapboxsdk.testapp.espresso;
+package com.mapbox.mapboxsdk.activity;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;
-import com.mapbox.mapboxsdk.testapp.activity.annotation.DynamicMarkerChangeActivity;
+import com.mapbox.mapboxsdk.activity.utils.ViewUtils;
import com.mapbox.mapboxsdk.testapp.R;
-import com.mapbox.mapboxsdk.testapp.espresso.utils.ViewUtils;
+import com.mapbox.mapboxsdk.testapp.activity.annotation.DynamicMarkerChangeActivity;
import org.junit.Rule;
import org.junit.Test;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/GeocoderActivityTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/GeocoderActivityTest.java
index 9bd7a49b9c..0197388543 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/GeocoderActivityTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/GeocoderActivityTest.java
@@ -1,12 +1,12 @@
-package com.mapbox.mapboxsdk.testapp.espresso;
+package com.mapbox.mapboxsdk.activity;
import android.app.Activity;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;
-import com.mapbox.mapboxsdk.testapp.activity.geocoding.GeocoderActivity;
import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.geocoding.GeocoderActivity;
import org.junit.Before;
import org.junit.Rule;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/InfoWindowActivityTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/InfoWindowActivityTest.java
index feb0bb1a02..df32ec9e9e 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/InfoWindowActivityTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/InfoWindowActivityTest.java
@@ -1,11 +1,11 @@
-package com.mapbox.mapboxsdk.testapp.espresso;
+package com.mapbox.mapboxsdk.activity;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;
-import com.mapbox.mapboxsdk.testapp.activity.infowindow.InfoWindowActivity;
import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.infowindow.InfoWindowActivity;
import org.junit.Before;
import org.junit.Rule;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/InfoWindowAdapterActivityTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/InfoWindowAdapterActivityTest.java
index 0c62387e36..34dc06ed1b 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/InfoWindowAdapterActivityTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/InfoWindowAdapterActivityTest.java
@@ -1,11 +1,11 @@
-package com.mapbox.mapboxsdk.testapp.espresso;
+package com.mapbox.mapboxsdk.activity;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;
-import com.mapbox.mapboxsdk.testapp.activity.infowindow.InfoWindowAdapterActivity;
import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.infowindow.InfoWindowAdapterActivity;
import org.junit.Before;
import org.junit.Rule;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/LatLngBoundsActivityTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/LatLngBoundsActivityTest.java
index 39e7e4766e..09d164c975 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/LatLngBoundsActivityTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/LatLngBoundsActivityTest.java
@@ -1,11 +1,11 @@
-package com.mapbox.mapboxsdk.testapp.espresso;
+package com.mapbox.mapboxsdk.activity;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;
-import com.mapbox.mapboxsdk.testapp.activity.camera.LatLngBoundsActivity;
import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.camera.LatLngBoundsActivity;
import org.junit.Before;
import org.junit.Rule;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/ManualZoomActivityTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/ManualZoomActivityTest.java
index 5c88bd371a..3fa1390e9a 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/ManualZoomActivityTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/ManualZoomActivityTest.java
@@ -1,12 +1,12 @@
-package com.mapbox.mapboxsdk.testapp.espresso;
+package com.mapbox.mapboxsdk.activity;
import android.app.Activity;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;
-import com.mapbox.mapboxsdk.testapp.activity.camera.ManualZoomActivity;
import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.camera.ManualZoomActivity;
import org.junit.Before;
import org.junit.Rule;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/MapFragmentActivityTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/MapFragmentActivityTest.java
index d7522b2d7f..1847e2db02 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/MapFragmentActivityTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/MapFragmentActivityTest.java
@@ -1,11 +1,11 @@
-package com.mapbox.mapboxsdk.testapp.espresso;
+package com.mapbox.mapboxsdk.activity;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;
-import com.mapbox.mapboxsdk.testapp.activity.fragment.MapFragmentActivity;
import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.fragment.MapFragmentActivity;
import org.junit.Before;
import org.junit.Rule;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/MapPaddingActivityTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/MapPaddingActivityTest.java
index fe6c4eb487..5edca393f4 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/MapPaddingActivityTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/MapPaddingActivityTest.java
@@ -1,12 +1,12 @@
-package com.mapbox.mapboxsdk.testapp.espresso;
+package com.mapbox.mapboxsdk.activity;
import android.app.Activity;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;
-import com.mapbox.mapboxsdk.testapp.activity.maplayout.MapPaddingActivity;
import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.maplayout.MapPaddingActivity;
import org.junit.Before;
import org.junit.Rule;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/MaxMinZoomActivityTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/MaxMinZoomActivityTest.java
index 48152286e9..901d2b0b2a 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/MaxMinZoomActivityTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/MaxMinZoomActivityTest.java
@@ -1,12 +1,12 @@
-package com.mapbox.mapboxsdk.testapp.espresso;
+package com.mapbox.mapboxsdk.activity;
import android.app.Activity;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;
-import com.mapbox.mapboxsdk.testapp.activity.camera.MaxMinZoomActivity;
import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.camera.MaxMinZoomActivity;
import org.junit.Before;
import org.junit.Rule;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/MyLocationTrackingModeActivityTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/MyLocationTrackingModeActivityTest.java
index ceda7cff2c..8a4b7d856d 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/MyLocationTrackingModeActivityTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/MyLocationTrackingModeActivityTest.java
@@ -1,11 +1,11 @@
-package com.mapbox.mapboxsdk.testapp.espresso;
+package com.mapbox.mapboxsdk.activity;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;
-import com.mapbox.mapboxsdk.testapp.activity.userlocation.MyLocationTrackingModeActivity;
import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.userlocation.MyLocationTrackingModeActivity;
import org.junit.Before;
import org.junit.Rule;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/PolylineActivityTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/PolylineActivityTest.java
index 425d803952..2172d226d1 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/PolylineActivityTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/PolylineActivityTest.java
@@ -1,11 +1,11 @@
-package com.mapbox.mapboxsdk.testapp.espresso;
+package com.mapbox.mapboxsdk.activity;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;
-import com.mapbox.mapboxsdk.testapp.activity.annotation.PolylineActivity;
import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.annotation.PolylineActivity;
import org.junit.Before;
import org.junit.Rule;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/ScrollByActivityTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/ScrollByActivityTest.java
index c545bc6e04..f337f38c79 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/ScrollByActivityTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/ScrollByActivityTest.java
@@ -1,4 +1,4 @@
-package com.mapbox.mapboxsdk.testapp.espresso;
+package com.mapbox.mapboxsdk.activity;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/SupportMapFragmentActivityTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/SupportMapFragmentActivityTest.java
index e6c1cadf1e..bc32cd8d85 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/SupportMapFragmentActivityTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/SupportMapFragmentActivityTest.java
@@ -1,4 +1,4 @@
-package com.mapbox.mapboxsdk.testapp.espresso;
+package com.mapbox.mapboxsdk.activity;
import android.app.Activity;
import android.support.test.rule.ActivityTestRule;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/utils/DrawerUtils.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/utils/DrawerUtils.java
index 7143fa948f..c1ee47d05e 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/utils/DrawerUtils.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/utils/DrawerUtils.java
@@ -1,4 +1,4 @@
-package com.mapbox.mapboxsdk.testapp.espresso.utils;
+package com.mapbox.mapboxsdk.activity.utils;
import android.support.annotation.StringRes;
import android.support.test.espresso.Espresso;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/utils/GestureUtils.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/utils/GestureUtils.java
index e2807af5b5..da26e938b2 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/utils/GestureUtils.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/utils/GestureUtils.java
@@ -1,4 +1,4 @@
-package com.mapbox.mapboxsdk.testapp.espresso.utils;
+package com.mapbox.mapboxsdk.activity.utils;
import android.support.annotation.IdRes;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/utils/OnMapReadyIdlingResource.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/utils/OnMapReadyIdlingResource.java
new file mode 100644
index 0000000000..95db88d96b
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/utils/OnMapReadyIdlingResource.java
@@ -0,0 +1,57 @@
+package com.mapbox.mapboxsdk.activity.utils;
+
+import android.app.Activity;
+import android.support.test.espresso.IdlingResource;
+import android.util.Log;
+
+import com.mapbox.mapboxsdk.constants.MapboxConstants;
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+
+import java.lang.reflect.Field;
+
+public class OnMapReadyIdlingResource implements IdlingResource {
+
+ private final Activity activity;
+ private MapboxMap mapboxMap;
+ private IdlingResource.ResourceCallback resourceCallback;
+
+ public OnMapReadyIdlingResource(Activity activity) {
+ this.activity = activity;
+ }
+
+ @Override
+ public String getName() {
+ return getClass().getSimpleName();
+ }
+
+ @Override
+ public boolean isIdleNow() {
+ boolean idle = isMapboxMapReady();
+ if (idle && resourceCallback != null) {
+ resourceCallback.onTransitionToIdle();
+ }
+ return idle;
+ }
+
+ @Override
+ public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
+ this.resourceCallback = resourceCallback;
+ }
+
+ private boolean isMapboxMapReady() {
+ try {
+ Field field = activity.getClass().getDeclaredField("mapboxMap");
+ field.setAccessible(true);
+ mapboxMap = (MapboxMap) field.get(activity);
+ Log.e(MapboxConstants.TAG, "isMapboxReady called with value " + (mapboxMap != null));
+ return mapboxMap != null;
+ } catch (Exception e) {
+ Log.e(MapboxConstants.TAG, "could not reflect", e);
+ return false;
+ }
+ }
+
+ public MapboxMap getMapboxMap() {
+ return mapboxMap;
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/utils/ScreenshotUtil.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/utils/ScreenshotUtil.java
index fdb06e52d8..f28780b9e2 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/utils/ScreenshotUtil.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/utils/ScreenshotUtil.java
@@ -1,4 +1,4 @@
-package com.mapbox.mapboxsdk.testapp.espresso.utils;
+package com.mapbox.mapboxsdk.activity.utils;
import android.app.Activity;
import android.graphics.Bitmap;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/utils/ViewUtils.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/utils/ViewUtils.java
index 6611c83545..9ba02f8e6a 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/utils/ViewUtils.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/activity/utils/ViewUtils.java
@@ -1,4 +1,4 @@
-package com.mapbox.mapboxsdk.testapp.espresso.utils;
+package com.mapbox.mapboxsdk.activity.utils;
import android.support.annotation.IdRes;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/camera/RotateTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/camera/RotateTest.java
new file mode 100644
index 0000000000..948ed99570
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/camera/RotateTest.java
@@ -0,0 +1,67 @@
+package com.mapbox.mapboxsdk.camera;
+
+import android.app.Activity;
+import android.support.test.espresso.UiController;
+import android.support.test.espresso.ViewAction;
+import android.support.test.rule.ActivityTestRule;
+import android.view.View;
+
+import com.mapbox.mapboxsdk.activity.BaseMapboxMapTest;
+import com.mapbox.mapboxsdk.maps.MapView;
+import com.mapbox.mapboxsdk.maps.MapboxMapUtils;
+import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.infowindow.InfoWindowActivity;
+
+import org.hamcrest.Matcher;
+import org.junit.Rule;
+import org.junit.Test;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+
+public class RotateTest extends BaseMapboxMapTest {
+
+ @Rule
+ public final ActivityTestRule<InfoWindowActivity> rule = new ActivityTestRule<>(InfoWindowActivity.class);
+
+ @Test
+ public void testRotate() {
+ onView(withId(R.id.mapView)).perform(new RotateAction(0, 180));
+ }
+
+ @Override
+ public Activity getActivity() {
+ return rule.getActivity();
+ }
+
+ private class RotateAction implements ViewAction {
+
+ private float startDegree;
+ private float endDegree;
+
+ public RotateAction(float startDegree, float endDegree) {
+ this.startDegree = startDegree;
+ this.endDegree = endDegree;
+ }
+
+ @Override
+ public Matcher<View> getConstraints() {
+ return isDisplayed();
+ }
+
+ @Override
+ public String getDescription() {
+ return "rotateAction";
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ uiController.loopMainThreadForAtLeast(500);
+ for (float i = startDegree; i < endDegree; i++) {
+ MapboxMapUtils.setDirection((MapView) view, i);
+ uiController.loopMainThreadForAtLeast(1);
+ }
+ }
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/camera/TiltTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/camera/TiltTest.java
new file mode 100644
index 0000000000..28061ae1ff
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/camera/TiltTest.java
@@ -0,0 +1,67 @@
+package com.mapbox.mapboxsdk.camera;
+
+import android.app.Activity;
+import android.support.test.espresso.UiController;
+import android.support.test.espresso.ViewAction;
+import android.support.test.rule.ActivityTestRule;
+import android.view.View;
+
+import com.mapbox.mapboxsdk.activity.BaseMapboxMapTest;
+import com.mapbox.mapboxsdk.maps.MapView;
+import com.mapbox.mapboxsdk.maps.MapboxMapUtils;
+import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.annotation.DynamicMarkerChangeActivity;
+
+import org.hamcrest.Matcher;
+import org.junit.Rule;
+import org.junit.Test;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+
+public class TiltTest extends BaseMapboxMapTest {
+
+ @Rule
+ public final ActivityTestRule<DynamicMarkerChangeActivity> rule = new ActivityTestRule<>(DynamicMarkerChangeActivity.class);
+
+ @Test
+ public void testTilt() {
+ onView(withId(R.id.mapView)).perform(new TiltAction(0, 60));
+ }
+
+ @Override
+ public Activity getActivity() {
+ return rule.getActivity();
+ }
+
+ private class TiltAction implements ViewAction {
+
+ private float startDegree;
+ private float endDegree;
+
+ public TiltAction(float startDegree, float endDegree) {
+ this.startDegree = startDegree;
+ this.endDegree = endDegree;
+ }
+
+ @Override
+ public Matcher<View> getConstraints() {
+ return isDisplayed();
+ }
+
+ @Override
+ public String getDescription() {
+ return "tiltAction";
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ uiController.loopMainThreadForAtLeast(500);
+ for (float i = startDegree; i < endDegree; i++) {
+ MapboxMapUtils.setTilt((MapView) view, i);
+ uiController.loopMainThreadForAtLeast(1);
+ }
+ }
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/camera/ZoomTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/camera/ZoomTest.java
new file mode 100644
index 0000000000..f84bcaa2a0
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/camera/ZoomTest.java
@@ -0,0 +1,74 @@
+package com.mapbox.mapboxsdk.camera;
+
+import android.app.Activity;
+import android.support.test.espresso.UiController;
+import android.support.test.espresso.ViewAction;
+import android.support.test.rule.ActivityTestRule;
+import android.view.View;
+
+import com.mapbox.mapboxsdk.activity.BaseMapboxMapTest;
+import com.mapbox.mapboxsdk.constants.MapboxConstants;
+import com.mapbox.mapboxsdk.geometry.LatLng;
+import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.maplayout.DebugModeActivity;
+
+import org.hamcrest.Matcher;
+import org.junit.Rule;
+import org.junit.Test;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+
+public class ZoomTest extends BaseMapboxMapTest {
+
+ @Rule
+ public final ActivityTestRule<DebugModeActivity> rule = new ActivityTestRule<>(DebugModeActivity.class);
+
+ @Test
+ public void testZoom() throws Exception {
+ onView(withId(R.id.mapView)).perform(new ZoomAction(MapboxConstants.MINIMUM_ZOOM, MapboxConstants.MAXIMUM_ZOOM));
+ }
+
+ @Override
+ public Activity getActivity() {
+ return rule.getActivity();
+ }
+
+ private class ZoomAction implements ViewAction {
+
+ private float fromZoom;
+ private float toZoom;
+
+ public ZoomAction(float fromZoom, float toZoom) {
+ this.fromZoom = fromZoom;
+ this.toZoom = toZoom;
+ }
+
+ @Override
+ public Matcher<View> getConstraints() {
+ return isDisplayed();
+ }
+
+ @Override
+ public String getDescription() {
+ return "zoomAction";
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ // move camera above denver
+ mapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition(
+ new CameraPosition.Builder()
+ .target(new LatLng(39.749750, -104.949559))
+ .build()));
+
+ uiController.loopMainThreadForAtLeast(500);
+
+ for (float i = fromZoom; i < toZoom; i++) {
+ mapboxMap.animateCamera(CameraUpdateFactory.zoomTo(i));
+ uiController.loopMainThreadForAtLeast(200);
+ }
+ }
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapUtils.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapUtils.java
index d41c692509..4c793a7db1 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapUtils.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapUtils.java
@@ -5,24 +5,11 @@ package com.mapbox.mapboxsdk.maps;
*/
public class MapboxMapUtils {
- /**
- * Get the MapboxMap instance linked to passed MapView
- *
- * @param mapView
- * @return
- */
- public static MapboxMap getMapboxMap(MapView mapView) {
- return mapView.getMapboxMap();
+ public static void setDirection(MapView mapView, float direction) {
+ mapView.setBearing(direction);
}
- /**
- * Set the direction of the user
- *
- * @param mapView
- * @param direction
- */
- public static void setDirection(MapView mapView, double direction) {
- mapView.setDirection(direction);
+ public static void setTilt(MapView mapView, float tilt) {
+ mapView.setTilt((double) tilt);
}
-
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/BackgroundLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/BackgroundLayerTest.java
new file mode 100644
index 0000000000..009e07b00e
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/BackgroundLayerTest.java
@@ -0,0 +1,142 @@
+// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make style-code-android`.
+package com.mapbox.mapboxsdk.style;
+
+import android.graphics.Color;
+import android.support.test.espresso.Espresso;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
+
+import com.mapbox.mapboxsdk.activity.BaseTest;
+import com.mapbox.mapboxsdk.activity.utils.OnMapReadyIdlingResource;
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.style.layers.BackgroundLayer;
+import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.style.RuntimeStyleTestActivity;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static com.mapbox.mapboxsdk.style.layers.Property.NONE;
+import static com.mapbox.mapboxsdk.style.layers.Property.VISIBLE;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.backgroundColor;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.backgroundOpacity;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.backgroundPattern;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * Basic smoke tests for BackgroundLayer
+ */
+@RunWith(AndroidJUnit4.class)
+public class BackgroundLayerTest extends BaseTest {
+ private static final String TAG = BackgroundLayerTest.class.getSimpleName();
+
+ @Rule
+ public final ActivityTestRule<RuntimeStyleTestActivity> rule = new ActivityTestRule<>(RuntimeStyleTestActivity.class);
+
+ private BackgroundLayer layer;
+
+ private OnMapReadyIdlingResource idlingResource;
+
+ private MapboxMap mapboxMap;
+
+ @Before
+ public void setup() {
+ idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
+ Espresso.registerIdlingResources(idlingResource);
+ }
+
+ @Test
+ public void testSetVisibility() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ Log.i(TAG, "Retrieving layer");
+ layer = mapboxMap.getLayerAs("background");
+ Log.i(TAG, "visibility");
+ assertNotNull(layer);
+
+ //Get initial
+ assertEquals(layer.getVisibility().getValue(), VISIBLE);
+
+ //Set
+ layer.setProperties(visibility(NONE));
+ assertEquals(layer.getVisibility().getValue(), NONE);
+ }
+
+ @Test
+ public void testBackgroundColor() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ Log.i(TAG, "Retrieving layer");
+ layer = mapboxMap.getLayerAs("background");
+ Log.i(TAG, "background-color");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(backgroundColor("rgba(0, 0, 0, 1)"));
+ assertEquals((String) layer.getBackgroundColor().getValue(), (String) "rgba(0, 0, 0, 1)");
+ }
+
+ @Test
+ public void testBackgroundColorAsInt() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ Log.i(TAG, "Retrieving layer");
+ layer = mapboxMap.getLayerAs("background");
+ Log.i(TAG, "background-color");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(backgroundColor(Color.RED));
+ assertEquals(layer.getBackgroundColorAsInt(), Color.RED);
+ }
+
+ @Test
+ public void testBackgroundPattern() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ Log.i(TAG, "Retrieving layer");
+ layer = mapboxMap.getLayerAs("background");
+ Log.i(TAG, "background-pattern");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(backgroundPattern("pedestrian-polygon"));
+ assertEquals((String) layer.getBackgroundPattern().getValue(), (String) "pedestrian-polygon");
+ }
+
+ @Test
+ public void testBackgroundOpacity() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ Log.i(TAG, "Retrieving layer");
+ layer = mapboxMap.getLayerAs("background");
+ Log.i(TAG, "background-opacity");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(backgroundOpacity(0.3f));
+ assertEquals((Float) layer.getBackgroundOpacity().getValue(), (Float) 0.3f);
+ }
+
+
+ @After
+ public void unregisterIntentServiceIdlingResource() {
+ Espresso.unregisterIdlingResources(idlingResource);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/CircleLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/CircleLayerTest.java
new file mode 100644
index 0000000000..51d0cd94b1
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/CircleLayerTest.java
@@ -0,0 +1,255 @@
+// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make style-code-android`.
+package com.mapbox.mapboxsdk.style;
+
+import android.graphics.Color;
+import android.support.test.espresso.Espresso;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
+
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.style.layers.CircleLayer;
+import com.mapbox.mapboxsdk.activity.BaseTest;
+import com.mapbox.mapboxsdk.activity.utils.OnMapReadyIdlingResource;
+import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.style.RuntimeStyleTestActivity;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+import static com.mapbox.mapboxsdk.style.layers.Property.*;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.*;
+
+/**
+ * Basic smoke tests for CircleLayer
+ */
+@RunWith(AndroidJUnit4.class)
+public class CircleLayerTest extends BaseTest {
+ private static final String TAG = CircleLayerTest.class.getSimpleName();
+
+ @Rule
+ public final ActivityTestRule<RuntimeStyleTestActivity> rule = new ActivityTestRule<>(RuntimeStyleTestActivity.class);
+
+ private CircleLayer layer;
+
+ private OnMapReadyIdlingResource idlingResource;
+
+ private MapboxMap mapboxMap;
+
+ @Before
+ public void setup() {
+ idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
+ Espresso.registerIdlingResources(idlingResource);
+ }
+
+ @Test
+ public void testSetVisibility() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new CircleLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "visibility");
+ assertNotNull(layer);
+
+ //Get initial
+ assertEquals(layer.getVisibility().getValue(), VISIBLE);
+
+ //Set
+ layer.setProperties(visibility(NONE));
+ assertEquals(layer.getVisibility().getValue(), NONE);
+ }
+
+ @Test
+ public void testCircleRadius() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new CircleLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "circle-radius");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(circleRadius(0.3f));
+ assertEquals((Float) layer.getCircleRadius().getValue(), (Float) 0.3f);
+ }
+
+ @Test
+ public void testCircleColor() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new CircleLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "circle-color");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(circleColor("rgba(0, 0, 0, 1)"));
+ assertEquals((String) layer.getCircleColor().getValue(), (String) "rgba(0, 0, 0, 1)");
+ }
+
+ @Test
+ public void testCircleColorAsInt() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new CircleLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "circle-color");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(circleColor(Color.RED));
+ assertEquals(layer.getCircleColorAsInt(), Color.RED);
+ }
+
+ @Test
+ public void testCircleBlur() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new CircleLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "circle-blur");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(circleBlur(0.3f));
+ assertEquals((Float) layer.getCircleBlur().getValue(), (Float) 0.3f);
+ }
+
+ @Test
+ public void testCircleOpacity() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new CircleLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "circle-opacity");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(circleOpacity(0.3f));
+ assertEquals((Float) layer.getCircleOpacity().getValue(), (Float) 0.3f);
+ }
+
+ @Test
+ public void testCircleTranslate() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new CircleLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "circle-translate");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(circleTranslate(new Float[]{0f,0f}));
+ assertEquals((Float[]) layer.getCircleTranslate().getValue(), (Float[]) new Float[]{0f,0f});
+ }
+
+ @Test
+ public void testCircleTranslateAnchor() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new CircleLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "circle-translate-anchor");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(circleTranslateAnchor(CIRCLE_TRANSLATE_ANCHOR_MAP));
+ assertEquals((String) layer.getCircleTranslateAnchor().getValue(), (String) CIRCLE_TRANSLATE_ANCHOR_MAP);
+ }
+
+ @Test
+ public void testCirclePitchScale() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new CircleLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "circle-pitch-scale");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(circlePitchScale(CIRCLE_PITCH_SCALE_MAP));
+ assertEquals((String) layer.getCirclePitchScale().getValue(), (String) CIRCLE_PITCH_SCALE_MAP);
+ }
+
+
+ @After
+ public void unregisterIntentServiceIdlingResource() {
+ Espresso.unregisterIdlingResources(idlingResource);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/FillLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/FillLayerTest.java
new file mode 100644
index 0000000000..0773e28ae9
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/FillLayerTest.java
@@ -0,0 +1,287 @@
+// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make style-code-android`.
+package com.mapbox.mapboxsdk.style;
+
+import android.graphics.Color;
+import android.support.test.espresso.Espresso;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
+
+import com.mapbox.mapboxsdk.activity.BaseTest;
+import com.mapbox.mapboxsdk.activity.utils.OnMapReadyIdlingResource;
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.style.layers.FillLayer;
+import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.style.RuntimeStyleTestActivity;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static com.mapbox.mapboxsdk.style.layers.Property.FILL_TRANSLATE_ANCHOR_MAP;
+import static com.mapbox.mapboxsdk.style.layers.Property.NONE;
+import static com.mapbox.mapboxsdk.style.layers.Property.VISIBLE;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillAntialias;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillColor;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillOpacity;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillOutlineColor;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillPattern;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillTranslate;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillTranslateAnchor;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * Basic smoke tests for FillLayer
+ */
+@RunWith(AndroidJUnit4.class)
+public class FillLayerTest extends BaseTest {
+ private static final String TAG = FillLayerTest.class.getSimpleName();
+
+ @Rule
+ public final ActivityTestRule<RuntimeStyleTestActivity> rule = new ActivityTestRule<>(RuntimeStyleTestActivity.class);
+
+ private FillLayer layer;
+
+ private OnMapReadyIdlingResource idlingResource;
+
+ private MapboxMap mapboxMap;
+
+ @Before
+ public void setup() {
+ idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
+ Espresso.registerIdlingResources(idlingResource);
+ }
+
+ @Test
+ public void testSetVisibility() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new FillLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "visibility");
+ assertNotNull(layer);
+
+ //Get initial
+ assertEquals(layer.getVisibility().getValue(), VISIBLE);
+
+ //Set
+ layer.setProperties(visibility(NONE));
+ assertEquals(layer.getVisibility().getValue(), NONE);
+ }
+
+ @Test
+ public void testFillAntialias() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new FillLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "fill-antialias");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(fillAntialias(true));
+ assertEquals((Boolean) layer.getFillAntialias().getValue(), (Boolean) true);
+ }
+
+ @Test
+ public void testFillOpacity() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new FillLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "fill-opacity");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(fillOpacity(0.3f));
+ assertEquals((Float) layer.getFillOpacity().getValue(), (Float) 0.3f);
+ }
+
+ @Test
+ public void testFillColor() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new FillLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "fill-color");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(fillColor("rgba(0, 0, 0, 1)"));
+ assertEquals((String) layer.getFillColor().getValue(), (String) "rgba(0, 0, 0, 1)");
+ }
+
+ @Test
+ public void testFillColorAsInt() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new FillLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "fill-color");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(fillColor(Color.RED));
+ assertEquals(layer.getFillColorAsInt(), Color.RED);
+ }
+
+ @Test
+ public void testFillOutlineColor() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new FillLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "fill-outline-color");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(fillOutlineColor("rgba(0, 0, 0, 1)"));
+ assertEquals((String) layer.getFillOutlineColor().getValue(), (String) "rgba(0, 0, 0, 1)");
+ }
+
+ @Test
+ public void testFillOutlineColorAsInt() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new FillLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "fill-outline-color");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(fillOutlineColor(Color.RED));
+ assertEquals(layer.getFillOutlineColorAsInt(), Color.RED);
+ }
+
+ @Test
+ public void testFillTranslate() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new FillLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "fill-translate");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(fillTranslate(new Float[]{0f, 0f}));
+ assertEquals((Float[]) layer.getFillTranslate().getValue(), (Float[]) new Float[]{0f, 0f});
+ }
+
+ @Test
+ public void testFillTranslateAnchor() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new FillLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "fill-translate-anchor");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(fillTranslateAnchor(FILL_TRANSLATE_ANCHOR_MAP));
+ assertEquals((String) layer.getFillTranslateAnchor().getValue(), (String) FILL_TRANSLATE_ANCHOR_MAP);
+ }
+
+ @Test
+ public void testFillPattern() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new FillLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "fill-pattern");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(fillPattern("pedestrian-polygon"));
+ assertEquals((String) layer.getFillPattern().getValue(), (String) "pedestrian-polygon");
+ }
+
+
+ @After
+ public void unregisterIntentServiceIdlingResource() {
+ Espresso.unregisterIdlingResources(idlingResource);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/LineLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/LineLayerTest.java
new file mode 100644
index 0000000000..5fee78bc63
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/LineLayerTest.java
@@ -0,0 +1,428 @@
+// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make style-code-android`.
+package com.mapbox.mapboxsdk.style;
+
+import android.graphics.Color;
+import android.support.test.espresso.Espresso;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
+
+import com.mapbox.mapboxsdk.activity.BaseTest;
+import com.mapbox.mapboxsdk.activity.utils.OnMapReadyIdlingResource;
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.style.layers.LineLayer;
+import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.style.RuntimeStyleTestActivity;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static com.mapbox.mapboxsdk.style.layers.Property.LINE_CAP_BUTT;
+import static com.mapbox.mapboxsdk.style.layers.Property.LINE_JOIN_BEVEL;
+import static com.mapbox.mapboxsdk.style.layers.Property.LINE_TRANSLATE_ANCHOR_MAP;
+import static com.mapbox.mapboxsdk.style.layers.Property.NONE;
+import static com.mapbox.mapboxsdk.style.layers.Property.VISIBLE;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineBlur;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineCap;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineColor;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineDasharray;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineGapWidth;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineJoin;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineMiterLimit;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineOffset;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineOpacity;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.linePattern;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineRoundLimit;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineTranslate;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineTranslateAnchor;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineWidth;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * Basic smoke tests for LineLayer
+ */
+@RunWith(AndroidJUnit4.class)
+public class LineLayerTest extends BaseTest {
+ private static final String TAG = LineLayerTest.class.getSimpleName();
+
+ @Rule
+ public final ActivityTestRule<RuntimeStyleTestActivity> rule = new ActivityTestRule<>(RuntimeStyleTestActivity.class);
+
+ private LineLayer layer;
+
+ private OnMapReadyIdlingResource idlingResource;
+
+ private MapboxMap mapboxMap;
+
+ @Before
+ public void setup() {
+ idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
+ Espresso.registerIdlingResources(idlingResource);
+ }
+
+ @Test
+ public void testSetVisibility() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new LineLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "visibility");
+ assertNotNull(layer);
+
+ //Get initial
+ assertEquals(layer.getVisibility().getValue(), VISIBLE);
+
+ //Set
+ layer.setProperties(visibility(NONE));
+ assertEquals(layer.getVisibility().getValue(), NONE);
+ }
+
+ @Test
+ public void testLineCap() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new LineLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "line-cap");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(lineCap(LINE_CAP_BUTT));
+ assertEquals((String) layer.getLineCap().getValue(), (String) LINE_CAP_BUTT);
+ }
+
+ @Test
+ public void testLineJoin() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new LineLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "line-join");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(lineJoin(LINE_JOIN_BEVEL));
+ assertEquals((String) layer.getLineJoin().getValue(), (String) LINE_JOIN_BEVEL);
+ }
+
+ @Test
+ public void testLineMiterLimit() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new LineLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "line-miter-limit");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(lineMiterLimit(0.3f));
+ assertEquals((Float) layer.getLineMiterLimit().getValue(), (Float) 0.3f);
+ }
+
+ @Test
+ public void testLineRoundLimit() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new LineLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "line-round-limit");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(lineRoundLimit(0.3f));
+ assertEquals((Float) layer.getLineRoundLimit().getValue(), (Float) 0.3f);
+ }
+
+ @Test
+ public void testLineOpacity() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new LineLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "line-opacity");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(lineOpacity(0.3f));
+ assertEquals((Float) layer.getLineOpacity().getValue(), (Float) 0.3f);
+ }
+
+ @Test
+ public void testLineColor() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new LineLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "line-color");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(lineColor("rgba(0, 0, 0, 1)"));
+ assertEquals((String) layer.getLineColor().getValue(), (String) "rgba(0, 0, 0, 1)");
+ }
+
+ @Test
+ public void testLineColorAsInt() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new LineLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "line-color");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(lineColor(Color.RED));
+ assertEquals(layer.getLineColorAsInt(), Color.RED);
+ }
+
+ @Test
+ public void testLineTranslate() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new LineLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "line-translate");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(lineTranslate(new Float[]{0f, 0f}));
+ assertEquals((Float[]) layer.getLineTranslate().getValue(), (Float[]) new Float[]{0f, 0f});
+ }
+
+ @Test
+ public void testLineTranslateAnchor() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new LineLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "line-translate-anchor");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(lineTranslateAnchor(LINE_TRANSLATE_ANCHOR_MAP));
+ assertEquals((String) layer.getLineTranslateAnchor().getValue(), (String) LINE_TRANSLATE_ANCHOR_MAP);
+ }
+
+ @Test
+ public void testLineWidth() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new LineLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "line-width");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(lineWidth(0.3f));
+ assertEquals((Float) layer.getLineWidth().getValue(), (Float) 0.3f);
+ }
+
+ @Test
+ public void testLineGapWidth() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new LineLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "line-gap-width");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(lineGapWidth(0.3f));
+ assertEquals((Float) layer.getLineGapWidth().getValue(), (Float) 0.3f);
+ }
+
+ @Test
+ public void testLineOffset() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new LineLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "line-offset");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(lineOffset(0.3f));
+ assertEquals((Float) layer.getLineOffset().getValue(), (Float) 0.3f);
+ }
+
+ @Test
+ public void testLineBlur() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new LineLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "line-blur");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(lineBlur(0.3f));
+ assertEquals((Float) layer.getLineBlur().getValue(), (Float) 0.3f);
+ }
+
+ @Test
+ public void testLineDasharray() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new LineLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "line-dasharray");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(lineDasharray(new Float[]{}));
+ assertEquals((Float[]) layer.getLineDasharray().getValue(), (Float[]) new Float[]{});
+ }
+
+ @Test
+ public void testLinePattern() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new LineLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "line-pattern");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(linePattern("pedestrian-polygon"));
+ assertEquals((String) layer.getLinePattern().getValue(), (String) "pedestrian-polygon");
+ }
+
+
+ @After
+ public void unregisterIntentServiceIdlingResource() {
+ Espresso.unregisterIdlingResources(idlingResource);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/RasterLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/RasterLayerTest.java
new file mode 100644
index 0000000000..a40127148b
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/RasterLayerTest.java
@@ -0,0 +1,242 @@
+// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make style-code-android`.
+package com.mapbox.mapboxsdk.style;
+
+import android.graphics.Color;
+import android.support.test.espresso.Espresso;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
+
+import com.mapbox.mapboxsdk.activity.BaseTest;
+import com.mapbox.mapboxsdk.activity.utils.OnMapReadyIdlingResource;
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.style.layers.RasterLayer;
+import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.style.RuntimeStyleTestActivity;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static com.mapbox.mapboxsdk.style.layers.Property.NONE;
+import static com.mapbox.mapboxsdk.style.layers.Property.VISIBLE;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.rasterBrightnessMax;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.rasterBrightnessMin;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.rasterContrast;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.rasterFadeDuration;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.rasterHueRotate;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.rasterOpacity;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.rasterSaturation;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * Basic smoke tests for RasterLayer
+ */
+@RunWith(AndroidJUnit4.class)
+public class RasterLayerTest extends BaseTest {
+ private static final String TAG = RasterLayerTest.class.getSimpleName();
+
+ @Rule
+ public final ActivityTestRule<RuntimeStyleTestActivity> rule = new ActivityTestRule<>(RuntimeStyleTestActivity.class);
+
+ private RasterLayer layer;
+
+ private OnMapReadyIdlingResource idlingResource;
+
+ private MapboxMap mapboxMap;
+
+ @Before
+ public void setup() {
+ idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
+ Espresso.registerIdlingResources(idlingResource);
+ }
+
+ @Test
+ public void testSetVisibility() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new RasterLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "visibility");
+ assertNotNull(layer);
+
+ //Get initial
+ assertEquals(layer.getVisibility().getValue(), VISIBLE);
+
+ //Set
+ layer.setProperties(visibility(NONE));
+ assertEquals(layer.getVisibility().getValue(), NONE);
+ }
+
+ @Test
+ public void testRasterOpacity() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new RasterLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "raster-opacity");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(rasterOpacity(0.3f));
+ assertEquals((Float) layer.getRasterOpacity().getValue(), (Float) 0.3f);
+ }
+
+ @Test
+ public void testRasterHueRotate() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new RasterLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "raster-hue-rotate");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(rasterHueRotate(0.3f));
+ assertEquals((Float) layer.getRasterHueRotate().getValue(), (Float) 0.3f);
+ }
+
+ @Test
+ public void testRasterBrightnessMin() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new RasterLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "raster-brightness-min");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(rasterBrightnessMin(0.3f));
+ assertEquals((Float) layer.getRasterBrightnessMin().getValue(), (Float) 0.3f);
+ }
+
+ @Test
+ public void testRasterBrightnessMax() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new RasterLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "raster-brightness-max");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(rasterBrightnessMax(0.3f));
+ assertEquals((Float) layer.getRasterBrightnessMax().getValue(), (Float) 0.3f);
+ }
+
+ @Test
+ public void testRasterSaturation() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new RasterLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "raster-saturation");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(rasterSaturation(0.3f));
+ assertEquals((Float) layer.getRasterSaturation().getValue(), (Float) 0.3f);
+ }
+
+ @Test
+ public void testRasterContrast() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new RasterLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "raster-contrast");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(rasterContrast(0.3f));
+ assertEquals((Float) layer.getRasterContrast().getValue(), (Float) 0.3f);
+ }
+
+ @Test
+ public void testRasterFadeDuration() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new RasterLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "raster-fade-duration");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(rasterFadeDuration(0.3f));
+ assertEquals((Float) layer.getRasterFadeDuration().getValue(), (Float) 0.3f);
+ }
+
+
+ @After
+ public void unregisterIntentServiceIdlingResource() {
+ Espresso.unregisterIdlingResources(idlingResource);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/RuntimeStyleBackgroundLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/RuntimeStyleBackgroundLayerTest.java
new file mode 100644
index 0000000000..70ebf78556
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/RuntimeStyleBackgroundLayerTest.java
@@ -0,0 +1,61 @@
+package com.mapbox.mapboxsdk.style;
+
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
+import com.mapbox.mapboxsdk.style.layers.BackgroundLayer;
+import com.mapbox.mapboxsdk.style.layers.Property;
+import com.mapbox.mapboxsdk.style.layers.PropertyFactory;
+import com.mapbox.mapboxsdk.testapp.activity.style.RuntimeStyleTestActivity;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Basic smoke tests for BackgroundLayer
+ */
+@RunWith(AndroidJUnit4.class)
+public class RuntimeStyleBackgroundLayerTest
+ extends ActivityInstrumentationTestCase2<RuntimeStyleTestActivity> {
+ private static final String TAG = RuntimeStyleBackgroundLayerTest.class.getSimpleName();
+
+ public RuntimeStyleBackgroundLayerTest() {
+ super(RuntimeStyleTestActivity.class);
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ injectInstrumentation(InstrumentationRegistry.getInstrumentation());
+ }
+
+ @Test
+ public void testSetVisibility() {
+ getActivity().mapView.getMapAsync(new OnMapReadyCallback() {
+ @Override
+ public void onMapReady(MapboxMap mapboxMap) {
+ Log.i(TAG, "visibility");
+ BackgroundLayer layer = mapboxMap.getLayerAs("background");
+ assertNotNull(layer);
+
+ //Get initial
+ assertEquals(layer.getVisibility().getValue(), Property.VISIBLE);
+
+ //Set
+ layer.setProperties(PropertyFactory.visibility(Property.NONE));
+ assertEquals(layer.getVisibility().getValue(), Property.NONE);
+ }
+ });
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ super.tearDown();
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/RuntimeStyleTests.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/RuntimeStyleTests.java
new file mode 100644
index 0000000000..a99a84ea9f
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/RuntimeStyleTests.java
@@ -0,0 +1,91 @@
+package com.mapbox.mapboxsdk.style;
+
+import android.support.test.espresso.Espresso;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.style.layers.FillLayer;
+import com.mapbox.mapboxsdk.style.layers.NoSuchLayerException;
+import com.mapbox.mapboxsdk.style.layers.Property;
+import com.mapbox.mapboxsdk.style.layers.PropertyFactory;
+import com.mapbox.mapboxsdk.style.sources.VectorSource;
+import com.mapbox.mapboxsdk.activity.BaseTest;
+import com.mapbox.mapboxsdk.activity.utils.OnMapReadyIdlingResource;
+import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.style.RuntimeStyleTestActivity;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Basic smoke tests for Layer and Source
+ */
+@RunWith(AndroidJUnit4.class)
+public class RuntimeStyleTests extends BaseTest {
+
+ @Rule
+ public final ActivityTestRule<RuntimeStyleTestActivity> rule = new ActivityTestRule<>(RuntimeStyleTestActivity.class);
+
+ private OnMapReadyIdlingResource idlingResource;
+
+ @Before
+ public void registerIdlingResource() {
+ idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
+ Espresso.registerIdlingResources(idlingResource);
+ }
+
+ @Test
+ public void testGetAddRemoveLayer() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+
+ //Get initial
+ assertNotNull(mapboxMap.getLayer("building"));
+
+ //Remove
+ try {
+ mapboxMap.removeLayer("building");
+ } catch (NoSuchLayerException e) {
+ assertFalse(true);
+ }
+ assertNull(mapboxMap.getLayer("building"));
+
+ //Add
+ FillLayer layer = new FillLayer("building", "composite");
+ layer.setSourceLayer("building");
+ mapboxMap.addLayer(layer);
+
+ assertNotNull(mapboxMap.getLayer("building"));
+
+ try {
+ layer.setProperties(PropertyFactory.visibility(Property.VISIBLE));
+ assertTrue("Never reached as the reference is invalid after adding", false);
+ } catch (Exception e) {
+ //Expected, reference is no longer valid
+ }
+ }
+
+ @Test
+ public void testAddRemoveSource() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ mapboxMap.addSource(new VectorSource("my-source", "mapbox://mapbox.mapbox-terrain-v2"));
+ mapboxMap.removeSource("my-source");
+ }
+
+ @After
+ public void unregisterIntentServiceIdlingResource() {
+ Espresso.unregisterIdlingResources(idlingResource);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/RuntimeStyleTimingTests.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/RuntimeStyleTimingTests.java
new file mode 100644
index 0000000000..fd166b7b33
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/RuntimeStyleTimingTests.java
@@ -0,0 +1,45 @@
+package com.mapbox.mapboxsdk.style;
+
+import android.support.test.espresso.Espresso;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.mapbox.mapboxsdk.activity.BaseTest;
+import com.mapbox.mapboxsdk.activity.utils.OnMapReadyIdlingResource;
+import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.style.RuntimeStyleTimingTestActivity;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Basic smoke tests for adding Layer and Source as early as possible (in onCreate)
+ */
+@RunWith(AndroidJUnit4.class)
+public class RuntimeStyleTimingTests extends BaseTest {
+
+ @Rule
+ public final ActivityTestRule<RuntimeStyleTimingTestActivity> rule = new ActivityTestRule<>(RuntimeStyleTimingTestActivity.class);
+
+ private OnMapReadyIdlingResource idlingResource;
+
+ @Before
+ public void registerIdlingResource() {
+ idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
+ Espresso.registerIdlingResources(idlingResource);
+ }
+
+ @Test
+ public void testGetAddRemoveLayer() {
+ checkViewIsDisplayed(R.id.mapView);
+ //We're good if it didn't crash
+ }
+
+ @After
+ public void unregisterIntentServiceIdlingResource() {
+ Espresso.unregisterIdlingResources(idlingResource);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/SymbolLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/SymbolLayerTest.java
new file mode 100644
index 0000000000..3b860866a5
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/SymbolLayerTest.java
@@ -0,0 +1,1283 @@
+// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make style-code-android`.
+package com.mapbox.mapboxsdk.style;
+
+import android.graphics.Color;
+import android.support.test.espresso.Espresso;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
+
+import com.mapbox.mapboxsdk.activity.BaseTest;
+import com.mapbox.mapboxsdk.activity.utils.OnMapReadyIdlingResource;
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.style.layers.SymbolLayer;
+import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.style.RuntimeStyleTestActivity;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static com.mapbox.mapboxsdk.style.layers.Property.ICON_ROTATION_ALIGNMENT_MAP;
+import static com.mapbox.mapboxsdk.style.layers.Property.ICON_TEXT_FIT_NONE;
+import static com.mapbox.mapboxsdk.style.layers.Property.ICON_TRANSLATE_ANCHOR_MAP;
+import static com.mapbox.mapboxsdk.style.layers.Property.NONE;
+import static com.mapbox.mapboxsdk.style.layers.Property.SYMBOL_PLACEMENT_POINT;
+import static com.mapbox.mapboxsdk.style.layers.Property.TEXT_ANCHOR_CENTER;
+import static com.mapbox.mapboxsdk.style.layers.Property.TEXT_JUSTIFY_LEFT;
+import static com.mapbox.mapboxsdk.style.layers.Property.TEXT_PITCH_ALIGNMENT_MAP;
+import static com.mapbox.mapboxsdk.style.layers.Property.TEXT_ROTATION_ALIGNMENT_MAP;
+import static com.mapbox.mapboxsdk.style.layers.Property.TEXT_TRANSFORM_NONE;
+import static com.mapbox.mapboxsdk.style.layers.Property.TEXT_TRANSLATE_ANCHOR_MAP;
+import static com.mapbox.mapboxsdk.style.layers.Property.VISIBLE;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconAllowOverlap;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconColor;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconHaloBlur;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconHaloColor;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconHaloWidth;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconIgnorePlacement;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconImage;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconKeepUpright;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconOffset;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconOpacity;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconOptional;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconPadding;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconRotate;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconRotationAlignment;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconSize;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconTextFit;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconTextFitPadding;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconTranslate;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconTranslateAnchor;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.symbolAvoidEdges;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.symbolPlacement;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.symbolSpacing;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textAllowOverlap;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textAnchor;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textColor;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textField;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textFont;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textHaloBlur;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textHaloColor;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textHaloWidth;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textIgnorePlacement;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textJustify;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textKeepUpright;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textLetterSpacing;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textLineHeight;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textMaxAngle;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textMaxWidth;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textOffset;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textOpacity;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textOptional;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textPadding;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textPitchAlignment;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textRotate;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textRotationAlignment;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textSize;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textTransform;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textTranslate;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textTranslateAnchor;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * Basic smoke tests for SymbolLayer
+ */
+@RunWith(AndroidJUnit4.class)
+public class SymbolLayerTest extends BaseTest {
+ private static final String TAG = SymbolLayerTest.class.getSimpleName();
+
+ @Rule
+ public final ActivityTestRule<RuntimeStyleTestActivity> rule = new ActivityTestRule<>(RuntimeStyleTestActivity.class);
+
+ private SymbolLayer layer;
+
+ private OnMapReadyIdlingResource idlingResource;
+
+ private MapboxMap mapboxMap;
+
+ @Before
+ public void setup() {
+ idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
+ Espresso.registerIdlingResources(idlingResource);
+ }
+
+ @Test
+ public void testSetVisibility() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "visibility");
+ assertNotNull(layer);
+
+ //Get initial
+ assertEquals(layer.getVisibility().getValue(), VISIBLE);
+
+ //Set
+ layer.setProperties(visibility(NONE));
+ assertEquals(layer.getVisibility().getValue(), NONE);
+ }
+
+ @Test
+ public void testSymbolPlacement() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "symbol-placement");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(symbolPlacement(SYMBOL_PLACEMENT_POINT));
+ assertEquals((String) layer.getSymbolPlacement().getValue(), (String) SYMBOL_PLACEMENT_POINT);
+ }
+
+ @Test
+ public void testSymbolSpacing() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "symbol-spacing");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(symbolSpacing(0.3f));
+ assertEquals((Float) layer.getSymbolSpacing().getValue(), (Float) 0.3f);
+ }
+
+ @Test
+ public void testSymbolAvoidEdges() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "symbol-avoid-edges");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(symbolAvoidEdges(true));
+ assertEquals((Boolean) layer.getSymbolAvoidEdges().getValue(), (Boolean) true);
+ }
+
+ @Test
+ public void testIconAllowOverlap() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "icon-allow-overlap");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(iconAllowOverlap(true));
+ assertEquals((Boolean) layer.getIconAllowOverlap().getValue(), (Boolean) true);
+ }
+
+ @Test
+ public void testIconIgnorePlacement() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "icon-ignore-placement");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(iconIgnorePlacement(true));
+ assertEquals((Boolean) layer.getIconIgnorePlacement().getValue(), (Boolean) true);
+ }
+
+ @Test
+ public void testIconOptional() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "icon-optional");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(iconOptional(true));
+ assertEquals((Boolean) layer.getIconOptional().getValue(), (Boolean) true);
+ }
+
+ @Test
+ public void testIconRotationAlignment() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "icon-rotation-alignment");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(iconRotationAlignment(ICON_ROTATION_ALIGNMENT_MAP));
+ assertEquals((String) layer.getIconRotationAlignment().getValue(), (String) ICON_ROTATION_ALIGNMENT_MAP);
+ }
+
+ @Test
+ public void testIconSize() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "icon-size");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(iconSize(0.3f));
+ assertEquals((Float) layer.getIconSize().getValue(), (Float) 0.3f);
+ }
+
+ @Test
+ public void testIconTextFit() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "icon-text-fit");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(iconTextFit(ICON_TEXT_FIT_NONE));
+ assertEquals((String) layer.getIconTextFit().getValue(), (String) ICON_TEXT_FIT_NONE);
+ }
+
+ @Test
+ public void testIconTextFitPadding() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "icon-text-fit-padding");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(iconTextFitPadding(new Float[]{0f, 0f, 0f, 0f}));
+ assertEquals((Float[]) layer.getIconTextFitPadding().getValue(), (Float[]) new Float[]{0f, 0f, 0f, 0f});
+ }
+
+ @Test
+ public void testIconImage() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "icon-image");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(iconImage("undefined"));
+ assertEquals((String) layer.getIconImage().getValue(), (String) "undefined");
+ }
+
+ @Test
+ public void testIconRotate() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "icon-rotate");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(iconRotate(0.3f));
+ assertEquals((Float) layer.getIconRotate().getValue(), (Float) 0.3f);
+ }
+
+ @Test
+ public void testIconPadding() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "icon-padding");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(iconPadding(0.3f));
+ assertEquals((Float) layer.getIconPadding().getValue(), (Float) 0.3f);
+ }
+
+ @Test
+ public void testIconKeepUpright() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "icon-keep-upright");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(iconKeepUpright(true));
+ assertEquals((Boolean) layer.getIconKeepUpright().getValue(), (Boolean) true);
+ }
+
+ @Test
+ public void testIconOffset() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "icon-offset");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(iconOffset(new Float[]{0f, 0f}));
+ assertEquals((Float[]) layer.getIconOffset().getValue(), (Float[]) new Float[]{0f, 0f});
+ }
+
+ @Test
+ public void testTextPitchAlignment() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "text-pitch-alignment");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(textPitchAlignment(TEXT_PITCH_ALIGNMENT_MAP));
+ assertEquals((String) layer.getTextPitchAlignment().getValue(), (String) TEXT_PITCH_ALIGNMENT_MAP);
+ }
+
+ @Test
+ public void testTextRotationAlignment() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "text-rotation-alignment");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(textRotationAlignment(TEXT_ROTATION_ALIGNMENT_MAP));
+ assertEquals((String) layer.getTextRotationAlignment().getValue(), (String) TEXT_ROTATION_ALIGNMENT_MAP);
+ }
+
+ @Test
+ public void testTextField() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "text-field");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(textField(""));
+ assertEquals((String) layer.getTextField().getValue(), (String) "");
+ }
+
+ @Test
+ public void testTextFont() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "text-font");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(textFont(new String[]{"Open Sans Regular", "Arial Unicode MS Regular"}));
+ assertEquals((String[]) layer.getTextFont().getValue(), (String[]) new String[]{"Open Sans Regular", "Arial Unicode MS Regular"});
+ }
+
+ @Test
+ public void testTextSize() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "text-size");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(textSize(0.3f));
+ assertEquals((Float) layer.getTextSize().getValue(), (Float) 0.3f);
+ }
+
+ @Test
+ public void testTextMaxWidth() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "text-max-width");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(textMaxWidth(0.3f));
+ assertEquals((Float) layer.getTextMaxWidth().getValue(), (Float) 0.3f);
+ }
+
+ @Test
+ public void testTextLineHeight() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "text-line-height");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(textLineHeight(0.3f));
+ assertEquals((Float) layer.getTextLineHeight().getValue(), (Float) 0.3f);
+ }
+
+ @Test
+ public void testTextLetterSpacing() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "text-letter-spacing");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(textLetterSpacing(0.3f));
+ assertEquals((Float) layer.getTextLetterSpacing().getValue(), (Float) 0.3f);
+ }
+
+ @Test
+ public void testTextJustify() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "text-justify");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(textJustify(TEXT_JUSTIFY_LEFT));
+ assertEquals((String) layer.getTextJustify().getValue(), (String) TEXT_JUSTIFY_LEFT);
+ }
+
+ @Test
+ public void testTextAnchor() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "text-anchor");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(textAnchor(TEXT_ANCHOR_CENTER));
+ assertEquals((String) layer.getTextAnchor().getValue(), (String) TEXT_ANCHOR_CENTER);
+ }
+
+ @Test
+ public void testTextMaxAngle() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "text-max-angle");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(textMaxAngle(0.3f));
+ assertEquals((Float) layer.getTextMaxAngle().getValue(), (Float) 0.3f);
+ }
+
+ @Test
+ public void testTextRotate() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "text-rotate");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(textRotate(0.3f));
+ assertEquals((Float) layer.getTextRotate().getValue(), (Float) 0.3f);
+ }
+
+ @Test
+ public void testTextPadding() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "text-padding");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(textPadding(0.3f));
+ assertEquals((Float) layer.getTextPadding().getValue(), (Float) 0.3f);
+ }
+
+ @Test
+ public void testTextKeepUpright() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "text-keep-upright");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(textKeepUpright(true));
+ assertEquals((Boolean) layer.getTextKeepUpright().getValue(), (Boolean) true);
+ }
+
+ @Test
+ public void testTextTransform() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "text-transform");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(textTransform(TEXT_TRANSFORM_NONE));
+ assertEquals((String) layer.getTextTransform().getValue(), (String) TEXT_TRANSFORM_NONE);
+ }
+
+ @Test
+ public void testTextOffset() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "text-offset");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(textOffset(new Float[]{0f, 0f}));
+ assertEquals((Float[]) layer.getTextOffset().getValue(), (Float[]) new Float[]{0f, 0f});
+ }
+
+ @Test
+ public void testTextAllowOverlap() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "text-allow-overlap");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(textAllowOverlap(true));
+ assertEquals((Boolean) layer.getTextAllowOverlap().getValue(), (Boolean) true);
+ }
+
+ @Test
+ public void testTextIgnorePlacement() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "text-ignore-placement");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(textIgnorePlacement(true));
+ assertEquals((Boolean) layer.getTextIgnorePlacement().getValue(), (Boolean) true);
+ }
+
+ @Test
+ public void testTextOptional() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "text-optional");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(textOptional(true));
+ assertEquals((Boolean) layer.getTextOptional().getValue(), (Boolean) true);
+ }
+
+ @Test
+ public void testIconOpacity() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "icon-opacity");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(iconOpacity(0.3f));
+ assertEquals((Float) layer.getIconOpacity().getValue(), (Float) 0.3f);
+ }
+
+ @Test
+ public void testIconColor() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "icon-color");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(iconColor("rgba(0, 0, 0, 1)"));
+ assertEquals((String) layer.getIconColor().getValue(), (String) "rgba(0, 0, 0, 1)");
+ }
+
+ @Test
+ public void testIconColorAsInt() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "icon-color");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(iconColor(Color.RED));
+ assertEquals(layer.getIconColorAsInt(), Color.RED);
+ }
+
+ @Test
+ public void testIconHaloColor() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "icon-halo-color");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(iconHaloColor("rgba(0, 0, 0, 1)"));
+ assertEquals((String) layer.getIconHaloColor().getValue(), (String) "rgba(0, 0, 0, 1)");
+ }
+
+ @Test
+ public void testIconHaloColorAsInt() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "icon-halo-color");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(iconHaloColor(Color.RED));
+ assertEquals(layer.getIconHaloColorAsInt(), Color.RED);
+ }
+
+ @Test
+ public void testIconHaloWidth() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "icon-halo-width");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(iconHaloWidth(0.3f));
+ assertEquals((Float) layer.getIconHaloWidth().getValue(), (Float) 0.3f);
+ }
+
+ @Test
+ public void testIconHaloBlur() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "icon-halo-blur");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(iconHaloBlur(0.3f));
+ assertEquals((Float) layer.getIconHaloBlur().getValue(), (Float) 0.3f);
+ }
+
+ @Test
+ public void testIconTranslate() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "icon-translate");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(iconTranslate(new Float[]{0f, 0f}));
+ assertEquals((Float[]) layer.getIconTranslate().getValue(), (Float[]) new Float[]{0f, 0f});
+ }
+
+ @Test
+ public void testIconTranslateAnchor() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "icon-translate-anchor");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(iconTranslateAnchor(ICON_TRANSLATE_ANCHOR_MAP));
+ assertEquals((String) layer.getIconTranslateAnchor().getValue(), (String) ICON_TRANSLATE_ANCHOR_MAP);
+ }
+
+ @Test
+ public void testTextOpacity() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "text-opacity");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(textOpacity(0.3f));
+ assertEquals((Float) layer.getTextOpacity().getValue(), (Float) 0.3f);
+ }
+
+ @Test
+ public void testTextColor() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "text-color");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(textColor("rgba(0, 0, 0, 1)"));
+ assertEquals((String) layer.getTextColor().getValue(), (String) "rgba(0, 0, 0, 1)");
+ }
+
+ @Test
+ public void testTextColorAsInt() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "text-color");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(textColor(Color.RED));
+ assertEquals(layer.getTextColorAsInt(), Color.RED);
+ }
+
+ @Test
+ public void testTextHaloColor() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "text-halo-color");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(textHaloColor("rgba(0, 0, 0, 1)"));
+ assertEquals((String) layer.getTextHaloColor().getValue(), (String) "rgba(0, 0, 0, 1)");
+ }
+
+ @Test
+ public void testTextHaloColorAsInt() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "text-halo-color");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(textHaloColor(Color.RED));
+ assertEquals(layer.getTextHaloColorAsInt(), Color.RED);
+ }
+
+ @Test
+ public void testTextHaloWidth() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "text-halo-width");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(textHaloWidth(0.3f));
+ assertEquals((Float) layer.getTextHaloWidth().getValue(), (Float) 0.3f);
+ }
+
+ @Test
+ public void testTextHaloBlur() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "text-halo-blur");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(textHaloBlur(0.3f));
+ assertEquals((Float) layer.getTextHaloBlur().getValue(), (Float) 0.3f);
+ }
+
+ @Test
+ public void testTextTranslate() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "text-translate");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(textTranslate(new Float[]{0f, 0f}));
+ assertEquals((Float[]) layer.getTextTranslate().getValue(), (Float[]) new Float[]{0f, 0f});
+ }
+
+ @Test
+ public void testTextTranslateAnchor() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new SymbolLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ Log.i(TAG, "text-translate-anchor");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(textTranslateAnchor(TEXT_TRANSLATE_ANCHOR_MAP));
+ assertEquals((String) layer.getTextTranslateAnchor().getValue(), (String) TEXT_TRANSLATE_ANCHOR_MAP);
+ }
+
+
+ @After
+ public void unregisterIntentServiceIdlingResource() {
+ Espresso.unregisterIdlingResources(idlingResource);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/layer.junit.ejs b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/layer.junit.ejs
new file mode 100644
index 0000000000..115a27832b
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/layer.junit.ejs
@@ -0,0 +1,146 @@
+<%
+ const type = locals.type;
+ 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;
+
+import android.graphics.Color;
+import android.support.test.espresso.Espresso;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
+
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.style.layers.<%- camelize(type) %>Layer;
+import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.style.RuntimeStyleTestActivity;
+import com.mapbox.mapboxsdk.testapp.BaseTest;
+import com.mapbox.mapboxsdk.testapp.utils.OnMapReadyIdlingResource;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+import static com.mapbox.mapboxsdk.style.layers.Property.*;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.*;
+
+/**
+ * Basic smoke tests for <%- camelize(type) %>Layer
+ */
+@RunWith(AndroidJUnit4.class)
+public class <%- camelize(type) %>LayerTest extends BaseTest {
+ private static final String TAG = <%- camelize(type) %>LayerTest.class.getSimpleName();
+
+ @Rule
+ public final ActivityTestRule<RuntimeStyleTestActivity> rule = new ActivityTestRule<>(RuntimeStyleTestActivity.class);
+
+ private <%- camelize(type) %>Layer layer;
+
+ private OnMapReadyIdlingResource idlingResource;
+
+ private MapboxMap mapboxMap;
+
+ @Before
+ public void setup() {
+ idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
+ Espresso.registerIdlingResources(idlingResource);
+ }
+
+ @Test
+ public void testSetVisibility() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+<% if (type === 'background') { -%>
+ Log.i(TAG, "Retrieving layer");
+ layer = mapboxMap.getLayerAs("background");
+<% } else { -%>
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new <%- camelize(type) %>Layer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+<% } -%>
+ Log.i(TAG, "visibility");
+ assertNotNull(layer);
+
+ //Get initial
+ assertEquals(layer.getVisibility().getValue(), VISIBLE);
+
+ //Set
+ layer.setProperties(visibility(NONE));
+ assertEquals(layer.getVisibility().getValue(), NONE);
+ }
+
+<% for (const property of properties) { -%>
+ @Test
+ public void test<%- camelize(property.name) %>() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+<% if (type === 'background') { -%>
+ Log.i(TAG, "Retrieving layer");
+ layer = mapboxMap.getLayerAs("background");
+<% } else { -%>
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new <%- camelize(type) %>Layer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+<% } -%>
+ Log.i(TAG, "<%- property.name %>");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(<%- camelizeWithLeadingLowercase(property.name) %>(<%- defaultValueJava(property) %>));
+ assertEquals((<%- propertyType(property) %>) layer.get<%- camelize(property.name) %>().getValue(), (<%- propertyType(property) %>) <%- defaultValueJava(property) %>);
+ }
+<% if (property.type == 'color') { -%>
+
+ @Test
+ public void test<%- camelize(property.name) %>AsInt() {
+ checkViewIsDisplayed(R.id.mapView);
+
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+<% if (type === 'background') { -%>
+ Log.i(TAG, "Retrieving layer");
+ layer = mapboxMap.getLayerAs("background");
+<% } else { -%>
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Log.i(TAG, "Adding layer");
+ layer = new <%- camelize(type) %>Layer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ //Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+<% } -%>
+ Log.i(TAG, "<%- property.name %>");
+ assertNotNull(layer);
+
+ //Set and Get
+ layer.setProperties(<%- camelizeWithLeadingLowercase(property.name) %>(Color.RED));
+ assertEquals(layer.get<%- camelize(property.name) %>AsInt(), Color.RED);
+ }
+<% } -%>
+
+<% } -%>
+
+ @After
+ public void unregisterIntentServiceIdlingResource() {
+ Espresso.unregisterIdlingResources(idlingResource);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/ScreenshotActivityTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/ScreenshotActivityTest.java
deleted file mode 100644
index 60649ad4ae..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/espresso/ScreenshotActivityTest.java
+++ /dev/null
@@ -1,124 +0,0 @@
-package com.mapbox.mapboxsdk.testapp.espresso;
-
-import android.app.Activity;
-import android.support.test.espresso.Espresso;
-import android.support.test.espresso.IdlingPolicies;
-import android.support.test.espresso.IdlingResource;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.text.format.DateUtils;
-
-import com.mapbox.mapboxsdk.testapp.R;
-import com.mapbox.mapboxsdk.testapp.activity.camera.LatLngBoundsActivity;
-import com.mapbox.mapboxsdk.testapp.espresso.utils.ScreenshotUtil;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.concurrent.TimeUnit;
-
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.action.ViewActions.click;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-
-@RunWith(AndroidJUnit4.class)
-@LargeTest
-public class
-ScreenshotActivityTest {
-
- @Rule
- public ActivityTestRule<LatLngBoundsActivity> mActivityRule = new ActivityTestRule<>(LatLngBoundsActivity.class);
-
- private Activity mActivity = null;
-
- @Before
- public void setActivity() {
- mActivity = mActivityRule.getActivity();
-
- // Make sure Espresso does not time out
- IdlingPolicies.setMasterPolicyTimeout(60, TimeUnit.SECONDS);
- IdlingPolicies.setIdlingResourceTimeout(26, TimeUnit.SECONDS);
- }
-
- @Test
- public void testScreenshot() {
- waitFor(DateUtils.SECOND_IN_MILLIS * 5, mActivity);
- }
-
- private static void waitFor(long waitingTime, Activity a) {
- // Start
- onView(withId(R.id.mapView)).perform(click());
-
- // Make sure Espresso does not time out
- IdlingPolicies.setMasterPolicyTimeout(waitingTime * 2, TimeUnit.MILLISECONDS);
- IdlingPolicies.setIdlingResourceTimeout(waitingTime * 2, TimeUnit.MILLISECONDS);
-
- // Now we wait
- IdlingResource idlingResource = new ElapsedTimeIdlingResource(waitingTime);
- Espresso.registerIdlingResources(idlingResource);
-
- // Stop and verify
- onView(withId(R.id.mapView)).perform(click());
-
- ScreenshotUtil.take(a, "testing");
-
- // Clean up
- Espresso.unregisterIdlingResources(idlingResource);
- }
-
-// @Test
-// public void takeScreenshot() {
-// // Start
-// checkViewIsDisplayed(R.id.mapView);
-//
-//
-// // Now we wait
-// IdlingResource idlingResource = new ElapsedTimeIdlingResource(4);
-// Espresso.registerIdlingResources(idlingResource);
-//
-// // We take a screenshot
-// ScreenshotUtil.take(mActivity, "test");
-//
-// // Clean up
-// Espresso.unregisterIdlingResources(idlingResource);
-// }
-
-// @Test
-// public void testSanity() {
-// checkViewIsDisplayed(R.id.mapView);
-// }
-
- public static class ElapsedTimeIdlingResource implements IdlingResource {
- private final long startTime;
- private final long waitingTime;
- private ResourceCallback resourceCallback;
-
- public ElapsedTimeIdlingResource(long waitingTime) {
- this.startTime = System.currentTimeMillis();
- this.waitingTime = waitingTime;
- }
-
- @Override
- public String getName() {
- return ElapsedTimeIdlingResource.class.getName() + ":" + waitingTime;
- }
-
- @Override
- public boolean isIdleNow() {
- long elapsed = System.currentTimeMillis() - startTime;
- boolean idle = (elapsed >= waitingTime);
- if (idle) {
- resourceCallback.onTransitionToIdle();
- }
- return idle;
- }
-
- @Override
- public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
- this.resourceCallback = resourceCallback;
- }
- }
-}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/robotium/BaseMainActivityTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/robotium/BaseMainActivityTest.java
deleted file mode 100644
index 0eedca5458..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/robotium/BaseMainActivityTest.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.mapbox.mapboxsdk.testapp.robotium;
-
-import android.test.ActivityInstrumentationTestCase2;
-
-import com.mapbox.mapboxsdk.maps.MapView;
-import com.mapbox.mapboxsdk.maps.MapboxMap;
-import com.mapbox.mapboxsdk.maps.MapboxMapUtils;
-import com.mapbox.mapboxsdk.testapp.R;
-import com.mapbox.mapboxsdk.testapp.activity.annotation.PolygonActivity;
-import com.mapbox.mapboxsdk.testapp.activity.annotation.PolylineActivity;
-import com.mapbox.mapboxsdk.testapp.activity.infowindow.InfoWindowActivity;
-import com.robotium.solo.Solo;
-
-import org.junit.Test;
-
-public abstract class BaseMainActivityTest{
-//
-//} extends ActivityInstrumentationTestCase2<InfoWindowActivity> {
-//
-// protected Solo solo;
-// protected MapView mapView;
-// protected MapboxMap mapboxMap;
-//
-// public BaseMainActivityTest() {
-// super(InfoWindowActivity.class);
-// }
-//
-// @Override
-// public void setUp() throws Exception {
-// solo = new Solo(getInstrumentation(), getActivity());
-// mapView = (MapView) solo.getView(R.id.mapView);
-// mapboxMap = MapboxMapUtils.getMapboxMap(mapView);
-// }
-//
-// @Override
-// public void tearDown() throws Exception {
-// solo.finishOpenedActivities();
-// }
-//
-// @Test
-// public void testSanity() throws Exception {
-// assertNotNull("Should be non null", solo);
-// assertNotNull("Should be non null", mapView);
-// assertNotNull("Should be non null", mapboxMap);
-// }
-}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/robotium/CompassViewTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/robotium/CompassViewTest.java
deleted file mode 100644
index 9990d71d67..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/robotium/CompassViewTest.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package com.mapbox.mapboxsdk.testapp.robotium;
-
-import com.mapbox.mapboxsdk.camera.CameraPosition;
-import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.maps.widgets.CompassView;
-import com.mapbox.mapboxsdk.testapp.R;
-import com.mapbox.mapboxsdk.testapp.robotium.utils.ViewAssertion;
-
-import org.junit.Test;
-
-public class CompassViewTest {
-// extends
-//} BaseMainActivityTest {
-//
-// private CompassView compassView;
-//
-// @Override
-// public void setUp() throws Exception {
-// super.setUp();
-// compassView = (CompassView) solo.getView(R.id.compassView);
-// }
-//
-//// @Test
-//// public void testCompass() {
-//// setCameraDirection(0);
-//// solo.sleep(200);
-//// ViewAssertion.isInvisible(compassView);
-//// }
-//
-// @Test
-// public void testCompassClick() throws Exception {
-// setCameraDirection(20);
-// solo.sleep(200);
-// ViewAssertion.isVisible(compassView);
-// solo.clickOnView(compassView);
-// solo.sleep(200);
-// ViewAssertion.isVisible(compassView);
-// }
-//
-// private void setCameraDirection(float bearing) {
-// mapboxMap.setCameraPosition(new CameraPosition.Builder()
-// .target(new LatLng(0, 0))
-// .tilt(0)
-// .zoom(15)
-// .bearing(bearing)
-// .build());
-// }
-} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/robotium/SimpleRotateTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/robotium/SimpleRotateTest.java
deleted file mode 100644
index 8d1feed6ff..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/robotium/SimpleRotateTest.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.mapbox.mapboxsdk.testapp.robotium;
-
-import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
-import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.maps.MapboxMapUtils;
-
-import org.junit.Test;
-
-public class SimpleRotateTest {
-// extends
-//} BaseMainActivityTest {
-//
-// @Override
-// public void setUp() throws Exception {
-// super.setUp();
-// }
-//
-// @Test
-// public void testRotate() {
-// mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(47.376271, 8.539116), 15));
-// double rotation = 0;
-// for (int i = 0; i < 180; i++) {
-// rotation += 1;
-// MapboxMapUtils.setDirection(mapView, rotation);
-// solo.sleep(100);
-// }
-// }
-
-}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/robotium/SimpleZoomTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/robotium/SimpleZoomTest.java
deleted file mode 100644
index bc8e9caac0..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/robotium/SimpleZoomTest.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.mapbox.mapboxsdk.testapp.robotium;
-
-import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
-import com.mapbox.mapboxsdk.constants.MapboxConstants;
-import com.mapbox.mapboxsdk.geometry.LatLng;
-
-import org.junit.Test;
-
-public class SimpleZoomTest {
-// extends
-//} BaseMainActivityTest {
-//
-// @Override
-// public void setUp() throws Exception {
-// super.setUp();
-// }
-//
-// @Test
-// public void testZoomIn() {
-// float currentZoomlevel = MapboxConstants.MINIMUM_ZOOM;
-// while (currentZoomlevel < MapboxConstants.MAXIMUM_ZOOM - 5) {
-// mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(47.376271, 8.539116),currentZoomlevel));
-// currentZoomlevel++;
-// solo.sleep(1400);
-// }
-// }
-
-}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/robotium/utils/ViewAssertion.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/robotium/utils/ViewAssertion.java
deleted file mode 100644
index 74410cce50..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/robotium/utils/ViewAssertion.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.mapbox.mapboxsdk.testapp.robotium.utils;
-
-import android.view.View;
-
-import static junit.framework.Assert.assertEquals;
-
-public class ViewAssertion {
-
- public static void isVisible(View view) {
- assertEquals(view.getClass().getSimpleName() + " should be visible", view.getVisibility(), View.VISIBLE);
- }
-
- public static void isInvisible(View view) {
- assertEquals(view.getClass().getSimpleName() + " should be visible", view.getVisibility(), View.INVISIBLE);
- }
-
-}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
index 7268b7d551..cafca62135 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
@@ -6,13 +6,13 @@
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:name=".MapboxApplication"
android:allowBackup="true"
android:fullBackupContent="true"
- android:icon="@drawable/icon_burned"
+ android:icon="@drawable/icon"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
@@ -24,7 +24,6 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
-
<activity
android:name=".activity.infowindow.InfoWindowActivity"
android:description="@string/description_info_window"
@@ -42,6 +41,14 @@
android:value="@string/category_infowindow" />
</activity>
<activity
+ android:name=".activity.infowindow.DynamicInfoWindowAdapterActivity"
+ android:description="@string/description_dynamic_info_window_adapter"
+ android:label="@string/activity_dynamic_infowindow_adapter">
+ <meta-data
+ android:name="@string/category"
+ android:value="@string/category_infowindow" />
+ </activity>
+ <activity
android:name=".activity.annotation.BulkMarkerActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:description="@string/description_add_bulk_markers"
@@ -66,9 +73,10 @@
android:name="@string/category"
android:value="@string/category_annotation" />
</activity>
- <activity android:name=".activity.annotation.PressForMarkerActivity"
- android:description="@string/description_press_for_marker"
- android:label="@string/activity_press_for_marker">
+ <activity
+ android:name=".activity.annotation.PressForMarkerActivity"
+ android:description="@string/description_press_for_marker"
+ android:label="@string/activity_press_for_marker">
<meta-data
android:name="@string/category"
android:value="@string/category_annotation" />
@@ -92,8 +100,8 @@
<activity
android:name=".activity.camera.LatLngBoundsActivity"
android:description="@string/description_visible_bounds"
- android:screenOrientation="portrait"
- android:label="@string/activity_visible_coordinate_bounds">
+ android:label="@string/activity_visible_coordinate_bounds"
+ android:screenOrientation="portrait">
<meta-data
android:name="@string/category"
android:value="@string/category_camera" />
@@ -178,7 +186,6 @@
android:name="@string/category"
android:value="@string/category_annotation" />
</activity>
-
<activity
android:name=".activity.annotation.PolylineActivity"
android:description="@string/description_polyline"
@@ -252,7 +259,6 @@
android:name="@string/category"
android:value="@string/category_maplayout" />
</activity>
-
<activity
android:name=".activity.annotation.MarkerViewActivity"
android:description="@string/description_view_marker"
@@ -261,6 +267,67 @@
android:name="@string/category"
android:value="@string/category_annotation" />
</activity>
+ <activity
+ android:name=".activity.annotation.MarkerViewScaleActivity"
+ android:description="@string/description_view_marker_scale"
+ android:label="@string/activity_view_marker_scale">
+ <meta-data
+ android:name="@string/category"
+ android:value="@string/category_annotation" />
+ </activity>
+ <activity
+ android:name=".activity.navigation.LocationPickerActivity"
+ android:description="@string/description_location_picker"
+ android:label="@string/activity_location_picker">
+ <meta-data
+ android:name="@string/category"
+ android:value="@string/category_navigation" />
+ </activity>
+ <activity
+ android:name=".activity.fragment.ViewPagerActivity"
+ android:description="@string/description_viewpager"
+ android:label="@string/activity_viewpager">
+ <meta-data
+ android:name="@string/category"
+ android:value="@string/category_fragment" />
+ </activity>
+ <activity
+ android:name=".activity.maplayout.NavigationDrawerActivity"
+ android:description="@string/description_navigation_drawer"
+ android:label="@string/title_activity_navigation_drawer"
+ android:theme="@style/AppTheme.ActionBar.Transparent">
+ <meta-data
+ android:name="@string/category"
+ 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>
+ <activity
+ android:name=".activity.imagegenerator.PrintActivity"
+ android:description="@string/description_print"
+ android:label="@string/activity_print">
+ <meta-data
+ android:name="@string/category"
+ android:value="@string/category_imagegenerator" />
+ </activity>
+ <activity
+ android:name=".activity.maplayout.SurfaceViewMediaControlActivity"
+ android:description="@string/description_surfaceview_mediacontrols"
+ android:label="@string/activity_surfaceview_overlay">
+ <meta-data
+ android:name="@string/category"
+ android:value="@string/category_maplayout" />
+ </activity>
+
+ <!-- For Unit tests -->
+ <activity android:name=".activity.style.RuntimeStyleTestActivity" />
+ <activity android:name=".activity.style.RuntimeStyleTimingTestActivity" />
<!-- Configuration Settings -->
<meta-data
@@ -270,8 +337,13 @@
android:name="com.mapbox.TestEventsAccessToken"
android:value="sk.eyJ1IjoiYmxlZWdlIiwiYSI6InNpcml1c2x5In0.KyT-boMyC_xZYTYojTc8zg" />
+ <!-- Comment out this setting to switch to external storage (and disable internal) in your app -->
+ <!-- <meta-data -->
+ <!-- android:name="com.mapbox.SetStorageExternal" -->
+ <!-- android:value="true" /> -->
+
<service android:name="com.mapbox.mapboxsdk.telemetry.TelemetryService" />
</application>
-</manifest>
+</manifest> \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/FeatureOverviewActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/FeatureOverviewActivity.java
index 9d514b2870..359aedf096 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/FeatureOverviewActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/FeatureOverviewActivity.java
@@ -1,5 +1,6 @@
package com.mapbox.mapboxsdk.testapp.activity;
+import android.Manifest;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
@@ -9,7 +10,11 @@ import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.os.AsyncTask;
import android.os.Bundle;
+import android.support.annotation.NonNull;
import android.support.annotation.StringRes;
+import android.support.design.widget.Snackbar;
+import android.support.v4.app.ActivityCompat;
+import android.support.v4.content.ContextCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
@@ -61,10 +66,16 @@ public class FeatureOverviewActivity extends AppCompatActivity {
@Override
public void onItemClicked(RecyclerView recyclerView, int position, View v) {
if (!sectionAdapter.isSectionHeaderPosition(position)) {
- Intent intent = new Intent();
int realPosition = sectionAdapter.getConvertedPosition(position);
- intent.setComponent(new ComponentName(getPackageName(), features.get(realPosition).getName()));
- startActivity(intent);
+ Feature feature = features.get(realPosition);
+ if (feature.getCategory().equals(getString(R.string.category_userlocation))) {
+ if ((ContextCompat.checkSelfPermission(FeatureOverviewActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) ||
+ (ContextCompat.checkSelfPermission(FeatureOverviewActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED)) {
+ ActivityCompat.requestPermissions(FeatureOverviewActivity.this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, realPosition);
+ return;
+ }
+ }
+ startFeature(feature);
}
}
});
@@ -104,6 +115,22 @@ public class FeatureOverviewActivity extends AppCompatActivity {
recyclerView.setAdapter(sectionAdapter);
}
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
+ if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ startFeature(features.get(requestCode));
+ } else {
+ Snackbar.make(findViewById(android.R.id.content), "Can't open without the location permission.", Snackbar.LENGTH_SHORT).show();
+ }
+ }
+
+ private void startFeature(Feature feature) {
+ Intent intent = new Intent();
+ intent.setComponent(new ComponentName(getPackageName(), feature.getName()));
+ startActivity(intent);
+ }
+
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
@@ -120,7 +147,7 @@ public class FeatureOverviewActivity extends AppCompatActivity {
String packageName = getApplicationContext().getPackageName();
String metaDataKey = getString(R.string.category);
for (ActivityInfo info : app.activities) {
- if (info.name.startsWith(packageName) && !info.name.equals(FeatureOverviewActivity.class.getName())) {
+ if (info.labelRes != 0 && info.name.startsWith(packageName) && !info.name.equals(FeatureOverviewActivity.class.getName())) {
String label = getString(info.labelRes);
String description = resolveString(info.descriptionRes);
String category = resolveMetaData(info.metaData, metaDataKey);
@@ -149,10 +176,10 @@ public class FeatureOverviewActivity extends AppCompatActivity {
return category;
}
- private String resolveString(@StringRes int stringRes){
- try{
+ private String resolveString(@StringRes int stringRes) {
+ try {
return getString(stringRes);
- }catch (Resources.NotFoundException e){
+ } catch (Resources.NotFoundException e) {
return "-";
}
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java
index 1e15c9ea36..705716355e 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java
@@ -1,27 +1,44 @@
package com.mapbox.mapboxsdk.testapp.activity.annotation;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
import android.animation.TypeEvaluator;
import android.animation.ValueAnimator;
import android.os.Bundle;
+import android.support.annotation.DrawableRes;
import android.support.annotation.NonNull;
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.view.animation.AccelerateDecelerateInterpolator;
+import com.mapbox.mapboxsdk.annotations.Icon;
+import com.mapbox.mapboxsdk.annotations.IconFactory;
import com.mapbox.mapboxsdk.annotations.Marker;
-import com.mapbox.mapboxsdk.annotations.MarkerOptions;
+import com.mapbox.mapboxsdk.annotations.MarkerView;
+import com.mapbox.mapboxsdk.annotations.MarkerViewOptions;
+import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.geometry.LatLng;
+import com.mapbox.mapboxsdk.geometry.LatLngBounds;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.testapp.R;
+import java.util.Random;
+
public class AnimatedMarkerActivity extends AppCompatActivity {
private MapView mMapView;
+ private MapboxMap mMapboxMap;
+ private Random random = new Random();
+
+ private LatLng dupontCircle = new LatLng(38.90962, -77.04341);
+
+ private Marker passengerMarker = null;
+ private MarkerView carMarker = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -40,34 +57,121 @@ public class AnimatedMarkerActivity extends AppCompatActivity {
mMapView = (MapView) findViewById(R.id.mapView);
mMapView.onCreate(savedInstanceState);
mMapView.getMapAsync(new OnMapReadyCallback() {
+
@Override
public void onMapReady(@NonNull final MapboxMap mapboxMap) {
- LatLng brussels = new LatLng(50.900446, 4.485251);
- LatLng washington = new LatLng(38.897108, -77.036716);
-
- final Marker marker = mapboxMap.addMarker(new MarkerOptions().position(brussels));
- ValueAnimator markerAnimator = ValueAnimator.ofObject(new LatLngEvaluator(), (Object[]) new LatLng[]{brussels, washington});
- markerAnimator.setDuration(5000);
- markerAnimator.setRepeatCount(ValueAnimator.INFINITE);
- markerAnimator.setRepeatMode(ValueAnimator.REVERSE);
- markerAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
- markerAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- if (marker != null) {
- marker.setPosition((LatLng) animation.getAnimatedValue());
- }
- }
- });
- markerAnimator.start();
+ mMapboxMap = mapboxMap;
+ setupMap();
+
+ for (int i = 0; i < 10; i++) {
+ addRandomCar();
+ }
+
+ addPassenger();
+ addMainCar();
+ animateMoveToPassenger(carMarker);
}
});
}
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.menu_zoom, menu);
- return true;
+ private void setupMap() {
+ CameraPosition cameraPosition = new CameraPosition.Builder()
+ .target(dupontCircle)
+ .zoom(15)
+ .build();
+ mMapboxMap.setCameraPosition(cameraPosition);
+ }
+
+ private void addPassenger() {
+ LatLng randomLatLng = getLatLngInBounds();
+
+ if (passengerMarker == null) {
+ Icon icon = IconFactory.getInstance(AnimatedMarkerActivity.this)
+ .fromResource(R.drawable.ic_directions_run_black_24dp);
+ passengerMarker = mMapboxMap.addMarker(new MarkerViewOptions()
+ .position(randomLatLng)
+ .icon(icon));
+ } else {
+ passengerMarker.setPosition(randomLatLng);
+ }
+ }
+
+ private void addMainCar() {
+ LatLng randomLatLng = getLatLngInBounds();
+
+ if (carMarker == null) {
+ carMarker = createCarMarker(randomLatLng, R.drawable.ic_taxi_top);
+ } else {
+ carMarker.setPosition(randomLatLng);
+ }
+
+ // Make sure the car marker is selected so that it's always brought to the front (#5285)
+ mMapboxMap.selectMarker(carMarker);
+ }
+
+ private void animateMoveToPassenger(final MarkerView car) {
+ ValueAnimator animator = animateMoveMarker(car, passengerMarker.getPosition());
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ addPassenger();
+ animateMoveToPassenger(car);
+ }
+ });
+ }
+
+ protected void addRandomCar() {
+ MarkerView car = createCarMarker(getLatLngInBounds(), R.drawable.ic_car_top);
+ randomlyMoveMarker(car);
+ }
+
+ private void randomlyMoveMarker(final MarkerView marker) {
+ ValueAnimator animator = animateMoveMarker(marker, getLatLngInBounds());
+
+ //Add listener to restart animation on end
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ randomlyMoveMarker(marker);
+ }
+ });
+ }
+
+ private ValueAnimator animateMoveMarker(final MarkerView marker, LatLng to) {
+ marker.setRotation((float) getBearing(marker.getPosition(), to));
+
+ final ValueAnimator markerAnimator = ObjectAnimator.ofObject(marker, "position", new LatLngEvaluator(), marker.getPosition(), to);
+ markerAnimator.setDuration((long) (10 * marker.getPosition().distanceTo(to)));
+ markerAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
+
+ // Start
+ markerAnimator.start();
+
+ return markerAnimator;
+ }
+
+ private MarkerView createCarMarker(LatLng start, @DrawableRes int carResource) {
+ Icon icon = IconFactory.getInstance(AnimatedMarkerActivity.this)
+ .fromResource(carResource);
+
+ //View Markers
+ return mMapboxMap.addMarker(new MarkerViewOptions()
+ .position(start)
+ .icon(icon));
+
+ //GL Markers
+// return mMapboxMap.addMarker(new MarkerOptions()
+// .position(start)
+// .icon(icon));
+
+ }
+
+ private LatLng getLatLngInBounds() {
+ LatLngBounds bounds = mMapboxMap.getProjection().getVisibleRegion().latLngBounds;
+ Random generator = new Random();
+ double randomLat = bounds.getLatSouth() + generator.nextDouble() * (bounds.getLatNorth() - bounds.getLatSouth());
+ double randomLon = bounds.getLonWest() + generator.nextDouble() * (bounds.getLonEast() - bounds.getLonWest());
+ return new LatLng(randomLat, randomLon);
}
@Override
@@ -111,15 +215,33 @@ public class AnimatedMarkerActivity extends AppCompatActivity {
mMapView.onLowMemory();
}
- private class LatLngEvaluator implements TypeEvaluator<LatLng> {
+ /**
+ * Evaluator for LatLng pairs
+ */
+ private static class LatLngEvaluator implements TypeEvaluator<LatLng> {
private LatLng mLatLng = new LatLng();
@Override
public LatLng evaluate(float fraction, LatLng startValue, LatLng endValue) {
- mLatLng.setLatitude(startValue.getLatitude() + (endValue.getLatitude() - startValue.getLatitude()) * fraction);
- mLatLng.setLongitude(startValue.getLongitude() + (endValue.getLongitude() - startValue.getLongitude()) * fraction);
+ mLatLng.setLatitude(startValue.getLatitude() + ((endValue.getLatitude() - startValue.getLatitude()) * fraction));
+ mLatLng.setLongitude(startValue.getLongitude() + ((endValue.getLongitude() - startValue.getLongitude()) * fraction));
return mLatLng;
}
}
+
+ private double getBearing(LatLng from, LatLng to) {
+ double degrees2radians = Math.PI / 180;
+ double radians2degrees = 180 / Math.PI;
+
+ double lon1 = degrees2radians * from.getLongitude();
+ double lon2 = degrees2radians * to.getLongitude();
+ double lat1 = degrees2radians * from.getLatitude();
+ double lat2 = degrees2radians * to.getLatitude();
+ double a = Math.sin(lon2 - lon1) * Math.cos(lat2);
+ double b = Math.cos(lat1) * Math.sin(lat2) -
+ Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon2 - lon1);
+
+ return radians2degrees * Math.atan2(a, b);
+ }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/BulkMarkerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/BulkMarkerActivity.java
index 7a2241a84c..e4bf383c96 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/BulkMarkerActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/BulkMarkerActivity.java
@@ -3,28 +3,28 @@ package com.mapbox.mapboxsdk.testapp.activity.annotation;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.app.ProgressDialog;
-import android.content.Context;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
+import android.support.v4.content.res.ResourcesCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
-import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
-import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
+import com.mapbox.mapboxsdk.annotations.Icon;
+import com.mapbox.mapboxsdk.annotations.IconFactory;
import com.mapbox.mapboxsdk.annotations.Marker;
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
-import com.mapbox.mapboxsdk.annotations.MarkerView;
import com.mapbox.mapboxsdk.annotations.MarkerViewOptions;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapView;
@@ -86,36 +86,6 @@ public class BulkMarkerActivity extends AppCompatActivity implements AdapterView
}
}
- public static class TextAdapter extends MapboxMap.MarkerViewAdapter<MarkerView> {
-
- private LayoutInflater inflater;
-
- public TextAdapter(@NonNull Context context) {
- super(context);
- this.inflater = LayoutInflater.from(context);
- }
-
- @Nullable
- @Override
- public View getView(@NonNull MarkerView marker, @Nullable View convertView, @NonNull ViewGroup parent) {
- ViewHolder viewHolder;
- if (convertView == null) {
- viewHolder = new ViewHolder();
- convertView = inflater.inflate(R.layout.view_text_marker, parent, false);
- viewHolder.title = (TextView) convertView.findViewById(R.id.textView);
- convertView.setTag(viewHolder);
- } else {
- viewHolder = (ViewHolder) convertView.getTag();
- }
- viewHolder.title.setText(marker.getTitle());
- return convertView;
- }
-
- private static class ViewHolder {
- TextView title;
- }
- }
-
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
int amount = Integer.valueOf(getResources().getStringArray(R.array.bulk_marker_list)[position]);
@@ -126,7 +96,6 @@ public class BulkMarkerActivity extends AppCompatActivity implements AdapterView
}
}
-
private void onLatLngListLoaded(List<LatLng> latLngs, int amount) {
mLocations = latLngs;
showMarkers(amount);
@@ -140,26 +109,32 @@ public class BulkMarkerActivity extends AppCompatActivity implements AdapterView
}
if (mCustomMarkerView) {
- showNativeMarkers(amount);
+ showViewMarkers(amount);
} else {
showGlMarkers(amount);
}
}
- private void showNativeMarkers(int amount) {
+ private void showViewMarkers(int amount) {
DecimalFormat formatter = new DecimalFormat("#.#####");
Random random = new Random();
int randomIndex;
+ Drawable drawable = ResourcesCompat.getDrawable(getResources(), R.drawable.ic_droppin_24dp, getTheme());
+ int redColor = ResourcesCompat.getColor(getResources(), android.R.color.holo_red_dark, getTheme());
+ drawable.setColorFilter(redColor, PorterDuff.Mode.SRC_IN);
+ Icon icon = IconFactory.getInstance(this).fromDrawable(drawable);
+
for (int i = 0; i < amount; i++) {
randomIndex = random.nextInt(mLocations.size());
LatLng latLng = mLocations.get(randomIndex);
mMapboxMap.addMarker(new MarkerViewOptions()
.position(latLng)
+ .icon(icon)
.title(String.valueOf(i))
.snippet(formatter.format(latLng.getLatitude()) + ", " + formatter.format(latLng.getLongitude())));
}
- }
+ }
private void showGlMarkers(int amount) {
List<MarkerOptions> markerOptionsList = new ArrayList<>();
@@ -247,9 +222,6 @@ public class BulkMarkerActivity extends AppCompatActivity implements AdapterView
showMarkers(amount);
}
- // add adapter
- mMapboxMap.getMarkerViewManager().addMarkerViewAdapter(new TextAdapter(BulkMarkerActivity.this));
-
mMapView.addOnMapChangedListener(new MapView.OnMapChangedListener() {
@Override
public void onMapChanged(@MapView.MapChange int change) {
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/DynamicMarkerChangeActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/DynamicMarkerChangeActivity.java
index fcddf8ca54..53909dc051 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/DynamicMarkerChangeActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/DynamicMarkerChangeActivity.java
@@ -13,8 +13,8 @@ import android.view.View;
import com.mapbox.mapboxsdk.annotations.IconFactory;
import com.mapbox.mapboxsdk.annotations.Marker;
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
-import com.mapbox.mapboxsdk.geometry.LatLng;
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;
@@ -25,10 +25,10 @@ public class DynamicMarkerChangeActivity extends AppCompatActivity {
private static final LatLng LAT_LNG_CHELSEA = new LatLng(51.481670, -0.190849);
private static final LatLng LAT_LNG_ARSENAL = new LatLng(51.555062, -0.108417);
- private MapView mMapView;
- private MapboxMap mMapboxMap;
- private IconFactory mIconFactory;
- private Marker mMarker;
+ private MapView mapView;
+ private MapboxMap mapboxMap;
+ private IconFactory iconFactory;
+ private Marker marker;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -44,32 +44,33 @@ public class DynamicMarkerChangeActivity extends AppCompatActivity {
actionBar.setDisplayShowHomeEnabled(true);
}
- mIconFactory = IconFactory.getInstance(this);
+ iconFactory = IconFactory.getInstance(this);
- mMapView = (MapView) findViewById(R.id.mapView);
- mMapView.setTag(false);
- mMapView.onCreate(savedInstanceState);
- mMapView.getMapAsync(new OnMapReadyCallback() {
+ mapView = (MapView) findViewById(R.id.mapView);
+ mapView.setTag(false);
+ mapView.onCreate(savedInstanceState);
+ mapView.getMapAsync(new OnMapReadyCallback() {
@Override
public void onMapReady(@NonNull MapboxMap mapboxMap) {
- mMapboxMap = mapboxMap;
+ DynamicMarkerChangeActivity.this.mapboxMap = mapboxMap;
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(51.506675, -0.128699), 10));
// Create marker
MarkerOptions markerOptions = new MarkerOptions()
.position(LAT_LNG_CHELSEA)
- .icon(mIconFactory.fromResource(R.drawable.ic_chelsea));
- mMarker = mapboxMap.addMarker(markerOptions);
+ .icon(iconFactory.fromResource(R.drawable.ic_chelsea))
+ .title(getString(R.string.dynamic_marker_chelsea_title))
+ .snippet(getString(R.string.dynamic_marker_chelsea_snippet));
+ marker = mapboxMap.addMarker(markerOptions);
}
});
-
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setColorFilter(ContextCompat.getColor(this, R.color.primary));
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- if (mMapboxMap != null) {
+ if (mapboxMap != null) {
updateMarker();
}
}
@@ -78,42 +79,44 @@ public class DynamicMarkerChangeActivity extends AppCompatActivity {
private void updateMarker() {
// update model
- boolean first = (boolean) mMapView.getTag();
- mMapView.setTag(!first);
+ boolean first = (boolean) mapView.getTag();
+ mapView.setTag(!first);
// update marker
- mMarker.setPosition(first ? LAT_LNG_CHELSEA : LAT_LNG_ARSENAL);
- mMarker.setIcon(mIconFactory.fromResource(first ? R.drawable.ic_chelsea : R.drawable.ic_arsenal));
+ marker.setPosition(first ? LAT_LNG_CHELSEA : LAT_LNG_ARSENAL);
+ marker.setIcon(iconFactory.fromResource(first ? R.drawable.ic_chelsea : R.drawable.ic_arsenal));
+ marker.setTitle(first ? getString(R.string.dynamic_marker_chelsea_title) : getString(R.string.dynamic_marker_arsenal_title));
+ marker.setSnippet(first ? getString(R.string.dynamic_marker_chelsea_snippet) : getString(R.string.dynamic_marker_arsenal_snippet));
}
@Override
public void onResume() {
super.onResume();
- mMapView.onResume();
+ mapView.onResume();
}
@Override
public void onPause() {
super.onPause();
- mMapView.onPause();
+ mapView.onPause();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
- mMapView.onSaveInstanceState(outState);
+ mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
- mMapView.onDestroy();
+ mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
- mMapView.onLowMemory();
+ mapView.onLowMemory();
}
@Override
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewActivity.java
index 65a5afa602..0c4eeae5ad 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewActivity.java
@@ -1,7 +1,11 @@
package com.mapbox.mapboxsdk.testapp.activity.annotation;
+import android.animation.Animator;
+import android.animation.AnimatorInflater;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
import android.content.Context;
-import android.graphics.Point;
+import android.graphics.PointF;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.NonNull;
@@ -17,7 +21,10 @@ import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
+import com.mapbox.mapboxsdk.annotations.Icon;
+import com.mapbox.mapboxsdk.annotations.IconFactory;
import com.mapbox.mapboxsdk.annotations.Marker;
+import com.mapbox.mapboxsdk.annotations.MarkerOptions;
import com.mapbox.mapboxsdk.annotations.MarkerView;
import com.mapbox.mapboxsdk.annotations.MarkerViewManager;
import com.mapbox.mapboxsdk.annotations.MarkerViewOptions;
@@ -26,24 +33,31 @@ import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.testapp.R;
-import com.mapbox.mapboxsdk.testapp.model.annotations.CountryMarkerOptions;
import com.mapbox.mapboxsdk.testapp.model.annotations.CountryMarkerView;
import com.mapbox.mapboxsdk.testapp.model.annotations.CountryMarkerViewOptions;
+import com.mapbox.mapboxsdk.testapp.model.annotations.TextMarkerView;
+import com.mapbox.mapboxsdk.testapp.model.annotations.TextMarkerViewOptions;
+
+import java.util.Random;
public class MarkerViewActivity extends AppCompatActivity {
private MapboxMap mMapboxMap;
private MapView mMapView;
+ private MarkerView movingMarkerOne, movingMarkerTwo;
+ private Random randomAnimator = new Random();
+ private Handler locationUpdateHandler = new Handler();
+ private Runnable moveMarkerRunnable = new MoveMarkerRunnable();
+ private int rotation = 0;
+
private final static LatLng[] LAT_LNGS = new LatLng[]{
- new LatLng(38.907327, -77.041293),
+ new LatLng(38.897424, -77.036508),
new LatLng(38.909698, -77.029642),
new LatLng(38.907227, -77.036530),
new LatLng(38.905607, -77.031916),
- new LatLng(38.897424, -77.036508),
- new LatLng(38.897642, -77.041980),
- new LatLng(38.889876, -77.008849),
- new LatLng(38.889441, -77.050134)
+ new LatLng(38.889441, -77.050134),
+ new LatLng(38.888000, -77.050000) //Slight overlap to show re-ordering on selection
};
@Override
@@ -68,38 +82,56 @@ public class MarkerViewActivity extends AppCompatActivity {
public void onMapReady(@NonNull MapboxMap mapboxMap) {
mMapboxMap = mapboxMap;
- // add text markers
+ final MarkerViewManager markerViewManager = mapboxMap.getMarkerViewManager();
+
+ Icon usFlag = IconFactory.getInstance(MarkerViewActivity.this)
+ .fromResource(R.drawable.ic_us);
+
+ // add default ViewMarker markers
for (int i = 0; i < LAT_LNGS.length; i++) {
mMapboxMap.addMarker(new MarkerViewOptions()
.position(LAT_LNGS[i])
.title(String.valueOf(i))
- .selectAnimatorResource(R.animator.scale_up)
- .deselectAnimatorResource(R.animator.scale_down)
+ .alpha(0.5f)
+ .icon(usFlag)
);
}
- // add flag marker
+ // add custom ViewMarker
CountryMarkerViewOptions options = new CountryMarkerViewOptions();
- options.title("United States");
- options.abbrevName("us");
- options.flagRes(R.drawable.ic_us);
+ options.flagRes(R.drawable.icon_burned);
+ options.abbrevName("Mapbox");
+ options.title("Hello");
options.position(new LatLng(38.899774, -77.023237));
- options.selectAnimatorResource(R.animator.rotate_360);
- options.deselectAnimatorResource(R.animator.rotate_360);
options.flat(true);
mapboxMap.addMarker(options);
- // default GL marker
- mMapboxMap.addMarker(new CountryMarkerOptions()
+ mMapboxMap.addMarker(new MarkerOptions()
.title("United States")
.position(new LatLng(38.902580, -77.050102))
);
- // set adapters
- final MarkerViewManager markerViewManager = mapboxMap.getMarkerViewManager();
- markerViewManager.addMarkerViewAdapter(new TextAdapter(MarkerViewActivity.this));
- markerViewManager.addMarkerViewAdapter(new CountryAdapter(MarkerViewActivity.this));
+ mMapboxMap.addMarker(new TextMarkerViewOptions()
+ .text("A")
+ .position(new LatLng(38.889876, -77.008849))
+ );
+
+ mMapboxMap.addMarker(new TextMarkerViewOptions()
+ .text("B")
+ .position(new LatLng(38.907327, -77.041293))
+ );
+ mMapboxMap.addMarker(new TextMarkerViewOptions()
+ .text("C")
+ .position(new LatLng(38.897642, -77.041980))
+ );
+
+ // if you want to customise a ViewMarker you need to extend ViewMarker and provide an adapter implementation
+ // set adapters for child classes of ViewMarker
+ markerViewManager.addMarkerViewAdapter(new CountryAdapter(MarkerViewActivity.this, mapboxMap));
+ markerViewManager.addMarkerViewAdapter(new TextAdapter(MarkerViewActivity.this, mapboxMap));
+
+ // add a change listener to validate the size of amount of child views
mMapView.addOnMapChangedListener(new MapView.OnMapChangedListener() {
@Override
public void onMapChanged(@MapView.MapChange int change) {
@@ -111,6 +143,7 @@ public class MarkerViewActivity extends AppCompatActivity {
}
});
+ // add a OnMarkerView click listener
mMapboxMap.getMarkerViewManager().setOnMarkerViewClickListener(new MapboxMap.OnMarkerViewClickListener() {
@Override
public boolean onMarkerClick(@NonNull Marker marker, @NonNull View view, @NonNull MapboxMap.MarkerViewAdapter adapter) {
@@ -118,73 +151,219 @@ public class MarkerViewActivity extends AppCompatActivity {
return false;
}
});
+
+ movingMarkerOne = mMapboxMap.addMarker(new MarkerViewOptions()
+ .position(CarLocation.CAR_0_LNGS[0])
+ .icon(IconFactory.getInstance(mMapView.getContext())
+ .fromResource(R.drawable.ic_chelsea))
+ );
+
+ movingMarkerTwo = mapboxMap.addMarker(new MarkerViewOptions()
+ .position(CarLocation.CAR_1_LNGS[0])
+ .icon(IconFactory.getInstance(mMapView.getContext())
+ .fromResource(R.drawable.ic_arsenal))
+ );
}
});
}
- private static class TextAdapter extends MapboxMap.MarkerViewAdapter<MarkerView> {
+ @Override
+ protected void onStart() {
+ super.onStart();
+ loopMarkerMove();
+ }
+
+ private void loopMarkerMove() {
+ locationUpdateHandler.postDelayed(moveMarkerRunnable, randomAnimator.nextInt(3000) + 1000);
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ locationUpdateHandler.removeCallbacks(moveMarkerRunnable);
+ }
+
+ private class MoveMarkerRunnable implements Runnable {
+ @Override
+ public void run() {
+ int i = randomAnimator.nextInt(9);
+ if (randomAnimator.nextInt() % 2 == 0) {
+ movingMarkerOne.setPosition(CarLocation.CAR_0_LNGS[i]);
+ movingMarkerOne.setRotation(rotation = rotation + 45);
+ } else {
+ movingMarkerTwo.setPosition(CarLocation.CAR_1_LNGS[i]);
+ movingMarkerTwo.setRotation(rotation = rotation + 90);
+ }
+ loopMarkerMove();
+ }
+ }
+
+ private static class CountryAdapter extends MapboxMap.MarkerViewAdapter<CountryMarkerView> {
private LayoutInflater inflater;
+ private MapboxMap mapboxMap;
- public TextAdapter(@NonNull Context context) {
+ public CountryAdapter(@NonNull Context context, @NonNull MapboxMap mapboxMap) {
super(context);
this.inflater = LayoutInflater.from(context);
+ this.mapboxMap = mapboxMap;
}
@Nullable
@Override
- public View getView(@NonNull MarkerView marker, @Nullable View convertView, @NonNull ViewGroup parent) {
+ public View getView(@NonNull CountryMarkerView marker, @Nullable View convertView, @NonNull ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
viewHolder = new ViewHolder();
- convertView = inflater.inflate(R.layout.view_text_marker, parent, false);
- viewHolder.title = (TextView) convertView.findViewById(R.id.textView);
+ convertView = inflater.inflate(R.layout.view_custom_marker, parent, false);
+ viewHolder.flag = (ImageView) convertView.findViewById(R.id.imageView);
+ viewHolder.abbrev = (TextView) convertView.findViewById(R.id.textView);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
- viewHolder.title.setText(marker.getTitle());
+ viewHolder.flag.setImageResource(marker.getFlagRes());
+ viewHolder.abbrev.setText(marker.getAbbrevName());
return convertView;
}
+ @Override
+ public boolean onSelect(@NonNull final CountryMarkerView marker, @NonNull final View convertView, boolean reselectionForViewReuse) {
+ convertView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ ObjectAnimator rotateAnimator = ObjectAnimator.ofFloat(convertView, View.ROTATION, 0, 360);
+ rotateAnimator.setDuration(reselectionForViewReuse ? 0 : 350);
+ rotateAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ convertView.setLayerType(View.LAYER_TYPE_NONE, null);
+ mapboxMap.selectMarker(marker);
+ }
+ });
+ rotateAnimator.start();
+
+ // false indicates that we are calling selectMarker after our animation ourselves
+ // true will let the system call it for you, which will result in showing an InfoWindow instantly
+ return false;
+ }
+
+ @Override
+ public void onDeselect(@NonNull CountryMarkerView marker, @NonNull final View convertView) {
+ convertView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ ObjectAnimator rotateAnimator = ObjectAnimator.ofFloat(convertView, View.ROTATION, 360, 0);
+ rotateAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ convertView.setLayerType(View.LAYER_TYPE_NONE, null);
+ }
+ });
+ rotateAnimator.start();
+ }
+
private static class ViewHolder {
- TextView title;
+ ImageView flag;
+ TextView abbrev;
}
}
- private static class CountryAdapter extends MapboxMap.MarkerViewAdapter<CountryMarkerView> {
+
+ private static class TextAdapter extends MapboxMap.MarkerViewAdapter<TextMarkerView> {
private LayoutInflater inflater;
+ private MapboxMap mapboxMap;
- public CountryAdapter(@NonNull Context context) {
+ public TextAdapter(@NonNull Context context, @NonNull MapboxMap mapboxMap) {
super(context);
this.inflater = LayoutInflater.from(context);
+ this.mapboxMap = mapboxMap;
}
@Nullable
@Override
- public View getView(@NonNull CountryMarkerView marker, @Nullable View convertView, @NonNull ViewGroup parent) {
+ public View getView(@NonNull TextMarkerView marker, @Nullable View convertView, @NonNull ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
viewHolder = new ViewHolder();
- convertView = inflater.inflate(R.layout.view_custom_marker, parent, false);
- viewHolder.flag = (ImageView) convertView.findViewById(R.id.imageView);
- viewHolder.abbrev = (TextView) convertView.findViewById(R.id.textView);
+ convertView = inflater.inflate(R.layout.view_text_marker, parent, false);
+ viewHolder.textView = (TextView) convertView.findViewById(R.id.textView);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
- viewHolder.flag.setImageResource(marker.getFlagRes());
- viewHolder.abbrev.setText(marker.getAbbrevName());
+ viewHolder.textView.setText(marker.getText());
return convertView;
}
+ @Override
+ public boolean onSelect(@NonNull final TextMarkerView marker, @NonNull final View convertView, boolean reselectionForViewReuse) {
+ animateGrow(marker, convertView, 0);
+
+ // false indicates that we are calling selectMarker after our animation ourselves
+ // true will let the system call it for you, which will result in showing an InfoWindow instantly
+ return false;
+ }
+
+ @Override
+ public void onDeselect(@NonNull TextMarkerView marker, @NonNull final View convertView) {
+ animateShrink(convertView, 350);
+ }
+
+ @Override
+ public boolean prepareViewForReuse(@NonNull MarkerView marker, @NonNull View convertView) {
+ // this method is called before a view will be reused, we need to restore view state
+ // as we have scaled the view in onSelect. If not correctly applied other MarkerView will
+ // become large since these have been recycled
+
+ // cancel ongoing animation
+ convertView.animate().cancel();
+
+ if (marker.isSelected()) {
+ // shrink view to be able to be reused
+ animateShrink(convertView, 0);
+ }
+
+ // true if you want reuse to occur automatically, false if you want to manage this yourself
+ return true;
+ }
+
+ private void animateGrow(@NonNull final MarkerView marker, @NonNull final View convertView, int duration) {
+ convertView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ Animator animator = AnimatorInflater.loadAnimator(convertView.getContext(), R.animator.scale_up);
+ animator.setDuration(duration);
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ convertView.setLayerType(View.LAYER_TYPE_NONE, null);
+ mapboxMap.selectMarker(marker);
+ }
+ });
+ animator.setTarget(convertView);
+ animator.start();
+ }
+
+ private void animateShrink(@NonNull final View convertView, int duration) {
+ convertView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ Animator animator = AnimatorInflater.loadAnimator(convertView.getContext(), R.animator.scale_down);
+ animator.setDuration(duration);
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ convertView.setLayerType(View.LAYER_TYPE_NONE, null);
+ }
+ });
+ animator.setTarget(convertView);
+ animator.start();
+ }
+
private static class ViewHolder {
- ImageView flag;
- TextView abbrev;
+ TextView textView;
}
}
+
@Override
public void onResume() {
super.onResume();
@@ -225,4 +404,32 @@ public class MarkerViewActivity extends AppCompatActivity {
return super.onOptionsItemSelected(item);
}
}
+
+ private static class CarLocation {
+
+ public static LatLng[] CAR_0_LNGS = new LatLng[]{
+ new LatLng(38.92334425495122, -77.0533673443786),
+ new LatLng(38.9234737236897, -77.05389484528261),
+ new LatLng(38.9257094658146, -76.98819752280579),
+ new LatLng(38.8324328369647, -77.00690648325929),
+ new LatLng(38.87540698725855, -77.0093148713099),
+ new LatLng(38.96499498141065, -77.07707916040054),
+ new LatLng(38.90794910679896, -76.99695304153806),
+ new LatLng(38.86234025281626, -76.9950528034839),
+ new LatLng(38.862930274733635, -76.99647808241964)
+ };
+
+ public static LatLng[] CAR_1_LNGS = new LatLng[]{
+ new LatLng(38.94237975070426, -76.98324549005675),
+ new LatLng(38.941520236084486, -76.98234257804742),
+ new LatLng(38.85972219720714, -76.98955808483929),
+ new LatLng(38.944289166113776, -76.98584257252891),
+ new LatLng(38.94375860578053, -76.98470344318412),
+ new LatLng(38.943167431929645, -76.98373163938666),
+ new LatLng(38.882834728904605, -77.02862535635137),
+ new LatLng(38.882869724926245, -77.02992539231113),
+ new LatLng(38.9371988177896, -76.97786740676564)
+ };
+
+ }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewScaleActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewScaleActivity.java
new file mode 100644
index 0000000000..37b1d32a68
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewScaleActivity.java
@@ -0,0 +1,141 @@
+package com.mapbox.mapboxsdk.testapp.activity.annotation;
+
+import android.os.Bundle;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.Toolbar;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.SeekBar;
+import android.widget.TextView;
+
+import com.mapbox.mapboxsdk.annotations.Icon;
+import com.mapbox.mapboxsdk.annotations.IconFactory;
+import com.mapbox.mapboxsdk.annotations.MarkerView;
+import com.mapbox.mapboxsdk.annotations.MarkerViewOptions;
+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.testapp.R;
+
+import java.util.Locale;
+
+public class MarkerViewScaleActivity extends AppCompatActivity {
+
+ private MapView mMapView;
+ private View mMarkerView;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_marker_view_scale);
+
+ Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+
+ final ActionBar actionBar = getSupportActionBar();
+ if (actionBar != null) {
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ actionBar.setDisplayShowHomeEnabled(true);
+ }
+
+ final SeekBar xBar = (SeekBar) findViewById(R.id.seekbar_factor);
+ TextView xText = (TextView) findViewById(R.id.textview_factor);
+ xBar.setOnSeekBarChangeListener(new FactorChangeListener(xText));
+
+ mMapView = (MapView) findViewById(R.id.mapView);
+ mMapView.onCreate(savedInstanceState);
+ mMapView.getMapAsync(new OnMapReadyCallback() {
+ @Override
+ public void onMapReady(MapboxMap mapboxMap) {
+ Icon icon = IconFactory.getInstance(MarkerViewScaleActivity.this)
+ .fromResource(R.drawable.ic_circle);
+
+ MarkerView mMarker = mapboxMap.addMarker(new MarkerViewOptions()
+ .position(new LatLng(38.907192, -77.036871))
+ .icon(icon)
+ .flat(true));
+
+ mMarkerView = mapboxMap.getMarkerViewManager().getView(mMarker);
+ }
+ });
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case android.R.id.home:
+ onBackPressed();
+ return true;
+ default:
+ return super.onOptionsItemSelected(item);
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mMapView.onResume();
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ mMapView.onPause();
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ mMapView.onSaveInstanceState(outState);
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ mMapView.onDestroy();
+ }
+
+ @Override
+ public void onLowMemory() {
+ super.onLowMemory();
+ mMapView.onLowMemory();
+ }
+
+ private class FactorChangeListener implements SeekBar.OnSeekBarChangeListener {
+
+ private TextView xText;
+
+ public FactorChangeListener(TextView xText) {
+ this.xText = xText;
+ }
+
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ float newScale = getScale(progress);
+ xText.setText(String.format(Locale.US, "Scale: %.1f", newScale));
+ if (MarkerViewScaleActivity.this.mMarkerView != null) {
+ mMarkerView.setScaleX(newScale);
+ mMarkerView.setScaleY(newScale);
+
+ }
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ // Not used
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ // Not used
+ }
+
+ private float getScale(int progress) {
+ float scale = 1.0f * progress / 25;
+ return scale < 1.0 ? 1.0f : scale;
+ }
+ }
+
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PolygonActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PolygonActivity.java
index f08d65163b..9f3940bd3f 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PolygonActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PolygonActivity.java
@@ -5,9 +5,11 @@ import android.os.Bundle;
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.view.ViewGroup;
+import com.mapbox.mapboxsdk.annotations.Polygon;
import com.mapbox.mapboxsdk.annotations.PolygonOptions;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.constants.Style;
@@ -17,14 +19,45 @@ import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.MapboxMapOptions;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.testapp.R;
-import com.mapbox.mapboxsdk.testapp.model.constants.AppConstant;
import java.util.ArrayList;
import java.util.List;
public class PolygonActivity extends AppCompatActivity {
+ private static final int BLUE_COLOR = Color.parseColor("#3bb2d0");
+ private static final int RED_COLOR = Color.parseColor("#AF0000");
+
+ private static final float FULL_ALPHA = 1.0f;
+ private static final float PARTIAL_ALPHA = 0.5f;
+ private static final float NO_ALPHA = 0.0f;
+
+ private static final List<LatLng> POINTS = new ArrayList<LatLng>() {{
+ add(new LatLng(45.522585, -122.685699));
+ add(new LatLng(45.534611, -122.708873));
+ add(new LatLng(45.530883, -122.678833));
+ add(new LatLng(45.547115, -122.667503));
+ add(new LatLng(45.530643, -122.660121));
+ add(new LatLng(45.533529, -122.636260));
+ add(new LatLng(45.521743, -122.659091));
+ add(new LatLng(45.510677, -122.648792));
+ add(new LatLng(45.515008, -122.664070));
+ add(new LatLng(45.502496, -122.669048));
+ }};
+
+ private List<LatLng> ADDITIONAL_POINTS = new ArrayList<LatLng>() {{
+ add(new LatLng(45.515369, -122.678489));
+ add(new LatLng(45.506346, -122.702007));
+ add(new LatLng(45.522585, -122.685699));
+ }};
+
private MapView mapView;
+ private Polygon polygon;
+
+ private boolean fullAlpha = true;
+ private boolean visible = true;
+ private boolean allPoints = true;
+ private boolean color = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -42,9 +75,8 @@ public class PolygonActivity extends AppCompatActivity {
// configure inital map state
MapboxMapOptions options = new MapboxMapOptions()
- .attributionTintColor(Color.RED)
- .accessToken(getString(R.string.mapbox_access_token))
- .styleUrl(Style.getMapboxStreetsUrl(AppConstant.STYLE_VERSION))
+ .attributionTintColor(RED_COLOR)
+ .styleUrl(Style.MAPBOX_STREETS)
.camera(new CameraPosition.Builder()
.target(new LatLng(45.520486, -122.673541))
.zoom(12)
@@ -57,23 +89,10 @@ public class PolygonActivity extends AppCompatActivity {
mapView.getMapAsync(new OnMapReadyCallback() {
@Override
public void onMapReady(MapboxMap mapboxMap) {
- List<LatLng> polygon = new ArrayList<>();
- polygon.add(new LatLng(45.522585, -122.685699));
- polygon.add(new LatLng(45.534611, -122.708873));
- polygon.add(new LatLng(45.530883, -122.678833));
- polygon.add(new LatLng(45.547115, -122.667503));
- polygon.add(new LatLng(45.530643, -122.660121));
- polygon.add(new LatLng(45.533529, -122.636260));
- polygon.add(new LatLng(45.521743, -122.659091));
- polygon.add(new LatLng(45.510677, -122.648792));
- polygon.add(new LatLng(45.515008, -122.664070));
- polygon.add(new LatLng(45.502496, -122.669048));
- polygon.add(new LatLng(45.515369, -122.678489));
- polygon.add(new LatLng(45.506346, -122.702007));
- polygon.add(new LatLng(45.522585, -122.685699));
- mapboxMap.addPolygon(new PolygonOptions()
- .addAll(polygon)
- .fillColor(Color.parseColor("#3bb2d0")));
+ POINTS.addAll(ADDITIONAL_POINTS);
+ polygon = mapboxMap.addPolygon(new PolygonOptions()
+ .addAll(POINTS)
+ .fillColor(BLUE_COLOR));
}
});
@@ -117,8 +136,39 @@ public class PolygonActivity extends AppCompatActivity {
case android.R.id.home:
onBackPressed();
return true;
+
+ case R.id.action_id_alpha:
+ fullAlpha = !fullAlpha;
+ polygon.setAlpha(fullAlpha ? FULL_ALPHA : PARTIAL_ALPHA);
+ return true;
+
+ case R.id.action_id_visible:
+ visible = !visible;
+ polygon.setAlpha(visible ? (fullAlpha ? FULL_ALPHA : PARTIAL_ALPHA) : NO_ALPHA);
+ return true;
+
+ case R.id.action_id_points:
+ allPoints = !allPoints;
+ if (allPoints) {
+ POINTS.addAll(ADDITIONAL_POINTS);
+ } else {
+ POINTS.removeAll(ADDITIONAL_POINTS);
+ }
+ polygon.setPoints(POINTS);
+ return true;
+
+ case R.id.action_id_color:
+ color = !color;
+ polygon.setFillColor(color ? BLUE_COLOR : RED_COLOR);
+
default:
return super.onOptionsItemSelected(item);
}
}
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.menu_polygon, menu);
+ return true;
+ }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PolylineActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PolylineActivity.java
index 9eb4bc1741..5b45223da0 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PolylineActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PolylineActivity.java
@@ -25,6 +25,7 @@ import java.util.List;
public class PolylineActivity extends AppCompatActivity {
private static final String STATE_POLYLINE_OPTIONS = "polylineOptions";
+
private static final LatLng ANDORRA = new LatLng(42.505777, 1.52529);
private static final LatLng LUXEMBOURG = new LatLng(49.815273, 6.129583);
private static final LatLng MONACO = new LatLng(43.738418, 7.424616);
@@ -32,11 +33,20 @@ public class PolylineActivity extends AppCompatActivity {
private static final LatLng SAN_MARINO = new LatLng(43.942360, 12.457777);
private static final LatLng LIECHTENSTEIN = new LatLng(47.166000, 9.555373);
+ private static final float FULL_ALPHA = 1.0f;
+ private static final float PARTIAL_ALPHA = 0.5f;
+ private static final float NO_ALPHA = 0.0f;
+
private List<Polyline> mPolylines;
private ArrayList<PolylineOptions> mPolylineOptions = new ArrayList<>();
private MapView mMapView;
private MapboxMap mMapboxMap;
+ private boolean fullAlpha = true;
+ private boolean visible = true;
+ private boolean width = true;
+ private boolean color = true;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -67,25 +77,29 @@ public class PolylineActivity extends AppCompatActivity {
}
});
- findViewById(R.id.fab).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (mMapboxMap != null) {
- if (mPolylines != null && mPolylines.size() > 0) {
- if (mPolylines.size() == 1) {
- // test for removing annotation
- mMapboxMap.removeAnnotation(mPolylines.get(0));
- } else {
- // test for removing annotations
- mMapboxMap.removeAnnotations(mPolylines);
+ View fab = findViewById(R.id.fab);
+ if (fab != null) {
+ fab.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mMapboxMap != null) {
+ if (mPolylines != null && mPolylines.size() > 0) {
+ if (mPolylines.size() == 1) {
+ // test for removing annotation
+ mMapboxMap.removeAnnotation(mPolylines.get(0));
+ } else {
+ // test for removing annotations
+ mMapboxMap.removeAnnotations(mPolylines);
+ }
}
+ mPolylineOptions.clear();
+ mPolylineOptions.addAll(getRandomLine());
+ mPolylines = mMapboxMap.addPolylines(mPolylineOptions);
+
}
- mPolylineOptions.clear();
- mPolylineOptions.addAll(getRandomLine());
- mPolylines = mMapboxMap.addPolylines(mPolylineOptions);
}
- }
- });
+ });
+ }
}
private List<PolylineOptions> getAllPolylines() {
@@ -161,6 +175,34 @@ public class PolylineActivity extends AppCompatActivity {
mMapboxMap.clear();
return true;
+ case R.id.action_id_alpha:
+ fullAlpha = !fullAlpha;
+ for (Polyline p : mPolylines) {
+ p.setAlpha(fullAlpha ? FULL_ALPHA : PARTIAL_ALPHA);
+ }
+ return true;
+
+ case R.id.action_id_color:
+ color = !color;
+ for (Polyline p : mPolylines) {
+ p.setColor(color ? Color.RED : Color.BLUE);
+ }
+ return true;
+
+ case R.id.action_id_width:
+ width = !width;
+ for (Polyline p : mPolylines) {
+ p.setWidth(width ? 3.0f : 5.0f);
+ }
+ return true;
+
+ case R.id.action_id_visible:
+ visible = !visible;
+ for (Polyline p : mPolylines) {
+ p.setAlpha(visible ? (fullAlpha ? FULL_ALPHA : PARTIAL_ALPHA) : NO_ALPHA);
+ }
+ return true;
+
case android.R.id.home:
onBackPressed();
return true;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PressForMarkerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PressForMarkerActivity.java
index 88008d64fb..0c014f7693 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PressForMarkerActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PressForMarkerActivity.java
@@ -9,14 +9,14 @@ import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
+
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
-import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
-import com.mapbox.mapboxsdk.constants.Style;
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.testapp.R;
+
import java.text.DecimalFormat;
import java.util.ArrayList;
@@ -50,7 +50,6 @@ public class PressForMarkerActivity extends AppCompatActivity {
@Override
public void onMapReady(final MapboxMap map) {
mapboxMap = map;
- mapboxMap.setStyleUrl(Style.getOutdoorsStyleUrl(9));
resetMap();
mapboxMap.setOnMapLongClickListener(new MapboxMap.OnMapLongClickListener() {
@@ -83,7 +82,6 @@ public class PressForMarkerActivity extends AppCompatActivity {
if (mapboxMap == null) {
return;
}
- mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(45.1855569, 5.7215506), 11));
mapboxMap.removeAnnotations();
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/LatLngBoundsActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/LatLngBoundsActivity.java
index b9a438b7d5..3ab8f7e763 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/LatLngBoundsActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/LatLngBoundsActivity.java
@@ -9,17 +9,19 @@ import android.util.Log;
import android.view.MenuItem;
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
-import com.mapbox.mapboxsdk.constants.MapboxConstants;
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
+import com.mapbox.mapboxsdk.constants.MapboxConstants;
import com.mapbox.mapboxsdk.constants.Style;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
+import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.maps.UiSettings;
import com.mapbox.mapboxsdk.testapp.R;
-import com.mapbox.mapboxsdk.maps.MapView;
-import com.mapbox.mapboxsdk.testapp.model.constants.AppConstant;
+
+import java.util.ArrayList;
+import java.util.List;
public class LatLngBoundsActivity extends AppCompatActivity {
@@ -43,7 +45,7 @@ public class LatLngBoundsActivity extends AppCompatActivity {
}
mMapView = (MapView) findViewById(R.id.mapView);
- mMapView.setStyleUrl(Style.getDarkStyleUrl(AppConstant.STYLE_VERSION));
+ mMapView.setStyleUrl(Style.DARK);
mMapView.onCreate(savedInstanceState);
mMapView.getMapAsync(new OnMapReadyCallback() {
@Override
@@ -62,10 +64,13 @@ public class LatLngBoundsActivity extends AppCompatActivity {
.snippet("City Hall")
.position(NEW_YORK));
+ List<LatLng> points = new ArrayList<>();
+ points.add(NEW_YORK);
+ points.add(LOS_ANGELES);
+
// Create Bounds
final LatLngBounds bounds = new LatLngBounds.Builder()
- .include(NEW_YORK)
- .include(LOS_ANGELES)
+ .includes(points)
.build();
// Add map padding
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/ManualZoomActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/ManualZoomActivity.java
index bc3691a2f7..897380d1aa 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/ManualZoomActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/ManualZoomActivity.java
@@ -12,12 +12,11 @@ import android.view.View;
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.constants.Style;
+import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.maps.UiSettings;
import com.mapbox.mapboxsdk.testapp.R;
-import com.mapbox.mapboxsdk.maps.MapView;
-import com.mapbox.mapboxsdk.testapp.model.constants.AppConstant;
public class ManualZoomActivity extends AppCompatActivity {
@@ -39,7 +38,7 @@ public class ManualZoomActivity extends AppCompatActivity {
}
mMapView = (MapView) findViewById(R.id.manualZoomMapView);
- mMapView.setStyleUrl(Style.getSatelliteStyleUrl(AppConstant.STYLE_VERSION));
+ mMapView.setStyleUrl(Style.SATELLITE);
mMapView.onCreate(savedInstanceState);
mMapView.getMapAsync(new OnMapReadyCallback() {
@Override
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/customlayer/CustomLayerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/customlayer/CustomLayerActivity.java
index 98c86d4313..4070216537 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/customlayer/CustomLayerActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/customlayer/CustomLayerActivity.java
@@ -6,18 +6,21 @@ import android.support.v4.content.ContextCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
+import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.layers.CustomLayer;
+import com.mapbox.mapboxsdk.style.layers.CustomLayer;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
+import com.mapbox.mapboxsdk.style.layers.NoSuchLayerException;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.model.customlayer.ExampleCustomLayer;
public class CustomLayerActivity extends AppCompatActivity {
+ private static final String TAG = CustomLayerActivity.class.getSimpleName();
private MapboxMap mapboxMap;
private MapView mapView;
@@ -66,10 +69,14 @@ public class CustomLayerActivity extends AppCompatActivity {
private void swapCustomLayer() {
if (isShowingCustomLayer) {
- mapboxMap.removeCustomLayer("custom");
+ try {
+ mapboxMap.removeLayer("custom");
+ } catch (NoSuchLayerException e) {
+ Log.e(TAG, "No custom layer to remove");
+ }
fab.setImageResource(R.drawable.ic_layers_24dp);
} else {
- mapboxMap.addCustomLayer(new CustomLayer("custom",
+ mapboxMap.addLayer(new CustomLayer("custom",
ExampleCustomLayer.createContext(),
ExampleCustomLayer.InitializeFunction,
ExampleCustomLayer.RenderFunction,
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/directions/DirectionsActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/directions/DirectionsActivity.java
index d5f248f89d..7d46cdb6bb 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/directions/DirectionsActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/directions/DirectionsActivity.java
@@ -8,12 +8,6 @@ import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.MenuItem;
-
-import com.mapbox.directions.DirectionsCriteria;
-import com.mapbox.directions.MapboxDirections;
-import com.mapbox.directions.service.models.DirectionsResponse;
-import com.mapbox.directions.service.models.DirectionsRoute;
-import com.mapbox.directions.service.models.Waypoint;
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
import com.mapbox.mapboxsdk.annotations.PolylineOptions;
import com.mapbox.mapboxsdk.camera.CameraPosition;
@@ -23,12 +17,18 @@ import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.maps.MapView;
-
-import java.util.List;
-
-import retrofit.Callback;
-import retrofit.Response;
-import retrofit.Retrofit;
+import com.mapbox.services.Constants;
+import com.mapbox.services.commons.ServicesException;
+import com.mapbox.services.commons.geojson.LineString;
+import com.mapbox.services.commons.models.Position;
+import com.mapbox.services.directions.v4.DirectionsCriteria;
+import com.mapbox.services.directions.v4.MapboxDirections;
+import com.mapbox.services.directions.v4.models.DirectionsResponse;
+import com.mapbox.services.directions.v4.models.DirectionsRoute;
+import com.mapbox.services.directions.v4.models.Waypoint;
+import retrofit2.Call;
+import retrofit2.Callback;
+import retrofit2.Response;
public class DirectionsActivity extends AppCompatActivity {
@@ -94,49 +94,55 @@ public class DirectionsActivity extends AppCompatActivity {
}
private void getRoute(Waypoint origin, Waypoint destination) {
- MapboxDirections md = new MapboxDirections.Builder()
- .setAccessToken(getString(R.string.mapbox_access_token))
- .setOrigin(origin)
- .setDestination(destination)
- .setProfile(DirectionsCriteria.PROFILE_WALKING)
- .build();
-
- md.enqueue(new Callback<DirectionsResponse>() {
- @Override
- public void onResponse(Response<DirectionsResponse> response, Retrofit retrofit) {
- // You can get generic HTTP info about the response
- Log.d(LOG_TAG, "Response code: " + response.code());
-
- // Print some info about the route
- DirectionsRoute currentRoute = response.body().getRoutes().get(0);
- Log.d(LOG_TAG, "Distance: " + currentRoute.getDistance());
-
- // Draw the route on the map
- drawRoute(currentRoute);
- }
-
- @Override
- public void onFailure(Throwable t) {
- Log.e(LOG_TAG, "Error: " + t.getMessage());
- }
- });
+ try {
+ MapboxDirections md = new MapboxDirections.Builder()
+ .setAccessToken(getString(R.string.mapbox_access_token))
+ .setOrigin(origin)
+ .setDestination(destination)
+ .setProfile(DirectionsCriteria.PROFILE_WALKING)
+ .build();
+
+ md.enqueueCall(new Callback<DirectionsResponse>() {
+
+ @Override
+ public void onFailure(Call<DirectionsResponse> call, Throwable t) {
+ Log.e(LOG_TAG, "Error: " + t.getMessage());
+ }
+
+ @Override
+ public void onResponse(Call<DirectionsResponse> call, Response<DirectionsResponse> response) {
+ // You can get generic HTTP info about the response
+ Log.d(LOG_TAG, "Response code: " + response.code());
+
+ // Print some info about the route
+ DirectionsRoute currentRoute = response.body().getRoutes().get(0);
+ Log.d(LOG_TAG, "Distance: " + currentRoute.getDistance());
+
+ // Draw the route on the map
+ drawRoute(currentRoute);
+ }
+
+ });
+ } catch (ServicesException e) {
+ Log.e(LOG_TAG, "Error displaying route: " + e.toString());
+ e.printStackTrace();
+ }
}
private void drawRoute(DirectionsRoute route) {
- // Convert List<Waypoint> into LatLng[]
- List<Waypoint> waypoints = route.getGeometry().getWaypoints();
- LatLng[] point = new LatLng[waypoints.size()];
- for (int i = 0; i < waypoints.size(); i++) {
- point[i] = new LatLng(
- waypoints.get(i).getLatitude(),
- waypoints.get(i).getLongitude());
+
+ PolylineOptions builder = new PolylineOptions();
+ builder.color(Color.parseColor("#3887be"));
+ builder.alpha(0.5f);
+ builder.width(5);
+ builder.width(5);
+ LineString lineString = route.asLineString(Constants.OSRM_PRECISION_V4);
+ for (Position coordinates : lineString.getCoordinates()) {
+ builder.add(new LatLng(coordinates.getLatitude(), coordinates.getLongitude()));
}
// Draw Points on MapView
- mMapboxMap.addPolyline(new PolylineOptions()
- .add(point)
- .color(Color.parseColor("#3887be"))
- .width(5));
+ mMapboxMap.addPolyline(builder);
}
@Override
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MapFragmentActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MapFragmentActivity.java
index 5987855aac..9d72c2b02a 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MapFragmentActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MapFragmentActivity.java
@@ -17,7 +17,6 @@ import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.MapboxMapOptions;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.testapp.R;
-import com.mapbox.mapboxsdk.testapp.model.constants.AppConstant;
public class MapFragmentActivity extends AppCompatActivity {
@@ -40,7 +39,7 @@ public class MapFragmentActivity extends AppCompatActivity {
FragmentTransaction transaction = getFragmentManager().beginTransaction();
MapboxMapOptions options = new MapboxMapOptions();
- options.styleUrl(Style.getOutdoorsStyleUrl(AppConstant.STYLE_VERSION));
+ options.styleUrl(Style.OUTDOORS);
options.scrollGesturesEnabled(false);
options.zoomGesturesEnabled(false);
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/SupportMapFragmentActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/SupportMapFragmentActivity.java
index bb391fc93d..cc61eb4698 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/SupportMapFragmentActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/SupportMapFragmentActivity.java
@@ -17,7 +17,6 @@ import com.mapbox.mapboxsdk.maps.MapboxMapOptions;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.maps.SupportMapFragment;
import com.mapbox.mapboxsdk.testapp.R;
-import com.mapbox.mapboxsdk.testapp.model.constants.AppConstant;
public class SupportMapFragmentActivity extends AppCompatActivity {
@@ -40,7 +39,7 @@ public class SupportMapFragmentActivity extends AppCompatActivity {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
MapboxMapOptions options = new MapboxMapOptions();
- options.styleUrl(Style.getSatelliteStreetsStyleUrl(AppConstant.STYLE_VERSION));
+ options.styleUrl(Style.SATELLITE_STREETS);
options.scrollGesturesEnabled(false);
options.zoomGesturesEnabled(false);
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/ViewPagerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/ViewPagerActivity.java
new file mode 100644
index 0000000000..bc1d742113
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/ViewPagerActivity.java
@@ -0,0 +1,111 @@
+package com.mapbox.mapboxsdk.testapp.activity.fragment;
+
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentPagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.Toolbar;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+
+import com.mapbox.mapboxsdk.annotations.MarkerOptions;
+import com.mapbox.mapboxsdk.camera.CameraPosition;
+import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
+import com.mapbox.mapboxsdk.constants.MapboxConstants;
+import com.mapbox.mapboxsdk.constants.MyLocationTracking;
+import com.mapbox.mapboxsdk.constants.Style;
+import com.mapbox.mapboxsdk.geometry.LatLng;
+import com.mapbox.mapboxsdk.maps.MapFragment;
+import com.mapbox.mapboxsdk.maps.MapView;
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.maps.MapboxMapOptions;
+import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
+import com.mapbox.mapboxsdk.maps.SupportMapFragment;
+import com.mapbox.mapboxsdk.maps.TrackingSettings;
+import com.mapbox.mapboxsdk.testapp.R;
+
+public class ViewPagerActivity extends AppCompatActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_viewpager);
+
+ final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+
+ ActionBar actionBar = getSupportActionBar();
+ if (actionBar != null) {
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ actionBar.setDisplayShowHomeEnabled(true);
+ }
+
+ ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
+ if (viewPager != null) {
+ MapFragmentAdapter adapter = new MapFragmentAdapter(getSupportFragmentManager());
+ viewPager.setAdapter(adapter);
+ }
+ }
+
+ public static class MapFragmentAdapter extends FragmentPagerAdapter {
+
+ private static int NUM_ITEMS = 3;
+
+ public MapFragmentAdapter(FragmentManager fragmentManager) {
+ super(fragmentManager);
+ }
+
+ @Override
+ public int getCount() {
+ return NUM_ITEMS;
+ }
+
+ @Override
+ public Fragment getItem(int position) {
+ SupportMapFragment fragment = null;
+ MapboxMapOptions options = new MapboxMapOptions();
+
+ switch (position) {
+ case 0:
+ options.styleUrl(Style.MAPBOX_STREETS);
+ options.camera(new CameraPosition.Builder().target(new LatLng(34.920526, 102.634774)).zoom(3).build());
+ fragment = SupportMapFragment.newInstance(options);
+ break;
+ case 1:
+ options.styleUrl(Style.DARK);
+ options.camera(new CameraPosition.Builder().target(new LatLng(62.326440, 92.764913)).zoom(3).build());
+ fragment = SupportMapFragment.newInstance(options);
+ break;
+ case 2:
+ options.styleUrl(Style.SATELLITE);
+ options.camera(new CameraPosition.Builder().target(new LatLng(-25.007786, 133.623852)).zoom(3).build());
+ fragment = SupportMapFragment.newInstance(options);
+ break;
+ }
+ return fragment;
+ }
+
+
+ @Override
+ public CharSequence getPageTitle(int position) {
+ return "Page " + position;
+ }
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case android.R.id.home:
+ onBackPressed();
+ return true;
+ default:
+ return super.onOptionsItemSelected(item);
+ }
+ }
+}
+
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/geocoding/GeocoderActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/geocoding/GeocoderActivity.java
index fc03066a4e..7c99e16b2e 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/geocoding/GeocoderActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/geocoding/GeocoderActivity.java
@@ -14,26 +14,27 @@ import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
-
-import com.mapbox.geocoder.GeocoderCriteria;
-import com.mapbox.geocoder.MapboxGeocoder;
-import com.mapbox.geocoder.service.models.GeocoderFeature;
-import com.mapbox.geocoder.service.models.GeocoderResponse;
-import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
import com.mapbox.mapboxsdk.constants.Style;
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.maps.Projection;
import com.mapbox.mapboxsdk.testapp.R;
-import com.mapbox.mapboxsdk.maps.MapView;
-import com.mapbox.mapboxsdk.testapp.model.constants.AppConstant;
+import com.mapbox.services.commons.ServicesException;
+import com.mapbox.services.commons.models.Position;
+import com.mapbox.services.geocoding.v5.GeocodingCriteria;
+import com.mapbox.services.geocoding.v5.MapboxGeocoding;
+import com.mapbox.services.geocoding.v5.models.GeocodingFeature;
+import com.mapbox.services.geocoding.v5.models.GeocodingResponse;
import java.util.List;
-import retrofit.Callback;
-import retrofit.Response;
-import retrofit.Retrofit;
+import retrofit2.Call;
+import retrofit2.Callback;
+import retrofit2.Response;
+import retrofit2.Retrofit;
public class GeocoderActivity extends AppCompatActivity {
@@ -60,7 +61,7 @@ public class GeocoderActivity extends AppCompatActivity {
setMessage(getString(R.string.geocoder_instructions));
mapView = (MapView) findViewById(R.id.mapView);
- mapView.setStyleUrl(Style.getMapboxStreetsUrl(AppConstant.STYLE_VERSION));
+ mapView.setStyleUrl(Style.MAPBOX_STREETS);
mapView.onCreate(savedInstanceState);
final ImageView dropPinView = new ImageView(this);
@@ -124,40 +125,38 @@ public class GeocoderActivity extends AppCompatActivity {
*/
private void geocode(final LatLng point) {
- new AsyncTask<Void, Void, Void>() {
- @Override
- protected Void doInBackground(Void... params) {
- MapboxGeocoder client = new MapboxGeocoder.Builder()
- .setAccessToken(getString(R.string.mapbox_access_token))
- .setCoordinates(point.getLongitude(), point.getLatitude())
- .setType(GeocoderCriteria.TYPE_POI)
- .build();
-
- client.enqueue(new Callback<GeocoderResponse>()
-
- {
- @Override
- public void onResponse(Response<GeocoderResponse> response, Retrofit retrofit) {
- List<GeocoderFeature> results = response.body().getFeatures();
- if (results.size() > 0) {
- String placeName = results.get(0).getPlaceName();
- setSuccess(placeName);
- } else {
- setMessage("No results.");
- }
- }
-
- @Override
- public void onFailure(Throwable t) {
- setError(t.getMessage());
- }
- }
-
- );
- return null;
- }
- }.execute();
+ try {
+ MapboxGeocoding client = new MapboxGeocoding.Builder()
+ .setAccessToken(getString(R.string.mapbox_access_token))
+ .setCoordinates(Position.fromCoordinates(point.getLongitude(), point.getLatitude()))
+ .setType(GeocodingCriteria.TYPE_POI)
+ .build();
+
+ client.enqueueCall(new Callback<GeocodingResponse>() {
+ @Override
+ public void onResponse(Call<GeocodingResponse> call, Response<GeocodingResponse> response) {
+
+ List<GeocodingFeature> results = response.body().getFeatures();
+ if (results.size() > 0) {
+ String placeName = results.get(0).getPlaceName();
+ setSuccess(placeName);
+ } else {
+ setMessage("No results.");
+ }
+
+ }
+
+ @Override
+ public void onFailure(Call<GeocodingResponse> call, Throwable t) {
+ setError(t.getMessage());
+ }
+ });
+ } catch (ServicesException e) {
+ Log.e(LOG_TAG, "Error geocoding: " + e.toString());
+ e.printStackTrace();
+ setError(e.getMessage());
+ }
}
/*
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/PrintActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/PrintActivity.java
new file mode 100644
index 0000000000..4d19b4702e
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/PrintActivity.java
@@ -0,0 +1,112 @@
+package com.mapbox.mapboxsdk.testapp.activity.imagegenerator;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Bundle;
+import android.app.Activity;
+import android.support.annotation.NonNull;
+import android.support.v4.print.PrintHelper;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.Toolbar;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.ArrayAdapter;
+import android.widget.Spinner;
+
+import com.mapbox.mapboxsdk.maps.MapView;
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
+import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.annotation.BulkMarkerActivity;
+
+public class PrintActivity extends AppCompatActivity implements MapboxMap.SnapshotReadyCallback {
+
+ private MapView mMapView;
+ private MapboxMap mMapboxMap;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_print);
+
+ Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+
+ final ActionBar actionBar = getSupportActionBar();
+ if (actionBar != null) {
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ actionBar.setDisplayShowHomeEnabled(true);
+ }
+
+ mMapView = (MapView) findViewById(R.id.mapView);
+ mMapView.onCreate(savedInstanceState);
+ mMapView.getMapAsync(new OnMapReadyCallback() {
+ @Override
+ public void onMapReady(@NonNull MapboxMap mapboxMap) {
+ mMapboxMap = mapboxMap;
+ }
+ });
+
+ final View fab = findViewById(R.id.fab);
+ if (fab != null) {
+ fab.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if(mMapboxMap!=null) {
+ mMapboxMap.snapshot(PrintActivity.this);
+ }
+ }
+ });
+ }
+ }
+
+ @Override
+ public void onSnapshotReady(Bitmap snapshot) {
+ PrintHelper photoPrinter = new PrintHelper(this);
+ photoPrinter.setScaleMode(PrintHelper.SCALE_MODE_FIT);
+ photoPrinter.printBitmap("map.jpg - mapbox print job", snapshot);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mMapView.onResume();
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ mMapView.onPause();
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ mMapView.onSaveInstanceState(outState);
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ mMapView.onDestroy();
+ }
+
+ @Override
+ public void onLowMemory() {
+ super.onLowMemory();
+ mMapView.onLowMemory();
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case android.R.id.home:
+ onBackPressed();
+ return true;
+ default:
+ return super.onOptionsItemSelected(item);
+ }
+ }
+
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/SnapshotActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/SnapshotActivity.java
index 93ebdcd157..84e394c72d 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/SnapshotActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/SnapshotActivity.java
@@ -12,7 +12,7 @@ import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;
-
+import com.mapbox.mapboxsdk.constants.Style;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
@@ -41,6 +41,7 @@ public class SnapshotActivity extends AppCompatActivity {
mapView.getMapAsync(new OnMapReadyCallback() {
@Override
public void onMapReady(@NonNull final MapboxMap mapboxMap) {
+ mapboxMap.setStyleUrl(Style.OUTDOORS);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setColorFilter(ContextCompat.getColor(SnapshotActivity.this, R.color.primary));
fab.setOnClickListener(new View.OnClickListener() {
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/DynamicInfoWindowAdapterActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/DynamicInfoWindowAdapterActivity.java
new file mode 100644
index 0000000000..5b2cae5e04
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/DynamicInfoWindowAdapterActivity.java
@@ -0,0 +1,169 @@
+package com.mapbox.mapboxsdk.testapp.activity.infowindow;
+
+import android.graphics.Color;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.content.ContextCompat;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.Toolbar;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.TextView;
+
+import com.mapbox.mapboxsdk.annotations.IconFactory;
+import com.mapbox.mapboxsdk.annotations.InfoWindow;
+import com.mapbox.mapboxsdk.annotations.Marker;
+import com.mapbox.mapboxsdk.annotations.MarkerView;
+import com.mapbox.mapboxsdk.annotations.MarkerViewOptions;
+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.testapp.R;
+
+/**
+ * Shows how to dynamically update InfoWindow when Using an MapboxMap.InfoWindowAdapter
+ */
+public class DynamicInfoWindowAdapterActivity extends AppCompatActivity {
+
+ private MapView mapView;
+
+ private LatLng paris = new LatLng(48.864716, 2.349014);
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_infowindow_adapter);
+
+ setupActionBar();
+
+ mapView = (MapView) findViewById(R.id.mapView);
+ mapView.onCreate(savedInstanceState);
+
+ mapView.getMapAsync(new OnMapReadyCallback() {
+ @Override
+ public void onMapReady(@NonNull final MapboxMap mapboxMap) {
+ //Add info window adapter
+ addCustomInfoWindowAdapter(mapboxMap);
+
+ //Keep info windows open on click
+ mapboxMap.getUiSettings().setDeselectMarkersOnTap(false);
+
+ //Add a marker
+ final MarkerView marker = addMarker(mapboxMap);
+ mapboxMap.selectMarker(marker);
+
+ //On map click, change the info window contents
+ mapboxMap.setOnMapClickListener(new MapboxMap.OnMapClickListener() {
+ @Override
+ public void onMapClick(@NonNull LatLng point) {
+ //Distance from click to marker
+ double distanceKm = marker.getPosition().distanceTo(point) / 1000;
+
+ //Get the info window
+ InfoWindow infoWindow = marker.getInfoWindow();
+
+ //Get the view from the info window
+ if (infoWindow != null && infoWindow.getView() != null) {
+ //Set the new text on the text view in the info window
+ ((TextView) infoWindow.getView()).setText(String.format("%.2fkm", distanceKm));
+
+ //Update the info window position (as the text length changes)
+ infoWindow.update();
+ }
+ }
+ });
+
+ //Focus on Paris
+ mapboxMap.animateCamera(CameraUpdateFactory.newLatLng(paris));
+ }
+ });
+ }
+
+ private MarkerView addMarker(MapboxMap mapboxMap) {
+ IconFactory iconFactory = IconFactory.getInstance(this);
+ Drawable iconDrawable = ContextCompat.getDrawable(this, R.drawable.ic_location_city_24dp);
+ iconDrawable.setColorFilter(getResources().getColor(R.color.mapbox_blue), PorterDuff.Mode.SRC_IN);
+
+ return mapboxMap.addMarker(
+ new MarkerViewOptions()
+ .position(paris)
+ .icon(iconFactory.fromDrawable(iconDrawable))
+ );
+ }
+
+ private void addCustomInfoWindowAdapter(final MapboxMap mapboxMap) {
+ final int padding = (int) getResources().getDimension(R.dimen.attr_margin);
+ mapboxMap.setInfoWindowAdapter(new MapboxMap.InfoWindowAdapter() {
+
+ @Nullable
+ @Override
+ public View getInfoWindow(@NonNull Marker marker) {
+ TextView textView = new TextView(DynamicInfoWindowAdapterActivity.this);
+ textView.setText(marker.getTitle());
+ textView.setBackgroundColor(Color.WHITE);
+ textView.setText("Click the map to calculate the distance");
+ textView.setPadding(padding, padding, padding, padding);
+
+ return textView;
+ }
+ });
+ }
+
+ @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;
+ default:
+ return super.onOptionsItemSelected(item);
+ }
+ }
+
+ private void setupActionBar() {
+ Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+
+ ActionBar actionBar = getSupportActionBar();
+ if (actionBar != null) {
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ actionBar.setDisplayShowHomeEnabled(true);
+ }
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowActivity.java
index 7ac3c59667..7ff0acdb29 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowActivity.java
@@ -8,7 +8,6 @@ import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
-
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.annotations.Marker;
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
@@ -16,7 +15,6 @@ import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.maps.MapView;
-
import java.text.DecimalFormat;
public class InfoWindowActivity extends AppCompatActivity implements OnMapReadyCallback, MapboxMap.OnInfoWindowCloseListener, MapboxMap.OnMapLongClickListener, MapboxMap.OnInfoWindowClickListener, MapboxMap.OnInfoWindowLongClickListener {
@@ -61,6 +59,12 @@ public class InfoWindowActivity extends AppCompatActivity implements OnMapReadyC
.snippet("E St NW with 17th St NW")
.position(new LatLng(38.8954236, -77.0394623)));
+ mapboxMap.addMarker(new MarkerOptions().title("The Ellipse").position(new LatLng(38.89393, -77.03654)));
+
+ mapboxMap.addMarker(new MarkerOptions().position(new LatLng(38.89596, -77.03434)));
+
+ mapboxMap.addMarker(new MarkerOptions().snippet("Lafayette Square").position(new LatLng(38.89949, -77.03656)));
+
Marker marker = mapboxMap.addMarker(new MarkerOptions()
.title("White House")
.snippet("The official residence and principal workplace of the President of the United States, located at 1600 Pennsylvania Avenue NW in Washington, D.C. It has been the residence of every U.S. president since John Adams in 1800.")
@@ -82,6 +86,10 @@ public class InfoWindowActivity extends AppCompatActivity implements OnMapReadyC
mapboxMap.setAllowConcurrentMultipleOpenInfoWindows(allowConcurrentInfoWindow);
}
+ private void toggleDeselectMarkersOnTap(boolean deselectMarkersOnTap) {
+ mapboxMap.getUiSettings().setDeselectMarkersOnTap(deselectMarkersOnTap);
+ }
+
@Override
public boolean onInfoWindowClick(@NonNull Marker marker) {
Toast.makeText(getApplicationContext(), "OnClick: " + marker.getTitle(), Toast.LENGTH_LONG).show();
@@ -157,6 +165,10 @@ public class InfoWindowActivity extends AppCompatActivity implements OnMapReadyC
toggleConcurrentInfoWindow(!item.isChecked());
item.setChecked(!item.isChecked());
return true;
+ case R.id.action_toggle_deselect_markers_on_tap:
+ toggleDeselectMarkersOnTap(!item.isChecked());
+ item.setChecked(!item.isChecked());
+ return true;
case android.R.id.home:
onBackPressed();
return true;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DebugModeActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DebugModeActivity.java
index f5835ab7bd..760501c17c 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DebugModeActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DebugModeActivity.java
@@ -15,7 +15,6 @@ import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.testapp.R;
-import com.mapbox.mapboxsdk.testapp.model.constants.AppConstant;
public class DebugModeActivity extends AppCompatActivity {
@@ -27,12 +26,12 @@ public class DebugModeActivity extends AppCompatActivity {
private int currentStyleIndex = 0;
private static final String[] STYLES = new String[]{
- Style.getMapboxStreetsUrl(AppConstant.STYLE_VERSION),
- Style.getOutdoorsStyleUrl(AppConstant.STYLE_VERSION),
- Style.getLightStyleUrl(AppConstant.STYLE_VERSION),
- Style.getDarkStyleUrl(AppConstant.STYLE_VERSION),
- Style.getSatelliteStyleUrl(AppConstant.STYLE_VERSION),
- Style.getSatelliteStreetsStyleUrl(AppConstant.STYLE_VERSION)
+ Style.MAPBOX_STREETS,
+ Style.OUTDOORS,
+ Style.LIGHT,
+ Style.DARK,
+ Style.SATELLITE,
+ Style.SATELLITE_STREETS
};
@Override
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DoubleMapActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DoubleMapActivity.java
index 288817d670..a3517df205 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DoubleMapActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DoubleMapActivity.java
@@ -23,7 +23,6 @@ import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.maps.TrackingSettings;
import com.mapbox.mapboxsdk.maps.UiSettings;
import com.mapbox.mapboxsdk.testapp.R;
-import com.mapbox.mapboxsdk.testapp.model.constants.AppConstant;
public class DoubleMapActivity extends AppCompatActivity {
@@ -73,7 +72,7 @@ public class DoubleMapActivity extends AppCompatActivity {
mMapView.getMapAsync(new OnMapReadyCallback() {
@Override
public void onMapReady(@NonNull MapboxMap mapboxMap) {
- mapboxMap.setStyleUrl(Style.getDarkStyleUrl(AppConstant.STYLE_VERSION));
+ mapboxMap.setStyleUrl(Style.DARK);
mapboxMap.moveCamera(CameraUpdateFactory.zoomTo(18));
try {
@@ -92,7 +91,7 @@ public class DoubleMapActivity extends AppCompatActivity {
mMapViewMini.getMapAsync(new OnMapReadyCallback() {
@Override
public void onMapReady(@NonNull MapboxMap mapboxMap) {
- mapboxMap.setStyleUrl(Style.getLightStyleUrl(AppConstant.STYLE_VERSION));
+ mapboxMap.setStyleUrl(Style.LIGHT);
mapboxMap.moveCamera(CameraUpdateFactory.zoomTo(4));
UiSettings uiSettings = mapboxMap.getUiSettings();
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/NavigationDrawerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/NavigationDrawerActivity.java
new file mode 100644
index 0000000000..baa4142489
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/NavigationDrawerActivity.java
@@ -0,0 +1,238 @@
+package com.mapbox.mapboxsdk.testapp.activity.maplayout;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.support.design.widget.Snackbar;
+import android.support.v4.widget.DrawerLayout;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.ActionBarDrawerToggle;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.Toolbar;
+import android.view.LayoutInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+
+import com.mapbox.mapboxsdk.camera.CameraPosition;
+import com.mapbox.mapboxsdk.constants.Style;
+import com.mapbox.mapboxsdk.geometry.LatLng;
+import com.mapbox.mapboxsdk.maps.MapFragment;
+import com.mapbox.mapboxsdk.maps.MapboxMapOptions;
+import com.mapbox.mapboxsdk.testapp.R;
+
+public class NavigationDrawerActivity extends AppCompatActivity {
+
+ private boolean firstStyle = true;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_navigation_drawer);
+
+ Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+
+ NavigationDrawerFragment navigationDrawerFragment;
+
+ getFragmentManager()
+ .beginTransaction()
+ .add(R.id.navigation_drawer, navigationDrawerFragment = new NavigationDrawerFragment())
+ .commit();
+
+ navigationDrawerFragment.setUp(this,
+ R.id.navigation_drawer,
+ (DrawerLayout) findViewById(R.id.drawer_layout),
+ getSupportActionBar());
+ }
+
+ public void onNavigationDrawerItemSelected(int position) {
+ // update the main content by replacing fragments
+ switch (position) {
+ case 0:
+ MapboxMapOptions options = new MapboxMapOptions();
+ options.styleUrl(firstStyle ? Style.LIGHT : Style.SATELLITE);
+ options.camera(new CameraPosition.Builder()
+ .target(new LatLng(39.913271, 116.413891))
+ .zoom(12)
+ .build());
+ FragmentManager fragmentManager = getFragmentManager();
+ fragmentManager.beginTransaction()
+ .replace(R.id.container, MapFragment.newInstance(options))
+ .commit();
+
+ firstStyle = !firstStyle;
+ break;
+ case 1:
+ Snackbar.make(
+ findViewById(android.R.id.content),
+ "Hello from snackbar",
+ Snackbar.LENGTH_LONG)
+ .show();
+ break;
+ }
+ }
+
+ public static class NavigationDrawerFragment extends Fragment {
+
+ private static final String STATE_SELECTED_POSITION = "selected_navigation_drawer_position";
+ private static final String PREF_USER_LEARNED_DRAWER = "navigation_drawer_learned";
+
+ private ActionBarDrawerToggle mDrawerToggle;
+
+ private DrawerLayout mDrawerLayout;
+ private ListView mDrawerListView;
+ private View mFragmentContainerView;
+
+ private int mCurrentSelectedPosition = 0;
+ private boolean mFromSavedInstanceState;
+ private boolean mUserLearnedDrawer;
+
+ public NavigationDrawerFragment() {
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getActivity());
+ mUserLearnedDrawer = sp.getBoolean(PREF_USER_LEARNED_DRAWER, false);
+
+ if (savedInstanceState != null) {
+ mCurrentSelectedPosition = savedInstanceState.getInt(STATE_SELECTED_POSITION);
+ mFromSavedInstanceState = true;
+ }
+ selectItem(mCurrentSelectedPosition);
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ setHasOptionsMenu(true);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ mDrawerListView = (ListView) inflater.inflate(
+ R.layout.drawer_navigation_drawer, container, false);
+ mDrawerListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ selectItem(position);
+ }
+ });
+ mDrawerListView.setAdapter(new ArrayAdapter<>(
+ inflater.getContext(),
+ android.R.layout.simple_list_item_activated_1,
+ android.R.id.text1,
+ new String[]{
+ getString(R.string.title_section1),
+ getString(R.string.title_section2)
+ }));
+ mDrawerListView.setItemChecked(mCurrentSelectedPosition, true);
+ return mDrawerListView;
+ }
+
+ /**
+ * Users of this fragment must call this method to set up the navigation drawer interactions.
+ *
+ * @param fragmentId The android:id of this fragment in its activity's layout.
+ * @param drawerLayout The DrawerLayout containing this fragment's UI.
+ */
+ public void setUp(Activity activity, int fragmentId, DrawerLayout drawerLayout, ActionBar actionBar) {
+ mFragmentContainerView = activity.findViewById(fragmentId);
+ mDrawerLayout = drawerLayout;
+// mDrawerLayout.setScrimColor(Color.TRANSPARENT);
+
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ actionBar.setHomeButtonEnabled(true);
+
+ mDrawerToggle = new ActionBarDrawerToggle(
+ activity,
+ mDrawerLayout,
+ R.string.navigation_drawer_open,
+ R.string.navigation_drawer_close
+ ) {
+ @Override
+ public void onDrawerClosed(View drawerView) {
+ super.onDrawerClosed(drawerView);
+ if (!isAdded()) {
+ return;
+ }
+ getActivity().invalidateOptionsMenu();
+ }
+
+ @Override
+ public void onDrawerOpened(View drawerView) {
+ super.onDrawerOpened(drawerView);
+ if (!isAdded()) {
+ return;
+ }
+
+ if (!mUserLearnedDrawer) {
+ mUserLearnedDrawer = true;
+ SharedPreferences sp = PreferenceManager
+ .getDefaultSharedPreferences(getActivity());
+ sp.edit().putBoolean(PREF_USER_LEARNED_DRAWER, true).apply();
+ }
+ getActivity().invalidateOptionsMenu();
+ }
+ };
+
+ if (!mUserLearnedDrawer && !mFromSavedInstanceState) {
+ mDrawerLayout.openDrawer(mFragmentContainerView);
+ }
+ mDrawerLayout.post(new Runnable() {
+ @Override
+ public void run() {
+ mDrawerToggle.syncState();
+ }
+ });
+ mDrawerLayout.setDrawerListener(mDrawerToggle);
+ }
+
+ private void selectItem(int position) {
+ mCurrentSelectedPosition = position;
+ if (mDrawerListView != null) {
+ mDrawerListView.setItemChecked(position, true);
+ }
+ if (mDrawerLayout != null) {
+ mDrawerLayout.closeDrawer(mFragmentContainerView);
+ }
+
+ Activity activity = getActivity();
+ if (activity != null && activity instanceof NavigationDrawerActivity) {
+ NavigationDrawerActivity navActivity = (NavigationDrawerActivity) activity;
+ navActivity.onNavigationDrawerItemSelected(position);
+ }
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putInt(STATE_SELECTED_POSITION, mCurrentSelectedPosition);
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ mDrawerToggle.onConfigurationChanged(newConfig);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (mDrawerToggle.onOptionsItemSelected(item)) {
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/SurfaceViewMediaControlActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/SurfaceViewMediaControlActivity.java
new file mode 100644
index 0000000000..4e193573dd
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/SurfaceViewMediaControlActivity.java
@@ -0,0 +1,142 @@
+package com.mapbox.mapboxsdk.testapp.activity.maplayout;
+
+import android.content.Context;
+import android.opengl.GLSurfaceView;
+import android.os.Bundle;
+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.view.MotionEvent;
+import android.widget.FrameLayout;
+
+import com.mapbox.mapboxsdk.maps.MapView;
+import com.mapbox.mapboxsdk.testapp.R;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+public class SurfaceViewMediaControlActivity extends AppCompatActivity {
+
+ private MapView mMapView;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_surfaceview_mediacontrols);
+
+ final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+
+ ActionBar actionBar = getSupportActionBar();
+ if (actionBar != null) {
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ actionBar.setDisplayShowHomeEnabled(true);
+ }
+
+ mMapView = (MapView) findViewById(R.id.mapView);
+ mMapView.onCreate(savedInstanceState);
+
+ // add another SurfaceView to the Layout
+ FrameLayout container = (FrameLayout) findViewById(R.id.container);
+ GLSurfaceView mediaControlSurfaceView = new ClearGLSurfaceView(this);
+ mediaControlSurfaceView.setZOrderMediaOverlay(true);
+ container.addView(mediaControlSurfaceView);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mMapView.onResume();
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ mMapView.onPause();
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ mMapView.onSaveInstanceState(outState);
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ mMapView.onDestroy();
+ }
+
+ @Override
+ public void onLowMemory() {
+ super.onLowMemory();
+ mMapView.onLowMemory();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.menu_padding, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case android.R.id.home:
+ onBackPressed();
+ return true;
+ default:
+ return super.onOptionsItemSelected(item);
+ }
+ }
+
+ class ClearGLSurfaceView extends GLSurfaceView {
+
+ private ClearRenderer mRenderer;
+
+ public ClearGLSurfaceView(Context context) {
+ super(context);
+ mRenderer = new ClearRenderer();
+ setRenderer(mRenderer);
+ }
+
+ public boolean onTouchEvent(final MotionEvent event) {
+ queueEvent(new Runnable() {
+ public void run() {
+ mRenderer.setColor(event.getRawX() / getWidth(),
+ event.getRawY() / getHeight(), 1.0f);
+ }
+ });
+ return true;
+ }
+ }
+
+ class ClearRenderer implements GLSurfaceView.Renderer {
+
+ private float mRed;
+ private float mGreen;
+ private float mBlue;
+
+ public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ // Do nothing special.
+ }
+
+ public void onSurfaceChanged(GL10 gl, int w, int h) {
+ gl.glViewport(0, 0, w, h);
+ }
+
+ public void onDrawFrame(GL10 gl) {
+ gl.glClearColor(mRed, mGreen, mBlue, 1.0f);
+ gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
+ }
+
+ public void setColor(float r, float g, float b) {
+ mRed = r;
+ mGreen = g;
+ mBlue = b;
+ }
+ }
+}
+
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/navigation/LocationPickerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/navigation/LocationPickerActivity.java
new file mode 100644
index 0000000000..7a6e425652
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/navigation/LocationPickerActivity.java
@@ -0,0 +1,467 @@
+package com.mapbox.mapboxsdk.testapp.activity.navigation;
+
+import android.Manifest;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.graphics.PointF;
+import android.location.Location;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.app.ActivityCompat;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.Toolbar;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+import android.widget.Button;
+import android.widget.FrameLayout;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.Toast;
+
+import com.mapbox.mapboxsdk.annotations.Icon;
+import com.mapbox.mapboxsdk.annotations.IconFactory;
+import com.mapbox.mapboxsdk.annotations.Marker;
+import com.mapbox.mapboxsdk.annotations.MarkerOptions;
+import com.mapbox.mapboxsdk.annotations.MarkerView;
+import com.mapbox.mapboxsdk.annotations.MarkerViewOptions;
+import com.mapbox.mapboxsdk.camera.CameraPosition;
+import com.mapbox.mapboxsdk.geometry.LatLng;
+import com.mapbox.mapboxsdk.location.LocationListener;
+import com.mapbox.mapboxsdk.location.LocationServices;
+import com.mapbox.mapboxsdk.maps.MapView;
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
+import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.model.annotations.PulseMarkerView;
+import com.mapbox.mapboxsdk.testapp.model.annotations.PulseMarkerViewOptions;
+import com.mapbox.services.commons.ServicesException;
+import com.mapbox.services.commons.models.Position;
+import com.mapbox.services.geocoding.v5.GeocodingCriteria;
+import com.mapbox.services.geocoding.v5.MapboxGeocoding;
+import com.mapbox.services.geocoding.v5.models.GeocodingFeature;
+import com.mapbox.services.geocoding.v5.models.GeocodingResponse;
+
+import java.util.List;
+
+import retrofit2.Call;
+import retrofit2.Callback;
+import retrofit2.Response;
+
+/**
+ * Sample Activity to show a typical location picker use case
+ */
+public class LocationPickerActivity extends AppCompatActivity {
+ private static final String TAG = "LocationPickerActivity";
+ private static final int REQUEST_PERMISSIONS = 101;
+
+ private MapView mapView;
+ private MapboxMap mapboxMap;
+
+ private ImageView dropPinView;
+ private Marker addressPin;
+ private ImageButton clearDisplayViewButton;
+ private MarkerView userMarker;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_location_picker);
+
+ setupActionBar();
+
+ //Initialize map as normal
+ mapView = (MapView) findViewById(R.id.mapView);
+ mapView.onCreate(savedInstanceState);
+
+ //Create ui elements
+ createDropPin();
+ createSelectLocationButton();
+ createClearSelectionButton();
+
+ mapView.getMapAsync(new OnMapReadyCallback() {
+ @Override
+ public void onMapReady(MapboxMap map) {
+ //Store for later
+ mapboxMap = map;
+
+ //Add user marker
+ mapboxMap.getMarkerViewManager().addMarkerViewAdapter(new PulseMarkerViewAdapter(LocationPickerActivity.this));
+ userMarker = createCustomUserMarker(new LatLng(0, 0));
+
+ //Fix the focal point to the center of the map
+ PointF focalPoint = new PointF((mapView.getX() + mapView.getWidth() / 2), (mapView.getY() + mapView.getHeight() / 2));
+ mapboxMap.getUiSettings().setFocalPoint(focalPoint);
+
+ //Track camera updates to animate the user location views
+ trackUserLocationView(userMarker);
+ }
+ });
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mapView.onResume();
+
+ //Check permissions
+ if (arePermissionsGranted()) {
+ mapView.getMapAsync(new OnMapReadyCallback() {
+
+ @Override
+ public void onMapReady(final MapboxMap mapboxMap) {
+ //Get the user's location
+ final LocationServices locationServices = LocationServices.getLocationServices(getApplicationContext());
+
+ Location location = locationServices.getLastLocation();
+ if (location != null) {
+ zoomInOn(location);
+ userMarker.setPosition(new LatLng(location));
+ } else {
+ final ProgressDialog loadingDialog = ProgressDialog.show(LocationPickerActivity.this, "Loading", "Getting user location", false);
+ locationServices.addLocationListener(new LocationListener() {
+ @Override
+ public void onLocationChanged(@Nullable Location location) {
+ //Move the camera to the user
+ if (location != null) {
+ zoomInOn(location);
+ userMarker.setPosition(new LatLng(location));
+ locationServices.removeLocationListener(this);
+ loadingDialog.hide();
+ }
+ }
+ });
+ }
+
+ locationServices.toggleGPS(true);
+ }
+ });
+ }
+ }
+
+ private void zoomInOn(Location location) {
+ //Move the camera to the user
+ if (location != null) {
+ mapboxMap.setCameraPosition(new CameraPosition.Builder()
+ .target(new LatLng(location))
+ .zoom(16)
+ .bearing(0)
+ .tilt(0)
+ .build());
+ }
+ }
+
+
+ /**
+ * Tracks the camera to animate the marker when overlapping with the picker.
+ * Makes sure the marker actually points to the user's position by tracking it.
+ */
+ private void trackUserLocationView(final MarkerView markerView) {
+ final float circleDiameterSize = getResources().getDimension(R.dimen.circle_size);
+
+ //Track camera changes to check for overlap
+ mapboxMap.setOnCameraChangeListener(new MapboxMap.OnCameraChangeListener() {
+
+ private Animation pulseAnimation;
+
+ @Override
+ public void onCameraChange(CameraPosition position) {
+ if (markerView == null) {
+ return;
+ }
+
+ //Make drop pin visible, if it wasn't already
+ showDropPin();
+
+ //Get the distance from the tip of the location picker to the MarkerView
+ double distance = getLocationPickerLocation().distanceTo(markerView.getPosition());
+
+ //If closeby, animate, otherwise, stop animation
+ View view = mapboxMap.getMarkerViewManager().getView(markerView);
+ if (view != null) {
+ View backgroundView = view.findViewById(R.id.background_imageview);
+ if (pulseAnimation == null && distance < 0.5f * circleDiameterSize) {
+ pulseAnimation = AnimationUtils.loadAnimation(LocationPickerActivity.this, R.anim.pulse);
+ pulseAnimation.setRepeatCount(Animation.INFINITE);
+ pulseAnimation.setRepeatMode(Animation.RESTART);
+ backgroundView.startAnimation(pulseAnimation);
+ } else if (pulseAnimation != null && distance >= 0.5f * circleDiameterSize) {
+ backgroundView.clearAnimation();
+ pulseAnimation = null;
+ }
+ }
+ }
+ });
+
+ //Track location updates to move the user marker
+ LocationServices.getLocationServices(getApplicationContext()).addLocationListener(new LocationListener() {
+ @Override
+ public void onLocationChanged(Location location) {
+ if (location != null && markerView != null) {
+ markerView.setPosition(new LatLng(location));
+ }
+ }
+ });
+ }
+
+ private MarkerView createCustomUserMarker(LatLng markerPosition) {
+ return mapboxMap.addMarker(new PulseMarkerViewOptions()
+ .icon(IconFactory.getInstance(getApplicationContext()).fromResource(R.drawable.ic_my_location_24dp))
+ .position(markerPosition)
+ );
+ }
+
+ private void createClearSelectionButton() {
+ clearDisplayViewButton = (ImageButton) findViewById(R.id.clearDisplayViewButton);
+ clearDisplayViewButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ removeAddressPin();
+ hide(clearDisplayViewButton);
+ showDropPin();
+ }
+ });
+ }
+
+ private void createSelectLocationButton() {
+ Button selectLocationButton = (Button) findViewById(R.id.selectLocationButton);
+ //noinspection ConstantConditions
+ selectLocationButton.setOnClickListener(
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Log.i(TAG, "Location Selected!");
+ if (mapboxMap != null) {
+ //Control button's state
+ clearDisplayViewButton.setVisibility(View.VISIBLE);
+ dropPinView.setVisibility(View.INVISIBLE);
+
+ //Get position for the drop pin
+ LatLng position = getLocationPickerLocation();
+
+ //Show the address pin (result)
+ showAddressPin(position);
+
+ //Get the address for that location and update the marker
+ geocode(position, new GeocodeCallbacks() {
+ @Override
+ public void onResult(String result) {
+ updateAddressPin(result);
+ }
+
+ @Override
+ public void onFailure(Throwable failure) {
+ showFeedbackMessage("Could not retrieve address: " + failure.getMessage());
+ }
+ });
+ }
+ }
+ }
+ );
+ }
+
+ private void createDropPin() {
+ float density = getResources().getDisplayMetrics().density;
+
+ dropPinView = new ImageView(this);
+ dropPinView.setImageResource(R.drawable.ic_droppin_24dp);
+ FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.CENTER);
+ params.bottomMargin = (int) (12 * density);
+ dropPinView.setLayoutParams(params);
+
+ mapView.addView(dropPinView);
+ }
+
+ private void showDropPin() {
+ if (dropPinView != null && dropPinView.getVisibility() != View.VISIBLE) {
+ dropPinView.setVisibility(View.VISIBLE);
+ }
+ }
+
+ private void hide(View view) {
+ if (view != null) {
+ view.setVisibility(View.INVISIBLE);
+ }
+ }
+
+ private void setupActionBar() {
+ Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+
+ ActionBar actionBar = getSupportActionBar();
+ if (actionBar != null) {
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ actionBar.setDisplayShowHomeEnabled(true);
+ }
+ }
+
+ /**
+ * Get address for the given location
+ */
+ private void geocode(LatLng point, final GeocodeCallbacks callbacks) {
+ try {
+ //Create Geocoding client
+ MapboxGeocoding client = new MapboxGeocoding.Builder()
+ .setAccessToken(getString(R.string.mapbox_access_token))
+ .setCoordinates(Position.fromCoordinates(point.getLongitude(), point.getLatitude()))
+ .setType(GeocodingCriteria.TYPE_ADDRESS)
+ .build();
+
+ //Place the request
+ client.enqueueCall(new Callback<GeocodingResponse>() {
+ @Override
+ public void onResponse(Call<GeocodingResponse> call, Response<GeocodingResponse> response) {
+
+ List<GeocodingFeature> results = response.body().getFeatures();
+ String address = null;
+ if (results.size() > 0) {
+ GeocodingFeature feature = results.get(0);
+ address = feature.getAddress() + " " + feature.getText();
+ Log.i(TAG, "address " + address);
+ } else {
+ showFeedbackMessage("No results for search.");
+ }
+
+ callbacks.onResult(address);
+ }
+
+ @Override
+ public void onFailure(Call<GeocodingResponse> call, Throwable t) {
+ Log.e(TAG, "Geocoding Failure: " + t.getMessage());
+ callbacks.onFailure(t);
+ }
+ });
+ } catch (ServicesException e) {
+ Log.e(TAG, "Error geocoding: " + e.toString());
+ callbacks.onFailure(e);
+ }
+ }
+
+ private LatLng getLocationPickerLocation() {
+ return mapboxMap.getProjection().fromScreenLocation(
+ new PointF(dropPinView.getLeft() + (dropPinView.getWidth() / 2), dropPinView.getBottom())
+ );
+ }
+
+ private Marker showAddressPin(LatLng position) {
+ if (addressPin != null) {
+ //Remove previous pin
+ removeAddressPin();
+ }
+
+ //Create new one
+ addressPin = mapboxMap.addMarker(new MarkerViewOptions().title("Loading address...").position(position));
+ mapboxMap.selectMarker(addressPin);
+ return addressPin;
+ }
+
+ private void removeAddressPin() {
+ if (mapboxMap != null && addressPin != null) {
+ mapboxMap.removeMarker(addressPin);
+ }
+ }
+
+ private void updateAddressPin(@Nullable String address) {
+ if (addressPin != null) {
+ addressPin.setTitle(address == null ? "No address found" : address);
+ }
+ }
+
+ private void showFeedbackMessage(String message) {
+ Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
+ }
+
+ private boolean arePermissionsGranted() {
+ if (Build.VERSION.SDK_INT >= 23 &&
+ checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
+ checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
+ Log.i(TAG, "Requesting permissions");
+ ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_PERMISSIONS);
+ return false;
+ }
+ Log.i(TAG, "Permissions already granted");
+ return true;
+ }
+
+ @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;
+ default:
+ return super.onOptionsItemSelected(item);
+ }
+ }
+
+ /**
+ * Custom MarkerViewAdapter for the pulsing marker
+ */
+ private static class PulseMarkerViewAdapter extends MapboxMap.MarkerViewAdapter<PulseMarkerView> {
+
+ private LayoutInflater inflater;
+
+ public PulseMarkerViewAdapter(@NonNull Context context) {
+ super(context);
+ this.inflater = LayoutInflater.from(context);
+ }
+
+ @Nullable
+ @Override
+ public View getView(@NonNull PulseMarkerView marker, @Nullable View convertView, @NonNull ViewGroup parent) {
+ ViewHolder viewHolder;
+ if (convertView == null) {
+ viewHolder = new ViewHolder();
+ convertView = inflater.inflate(R.layout.view_pulse_marker, parent, false);
+ viewHolder.foregroundImageView = (ImageView) convertView.findViewById(R.id.foreground_imageView);
+ viewHolder.backgroundImageView = (ImageView) convertView.findViewById(R.id.background_imageview);
+ convertView.setTag(viewHolder);
+ }
+ return convertView;
+ }
+
+ private static class ViewHolder {
+ ImageView foregroundImageView;
+ ImageView backgroundImageView;
+ }
+ }
+
+ private interface GeocodeCallbacks {
+ void onResult(String result);
+
+ void onFailure(Throwable failure);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java
index fde46b1cab..8819168478 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java
@@ -12,6 +12,7 @@ import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.Toast;
+
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.constants.Style;
@@ -26,10 +27,11 @@ import com.mapbox.mapboxsdk.offline.OfflineRegionError;
import com.mapbox.mapboxsdk.offline.OfflineRegionStatus;
import com.mapbox.mapboxsdk.offline.OfflineTilePyramidRegionDefinition;
import com.mapbox.mapboxsdk.testapp.R;
-import com.mapbox.mapboxsdk.testapp.model.constants.AppConstant;
import com.mapbox.mapboxsdk.testapp.model.other.OfflineDownloadRegionDialog;
import com.mapbox.mapboxsdk.testapp.model.other.OfflineListRegionsDialog;
+
import org.json.JSONObject;
+
import java.util.ArrayList;
public class OfflineActivity extends AppCompatActivity
@@ -74,7 +76,7 @@ public class OfflineActivity extends AppCompatActivity
// Set up map
mMapView = (MapView) findViewById(R.id.mapView);
- mMapView.setStyleUrl(Style.getMapboxStreetsUrl(AppConstant.STYLE_VERSION));
+ mMapView.setStyleUrl(Style.MAPBOX_STREETS);
mMapView.onCreate(savedInstanceState);
mMapView.getMapAsync(new OnMapReadyCallback() {
@Override
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleActivity.java
new file mode 100644
index 0000000000..4e0f5f8c41
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleActivity.java
@@ -0,0 +1,366 @@
+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.util.Log;
+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.Function;
+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.PropertyValue;
+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.TileSet;
+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.Function.*;
+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;
+ case R.id.action_update_water_color_on_zoom:
+ updateWaterColorOnZoom();
+ return true;
+ case R.id.action_add_custom_tiles:
+ addCustomTileSource();
+ 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.setProperties(visibility(VISIBLE));
+ }
+ }
+ }
+
+ 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.setProperties(symbolPlacement(SYMBOL_PLACEMENT_POINT));
+ }
+ }
+ }
+ });
+ }
+
+ private void setBackgroundOpacity() {
+ Layer background = mapboxMap.getLayer("background");
+ if (background != null) {
+ background.setProperties(backgroundOpacity(0.2f));
+ }
+ }
+
+ private void setWaterColor() {
+ Layer water = mapboxMap.getLayer("water");
+ if (water != null) {
+ water.setProperties(
+ visibility(VISIBLE),
+ 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.setProperties(
+ 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").setProperties(fillColor(Color.RED));
+
+ //You can get a typed layer, if you're sure it's of that type. Use with care
+ layer = mapboxMap.getLayerAs("parksLayer");
+ //And get some properties
+ PropertyValue<Boolean> fillAntialias = layer.getFillAntialias();
+ Log.d(TAG, "Fill anti alias: " + fillAntialias.getValue());
+ layer.setProperties(fillTranslateAnchor(FILL_TRANSLATE_ANCHOR_MAP));
+ PropertyValue<String> fillTranslateAnchor = layer.getFillTranslateAnchor();
+ Log.d(TAG, "Fill translate anchor: " + fillTranslateAnchor.getValue());
+ PropertyValue<String> visibility = layer.getVisibility();
+ Log.d(TAG, "Visibility: " + visibility.getValue());
+
+ //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.setProperties(
+ lineJoin(Property.LINE_JOIN_ROUND),
+ lineCap(Property.LINE_CAP_ROUND),
+ lineColor(Color.RED),
+ lineWidth(20f)
+ );
+
+ mapboxMap.addLayer(layer);
+
+ //Need to get a fresh handle
+ layer = mapboxMap.getLayerAs("terrainLayer");
+
+ //Make sure it's also applied after the fact
+ layer.setMinZoom(10);
+ layer.setMaxZoom(15);
+
+ layer = (LineLayer) mapboxMap.getLayer("terrainLayer");
+ Toast.makeText(this, String.format("Set min/max zoom to %s - %s", layer.getMinZoom(), layer.getMaxZoom()), Toast.LENGTH_SHORT).show();
+ }
+
+ private void addSatelliteLayer() {
+ //Add a source
+ Source source = new RasterSource("my-raster-source", "mapbox://mapbox.satellite").withTileSize(512);
+ mapboxMap.addSource(source);
+
+ //Add a layer
+ mapboxMap.addLayer(new RasterLayer("satellite-layer", "my-raster-source"));
+ }
+
+ private void updateWaterColorOnZoom() {
+ FillLayer layer = mapboxMap.getLayerAs("water");
+ if (layer == null) {
+ return;
+ }
+
+ //Set a zoom function to update the color of the water
+ layer.setProperties(fillColor(zoom(0.8f,
+ stop(1, fillColor(Color.GREEN)),
+ stop(4, fillColor(Color.BLUE)),
+ stop(12, fillColor(Color.RED)),
+ stop(20, fillColor(Color.BLACK))
+ )));
+
+ //do some animations to show it off properly
+ mapboxMap.animateCamera(CameraUpdateFactory.zoomTo(1), 1500);
+
+ PropertyValue<String> fillColor = layer.getFillColor();
+ Function<String> function = fillColor.getFunction();
+ Log.d(TAG, "Fill color base: " + function.getBase());
+ Log.d(TAG, "Fill color #stops: " + function.getStops().length);
+ }
+
+ 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 void addCustomTileSource() {
+ //Add a source
+ Source source = new VectorSource("custom-tile-source", new TileSet("2.1.0", "https://vector.mapzen.com/osm/all/{z}/{x}/{y}.mvt?api_key=vector-tiles-LM25tq4"));
+ mapboxMap.addSource(source);
+
+ //Add a layer
+ mapboxMap.addLayer(
+ new FillLayer("custom-tile-layers", "custom-tile-source")
+ .withSourceLayer("water")
+ );
+ }
+
+ private static class DefaultCallback implements MapboxMap.CancelableCallback {
+
+ @Override
+ public void onCancel() {
+ //noop
+ }
+
+ @Override
+ public void onFinish() {
+ //noop
+ }
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleTestActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleTestActivity.java
new file mode 100644
index 0000000000..6f04852ca1
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleTestActivity.java
@@ -0,0 +1,69 @@
+package com.mapbox.mapboxsdk.testapp.activity.style;
+
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+
+import com.mapbox.mapboxsdk.maps.MapView;
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
+import com.mapbox.mapboxsdk.testapp.R;
+
+/**
+ * Test activity for unit test execution
+ */
+public class RuntimeStyleTestActivity extends AppCompatActivity {
+ private static final String TAG = RuntimeStyleTestActivity.class.getSimpleName();
+
+ public MapView mapView;
+ private MapboxMap mapboxMap;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_runtime_style);
+
+ //Initialize map as normal
+ mapView = (MapView) findViewById(R.id.mapView);
+ mapView.onCreate(savedInstanceState);
+ mapView.getMapAsync(new OnMapReadyCallback() {
+ @Override
+ public void onMapReady(MapboxMap mapboxMap) {
+ RuntimeStyleTestActivity.this.mapboxMap = mapboxMap;
+ }
+ });
+ }
+
+ public MapboxMap getMapboxMap() {
+ return mapboxMap;
+ }
+
+ @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();
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleTimingTestActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleTimingTestActivity.java
new file mode 100644
index 0000000000..9463cfcf08
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleTimingTestActivity.java
@@ -0,0 +1,87 @@
+package com.mapbox.mapboxsdk.testapp.activity.style;
+
+import android.graphics.Color;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+
+import com.mapbox.mapboxsdk.maps.MapView;
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
+import com.mapbox.mapboxsdk.style.layers.CircleLayer;
+import com.mapbox.mapboxsdk.style.sources.VectorSource;
+import com.mapbox.mapboxsdk.testapp.R;
+
+import static com.mapbox.mapboxsdk.style.layers.Property.*;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.*;
+
+/**
+ * Test activity for unit test execution
+ */
+public class RuntimeStyleTimingTestActivity extends AppCompatActivity {
+ private static final String TAG = RuntimeStyleTimingTestActivity.class.getSimpleName();
+
+ public MapView mapView;
+ private MapboxMap mapboxMap;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_runtime_style);
+
+ //Initialize map as normal
+ mapView = (MapView) findViewById(R.id.mapView);
+ mapView.onCreate(savedInstanceState);
+ mapView.getMapAsync(new OnMapReadyCallback() {
+ @Override
+ public void onMapReady(MapboxMap mapboxMap) {
+ RuntimeStyleTimingTestActivity.this.mapboxMap = mapboxMap;
+ VectorSource museums = new VectorSource("museums_source", "mapbox://mapbox.2opop9hr");
+ mapboxMap.addSource(museums);
+
+ CircleLayer museumsLayer = new CircleLayer("museums", "museums_source");
+ museumsLayer.setSourceLayer("museum-cusco");
+ museumsLayer.setProperties(
+ visibility(VISIBLE),
+ circleRadius(8f),
+ circleColor(Color.argb(1, 55, 148, 179))
+ );
+
+ mapboxMap.addLayer(museumsLayer);
+ }
+ });
+ }
+
+ public MapboxMap getMapboxMap() {
+ return mapboxMap;
+ }
+
+ @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();
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationDrawableActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationDrawableActivity.java
index a4a283907e..d630ee6d21 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationDrawableActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationDrawableActivity.java
@@ -1,9 +1,14 @@
package com.mapbox.mapboxsdk.testapp.activity.userlocation;
+import android.Manifest;
+import android.content.pm.PackageManager;
import android.graphics.Color;
import android.location.Location;
import android.os.Bundle;
+import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+import android.support.annotation.UiThread;
+import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
@@ -11,6 +16,7 @@ import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
+
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.constants.Style;
@@ -22,10 +28,11 @@ import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.MapboxMapOptions;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.testapp.R;
-import com.mapbox.mapboxsdk.testapp.model.constants.AppConstant;
public class MyLocationDrawableActivity extends AppCompatActivity implements LocationListener {
+ private static final int PERMISSIONS_LOCATION = 0;
+
private MapView mapView;
private MapboxMap mapboxMap;
private Location location;
@@ -45,20 +52,13 @@ public class MyLocationDrawableActivity extends AppCompatActivity implements Loc
}
findViewById(R.id.progress).setVisibility(View.GONE);
- location = LocationServices.getLocationServices(this).getLastLocation();
MapboxMapOptions mapboxMapOptions = new MapboxMapOptions();
mapboxMapOptions.accessToken(getString(R.string.mapbox_access_token));
- mapboxMapOptions.styleUrl(Style.getMapboxStreetsUrl(AppConstant.STYLE_VERSION));
- mapboxMapOptions.locationEnabled(true);
- mapboxMapOptions.camera(new CameraPosition.Builder()
- .target(location != null ? new LatLng(location) : new LatLng(0, 0))
- .zoom(11)
- .tilt(25)
- .build());
-
- mapboxMapOptions.myLocationForegroundDrawables(ContextCompat.getDrawable(this, R.drawable.ic_chelsea),
- ContextCompat.getDrawable(this, R.drawable.ic_chelsea));
+ mapboxMapOptions.styleUrl(Style.MAPBOX_STREETS);
+
+ // configure MyLocationView drawables
+ mapboxMapOptions.myLocationForegroundDrawable(ContextCompat.getDrawable(this, R.drawable.ic_chelsea));
mapboxMapOptions.myLocationBackgroundDrawable(ContextCompat.getDrawable(this, R.drawable.ic_arsenal));
mapboxMapOptions.myLocationForegroundTintColor(Color.GREEN);
mapboxMapOptions.myLocationBackgroundTintColor(Color.YELLOW);
@@ -78,17 +78,53 @@ public class MyLocationDrawableActivity extends AppCompatActivity implements Loc
@Override
public void onMapReady(MapboxMap map) {
mapboxMap = map;
+ toggleGps(true);
}
});
+ }
+
+ public void toggleGps(boolean enableGps) {
+ if (enableGps) {
+ if ((ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) ||
+ (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED)) {
+ ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSIONS_LOCATION);
+ } else {
+ enableLocation(true);
+ }
+ } else {
+ enableLocation(false);
+ }
+ }
- LocationServices.getLocationServices(this).addLocationListener(this);
+ private void enableLocation(boolean enabled) {
+ if (enabled) {
+ mapboxMap.setMyLocationEnabled(true);
+ Location location = mapboxMap.getMyLocation();
+ if (location != null) {
+ onLocationChanged(location);
+ }else{
+ LocationServices.getLocationServices(this).addLocationListener(this);
+ }
+ } else {
+ mapboxMap.setMyLocationEnabled(false);
+ }
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
+ switch (requestCode) {
+ case PERMISSIONS_LOCATION: {
+ if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ enableLocation(true);
+ }
+ }
+ }
}
@Override
public void onLocationChanged(Location location) {
- if (mapboxMap != null && firstRun) {
- mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(location), 10));
- firstRun = false;
+ if (mapboxMap != null) {
+ mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(location), 14));
}
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationTrackingModeActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationTrackingModeActivity.java
index fcd61e70b4..273b5134c3 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationTrackingModeActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationTrackingModeActivity.java
@@ -1,10 +1,15 @@
package com.mapbox.mapboxsdk.testapp.activity.userlocation;
+import android.Manifest;
+import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+import android.support.annotation.UiThread;
import android.support.design.widget.Snackbar;
+import android.support.v4.app.ActivityCompat;
+import android.support.v4.content.ContextCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
@@ -33,6 +38,7 @@ public class MyLocationTrackingModeActivity extends AppCompatActivity implements
private MapboxMap mMapboxMap;
private Spinner mLocationSpinner, mBearingSpinner;
private Location mLocation;
+ private static final int PERMISSIONS_LOCATION = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -57,8 +63,9 @@ public class MyLocationTrackingModeActivity extends AppCompatActivity implements
mMapboxMap = mapboxMap;
// disable dismissal when a gesture occurs
- mMapboxMap.getTrackingSettings().setDismissLocationTrackingOnGesture(false);
- mMapboxMap.getTrackingSettings().setDismissBearingTrackingOnGesture(false);
+ TrackingSettings trackingSettings = mapboxMap.getTrackingSettings();
+ trackingSettings.setDismissLocationTrackingOnGesture(false);
+ trackingSettings.setDismissBearingTrackingOnGesture(false);
mapboxMap.setOnMyLocationChangeListener(MyLocationTrackingModeActivity.this);
@@ -96,13 +103,46 @@ public class MyLocationTrackingModeActivity extends AppCompatActivity implements
}
});
+ toggleGps(!mapboxMap.isMyLocationEnabled());
+ }
+ });
+ }
+
+ @UiThread
+ public void toggleGps(boolean enableGps) {
+ if (enableGps) {
+ if ((ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) ||
+ (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED)) {
+ ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSIONS_LOCATION);
+ } else {
+ enableLocation(true);
+ }
+ } else {
+ enableLocation(false);
+ }
+ }
- mLocation = LocationServices.getLocationServices(MyLocationTrackingModeActivity.this).getLastLocation();
- if(mLocation!=null){
- setInitialPosition(new LatLng(mLocation));
+ private void enableLocation(boolean enabled) {
+ if (enabled) {
+ mMapboxMap.setMyLocationEnabled(true);
+ Location location = mMapboxMap.getMyLocation();
+ if (location != null) {
+ setInitialPosition(new LatLng(location));
+ }
+ } else {
+ mMapboxMap.setMyLocationEnabled(false);
+ }
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
+ switch (requestCode) {
+ case PERMISSIONS_LOCATION: {
+ if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ enableLocation(true);
}
}
- });
+ }
}
private void setInitialPosition(LatLng latLng){
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/CountryMarkerViewOptions.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/CountryMarkerViewOptions.java
index c4ef4a8d13..a1df434ebc 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/CountryMarkerViewOptions.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/CountryMarkerViewOptions.java
@@ -1,8 +1,6 @@
package com.mapbox.mapboxsdk.testapp.model.annotations;
import android.graphics.Bitmap;
-import android.graphics.Point;
-import android.graphics.PointF;
import android.os.Parcel;
import android.os.Parcelable;
@@ -27,9 +25,9 @@ public class CountryMarkerViewOptions extends BaseMarkerViewOptions<CountryMarke
flat(in.readByte() != 0);
anchor(in.readFloat(), in.readFloat());
infoWindowAnchor(in.readFloat(), in.readFloat());
- selectAnimatorResource(in.readInt());
- deselectAnimatorResource(in.readInt());
- rotation(in.readInt());
+ rotation(in.readFloat());
+ visible(in.readByte() != 0);
+ alpha(in.readFloat());
if (in.readByte() != 0) {
// this means we have an icon
String iconId = in.readString();
@@ -61,9 +59,9 @@ public class CountryMarkerViewOptions extends BaseMarkerViewOptions<CountryMarke
out.writeFloat(getAnchorV());
out.writeFloat(getInfoWindowAnchorU());
out.writeFloat(getInfoWindowAnchorV());
- out.writeInt(getSelectAnimRes());
- out.writeInt(getDeselectAnimRes());
- out.writeInt(getRotation());
+ out.writeFloat(getRotation());
+ out.writeByte((byte) (isVisible() ? 1 : 0));
+ out.writeFloat(getAlpha());
Icon icon = getIcon();
out.writeByte((byte) (icon != null ? 1 : 0));
if (icon != null) {
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/PulseMarkerView.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/PulseMarkerView.java
new file mode 100644
index 0000000000..48867ea5eb
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/PulseMarkerView.java
@@ -0,0 +1,11 @@
+package com.mapbox.mapboxsdk.testapp.model.annotations;
+
+import com.mapbox.mapboxsdk.annotations.BaseMarkerViewOptions;
+import com.mapbox.mapboxsdk.annotations.MarkerView;
+
+public class PulseMarkerView extends MarkerView {
+
+ public PulseMarkerView(BaseMarkerViewOptions baseMarkerViewOptions) {
+ super(baseMarkerViewOptions);
+ }
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/PulseMarkerViewOptions.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/PulseMarkerViewOptions.java
new file mode 100644
index 0000000000..70ff6a22e2
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/PulseMarkerViewOptions.java
@@ -0,0 +1,79 @@
+package com.mapbox.mapboxsdk.testapp.model.annotations;
+
+import android.graphics.Bitmap;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.mapbox.mapboxsdk.annotations.BaseMarkerViewOptions;
+import com.mapbox.mapboxsdk.annotations.Icon;
+import com.mapbox.mapboxsdk.annotations.IconFactory;
+import com.mapbox.mapboxsdk.geometry.LatLng;
+
+public class PulseMarkerViewOptions extends BaseMarkerViewOptions<PulseMarkerView, PulseMarkerViewOptions> {
+
+ public PulseMarkerViewOptions() {
+ }
+
+ protected PulseMarkerViewOptions(Parcel in) {
+ position((LatLng) in.readParcelable(LatLng.class.getClassLoader()));
+ snippet(in.readString());
+ title(in.readString());
+ flat(in.readByte() != 0);
+ anchor(in.readFloat(), in.readFloat());
+ selected = in.readByte() != 0;
+ rotation(in.readFloat());
+ if (in.readByte() != 0) {
+ // this means we have an icon
+ String iconId = in.readString();
+ Bitmap iconBitmap = in.readParcelable(Bitmap.class.getClassLoader());
+ Icon icon = IconFactory.recreate(iconId, iconBitmap);
+ icon(icon);
+ }
+ }
+
+ @Override
+ public PulseMarkerViewOptions getThis() {
+ return this;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeParcelable(getPosition(), flags);
+ out.writeString(getSnippet());
+ out.writeString(getTitle());
+ out.writeByte((byte) (isFlat() ? 1 : 0));
+ out.writeFloat(getAnchorU());
+ out.writeFloat(getAnchorV());
+ out.writeFloat(getInfoWindowAnchorU());
+ out.writeFloat(getInfoWindowAnchorV());
+ out.writeByte((byte) (selected ? 1 : 0));
+ out.writeFloat(getRotation());
+ Icon icon = getIcon();
+ out.writeByte((byte) (icon != null ? 1 : 0));
+ if (icon != null) {
+ out.writeString(getIcon().getId());
+ out.writeParcelable(getIcon().getBitmap(), flags);
+ }
+ }
+
+ @Override
+ public PulseMarkerView getMarker() {
+ return new PulseMarkerView(this);
+ }
+
+ public static final Parcelable.Creator<CountryMarkerViewOptions> CREATOR
+ = new Parcelable.Creator<CountryMarkerViewOptions>() {
+ public CountryMarkerViewOptions createFromParcel(Parcel in) {
+ return new CountryMarkerViewOptions(in);
+ }
+
+ public CountryMarkerViewOptions[] newArray(int size) {
+ return new CountryMarkerViewOptions[size];
+ }
+ };
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/TextMarkerView.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/TextMarkerView.java
new file mode 100644
index 0000000000..c0a589cb57
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/TextMarkerView.java
@@ -0,0 +1,18 @@
+package com.mapbox.mapboxsdk.testapp.model.annotations;
+
+import com.mapbox.mapboxsdk.annotations.BaseMarkerViewOptions;
+import com.mapbox.mapboxsdk.annotations.MarkerView;
+
+public class TextMarkerView extends MarkerView {
+
+ private String text;
+
+ public TextMarkerView(BaseMarkerViewOptions baseMarkerViewOptions, String text) {
+ super(baseMarkerViewOptions);
+ this.text = text;
+ }
+
+ public String getText() {
+ return text;
+ }
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/TextMarkerViewOptions.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/TextMarkerViewOptions.java
new file mode 100644
index 0000000000..a8622e9790
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/TextMarkerViewOptions.java
@@ -0,0 +1,92 @@
+package com.mapbox.mapboxsdk.testapp.model.annotations;
+
+import android.graphics.Bitmap;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.mapbox.mapboxsdk.annotations.BaseMarkerViewOptions;
+import com.mapbox.mapboxsdk.annotations.Icon;
+import com.mapbox.mapboxsdk.annotations.IconFactory;
+import com.mapbox.mapboxsdk.annotations.MarkerView;
+import com.mapbox.mapboxsdk.geometry.LatLng;
+
+public class TextMarkerViewOptions extends BaseMarkerViewOptions<TextMarkerView, TextMarkerViewOptions> {
+
+ private String text;
+
+ public TextMarkerViewOptions() {
+ }
+
+ protected TextMarkerViewOptions(Parcel in) {
+ position((LatLng) in.readParcelable(LatLng.class.getClassLoader()));
+ snippet(in.readString());
+ title(in.readString());
+ flat(in.readByte() != 0);
+ anchor(in.readFloat(), in.readFloat());
+ infoWindowAnchor(in.readFloat(), in.readFloat());
+ rotation(in.readFloat());
+ visible(in.readByte() != 0);
+ alpha(in.readFloat());
+ if (in.readByte() != 0) {
+ // this means we have an icon
+ String iconId = in.readString();
+ Bitmap iconBitmap = in.readParcelable(Bitmap.class.getClassLoader());
+ Icon icon = IconFactory.recreate(iconId, iconBitmap);
+ icon(icon);
+ }
+ text(in.readString());
+ }
+
+ @Override
+ public TextMarkerViewOptions getThis() {
+ return this;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeParcelable(getPosition(), flags);
+ out.writeString(getSnippet());
+ out.writeString(getTitle());
+ out.writeByte((byte) (isFlat() ? 1 : 0));
+ out.writeFloat(getAnchorU());
+ out.writeFloat(getAnchorV());
+ out.writeFloat(getInfoWindowAnchorU());
+ out.writeFloat(getInfoWindowAnchorV());
+ out.writeFloat(getRotation());
+ out.writeByte((byte) (isVisible() ? 1 : 0));
+ out.writeFloat(alpha);
+ Icon icon = getIcon();
+ out.writeByte((byte) (icon != null ? 1 : 0));
+ if (icon != null) {
+ out.writeString(getIcon().getId());
+ out.writeParcelable(getIcon().getBitmap(), flags);
+ }
+ out.writeString(text);
+ }
+
+ @Override
+ public TextMarkerView getMarker() {
+ return new TextMarkerView(this, text);
+ }
+
+ public TextMarkerViewOptions text(String text) {
+ this.text = text;
+ return getThis();
+ }
+
+ public static final Parcelable.Creator<CountryMarkerViewOptions> CREATOR
+ = new Parcelable.Creator<CountryMarkerViewOptions>() {
+ public CountryMarkerViewOptions createFromParcel(Parcel in) {
+ return new CountryMarkerViewOptions(in);
+ }
+
+ public CountryMarkerViewOptions[] newArray(int size) {
+ return new CountryMarkerViewOptions[size];
+ }
+ };
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/anim/pulse.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/anim/pulse.xml
new file mode 100644
index 0000000000..40bc57ab68
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/anim/pulse.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@android:anim/decelerate_interpolator">
+
+ <scale
+ android:duration="1000"
+ android:fromXScale="1"
+ android:fromYScale="1"
+ android:pivotX="50%"
+ android:pivotY="50%"
+ android:repeatCount="infinite"
+ android:repeatMode="restart"
+ android:toXScale="1.8"
+ android:toYScale="1.8"/>
+
+ <set android:startOffset="200">
+ <alpha
+ android:duration="800"
+ android:fromAlpha="1.0"
+ android:repeatCount="infinite"
+ android:repeatMode="restart"
+ android:toAlpha="0.0"/>
+ </set>
+</set> \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/ic_drawer.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/ic_drawer.png
new file mode 100644
index 0000000000..c59f601ca3
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/ic_drawer.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/icon.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/icon.png
index c9d3f3d2d0..ac2ea61c73 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/icon.png
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/icon.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/ic_drawer.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/ic_drawer.png
new file mode 100644
index 0000000000..1ed2c56ee4
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/ic_drawer.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/icon.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/icon.png
index 235a854d71..99eed7146c 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/icon.png
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/icon.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/ic_drawer.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/ic_drawer.png
new file mode 100644
index 0000000000..a5fa74def4
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/ic_drawer.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/icon.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/icon.png
index c9d3f3d2d0..9b084daf91 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/icon.png
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/icon.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_drawer.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_drawer.png
new file mode 100644
index 0000000000..9c4685d6e0
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_drawer.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/icon.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/icon.png
index 8667ce6c44..6fa714b47d 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/icon.png
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/icon.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/ic_car_top.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/ic_car_top.png
new file mode 100644
index 0000000000..ca7590137b
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/ic_car_top.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/ic_taxi_top.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/ic_taxi_top.png
new file mode 100644
index 0000000000..09f84fd9cb
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/ic_taxi_top.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/icon.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/icon.png
index df0ca2e83d..77289b5d0a 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/icon.png
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/icon.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_circle.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_circle.xml
new file mode 100644
index 0000000000..006b2ce5a8
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_circle.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="oval">
+
+ <solid
+ android:color="@color/mapbox_blue"/>
+
+ <size
+ android:width="@dimen/circle_size"
+ android:height="@dimen/circle_size"/>
+</shape> \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_clear_24dp.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_clear_24dp.xml
new file mode 100644
index 0000000000..1e2d044bee
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_clear_24dp.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
+</vector>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_car_black_24dp.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_car_black_24dp.xml
new file mode 100644
index 0000000000..6d6337c3ab
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_car_black_24dp.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M18.92,6.01C18.72,5.42 18.16,5 17.5,5h-11c-0.66,0 -1.21,0.42 -1.42,1.01L3,12v8c0,0.55 0.45,1 1,1h1c0.55,0 1,-0.45 1,-1v-1h12v1c0,0.55 0.45,1 1,1h1c0.55,0 1,-0.45 1,-1v-8l-2.08,-5.99zM6.5,16c-0.83,0 -1.5,-0.67 -1.5,-1.5S5.67,13 6.5,13s1.5,0.67 1.5,1.5S7.33,16 6.5,16zM17.5,16c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5zM5,11l1.5,-4.5h11L19,11L5,11z"/>
+</vector>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_run_black_24dp.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_run_black_24dp.xml
new file mode 100644
index 0000000000..dfa43f020e
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_run_black_24dp.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="32dp"
+ android:height="32dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M13.49,5.48c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM9.89,19.38l1,-4.4 2.1,2v6h2v-7.5l-2.1,-2 0.6,-3c1.3,1.5 3.3,2.5 5.5,2.5v-2c-1.9,0 -3.5,-1 -4.3,-2.4l-1,-1.6c-0.4,-0.6 -1,-1 -1.7,-1 -0.3,0 -0.5,0.1 -0.8,0.1l-5.2,2.2v4.7h2v-3.4l1.8,-0.7 -1.6,8.1 -4.9,-1 -0.4,2 7,1.4z"/>
+</vector>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_print_24dp.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_print_24dp.xml
new file mode 100644
index 0000000000..7a9bc00287
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_print_24dp.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M19,8L5,8c-1.66,0 -3,1.34 -3,3v6h4v4h12v-4h4v-6c0,-1.66 -1.34,-3 -3,-3zM16,19L8,19v-5h8v5zM19,12c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1zM18,3L6,3v4h12L18,3z"/>
+</vector>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_marker.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_marker.xml
index 8c025d999c..b9bfa701a8 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_marker.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_marker.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
- xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
@@ -16,7 +16,10 @@
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_below="@id/toolbar"
+ app:center_latitude="51.502615"
+ app:center_longitude="4.972326"
app:style_url="@string/style_light"
- android:layout_below="@id/toolbar" />
+ app:zoom="6" />
</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_infowindow_adapter_dynamic.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_infowindow_adapter_dynamic.xml
new file mode 100644
index 0000000000..ccced6bbff
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_infowindow_adapter_dynamic.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <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"
+ app:style_url="@string/style_mapbox_streets"
+ app:center_latitude="47.798202"
+ app:center_longitude="7.573781"
+ app:zoom="4" />
+
+</LinearLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_picker.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_picker.xml
new file mode 100644
index 0000000000..f9fe77bfec
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_picker.xml
@@ -0,0 +1,41 @@
+<?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"/>
+
+ <ImageButton
+ android:id="@+id/clearDisplayViewButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_clear_24dp"
+ android:background="@color/accent"
+ android:visibility="gone"
+ android:layout_marginLeft="@dimen/full_button_margin"
+ android:layout_above="@+id/selectLocationButton"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"/>
+
+ <Button
+ android:id="@+id/selectLocationButton"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="@dimen/full_button_margin"
+ android:background="@color/primary"
+ android:text="@string/navigation_select_location_button_text"
+ android:textColor="@android:color/white"
+ android:layout_alignParentBottom="true"/>
+
+</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_marker_view_scale.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_marker_view_scale.xml
new file mode 100644
index 0000000000..c59f41539c
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_marker_view_scale.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ 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="wrap_content"
+ android:background="@color/primary"
+ android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingBottom="8dp">
+
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="12dp"
+ android:paddingBottom="8dp"
+ android:textSize="20sp"
+ android:textColor="#FFFFFF"
+ android:text="Scaling in the View Marker API" />
+
+ <TextView
+ android:id="@+id/textview_factor"
+ android:layout_alignBottom="@+id/seekbar_factor"
+ android:layout_below="@id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Scale: 1" />
+
+ <SeekBar
+ android:id="@+id/seekbar_factor"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/title"
+ android:layout_marginLeft="56dp"
+ android:progress="0" />
+
+ </RelativeLayout>
+
+
+ </android.support.v7.widget.Toolbar>
+
+ <com.mapbox.mapboxsdk.maps.MapView
+ android:id="@id/mapView"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_below="@id/toolbar"
+ app:center_latitude="38.907192"
+ app:center_longitude="-77.036871"
+ app:style_url="@string/style_mapbox_streets"
+ app:zoom="12" />
+
+</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_navigation_drawer.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_navigation_drawer.xml
new file mode 100644
index 0000000000..2bf08fbdc1
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_navigation_drawer.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/drawer_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context="com.mapbox.mapboxsdk.testapp.activity.maplayout.NavigationDrawerActivity">
+
+ <FrameLayout
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:fitsSystemWindows="true">
+
+ <android.support.v7.widget.Toolbar
+ android:id="@+id/toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="56dp" />
+
+ </FrameLayout>
+
+ <FrameLayout
+ android:id="@+id/navigation_drawer"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="start"
+ android:fitsSystemWindows="true" />
+
+</android.support.v4.widget.DrawerLayout> \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_press_for_marker.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_press_for_marker.xml
index 9378900dc3..86a97017b9 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_press_for_marker.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_press_for_marker.xml
@@ -1,8 +1,9 @@
<?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:orientation="vertical">
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
@@ -15,6 +16,13 @@
android:id="@+id/pressForMarkerMapView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ app:center_latitude="45.1855569"
+ app:center_longitude="5.7215506"
+ app:zoom="11"
+ app:style_url="@string/style_mapbox_streets"
+ app:logo_gravity="top|end"
+ app:attribution_gravity="top|end"
+ app:logo_margin_right="10dp"
android:layout_below="@id/toolbar"/>
</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_print.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_print.xml
new file mode 100644
index 0000000000..10e312e8c6
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_print.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <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">
+
+ </android.support.v7.widget.Toolbar>
+
+ <FrameLayout
+ android:id="@+id/content_frame"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <android.support.design.widget.CoordinatorLayout
+ android:id="@+id/coordinator_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <com.mapbox.mapboxsdk.maps.MapView
+ android:id="@+id/mapView"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ <android.support.design.widget.FloatingActionButton
+ android:id="@+id/fab"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end|bottom"
+ android:layout_margin="@dimen/fab_margin"
+ android:src="@drawable/ic_print_24dp"
+ app:backgroundTint="@color/accent"/>
+
+ </android.support.design.widget.CoordinatorLayout>
+
+ </FrameLayout>
+
+</LinearLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_runtime_style.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_runtime_style.xml
new file mode 100644
index 0000000000..4c0d067c14
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_runtime_style.xml
@@ -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>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_snapshot.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_snapshot.xml
index b9701b53e0..ac69780592 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_snapshot.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_snapshot.xml
@@ -29,8 +29,7 @@
android:id="@id/mapView"
android:layout_width="match_parent"
android:layout_height="0dp"
- android:layout_weight="1"
- app:style_url="@string/style_emerald" />
+ android:layout_weight="1"/>
</LinearLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_surfaceview_mediacontrols.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_surfaceview_mediacontrols.xml
new file mode 100644
index 0000000000..15394f8f33
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_surfaceview_mediacontrols.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <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="wrap_content"
+ android:layout_below="@id/toolbar"
+ app:style_url="@string/style_light" />
+
+ <FrameLayout
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="128dp"
+ android:layout_alignParentBottom="true"
+ android:paddingBottom="48dp"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp" />
+
+</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_viewpager.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_viewpager.xml
new file mode 100644
index 0000000000..9bb5560bb2
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_viewpager.xml
@@ -0,0 +1,30 @@
+<?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:orientation="vertical">
+
+ <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" />
+
+ <android.support.v4.view.ViewPager
+ android:id="@+id/viewpager"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_below="@id/toolbar">
+
+ <android.support.v4.view.PagerTabStrip
+ android:id="@+id/viewpager_header"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top"
+ android:paddingBottom="4dp"
+ android:paddingTop="4dp" />
+
+ </android.support.v4.view.ViewPager>
+
+</RelativeLayout> \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/drawer_navigation_drawer.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/drawer_navigation_drawer.xml
new file mode 100644
index 0000000000..e04a162d49
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/drawer_navigation_drawer.xml
@@ -0,0 +1,7 @@
+<ListView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="@dimen/navigation_drawer_width"
+ android:layout_height="match_parent"
+ android:background="#cccc"
+ android:choiceMode="singleChoice"
+ android:divider="@android:color/transparent"
+ android:dividerHeight="0dp" />
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/view_custom_marker.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/view_custom_marker.xml
index 08caf1df66..98050c061f 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/view_custom_marker.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/view_custom_marker.xml
@@ -14,6 +14,8 @@
android:textColor="@android:color/white"
android:layout_height="wrap_content"
android:textStyle="bold"
- android:layout_centerInParent="true" />
+ android:layout_alignBottom="@id/imageView"
+ android:layout_centerHorizontal="true"
+ android:padding="2dp"/>
</RelativeLayout> \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/view_pulse_marker.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/view_pulse_marker.xml
new file mode 100644
index 0000000000..e1ac50b440
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/view_pulse_marker.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="48dp"
+ android:layout_height="48dp">
+
+ <ImageView
+ android:id="@+id/foreground_imageView"
+ android:layout_width="@dimen/circle_size"
+ android:layout_height="@dimen/circle_size"
+ android:layout_gravity="center"
+ android:src="@drawable/ic_circle"/>
+
+ <ImageView
+ android:id="@+id/background_imageview"
+ android:layout_width="@dimen/circle_size"
+ android:layout_height="@dimen/circle_size"
+ android:layout_gravity="center"
+ android:alpha="0.5"
+ android:src="@drawable/ic_circle"/>
+
+</FrameLayout> \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_infowindow.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_infowindow.xml
index 583b760d7c..adca8d2e00 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_infowindow.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_infowindow.xml
@@ -8,6 +8,12 @@
android:id="@+id/action_toggle_concurrent_infowindow"
app:showAsAction="never"
android:checkable="true"/>
+ <item
+ android:title="@string/menuitem_title_deselect_markers_on_tap"
+ android:id="@+id/action_toggle_deselect_markers_on_tap"
+ app:showAsAction="never"
+ android:checkable="true"
+ android:checked="true"/>
</group>
</menu> \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_polygon.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_polygon.xml
new file mode 100644
index 0000000000..62d4c83594
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_polygon.xml
@@ -0,0 +1,20 @@
+<?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_id_alpha"
+ android:title="@string/action_alpha_polygon"
+ mapbox:showAsAction="never" />
+ <item
+ android:id="@+id/action_id_visible"
+ android:title="@string/action_visibility_polygon"
+ mapbox:showAsAction="never" />
+ <item
+ android:id="@+id/action_id_points"
+ android:title="@string/action_points_polygon"
+ mapbox:showAsAction="never" />
+ <item
+ android:id="@+id/action_id_color"
+ android:title="@string/action_color_polygon"
+ mapbox:showAsAction="never" />
+</menu> \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_polyline.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_polyline.xml
index 3590d0c68b..7c324fc9dc 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_polyline.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_polyline.xml
@@ -6,4 +6,20 @@
android:icon="@drawable/ic_delete_24dp"
android:title="@string/action_remove_polylines"
mapbox:showAsAction="ifRoom" />
+ <item
+ android:id="@+id/action_id_width"
+ android:title="@string/action_width_polyline"
+ mapbox:showAsAction="never" />
+ <item
+ android:id="@+id/action_id_alpha"
+ android:title="@string/action_alpha_polygon"
+ mapbox:showAsAction="never" />
+ <item
+ android:id="@+id/action_id_color"
+ android:title="@string/action_color_polygon"
+ mapbox:showAsAction="never" />
+ <item
+ android:id="@+id/action_id_visible"
+ android:title="@string/action_visibility_polygon"
+ mapbox:showAsAction="never" />
</menu> \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_runtime_style.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_runtime_style.xml
new file mode 100644
index 0000000000..189a33708f
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_runtime_style.xml
@@ -0,0 +1,45 @@
+<?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"/>
+ <item
+ android:id="@+id/action_update_water_color_on_zoom"
+ android:title="Change the water color on zoom"
+ mapbox:showAsAction="never"/>
+ <item
+ android:id="@+id/action_add_custom_tiles"
+ android:title="Custom tiles"
+ mapbox:showAsAction="never"/>
+</menu> \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/amsterdam.geojson b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/amsterdam.geojson
new file mode 100644
index 0000000000..2629a7c3c4
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/amsterdam.geojson
@@ -0,0 +1,2283 @@
+{
+ "type": "FeatureCollection",
+ "features": [
+ {
+ "type": "Feature",
+ "properties": {
+ "stroke": "#555555",
+ "stroke-width": 2,
+ "stroke-opacity": 1,
+ "fill": "#555555",
+ "fill-opacity": 0.5,
+ "name": "Westerpark",
+ "type": "park",
+ "description": "The \"Westerpark\" is a public urban park in Amsterdam, Netherlands. The former borough of Westerpark is named after the park, as is the current neighborhood. The verdant space of the former Westergasfabriek (gasworks) along Haarlemmerweg has become a place for cultural avant-garde businesses and events. The park is stretched along the railway, offering a biotope area to experience nature in the city. In addition Westerpark is home to one of the Netherlands’ oldest volkstuin (Gardenpark)."
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 4.88093376159668,
+ 52.38560608655206
+ ],
+ [
+ 4.881706237792968,
+ 52.3864966440161
+ ],
+ [
+ 4.870891571044922,
+ 52.388696767789725
+ ],
+ [
+ 4.864625930786133,
+ 52.38906344442449
+ ],
+ [
+ 4.85072135925293,
+ 52.389220590621235
+ ],
+ [
+ 4.846086502075195,
+ 52.38864438516467
+ ],
+ [
+ 4.84522819519043,
+ 52.38607756038855
+ ],
+ [
+ 4.845314025878906,
+ 52.38560608655206
+ ],
+ [
+ 4.84745979309082,
+ 52.38560608655206
+ ],
+ [
+ 4.848232269287109,
+ 52.38518699447024
+ ],
+ [
+ 4.88093376159668,
+ 52.38560608655206
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {
+ "stroke": "#555555",
+ "stroke-width": 2,
+ "stroke-opacity": 1,
+ "fill": "#555555",
+ "fill-opacity": 0.5,
+ "name": "vondelpark",
+ "type": "park",
+ "description": "Vondelpark has opened its gates since 1885 and is Amsterdam's busiest park, with 10 Million visitors per year, situated at the south-west corner of the canal ring. It is very popular in summer for both tourists and locals, and all year round as a training area for runners, with many bootcamps taking place all over the park."
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 4.881491661071777,
+ 52.36194735288177
+ ],
+ [
+ 4.882135391235352,
+ 52.361711487760196
+ ],
+ [
+ 4.882307052612305,
+ 52.361475621379526
+ ],
+ [
+ 4.875826835632324,
+ 52.35966727063089
+ ],
+ [
+ 4.875226020812988,
+ 52.35846166234964
+ ],
+ [
+ 4.866771697998047,
+ 52.356207610808546
+ ],
+ [
+ 4.867458343505859,
+ 52.355159175569305
+ ],
+ [
+ 4.86668586730957,
+ 52.35497569684526
+ ],
+ [
+ 4.864239692687988,
+ 52.35563097450493
+ ],
+ [
+ 4.861965179443359,
+ 52.35578823969753
+ ],
+ [
+ 4.858918190002441,
+ 52.35437283281734
+ ],
+ [
+ 4.857029914855957,
+ 52.35468737159704
+ ],
+ [
+ 4.855892658233642,
+ 52.354634948622525
+ ],
+ [
+ 4.855034351348877,
+ 52.356391084418235
+ ],
+ [
+ 4.875226020812988,
+ 52.36126596131745
+ ],
+ [
+ 4.876556396484375,
+ 52.360453519180375
+ ],
+ [
+ 4.881491661071777,
+ 52.36194735288177
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {
+ "stroke": "#555555",
+ "stroke-width": 2,
+ "stroke-opacity": 1,
+ "fill": "#555555",
+ "fill-opacity": 0.5,
+ "name": "Jordaan",
+ "type": "neighborhood",
+ "description": "The Jordan was originally a working-class neighbourhood, and has now become a more upscale neighborhood. It is home to many art galleries, particularly for modern art, and is also dotted with speciality shops and restaurants. Markets are held regularly at Noordermarkt, the Westerstraat and Lindengracht."
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 4.888465404510498,
+ 52.38053742479665
+ ],
+ [
+ 4.883208274841309,
+ 52.374865596670936
+ ],
+ [
+ 4.882457256317139,
+ 52.36667749309006
+ ],
+ [
+ 4.882757663726807,
+ 52.36619270976844
+ ],
+ [
+ 4.879302978515624,
+ 52.36490866337324
+ ],
+ [
+ 4.874324798583984,
+ 52.37186565170666
+ ],
+ [
+ 4.8818135261535645,
+ 52.38427021667093
+ ],
+ [
+ 4.888465404510498,
+ 52.38053742479665
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {
+ "stroke": "#555555",
+ "stroke-width": 2,
+ "stroke-opacity": 1,
+ "fill": "#555555",
+ "fill-opacity": 0.5,
+ "name": "Prinseneiland",
+ "type": "neighborhood",
+ "description": "Between 1610 and 1615 Prinseneiland was built as an extension of the harbor. Until the end of the 19th century this was an area with many wharfs, little industries and warehouses, related to the shipping trades. After the second World war the desolated area was discovered by many artists, who established their homes and studios in the vacant buildings. During the second half of the 20th century the old warehouses were transformed into apartments one after another, and new apartments were built. Nevertheless a lot of the atmosphere of the glorious past is still present in the old buildings and wooden drawbridges."
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 4.883251190185547,
+ 52.38618233166844
+ ],
+ [
+ 4.889817237854004,
+ 52.38264616355127
+ ],
+ [
+ 4.896254539489746,
+ 52.38356297507495
+ ],
+ [
+ 4.891490936279297,
+ 52.390425359543386
+ ],
+ [
+ 4.884967803955078,
+ 52.39068726147953
+ ],
+ [
+ 4.883251190185547,
+ 52.38618233166844
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {
+ "stroke": "#555555",
+ "stroke-width": 2,
+ "stroke-opacity": 1,
+ "fill": "#555555",
+ "fill-opacity": 0.5,
+ "name": "Sarphatipark",
+ "type": "park",
+ "description": "Sarphatipark is a small park in the popular De Pijp neighbourhood. It was openend in late 19th century, and named after Samuel Sarphati."
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 4.894580841064453,
+ 52.35337022551748
+ ],
+ [
+ 4.899033308029174,
+ 52.354267986060016
+ ],
+ [
+ 4.89815354347229,
+ 52.35544094498385
+ ],
+ [
+ 4.893786907196045,
+ 52.35446457352601
+ ],
+ [
+ 4.894580841064453,
+ 52.35337022551748
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {
+ "stroke": "#555555",
+ "stroke-width": 2,
+ "stroke-opacity": 1,
+ "fill": "#555555",
+ "fill-opacity": 0.5,
+ "name": "Museumsplein",
+ "type": "area",
+ "description": "Museumplein is a large open space which hosts different events throughout the year. Along the edges of the open square, some of the Dutch capitals most important art museums, such as Stedelijk Museum, Van Gogh Museum and Rijksmuseum."
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 4.880322217941284,
+ 52.35625347928239
+ ],
+ [
+ 4.881459474563598,
+ 52.35610932106146
+ ],
+ [
+ 4.882693290710448,
+ 52.356921843071525
+ ],
+ [
+ 4.883508682250977,
+ 52.357996446011384
+ ],
+ [
+ 4.884324073791504,
+ 52.35783263627572
+ ],
+ [
+ 4.884721040725708,
+ 52.35903498560687
+ ],
+ [
+ 4.886341094970703,
+ 52.35875651523955
+ ],
+ [
+ 4.886770248413086,
+ 52.36003418836164
+ ],
+ [
+ 4.884881973266602,
+ 52.36113492327348
+ ],
+ [
+ 4.884538650512695,
+ 52.36066318309746
+ ],
+ [
+ 4.883229732513428,
+ 52.36028971855292
+ ],
+ [
+ 4.883841276168823,
+ 52.35953622784582
+ ],
+ [
+ 4.882038831710815,
+ 52.35897929167382
+ ],
+ [
+ 4.882339239120483,
+ 52.35861236518361
+ ],
+ [
+ 4.880794286727905,
+ 52.35790471263422
+ ],
+ [
+ 4.880847930908203,
+ 52.357780217032044
+ ],
+ [
+ 4.879699945449829,
+ 52.35691529053445
+ ],
+ [
+ 4.880322217941284,
+ 52.35625347928239
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {
+ "stroke": "#555555",
+ "stroke-width": 2,
+ "stroke-opacity": 1,
+ "fill": "#555555",
+ "fill-opacity": 0.5,
+ "name": "Marineterrein",
+ "type": "area",
+ "description": "The Marineterrein exists already for more than 350 years. The area lies on the island known as ‘Kattenburg’, in close vicinity to Centraal Station and Amsterdam’s Maritime Museum. During the Golden Age the VOC used this area to build large warships. After years of use through the Dutch marines, the area has now been opened for the public and workspaces are filled by tech startups."
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 4.914064407348633,
+ 52.37083068892153
+ ],
+ [
+ 4.917154312133789,
+ 52.37187875234601
+ ],
+ [
+ 4.921102523803711,
+ 52.37444640263532
+ ],
+ [
+ 4.921188354492187,
+ 52.37481319763409
+ ],
+ [
+ 4.914150238037109,
+ 52.37586116655898
+ ],
+ [
+ 4.913034439086914,
+ 52.374917995645625
+ ],
+ [
+ 4.914493560791016,
+ 52.37339840013861
+ ],
+ [
+ 4.914064407348633,
+ 52.37083068892153
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {
+ "stroke": "#555555",
+ "stroke-width": 2,
+ "stroke-opacity": 1,
+ "fill": "#555555",
+ "fill-opacity": 0.5,
+ "name": "erasmuspark"
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 4.849905967712402,
+ 52.37300539279099
+ ],
+ [
+ 4.852695465087891,
+ 52.37350320150736
+ ],
+ [
+ 4.855098724365234,
+ 52.37428920384616
+ ],
+ [
+ 4.854240417480469,
+ 52.3765423330248
+ ],
+ [
+ 4.848318099975586,
+ 52.37552057938607
+ ],
+ [
+ 4.849905967712402,
+ 52.37300539279099
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {
+ "stroke": "#555555",
+ "stroke-width": 2,
+ "stroke-opacity": 1,
+ "fill": "#555555",
+ "fill-opacity": 0.5,
+ "name": "Sloterdijk",
+ "type": "area",
+ "description": "To protect the area around Sloten from the as-yet undrained IJ the Spaarndammerdijk was laid along the south bank of this inlet. In this vicinity at the same time, a dam on the Slochter (or Slooter) river was built, the Slooterdam. Trade grew in the vicinity, and in the 15th century a weigh house and a church were built. The area is nowadays best known as a large intersection of train lines and a business and industrial centre north-west of Amsterdam."
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 4.8665571212768555,
+ 52.39312287505632
+ ],
+ [
+ 4.849648475646973,
+ 52.400638383557414
+ ],
+ [
+ 4.845571517944336,
+ 52.39681532315127
+ ],
+ [
+ 4.8445844650268555,
+ 52.39411803332277
+ ],
+ [
+ 4.844756126403809,
+ 52.38911582655221
+ ],
+ [
+ 4.85072135925293,
+ 52.38935154535783
+ ],
+ [
+ 4.871063232421875,
+ 52.389299163509826
+ ],
+ [
+ 4.8665571212768555,
+ 52.39312287505632
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {
+ "stroke": "#555555",
+ "stroke-width": 2,
+ "stroke-opacity": 1,
+ "fill": "#555555",
+ "fill-opacity": 0.5,
+ "name": "Nine Streets (Negen Straatjes)",
+ "type": "poi",
+ "description": "De Negen Straatjes (Dutch for \"the nine little streets\") are nine side streets of the Prinsengracht, Keizersgracht, Herengracht and Singel in central Amsterdam which have been promoting themselves with that name since the 1990s. Together they form a sub-neighborhood within the larger western Grachtengordel (\"Canal Belt\"), one with many small and diverse shops and restaurants. The construction in this area goes back to the first half of the 17th century."
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 4.887650012969971,
+ 52.368629674781644
+ ],
+ [
+ 4.8884546756744385,
+ 52.37242897568859
+ ],
+ [
+ 4.883047342300415,
+ 52.372664783594274
+ ],
+ [
+ 4.882628917694092,
+ 52.36839384533322
+ ],
+ [
+ 4.887650012969971,
+ 52.368629674781644
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {
+ "stroke": "#555555",
+ "stroke-width": 2,
+ "stroke-opacity": 1,
+ "fill": "#555555",
+ "fill-opacity": 0.5,
+ "name": "Artis",
+ "type": "poi",
+ "description": "Artis, short for Natura Artis Magistra (Latin for \"Nature is the teacher of art and science\"), is a zoo in the centre of Amsterdam. It is the oldest zoo in the Netherlands and one of the oldest zoos of mainland Europe. Artis Royal Zoo is not just a zoo, it also contains an aquarium and a planetarium. Artis also has an arboretum and a fairly large art collection. A part of the art collection is on display in the Aquarium building of the zoo. Artis contains 27 monumental buildings, most of which are used as enclosures for the animals, making Artis a unique cultural heritage of the 19th century."
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 4.911768436431885,
+ 52.36642855096776
+ ],
+ [
+ 4.913313388824463,
+ 52.36802699702209
+ ],
+ [
+ 4.916939735412598,
+ 52.36679541255308
+ ],
+ [
+ 4.9175190925598145,
+ 52.3673456992188
+ ],
+ [
+ 4.921274185180664,
+ 52.366048583971256
+ ],
+ [
+ 4.921660423278808,
+ 52.36551138367574
+ ],
+ [
+ 4.918656349182129,
+ 52.36400456750192
+ ],
+ [
+ 4.911768436431885,
+ 52.36642855096776
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {
+ "stroke": "#555555",
+ "stroke-width": 2,
+ "stroke-opacity": 1,
+ "fill": "#555555",
+ "fill-opacity": 0.5,
+ "name": "Oosterpark",
+ "type": "park",
+ "description": "Oosterpark was the first large park opened by the municipality of Amsterdam in 1891. The park was designed as an English garden by Dutch landscape architect Leonard Anthony Springer."
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 4.915802478790282,
+ 52.36062387118878
+ ],
+ [
+ 4.9173688888549805,
+ 52.35804231262857
+ ],
+ [
+ 4.925351142883301,
+ 52.36002108420944
+ ],
+ [
+ 4.923892021179199,
+ 52.36192114570822
+ ],
+ [
+ 4.92213249206543,
+ 52.36150182881734
+ ],
+ [
+ 4.92161750793457,
+ 52.36223563076494
+ ],
+ [
+ 4.919493198394775,
+ 52.36159355472725
+ ],
+ [
+ 4.91987943649292,
+ 52.36101698870163
+ ],
+ [
+ 4.918956756591797,
+ 52.360741806809884
+ ],
+ [
+ 4.918656349182129,
+ 52.36097767710775
+ ],
+ [
+ 4.917240142822266,
+ 52.36063697516221
+ ],
+ [
+ 4.916982650756836,
+ 52.360899053815025
+ ],
+ [
+ 4.915802478790282,
+ 52.36062387118878
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {
+ "stroke": "#555555",
+ "stroke-width": 2,
+ "stroke-opacity": 1,
+ "fill": "#555555",
+ "fill-opacity": 0.5,
+ "name": "Park Frankendael",
+ "type": "park",
+ "description": "As Amsterdam rapidly grew in the sixteen and the beginning of eighteen century, the real estate in the city became so expensive, that rich people who wanted to enjoy a bigger property had to move further from the capital. The Park Frankendael (7 acres) in East Amsterdam, was originally one of these wealthy estates. The entrance to the park with an old ornamented gate is at the Middenweg, less than one mile (1300m) from the Tropenmuseum, driving out of the city. The beautiful old land house Frankendael (built in 1659) is visible from the street – it is one of the few of these estates remaining in Amsterdam"
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 4.925265312194824,
+ 52.35007391180776
+ ],
+ [
+ 4.9283552169799805,
+ 52.352079253210675
+ ],
+ [
+ 4.930479526519775,
+ 52.3535995821349
+ ],
+ [
+ 4.93483543395996,
+ 52.35080790353051
+ ],
+ [
+ 4.929170608520508,
+ 52.34772767795072
+ ],
+ [
+ 4.925265312194824,
+ 52.35007391180776
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {
+ "stroke": "#555555",
+ "stroke-width": 2,
+ "stroke-opacity": 1,
+ "fill": "#555555",
+ "fill-opacity": 0.5,
+ "name": "Stedelijk Museum",
+ "type": "poi",
+ "description": "Colloquially known as the Stedelijk, it is a museum for modern art, contemporary art, and design. The 19th century building was designed by Adriaan Willem Weissman and the 21st century wing with the current entrance was designed by Benthem Crouwel Architects. The collection comprises art from the early 20th century up to the 21st century. "
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 4.879399538040161,
+ 52.357400175655954
+ ],
+ [
+ 4.88067626953125,
+ 52.3577933218488
+ ],
+ [
+ 4.880236387252808,
+ 52.35841579616774
+ ],
+ [
+ 4.8789381980896,
+ 52.35808817919812
+ ],
+ [
+ 4.879399538040161,
+ 52.357400175655954
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {
+ "stroke": "#555555",
+ "stroke-width": 2,
+ "stroke-opacity": 1,
+ "fill": "#555555",
+ "fill-opacity": 0.5,
+ "name": "Rembrandtpark",
+ "type": "park",
+ "description": "Rembrandtpark is a hidden gem west of the 'famous' Vondelpark. It is often not known to tourists and expats, but loved by locals for the outdoor gym and kids' playgrounds. It's great to combine both, Vondelpark and Rembrandtpark on a run or walk."
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 4.845314025878906,
+ 52.369179938598464
+ ],
+ [
+ 4.84522819519043,
+ 52.36763394187947
+ ],
+ [
+ 4.843039512634277,
+ 52.36755533043126
+ ],
+ [
+ 4.8429107666015625,
+ 52.36490866337324
+ ],
+ [
+ 4.8442840576171875,
+ 52.36456799173892
+ ],
+ [
+ 4.84419822692871,
+ 52.36323148534417
+ ],
+ [
+ 4.843082427978516,
+ 52.36302183361385
+ ],
+ [
+ 4.843254089355469,
+ 52.36019143788499
+ ],
+ [
+ 4.844799041748047,
+ 52.36027006243683
+ ],
+ [
+ 4.8451852798461905,
+ 52.35924793235075
+ ],
+ [
+ 4.843854904174805,
+ 52.35888100809126
+ ],
+ [
+ 4.844112396240234,
+ 52.35822577862119
+ ],
+ [
+ 4.848747253417969,
+ 52.35825198798652
+ ],
+ [
+ 4.8487043380737305,
+ 52.36079422254044
+ ],
+ [
+ 4.849519729614258,
+ 52.361292168879636
+ ],
+ [
+ 4.849262237548828,
+ 52.363572167284175
+ ],
+ [
+ 4.850249290466309,
+ 52.3637031981001
+ ],
+ [
+ 4.850249290466309,
+ 52.36540656334422
+ ],
+ [
+ 4.8484039306640625,
+ 52.369546777334904
+ ],
+ [
+ 4.845314025878906,
+ 52.369179938598464
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {
+ "stroke": "#555555",
+ "stroke-width": 2,
+ "stroke-opacity": 1,
+ "fill": "#555555",
+ "fill-opacity": 0.5,
+ "name": "Sloterpark",
+ "type": "park",
+ "description": "Amsterdam's largest park is Sloter Park with 91 hectares. It was created in the 1950s using excavated soil of the former Sloterdijkermeer Polder."
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 4.823555946350098,
+ 52.3639652585661
+ ],
+ [
+ 4.826860427856445,
+ 52.36414869996741
+ ],
+ [
+ 4.826817512512207,
+ 52.36585204803552
+ ],
+ [
+ 4.830508232116699,
+ 52.370280445668364
+ ],
+ [
+ 4.826602935791016,
+ 52.373031593389626
+ ],
+ [
+ 4.822740554809569,
+ 52.37360800262741
+ ],
+ [
+ 4.821324348449707,
+ 52.37235037277361
+ ],
+ [
+ 4.819135665893555,
+ 52.371695343041914
+ ],
+ [
+ 4.81201171875,
+ 52.37187875234601
+ ],
+ [
+ 4.807548522949219,
+ 52.372402774732464
+ ],
+ [
+ 4.805660247802734,
+ 52.37046386084771
+ ],
+ [
+ 4.80926513671875,
+ 52.36349354860812
+ ],
+ [
+ 4.8105525970458975,
+ 52.36328389812132
+ ],
+ [
+ 4.8113250732421875,
+ 52.36150182881734
+ ],
+ [
+ 4.807033538818359,
+ 52.360899053815025
+ ],
+ [
+ 4.809608459472655,
+ 52.35654834690599
+ ],
+ [
+ 4.815659523010254,
+ 52.3577540073869
+ ],
+ [
+ 4.818663597106934,
+ 52.357963684112846
+ ],
+ [
+ 4.818620681762695,
+ 52.359483810623004
+ ],
+ [
+ 4.823555946350098,
+ 52.3639652585661
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {
+ "stroke": "#555555",
+ "stroke-width": 2,
+ "stroke-opacity": 1,
+ "fill": "#555555",
+ "fill-opacity": 0.5,
+ "name": "Amsterdamse Bos",
+ "type": "park",
+ "description": "Every year almost 4.5 million people visit the Amsterdamse Bos, which has a size of 1,000 hectares and is approximately three times the size of New York's Central Park. The park was designed as a landscape park and is great for running, walking and cycling."
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 4.849991798400879,
+ 52.33090717211467
+ ],
+ [
+ 4.849863052368164,
+ 52.331746382485676
+ ],
+ [
+ 4.853982925415039,
+ 52.33187750766789
+ ],
+ [
+ 4.853467941284179,
+ 52.332323330379836
+ ],
+ [
+ 4.848232269287109,
+ 52.33258557693488
+ ],
+ [
+ 4.848318099975586,
+ 52.33321496232317
+ ],
+ [
+ 4.8319244384765625,
+ 52.33145790571652
+ ],
+ [
+ 4.8181915283203125,
+ 52.330828495326095
+ ],
+ [
+ 4.820079803466797,
+ 52.32327487205222
+ ],
+ [
+ 4.816474914550781,
+ 52.31299147898779
+ ],
+ [
+ 4.813899993896484,
+ 52.30879348896445
+ ],
+ [
+ 4.809093475341796,
+ 52.30585465906291
+ ],
+ [
+ 4.824028015136719,
+ 52.29000260620264
+ ],
+ [
+ 4.832954406738281,
+ 52.29441235610253
+ ],
+ [
+ 4.8427391052246085,
+ 52.29220753602784
+ ],
+ [
+ 4.844627380371094,
+ 52.30060626328963
+ ],
+ [
+ 4.842395782470703,
+ 52.30396530825102
+ ],
+ [
+ 4.842395782470703,
+ 52.30407027430016
+ ],
+ [
+ 4.839649200439453,
+ 52.30504119845803
+ ],
+ [
+ 4.841108322143555,
+ 52.30732409839935
+ ],
+ [
+ 4.840335845947266,
+ 52.31708413595253
+ ],
+ [
+ 4.848575592041015,
+ 52.317189070898415
+ ],
+ [
+ 4.8558712005615225,
+ 52.31645452105213
+ ],
+ [
+ 4.8566436767578125,
+ 52.323484712336324
+ ],
+ [
+ 4.856557846069336,
+ 52.32757639896581
+ ],
+ [
+ 4.855785369873047,
+ 52.33085472093785
+ ],
+ [
+ 4.849991798400879,
+ 52.33090717211467
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {
+ "stroke": "#555555",
+ "stroke-width": 2,
+ "stroke-opacity": 1,
+ "fill": "#555555",
+ "fill-opacity": 0.5,
+ "name": "Amstelpark",
+ "type": "park",
+ "description": "The Amstelpark is a park in Amsterdam-Zuid. The park includes a labyrinth, a café, a restaurant, two galleries, an orangery, petting zoo and a mini-golf course. The Amstelpark was built and opened for the 1972 Floriade gardening exhibition. The park offers the Amstel train which runs through the Rosarium, the rhododendron valley and the Riekermolen. The park lost about 30 percent of its larger trees due to disease. The rhododendron valley contains about 139 species of rhododendrons, blooming between April and May. At the Great Pond in the park is the Japanese Garden. At the time of the celebration of the 400-year relationship between the Netherlands and Japan in 2001, the gardens were renovated."
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 4.892907142639159,
+ 52.32445521070514
+ ],
+ [
+ 4.891705513000488,
+ 52.325110940795255
+ ],
+ [
+ 4.890632629394531,
+ 52.32513716979672
+ ],
+ [
+ 4.89041805267334,
+ 52.3336869954871
+ ],
+ [
+ 4.892778396606445,
+ 52.33373944330546
+ ],
+ [
+ 4.894108772277832,
+ 52.333949233956965
+ ],
+ [
+ 4.897370338439941,
+ 52.33255935234935
+ ],
+ [
+ 4.897799491882323,
+ 52.33085472093785
+ ],
+ [
+ 4.897327423095702,
+ 52.32907134391899
+ ],
+ [
+ 4.895954132080078,
+ 52.32734035040776
+ ],
+ [
+ 4.894537925720215,
+ 52.32458635750065
+ ],
+ [
+ 4.892907142639159,
+ 52.32445521070514
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {
+ "stroke": "#555555",
+ "stroke-width": 2,
+ "stroke-opacity": 1,
+ "fill": "#555555",
+ "fill-opacity": 0.5,
+ "name": "Martin Luther Kingpark",
+ "type": "park",
+ "description": "Martin Luther Kingpark is part of the Rivierenbuurt and has been renamed from Amstelpark, after the new Amstelpark in Buitenveldert was created. The park hosts the famous theater festival Parade every year in summer since the 1990s. "
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 4.906554222106933,
+ 52.33813172737753
+ ],
+ [
+ 4.906167984008789,
+ 52.33685997655858
+ ],
+ [
+ 4.90389347076416,
+ 52.33743685775091
+ ],
+ [
+ 4.901747703552246,
+ 52.33821039117558
+ ],
+ [
+ 4.901790618896484,
+ 52.3400982803501
+ ],
+ [
+ 4.90689754486084,
+ 52.34004584007248
+ ],
+ [
+ 4.905717372894287,
+ 52.33836771835187
+ ],
+ [
+ 4.906554222106933,
+ 52.33813172737753
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {
+ "stroke": "#555555",
+ "stroke-width": 2,
+ "stroke-opacity": 1,
+ "fill": "#555555",
+ "fill-opacity": 0.5,
+ "name": "Beatrixpark",
+ "type": "park",
+ "description": "Beatrixpark, named after Queen Beatrix is located in the borough of Amsterdam-Zuid."
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 4.87818717956543,
+ 52.34435884510934
+ ],
+ [
+ 4.88093376159668,
+ 52.34582700615622
+ ],
+ [
+ 4.882993698120117,
+ 52.34456858538671
+ ],
+ [
+ 4.8854827880859375,
+ 52.34435884510934
+ ],
+ [
+ 4.884710311889648,
+ 52.33984918847747
+ ],
+ [
+ 4.882392883300781,
+ 52.33995406943698
+ ],
+ [
+ 4.879045486450195,
+ 52.33984918847747
+ ],
+ [
+ 4.878787994384765,
+ 52.340688229188224
+ ],
+ [
+ 4.881620407104492,
+ 52.34074066870404
+ ],
+ [
+ 4.881706237792968,
+ 52.341789445960536
+ ],
+ [
+ 4.878444671630859,
+ 52.341789445960536
+ ],
+ [
+ 4.87818717956543,
+ 52.34435884510934
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {
+ "stroke": "#555555",
+ "stroke-width": 2,
+ "stroke-opacity": 1,
+ "fill": "#555555",
+ "fill-opacity": 0.5,
+ "name": "Park de Schinkeleilanden",
+ "type": "Park",
+ "description": "This park was built between 2005 and 2010 and is popular for the neighborhoods surrounding the Schinkel waterway. It's allowed to BBQ here, and it's a popular spot for running and hiking."
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 4.851171970367432,
+ 52.34405734171741
+ ],
+ [
+ 4.851021766662597,
+ 52.34514536601911
+ ],
+ [
+ 4.851686954498291,
+ 52.34628579648493
+ ],
+ [
+ 4.851021766662597,
+ 52.3465610683968
+ ],
+ [
+ 4.848833084106445,
+ 52.342785761313266
+ ],
+ [
+ 4.849659204483032,
+ 52.340747223639156
+ ],
+ [
+ 4.852405786514282,
+ 52.34110774357341
+ ],
+ [
+ 4.852041006088257,
+ 52.34196642466951
+ ],
+ [
+ 4.852041006088257,
+ 52.341979534175316
+ ],
+ [
+ 4.851665496826172,
+ 52.34280870252078
+ ],
+ [
+ 4.851171970367432,
+ 52.34405734171741
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {
+ "stroke": "#555555",
+ "stroke-width": 2,
+ "stroke-opacity": 1,
+ "fill": "#555555",
+ "fill-opacity": 0.5,
+ "name": "Schiphol",
+ "type": "area",
+ "description": "Schiphol is the main international airport of the Netherlands. Schiphol Airport is an important European airport, ranking as Europe's fifth busiest and the world's fourteenth busiest by total passenger traffic in 2015. It also ranks as the world's fifth busiest by international passenger traffic. The entire airport is below sea level; the lowest point sits at 3.4 m (11 ft) below sea level."
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 4.729099273681641,
+ 52.28811257899827
+ ],
+ [
+ 4.734764099121094,
+ 52.28559241729168
+ ],
+ [
+ 4.762744903564453,
+ 52.292522517043615
+ ],
+ [
+ 4.776134490966797,
+ 52.284857343123655
+ ],
+ [
+ 4.7907257080078125,
+ 52.293992398835414
+ ],
+ [
+ 4.793128967285156,
+ 52.30081621106509
+ ],
+ [
+ 4.803943634033203,
+ 52.30564473517634
+ ],
+ [
+ 4.810981750488281,
+ 52.311942018805624
+ ],
+ [
+ 4.796905517578125,
+ 52.319707434957024
+ ],
+ [
+ 4.788494110107422,
+ 52.320966563244205
+ ],
+ [
+ 4.779567718505859,
+ 52.32442898129939
+ ],
+ [
+ 4.77081298828125,
+ 52.3191827875965
+ ],
+ [
+ 4.756736755371094,
+ 52.31886799619451
+ ],
+ [
+ 4.750041961669922,
+ 52.310367781878
+ ],
+ [
+ 4.7454071044921875,
+ 52.30281066528705
+ ],
+ [
+ 4.7426605224609375,
+ 52.29798183210937
+ ],
+ [
+ 4.729099273681641,
+ 52.28811257899827
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {
+ "stroke": "#555555",
+ "stroke-width": 2,
+ "stroke-opacity": 1,
+ "fill": "#555555",
+ "fill-opacity": 0.5,
+ "name": "Noorderpark",
+ "type": "park",
+ "description": "The Noorderpark is a park just 5 minutes north of the ferry that crosses the IJ canal behind Amsterdam Central Station. It came to exist in 2014 after combining Florapark and Volewijkspark."
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 4.921703338623047,
+ 52.39046464493288
+ ],
+ [
+ 4.921939373016357,
+ 52.389652739777624
+ ],
+ [
+ 4.92436408996582,
+ 52.39068726147955
+ ],
+ [
+ 4.924213886260986,
+ 52.390922971893374
+ ],
+ [
+ 4.92460012435913,
+ 52.39105392157937
+ ],
+ [
+ 4.923999309539795,
+ 52.39326691251008
+ ],
+ [
+ 4.924793243408203,
+ 52.39486438729677
+ ],
+ [
+ 4.922282695770264,
+ 52.39698553494043
+ ],
+ [
+ 4.919922351837158,
+ 52.39847813327716
+ ],
+ [
+ 4.917948246002197,
+ 52.397705654476155
+ ],
+ [
+ 4.918398857116699,
+ 52.39618684316538
+ ],
+ [
+ 4.917948246002197,
+ 52.39527029380819
+ ],
+ [
+ 4.917197227478027,
+ 52.39200984251752
+ ],
+ [
+ 4.9161458015441895,
+ 52.39068726147955
+ ],
+ [
+ 4.918420314788818,
+ 52.389901551009025
+ ],
+ [
+ 4.920244216918945,
+ 52.39115868104846
+ ],
+ [
+ 4.921402931213379,
+ 52.39157771643836
+ ],
+ [
+ 4.922153949737548,
+ 52.39121106068977
+ ],
+ [
+ 4.921703338623047,
+ 52.39046464493288
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {
+ "stroke": "#555555",
+ "stroke-width": 2,
+ "stroke-opacity": 1,
+ "fill": "#555555",
+ "fill-opacity": 0.5,
+ "name": "Vliegenbos",
+ "type": "park",
+ "description": "The Vliegenbos is the oldest city forest in Amsterdam. Here you've got plenty of space to run or cycle through a dense forest. It also hosts a camping ground, and is an amazingly well located starting point for excursions to the fishing villages along the IJsselmeer. "
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 4.925222396850586,
+ 52.389403927143704
+ ],
+ [
+ 4.925136566162109,
+ 52.39003250372539
+ ],
+ [
+ 4.926724433898926,
+ 52.39105392157937
+ ],
+ [
+ 4.933032989501953,
+ 52.391525337232174
+ ],
+ [
+ 4.93311882019043,
+ 52.390739641680284
+ ],
+ [
+ 4.938998222351074,
+ 52.38969202585476
+ ],
+ [
+ 4.9376678466796875,
+ 52.38686333892666
+ ],
+ [
+ 4.927024841308593,
+ 52.38906344442449
+ ],
+ [
+ 4.926466941833496,
+ 52.38948249970591
+ ],
+ [
+ 4.9253082275390625,
+ 52.38945630886739
+ ],
+ [
+ 4.925222396850586,
+ 52.389403927143704
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {
+ "stroke": "#555555",
+ "stroke-width": 2,
+ "stroke-opacity": 1,
+ "fill": "#555555",
+ "fill-opacity": 0.5,
+ "name": "Flevopark",
+ "type": "park",
+ "description": "Flevopark is the jewel in the East of Amsterdam. Its offerings include an outdoor swimming pool, several lakes, restaurants. It's awesome for a bbq in summer or a foggy walk or run on a winter morning."
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 4.948225021362305,
+ 52.36493486877479
+ ],
+ [
+ 4.9527740478515625,
+ 52.36517071668903
+ ],
+ [
+ 4.954404830932617,
+ 52.36517071668903
+ ],
+ [
+ 4.955005645751953,
+ 52.36459419734253
+ ],
+ [
+ 4.952559471130371,
+ 52.36215700971062
+ ],
+ [
+ 4.952859878540038,
+ 52.35953622784585
+ ],
+ [
+ 4.952731132507324,
+ 52.35809473156134
+ ],
+ [
+ 4.944963455200195,
+ 52.35859270832139
+ ],
+ [
+ 4.946165084838867,
+ 52.362314251679365
+ ],
+ [
+ 4.947195053100586,
+ 52.362602527168704
+ ],
+ [
+ 4.947667121887207,
+ 52.36417490581972
+ ],
+ [
+ 4.948225021362305,
+ 52.36493486877479
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {
+ "stroke": "#555555",
+ "stroke-width": 2,
+ "stroke-opacity": 1,
+ "fill": "#555555",
+ "fill-opacity": 0.5,
+ "name": "Amsterdam Centraal",
+ "type": "station",
+ "description": "Amsterdam's Central Station."
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 4.896576404571533,
+ 52.37985631995486
+ ],
+ [
+ 4.89715576171875,
+ 52.38066840529253
+ ],
+ [
+ 4.90389347076416,
+ 52.37820590695898
+ ],
+ [
+ 4.902949333190918,
+ 52.37738067732881
+ ],
+ [
+ 4.896576404571533,
+ 52.37985631995486
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {
+ "stroke": "#555555",
+ "stroke-width": 2,
+ "stroke-opacity": 1,
+ "fill": "#555555",
+ "fill-opacity": 0.5,
+ "name": "Amsterdam Amstel",
+ "type": "station",
+ "description": "Amsterdam Amstel is a trainstation in the South East, close to the river Amstel."
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 4.916896820068359,
+ 52.3468101224592
+ ],
+ [
+ 4.917690753936768,
+ 52.34704606711881
+ ],
+ [
+ 4.918248653411864,
+ 52.34604984776767
+ ],
+ [
+ 4.9173903465271,
+ 52.34584011451739
+ ],
+ [
+ 4.916896820068359,
+ 52.3468101224592
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {
+ "stroke": "#555555",
+ "stroke-width": 2,
+ "stroke-opacity": 1,
+ "fill": "#555555",
+ "fill-opacity": 0.5,
+ "name": "Ouderkerk",
+ "type": "poi",
+ "description": "Ouderkerk aan de Amstel is a picturesque village in the Dutch province of North Holland. It lies about 9 km south of Amsterdam. The town is a popular destination for Amsterdammers on the weekends. The town is the location of the Beth Haim of Ouderkerk aan de Amstel, the oldest Jewish cemetery in the Netherlands."
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 4.922518730163574,
+ 52.29236502681571
+ ],
+ [
+ 4.922819137573242,
+ 52.28777131549237
+ ],
+ [
+ 4.90788459777832,
+ 52.29034385252062
+ ],
+ [
+ 4.892692565917969,
+ 52.29456983905114
+ ],
+ [
+ 4.898228645324707,
+ 52.29824428222637
+ ],
+ [
+ 4.902563095092773,
+ 52.299267822821434
+ ],
+ [
+ 4.908742904663086,
+ 52.29879542240944
+ ],
+ [
+ 4.916167259216309,
+ 52.30149853446092
+ ],
+ [
+ 4.920544624328613,
+ 52.29666955819423
+ ],
+ [
+ 4.922518730163574,
+ 52.29236502681571
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {
+ "stroke": "#555555",
+ "stroke-width": 2,
+ "stroke-opacity": 1,
+ "fill": "#555555",
+ "fill-opacity": 0.5,
+ "name": "NDSM terrein",
+ "type": "poi",
+ "description": "The former NDSM Amsterdam ship wharf is a stunning hangout. Just 10 minutes by free ferry and a large area is there to explore. Restaurants, bars, terraces, skatepark, new and old architecture, all with the amazing view on the IJ-waters. Many of the old buildings that were in use for the making of large ships are still there, housing creative enterprises."
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 4.890182018280029,
+ 52.401711923144106
+ ],
+ [
+ 4.894495010375977,
+ 52.40307344797437
+ ],
+ [
+ 4.899129867553711,
+ 52.400939500955296
+ ],
+ [
+ 4.896554946899414,
+ 52.39881854337136
+ ],
+ [
+ 4.8909544944763175,
+ 52.39813772055684
+ ],
+ [
+ 4.891490936279297,
+ 52.400847856747404
+ ],
+ [
+ 4.890182018280029,
+ 52.401711923144106
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {
+ "stroke": "#555555",
+ "stroke-width": 2,
+ "stroke-opacity": 1,
+ "fill": "#555555",
+ "fill-opacity": 0.5,
+ "name": "Amsterdam Zuid",
+ "type": "station",
+ "description": "Station Amsterdam Zuid"
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 4.8720502853393555,
+ 52.33950832364112
+ ],
+ [
+ 4.874711036682129,
+ 52.33969186657182
+ ],
+ [
+ 4.8749041557312,
+ 52.338459492279576
+ ],
+ [
+ 4.872071743011475,
+ 52.33835460777523
+ ],
+ [
+ 4.8720502853393555,
+ 52.33950832364112
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {
+ "stroke": "#555555",
+ "stroke-width": 2,
+ "stroke-opacity": 1,
+ "fill": "#555555",
+ "fill-opacity": 0.5,
+ "name": "Het Twiske",
+ "type": "park",
+ "description": "Het Twiske recreational area lies to the north of Amsterdam between Zaanstad and Purmerend. It’s the ideal place for a day out on your bicycle, as Amsterdam’s bike paths connect directly to the paths in Het Twiske."
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 4.888744354248047,
+ 52.43555429631541
+ ],
+ [
+ 4.900503158569336,
+ 52.43445541622349
+ ],
+ [
+ 4.910116195678711,
+ 52.43586825702301
+ ],
+ [
+ 4.910888671875,
+ 52.442199320554714
+ ],
+ [
+ 4.907197952270508,
+ 52.44852947442261
+ ],
+ [
+ 4.90565299987793,
+ 52.449941863962756
+ ],
+ [
+ 4.905910491943359,
+ 52.45135420821245
+ ],
+ [
+ 4.903764724731445,
+ 52.4549633266463
+ ],
+ [
+ 4.903507232666016,
+ 52.45846754991504
+ ],
+ [
+ 4.904794692993164,
+ 52.461866903001194
+ ],
+ [
+ 4.906854629516602,
+ 52.46489995032684
+ ],
+ [
+ 4.906940460205078,
+ 52.465736616263186
+ ],
+ [
+ 4.9031639099121085,
+ 52.4673576112622
+ ],
+ [
+ 4.896640777587891,
+ 52.468560246396606
+ ],
+ [
+ 4.895782470703125,
+ 52.46793278868704
+ ],
+ [
+ 4.892778396606445,
+ 52.465422868400594
+ ],
+ [
+ 4.890289306640625,
+ 52.46416785458775
+ ],
+ [
+ 4.882049560546875,
+ 52.46191919869101
+ ],
+ [
+ 4.876041412353516,
+ 52.45982732264483
+ ],
+ [
+ 4.87492561340332,
+ 52.45825835038316
+ ],
+ [
+ 4.873895645141601,
+ 52.45648011423114
+ ],
+ [
+ 4.873037338256836,
+ 52.454911022694276
+ ],
+ [
+ 4.873552322387695,
+ 52.452714200611055
+ ],
+ [
+ 4.874839782714844,
+ 52.44805866784458
+ ],
+ [
+ 4.879388809204102,
+ 52.44277482667677
+ ],
+ [
+ 4.883165359497069,
+ 52.43926935464697
+ ],
+ [
+ 4.887542724609374,
+ 52.43597291009513
+ ],
+ [
+ 4.888744354248047,
+ 52.43555429631541
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {
+ "stroke": "#555555",
+ "stroke-width": 2,
+ "stroke-opacity": 1,
+ "fill": "#555555",
+ "fill-opacity": 0.5,
+ "name": "Diemerpark",
+ "type": "park"
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 4.974660873413086,
+ 52.35694150067703
+ ],
+ [
+ 4.980497360229492,
+ 52.357989893633615
+ ],
+ [
+ 4.985218048095703,
+ 52.35827819733633
+ ],
+ [
+ 4.986248016357422,
+ 52.35720360124792
+ ],
+ [
+ 4.985218048095703,
+ 52.355971715048284
+ ],
+ [
+ 4.985218048095703,
+ 52.3552640202125
+ ],
+ [
+ 4.986376762390137,
+ 52.3545563140442
+ ],
+ [
+ 4.987921714782714,
+ 52.353901020450564
+ ],
+ [
+ 4.988865852355957,
+ 52.353901020450564
+ ],
+ [
+ 4.989681243896484,
+ 52.353219504806525
+ ],
+ [
+ 4.991183280944824,
+ 52.352642829515084
+ ],
+ [
+ 4.992728233337402,
+ 52.35169916280845
+ ],
+ [
+ 4.994831085205078,
+ 52.34996905485244
+ ],
+ [
+ 4.995818138122559,
+ 52.34991662628147
+ ],
+ [
+ 4.997320175170898,
+ 52.348763181988105
+ ],
+ [
+ 4.997320175170898,
+ 52.348081587122245
+ ],
+ [
+ 4.99852180480957,
+ 52.34658728467996
+ ],
+ [
+ 4.999551773071289,
+ 52.34535510256526
+ ],
+ [
+ 4.999337196350098,
+ 52.345197800248926
+ ],
+ [
+ 4.976506233215332,
+ 52.35573581802885
+ ],
+ [
+ 4.974660873413086,
+ 52.35694150067703
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {
+ "stroke": "#555555",
+ "stroke-width": 2,
+ "stroke-opacity": 1,
+ "fill": "#555555",
+ "fill-opacity": 0.5,
+ "name": "Amstelfeld",
+ "type": "poi"
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 4.897080659866332,
+ 52.36253045847271
+ ],
+ [
+ 4.8978424072265625,
+ 52.36269425079362
+ ],
+ [
+ 4.89815354347229,
+ 52.362137354425165
+ ],
+ [
+ 4.896329641342163,
+ 52.36185562770631
+ ],
+ [
+ 4.896275997161865,
+ 52.36240597590272
+ ],
+ [
+ 4.897080659866332,
+ 52.36253045847271
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {
+ "stroke": "#555555",
+ "stroke-width": 2,
+ "stroke-opacity": 1,
+ "fill": "#555555",
+ "fill-opacity": 0.5,
+ "name": "Albert Cuyp Markt",
+ "type": "poi"
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 4.890514612197876,
+ 52.35491672137934
+ ],
+ [
+ 4.894967079162598,
+ 52.35580134510498
+ ],
+ [
+ 4.896436929702759,
+ 52.356168294935955
+ ],
+ [
+ 4.899580478668213,
+ 52.3570725511568
+ ],
+ [
+ 4.899430274963379,
+ 52.35731499351983
+ ],
+ [
+ 4.897252321243286,
+ 52.356587662440496
+ ],
+ [
+ 4.895503520965576,
+ 52.356076557763856
+ ],
+ [
+ 4.893561601638794,
+ 52.355683396297984
+ ],
+ [
+ 4.8904502391815186,
+ 52.35510020034824
+ ],
+ [
+ 4.890514612197876,
+ 52.35491672137934
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {
+ "stroke": "#555555",
+ "stroke-width": 2,
+ "stroke-opacity": 1,
+ "fill": "#555555",
+ "fill-opacity": 0.5,
+ "name": "Noordermarkt",
+ "type": "poi"
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 4.885987043380737,
+ 52.37978100483205
+ ],
+ [
+ 4.886265993118286,
+ 52.37907041669766
+ ],
+ [
+ 4.886485934257507,
+ 52.37900819875896
+ ],
+ [
+ 4.886732697486877,
+ 52.37907041669766
+ ],
+ [
+ 4.887698292732239,
+ 52.38007244089837
+ ],
+ [
+ 4.885987043380737,
+ 52.37978100483205
+ ]
+ ]
+ ]
+ }
+ }
+ ]
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values-v21/attrs.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values-v21/attrs.xml
new file mode 100644
index 0000000000..2eb503b057
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values-v21/attrs.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <declare-styleable name="ScrimInsetsView">
+ <attr name="appInsetForeground" format="reference|color" />
+ </declare-styleable>
+</resources> \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values-v21/dimens.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values-v21/dimens.xml
new file mode 100644
index 0000000000..035b9f3564
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values-v21/dimens.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <dimen name="toolbar_padding_top">25dp</dimen>
+</resources> \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values-v21/styles.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values-v21/styles.xml
new file mode 100644
index 0000000000..3d61b9a36d
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values-v21/styles.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <style name="AppTheme" parent="AppBaseTheme">
+
+ </style>r
+
+ <style name="AppTheme.ActionBar.Transparent" parent="AppTheme">
+ <item name="colorPrimary">@android:color/transparent</item>
+ <item name="android:windowDrawsSystemBarBackgrounds">true</item>
+ <item name="android:windowTranslucentStatus">true</item>
+ </style>
+
+ <style name="AppTheme.ActionBar" parent="AppTheme">
+ <item name="colorPrimaryDark">@color/primary_dark</item>
+ <item name="colorPrimary">@color/primary</item>
+ </style>
+
+</resources> \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values-w820dp/dimens.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values-w820dp/dimens.xml
new file mode 100644
index 0000000000..63fc816444
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values-w820dp/dimens.xml
@@ -0,0 +1,6 @@
+<resources>
+ <!-- Example customization of dimensions originally defined in res/values/dimens.xml
+ (such as screen margins) for screens with more than 820dp of available width. This
+ would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
+ <dimen name="activity_horizontal_margin">64dp</dimen>
+</resources>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/dimens.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/dimens.xml
index 98ec90c6fd..b77a25b681 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/dimens.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/dimens.xml
@@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
+ <dimen name="circle_size">24dp</dimen>
<dimen name="fab_margin">16dp</dimen>
+ <dimen name="full_button_margin">8dp</dimen>
<dimen name="attr_margin">10dp</dimen>
<dimen name="coordinatebounds_margin">32dp</dimen>
<dimen name="map_padding_left">96dp</dimen>
@@ -9,4 +11,9 @@
<dimen name="toolbar_shadow">4dp</dimen>
<dimen name="locationview_background_drawable_padding">2dp</dimen>
<dimen name="locationview_padding_top">350dp</dimen>
+ <!-- Default screen margins, per the Android Design guidelines. -->
+ <dimen name="activity_horizontal_margin">16dp</dimen>
+ <dimen name="activity_vertical_margin">16dp</dimen>
+ <dimen name="navigation_drawer_width">240dp</dimen>
+ <dimen name="toolbar_padding_top">0dp</dimen>
</resources>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml
index a84035aa58..00c421bfef 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml
@@ -18,10 +18,12 @@
<string name="activity_polygon">Polygon</string>
<string name="activity_press_for_marker">Press Map For Marker</string>
<string name="activity_view_marker">View Marker API</string>
+ <string name="activity_view_marker_scale">Scaling in the View Marker API</string>
<!-- InfoWindow-->
- <string name="activity_info_window">Standard InfoWindow example</string>
- <string name="activity_infowindow_adapter">Custom InfoWindow Adapter</string>
+ <string name="activity_info_window">Standard InfoWindow</string>
+ <string name="activity_infowindow_adapter">Custom InfoWindow</string>
+ <string name="activity_dynamic_infowindow_adapter">Custom Dynamic InfoWindow</string>
<!-- Camera -->
<string name="activity_camera_animation_types">Animation Types</string>
@@ -34,11 +36,15 @@
<string name="activity_directions">Directions</string>
<string name="activity_geocoder">Geocoder</string>
+ <!-- Navigation -->
+ <string name="activity_location_picker">Location Picker</string>
+
<!-- Other -->
<string name="activity_double_map">Double Map Activity</string>
+ <string name="activity_back_to_map">Back to map activity</string>
<string name="activity_snapshot">Snapshot Activity</string>
<string name="activity_user_tracking_mode">User tracking mode</string>
- <string name="activity_user_tracking_customization">User location customization</string>
+ <string name="activity_user_tracking_customization">User location drawable</string>
<string name="activity_user_dot_color">User location tint color</string>
<string name="activity_user_location_toggle">User location toggle</string>
<string name="activity_custom_layer">Custom Layer</string>
@@ -46,6 +52,11 @@
<string name="activity_debug_mode">Debug Mode</string>
<string name="activity_offline">Offline Map</string>
<string name="activity_minmax_zoom">Min/Max Zoom</string>
+ <string name="activity_viewpager">ViewPager</string>
+ <string name="activity_runtime_style">Runtime Style</string>
+ <string name="activity_print">Print a map</string>
+ <string name="activity_surfaceview_overlay">SurfaceView MediaOverlay</string>
+ <string name="title_activity_navigation_drawer">Android SDK View integration</string>
<!-- Description -->
<string name="description_user_location_tracking">Tracks the location of the user</string>
@@ -77,9 +88,19 @@
<string name="description_scroll_by">Scroll with pixels in x,y direction</string>
<string name="description_snapshot">Example to make a snapshot of the map</string>
<string name="description_doublemap">2 maps in a view hierarchy</string>
+ <string name="description_back_to_map">Restart map view after temporarily leaving to another activity</string>
<string name="description_view_marker">Use an Android SDK View as marker</string>
-
- <string name="menuitem_title_concurrent_infowindow">Concurrent Open InfoWindows</string>r
+ <string name="description_view_marker_scale">Scale a View Marker</string>
+ <string name="description_dynamic_info_window_adapter">Learn how to create a dynamic custom InfoWindow</string>
+ <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_runtime_style">Adopt the map style on the fly</string>
+ <string name="description_print">Shows how to print a map</string>
+ <string name="description_navigation_drawer">Test animation of Android SDK View components</string>
+ <string name="description_surfaceview_mediacontrols">Test overlaying SurfaceView</string>
+
+ <string name="menuitem_title_concurrent_infowindow">Concurrent Open InfoWindows</string>
+ <string name="menuitem_title_deselect_markers_on_tap">Deselect Markers On Tap</string>
<string name="menuitem_title_tracking_mode_dismiss_on_gesture">Dismiss location tracking on gesture</string>
<string name="menuitem_title_bearing_mode_dismiss_on_gesture">Dismiss bearing tracking on gesture</string>
<string name="menuitem_title_reset">Reset</string>
@@ -96,10 +117,18 @@
<string name="category_maplayout">Map Layout</string>
<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>
+ <string name="action_visibility_polygon">Change visibility</string>
+ <string name="action_alpha_polygon">Change alpha</string>
+ <string name="action_points_polygon">Change points</string>
+ <string name="action_color_polygon">Change color</string>
+ <string name="action_width_polyline">Change width</string>
+
<string name="button_camera_move">Move</string>
<string name="button_camera_ease">Ease</string>
<string name="button_camera_animate">Animate</string>
@@ -152,4 +181,21 @@
<string name="geocoder_instructions">Tap Map To Geocode Where Black Marker Is Currently Located</string>
+ <string name="dynamic_marker_chelsea_title">Chelsea</string>
+ <string name="dynamic_marker_chelsea_snippet">Stamford Bridge</string>
+ <string name="dynamic_marker_arsenal_title">Arsenal</string>
+ <string name="dynamic_marker_arsenal_snippet">Emirates Stadium</string>
+
+ <string name="navigation_select_location_button_text">Select Location!</string>
+
+ <string name="title_section1">Different style</string>
+ <string name="title_section2">Show Snackbar</string>
+
+ <string name="navigation_drawer_open">Open navigation drawer</string>
+ <string name="navigation_drawer_close">Close navigation drawer</string>
+
+ <string name="action_example">Example action</string>
+
+ <string name="action_settings">Settings</string>
+
</resources>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/styles.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/styles.xml
index d01b9d313f..e358fcd5a0 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/styles.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/styles.xml
@@ -1,8 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
- <style name="AppTheme" parent="AppBaseTheme" />
-
<style name="AppBaseTheme" parent="@style/Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">@color/primary</item>
<item name="colorPrimaryDark">@color/primary_dark</item>
@@ -10,4 +8,16 @@
<item name="android:windowBackground">@color/white</item>
</style>
+ <style name="AppTheme.ActionBar.Transparent" parent="AppTheme">
+ <item name="android:windowContentOverlay">@null</item>
+ <item name="windowActionBarOverlay">true</item>
+ <item name="colorPrimary">@android:color/transparent</item>
+ </style>
+
+ <style name="AppTheme.ActionBar" parent="AppTheme">
+ <item name="windowActionBarOverlay">false</item>
+ </style>
+
+ <style name="AppTheme" parent="AppBaseTheme" />
+
</resources>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/InfoWindowTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/InfoWindowTest.java
index 11ab8173fd..1398f40009 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/InfoWindowTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/InfoWindowTest.java
@@ -32,7 +32,7 @@ public class InfoWindowTest {
@Test
public void testBoundMarker() {
MarkerOptions markerOptions = new MarkerOptions();
- Marker marker = markerOptions.getMarker();
+ Marker marker = markerOptions.position(new LatLng()).getMarker();
InfoWindow infoWindow = new InfoWindow(mMapView, mMapboxMap).setBoundMarker(marker);
assertEquals("marker should match", marker, infoWindow.getBoundMarker());
}
@@ -53,7 +53,7 @@ public class InfoWindowTest {
when(projection.toScreenLocation(latLng)).thenReturn(new PointF(0, 0));
InfoWindow infoWindow = new InfoWindow(mMapView, mMapboxMap);
- infoWindow.open(mMapView, new MarkerOptions().getMarker(), latLng, 0, 0);
+ infoWindow.open(mMapView, new MarkerOptions().position(new LatLng()).getMarker(), latLng, 0, 0);
assertEquals("infowindow should not be visible", true, infoWindow.isVisible());
}
@@ -65,7 +65,7 @@ public class InfoWindowTest {
when(projection.toScreenLocation(latLng)).thenReturn(new PointF(0, 0));
InfoWindow infoWindow = new InfoWindow(mMapView, mMapboxMap);
- infoWindow.open(mMapView, new MarkerOptions().getMarker(), latLng, 0, 0);
+ infoWindow.open(mMapView, new MarkerOptions().position(new LatLng()).getMarker(), latLng, 0, 0);
infoWindow.close();
assertEquals("infowindow should not be visible", false, infoWindow.isVisible());
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerTest.java
index a55672e86b..c4c294fb98 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerTest.java
@@ -3,6 +3,7 @@ package com.mapbox.mapboxsdk.annotations;
import android.graphics.Bitmap;
import android.os.Parcelable;
+import com.mapbox.mapboxsdk.exceptions.InvalidMarkerPositionException;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.utils.MockParcel;
@@ -23,10 +24,15 @@ public class MarkerTest {
@Test
public void testMarker() {
- MarkerOptions markerOptions = new MarkerOptions();
+ MarkerOptions markerOptions = new MarkerOptions().position(new LatLng());
assertNotNull("marker should not be null", markerOptions.getMarker());
}
+ @Test(expected = InvalidMarkerPositionException.class)
+ public void testInvalidMarker(){
+ new MarkerOptions().getMarker();
+ }
+
@Test
public void testPosition() {
MarkerOptions markerOptions = new MarkerOptions().position(new LatLng(10, 12));
@@ -37,7 +43,7 @@ public class MarkerTest {
@Test
public void testTitle() {
- MarkerOptions markerOptions = new MarkerOptions().title("Mapbox");
+ MarkerOptions markerOptions = new MarkerOptions().title("Mapbox").position(new LatLng());
Marker marker = markerOptions.getMarker();
assertEquals(marker.getTitle(), "Mapbox");
assertEquals(markerOptions.getTitle(), "Mapbox");
@@ -45,7 +51,7 @@ public class MarkerTest {
@Test
public void testSnippet() {
- MarkerOptions markerOptions = new MarkerOptions().snippet("Mapbox");
+ MarkerOptions markerOptions = new MarkerOptions().snippet("Mapbox").position(new LatLng());
Marker marker = markerOptions.getMarker();
assertEquals(marker.getSnippet(), "Mapbox");
}
@@ -62,7 +68,7 @@ public class MarkerTest {
public void testIcon() {
Bitmap bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_4444);
Icon icon = IconFactory.recreate("test", bitmap);
- MarkerOptions markerOptions = new MarkerOptions().icon(icon);
+ MarkerOptions markerOptions = new MarkerOptions().position(new LatLng()).icon(icon);
Marker marker = markerOptions.getMarker();
assertEquals("Icon should match", icon, marker.getIcon());
assertEquals("Icon should match", icon, markerOptions.getIcon());
@@ -70,7 +76,7 @@ public class MarkerTest {
@Test
public void testHashCode() {
- Marker marker = new MarkerOptions().getMarker();
+ Marker marker = new MarkerOptions().position(new LatLng()).getMarker();
assertEquals("hash code should match", marker.hashCode(), 0);
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerViewTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerViewTest.java
index ed8e4ff323..e6c30f4aac 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerViewTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerViewTest.java
@@ -1,10 +1,9 @@
package com.mapbox.mapboxsdk.annotations;
-import android.graphics.Bitmap;
import android.os.Parcelable;
+import com.mapbox.mapboxsdk.exceptions.InvalidMarkerPositionException;
import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.utils.MockParcel;
import org.junit.Test;
@@ -25,10 +24,15 @@ public class MarkerViewTest {
@Test
public void testMarker() {
- MarkerViewOptions markerOptions = new MarkerViewOptions();
+ MarkerViewOptions markerOptions = new MarkerViewOptions().position(new LatLng());
assertNotNull("marker should not be null", markerOptions.getMarker());
}
+ @Test(expected = InvalidMarkerPositionException.class)
+ public void testInvalidMarker(){
+ new MarkerViewOptions().getMarker();
+ }
+
@Test
public void testPosition() {
MarkerViewOptions markerOptions = new MarkerViewOptions().position(new LatLng(10, 12));
@@ -39,46 +43,36 @@ public class MarkerViewTest {
@Test
public void testSnippet() {
- MarkerViewOptions markerOptions = new MarkerViewOptions().snippet("Mapbox");
+ MarkerViewOptions markerOptions = new MarkerViewOptions().snippet("Mapbox").position(new LatLng());
MarkerView marker = markerOptions.getMarker();
assertEquals(marker.getSnippet(), "Mapbox");
}
@Test
public void testTitle() {
- MarkerViewOptions markerOptions = new MarkerViewOptions().title("Mapbox");
+ MarkerViewOptions markerOptions = new MarkerViewOptions().title("Mapbox").position(new LatLng());
MarkerView marker = markerOptions.getMarker();
assertEquals(marker.getTitle(), "Mapbox");
assertEquals(markerOptions.getTitle(), "Mapbox");
}
@Test
- public void testIcon() {
- Bitmap bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_4444);
- Icon icon = IconFactory.recreate("test", bitmap);
- MarkerViewOptions markerOptions = new MarkerViewOptions().icon(icon);
- MarkerView marker = markerOptions.getMarker();
- assertEquals("Icon should match", icon, marker.getIcon());
- assertEquals("Icon should match", icon, markerOptions.getIcon());
- }
-
- @Test
public void testFlat() {
- MarkerViewOptions markerOptions = new MarkerViewOptions().flat(true);
+ MarkerViewOptions markerOptions = new MarkerViewOptions().flat(true).position(new LatLng());
MarkerView marker = markerOptions.getMarker();
assertTrue("flat should be true", marker.isFlat());
}
@Test
public void testFlatDefault() {
- assertFalse("default value of flat should be false", new MarkerViewOptions().getMarker().isFlat());
+ assertFalse("default value of flat should be false", new MarkerViewOptions().position(new LatLng()).getMarker().isFlat());
}
@Test
public void testAnchor() {
float anchorU = 1;
float anchorV = 1;
- MarkerViewOptions markerOptions = new MarkerViewOptions().anchor(anchorU, anchorV);
+ MarkerViewOptions markerOptions = new MarkerViewOptions().anchor(anchorU, anchorV).position(new LatLng());
MarkerView marker = markerOptions.getMarker();
assertEquals("anchorU should match ", anchorU, marker.getAnchorU(), 0);
assertEquals("anchorU should match ", anchorV, marker.getAnchorV(), 0);
@@ -86,7 +80,7 @@ public class MarkerViewTest {
@Test
public void testAnchorDefault() {
- MarkerView marker = new MarkerViewOptions().getMarker();
+ MarkerView marker = new MarkerViewOptions().position(new LatLng()).getMarker();
assertEquals("anchorU should match ", 0.5, marker.getAnchorU(), 0);
assertEquals("anchorU should match ", 1, marker.getAnchorV(), 0);
}
@@ -95,7 +89,7 @@ public class MarkerViewTest {
public void testInfoWindowAnchor() {
float anchorU = 1;
float anchorV = 1;
- MarkerViewOptions markerOptions = new MarkerViewOptions().infoWindowAnchor(anchorU, anchorV);
+ MarkerViewOptions markerOptions = new MarkerViewOptions().position(new LatLng()).infoWindowAnchor(anchorU, anchorV);
MarkerView marker = markerOptions.getMarker();
assertEquals("anchorU should match ", 1, marker.getInfoWindowAnchorU(), 0);
assertEquals("anchorU should match ", 1, marker.getInfoWindowAnchorV(), 0);
@@ -103,31 +97,15 @@ public class MarkerViewTest {
@Test
public void testInfoWindowAnchorDefault() {
- MarkerView marker = new MarkerViewOptions().getMarker();
+ MarkerView marker = new MarkerViewOptions().position(new LatLng()).getMarker();
assertEquals("anchorU should match ", 0.5, marker.getInfoWindowAnchorU(), 0);
assertEquals("anchorU should match ", 0, marker.getInfoWindowAnchorV(), 0);
}
@Test
- public void testSelectAnimRes() {
- int animatorRes = R.animator.rotate_360;
- MarkerViewOptions markerOptions = new MarkerViewOptions().selectAnimatorResource(animatorRes);
- MarkerView marker = markerOptions.getMarker();
- assertEquals("select animator resource should match ", animatorRes, marker.getSelectAnimRes(), 0);
- }
-
- @Test
- public void testDeselectAnimRes() {
- int animatorRes = R.animator.rotate_360;
- MarkerViewOptions markerOptions = new MarkerViewOptions().deselectAnimatorResource(animatorRes);
- MarkerView marker = markerOptions.getMarker();
- assertEquals("deselect animator resource should match ", animatorRes, marker.getDeselectAnimRes(), 0);
- }
-
- @Test
public void testRotation() {
int rotation = 90;
- MarkerViewOptions markerOptions = new MarkerViewOptions().rotation(rotation);
+ MarkerViewOptions markerOptions = new MarkerViewOptions().position(new LatLng()).rotation(rotation);
MarkerView marker = markerOptions.getMarker();
assertEquals("rotation should match ", rotation, marker.getRotation(), 0);
}
@@ -135,27 +113,26 @@ public class MarkerViewTest {
@Test
public void testVisible() {
boolean visible = false;
- MarkerViewOptions markerOptions = new MarkerViewOptions().visible(visible);
+ MarkerViewOptions markerOptions = new MarkerViewOptions().visible(visible).position(new LatLng());
MarkerView marker = markerOptions.getMarker();
assertEquals("visible should match ", visible, marker.isVisible());
}
@Test
public void testVisibleDefault() {
- assertTrue(new MarkerViewOptions().getMarker().isVisible());
+ assertTrue(new MarkerViewOptions().position(new LatLng()).getMarker().isVisible());
}
@Test
public void testBuilder() {
MarkerView marker = new MarkerViewOptions().title("title").snippet("snippet").position(new LatLng(10, 12)).getMarker();
assertEquals(marker.getSnippet(), "snippet");
-
assertEquals(marker.getPosition(), new LatLng(10, 12));
}
@Test
public void testHashCode() {
- MarkerView marker = new MarkerViewOptions().getMarker();
+ MarkerView marker = new MarkerViewOptions().position(new LatLng()).getMarker();
assertEquals("hash code should match", marker.hashCode(), 0);
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java
index a8cca4c3c8..4775bb39a4 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java
@@ -3,10 +3,10 @@ package com.mapbox.mapboxsdk.camera;
import android.content.res.TypedArray;
import android.os.Parcelable;
+import com.mapbox.mapboxsdk.R;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
import com.mapbox.mapboxsdk.constants.MathConstants;
import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.utils.MathUtils;
import com.mapbox.mapboxsdk.utils.MockParcel;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/constants/StyleVersionTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/constants/StyleVersionTest.java
index 078b4184ca..3d9b2a9364 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/constants/StyleVersionTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/constants/StyleVersionTest.java
@@ -1,5 +1,6 @@
package com.mapbox.mapboxsdk.constants;
+
import com.mapbox.mapboxsdk.testapp.model.constants.AppConstant;
import org.junit.Test;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java
index b667940a6f..b2cc1e9046 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java
@@ -8,6 +8,9 @@ import com.mapbox.mapboxsdk.utils.MockParcel;
import org.junit.Before;
import org.junit.Test;
+import java.util.ArrayList;
+import java.util.List;
+
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -106,6 +109,24 @@ public class LatLngBoundsTest {
}
@Test
+ public void testIncludes() {
+ List<LatLng> points = new ArrayList<>();
+ points.add(LAT_LNG_NULL_ISLAND);
+ points.add(LAT_LNG_NOT_NULL_ISLAND);
+
+ LatLngBounds latLngBounds1 = new LatLngBounds.Builder()
+ .includes(points)
+ .build();
+
+ LatLngBounds latLngBounds2 = new LatLngBounds.Builder()
+ .include(LAT_LNG_NULL_ISLAND)
+ .include(LAT_LNG_NOT_NULL_ISLAND)
+ .build();
+
+ assertEquals("LatLngBounds should match", latLngBounds1, latLngBounds2);
+ }
+
+ @Test
public void testNoIncluding() {
assertFalse("LatLng should not be included", mLatLngBounds.contains(new LatLng(3, 1)));
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java
index b69ba4e3f8..33fd77521d 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java
@@ -13,6 +13,7 @@ import com.mapbox.mapboxsdk.annotations.Polyline;
import com.mapbox.mapboxsdk.annotations.PolylineOptions;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
+import com.mapbox.mapboxsdk.exceptions.InvalidMarkerPositionException;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
@@ -572,16 +573,21 @@ public class MapboxMapTest {
@Test
public void testAddMarker() {
- MarkerOptions markerOptions = new MarkerOptions();
+ MarkerOptions markerOptions = new MarkerOptions().position(new LatLng());
Marker marker = mMapboxMap.addMarker(markerOptions);
assertTrue("Marker should be contained", mMapboxMap.getMarkers().contains(marker));
}
+ @Test(expected = InvalidMarkerPositionException.class)
+ public void testAddMarkerInvalidPosition(){
+ new MarkerOptions().getMarker();
+ }
+
@Test
public void testAddMarkers() {
List<BaseMarkerOptions> markerList = new ArrayList<>();
- MarkerOptions markerOptions1 = new MarkerOptions().title("a");
- MarkerOptions markerOptions2 = new MarkerOptions().title("b");
+ MarkerOptions markerOptions1 = new MarkerOptions().position(new LatLng()).title("a");
+ MarkerOptions markerOptions2 = new MarkerOptions().position(new LatLng()).title("b");
markerList.add(markerOptions1);
markerList.add(markerOptions2);
mMapboxMap.addMarkers(markerList);
@@ -600,7 +606,7 @@ public class MapboxMapTest {
@Test
public void testAddMarkersSingleMarker() {
List<BaseMarkerOptions> markerList = new ArrayList<>();
- MarkerOptions markerOptions = new MarkerOptions().title("a");
+ MarkerOptions markerOptions = new MarkerOptions().title("a").position(new LatLng());
markerList.add(markerOptions);
mMapboxMap.addMarkers(markerList);
assertEquals("Markers size should be 1", 1, mMapboxMap.getMarkers().size());
@@ -701,7 +707,7 @@ public class MapboxMapTest {
@Test
public void testRemoveMarker() {
- MarkerOptions markerOptions = new MarkerOptions();
+ MarkerOptions markerOptions = new MarkerOptions().position(new LatLng());
Marker marker = mMapboxMap.addMarker(markerOptions);
mMapboxMap.removeMarker(marker);
assertTrue("Markers should be empty", mMapboxMap.getMarkers().isEmpty());
@@ -725,7 +731,7 @@ public class MapboxMapTest {
@Test
public void testRemoveAnnotation() {
- MarkerOptions markerOptions = new MarkerOptions();
+ MarkerOptions markerOptions = new MarkerOptions().position(new LatLng());
Marker marker = mMapboxMap.addMarker(markerOptions);
mMapboxMap.removeAnnotation(marker);
assertTrue("Annotations should be empty", mMapboxMap.getAnnotations().isEmpty());
@@ -733,7 +739,7 @@ public class MapboxMapTest {
@Test
public void testRemoveAnnotationById() {
- MarkerOptions markerOptions = new MarkerOptions();
+ MarkerOptions markerOptions = new MarkerOptions().position(new LatLng());
mMapboxMap.addMarker(markerOptions);
// id will always be 0 in unit tests
mMapboxMap.removeAnnotation(0);
@@ -743,8 +749,8 @@ public class MapboxMapTest {
@Test
public void testRemoveAnnotations() {
List<BaseMarkerOptions> markerList = new ArrayList<>();
- MarkerOptions markerOptions1 = new MarkerOptions().title("a");
- MarkerOptions markerOptions2 = new MarkerOptions().title("b");
+ MarkerOptions markerOptions1 = new MarkerOptions().title("a").position(new LatLng());
+ MarkerOptions markerOptions2 = new MarkerOptions().title("b").position(new LatLng());
markerList.add(markerOptions1);
markerList.add(markerOptions2);
mMapboxMap.addMarkers(markerList);
@@ -755,8 +761,8 @@ public class MapboxMapTest {
@Test
public void testClear() {
List<BaseMarkerOptions> markerList = new ArrayList<>();
- MarkerOptions markerOptions1 = new MarkerOptions().title("a");
- MarkerOptions markerOptions2 = new MarkerOptions().title("b");
+ MarkerOptions markerOptions1 = new MarkerOptions().title("a").position(new LatLng());
+ MarkerOptions markerOptions2 = new MarkerOptions().title("b").position(new LatLng());
markerList.add(markerOptions1);
markerList.add(markerOptions2);
mMapboxMap.addMarkers(markerList);
@@ -767,12 +773,12 @@ public class MapboxMapTest {
@Test
public void testRemoveAnnotationsByList() {
List<BaseMarkerOptions> markerList = new ArrayList<>();
- MarkerOptions markerOptions1 = new MarkerOptions().title("a");
- MarkerOptions markerOptions2 = new MarkerOptions().title("b");
+ MarkerOptions markerOptions1 = new MarkerOptions().title("a").position(new LatLng());
+ MarkerOptions markerOptions2 = new MarkerOptions().title("b").position(new LatLng());
markerList.add(markerOptions1);
markerList.add(markerOptions2);
List<Marker> markers = mMapboxMap.addMarkers(markerList);
- Marker marker = mMapboxMap.addMarker(new MarkerOptions().title("c"));
+ Marker marker = mMapboxMap.addMarker(new MarkerOptions().position(new LatLng()).title("c"));
mMapboxMap.removeAnnotations(markers);
assertTrue("Annotations should not be empty", mMapboxMap.getAnnotations().size() == 1);
assertTrue("Marker should be contained", mMapboxMap.getAnnotations().contains(marker));
@@ -780,7 +786,7 @@ public class MapboxMapTest {
@Test
public void testGetAnnotationById() {
- MarkerOptions markerOptions = new MarkerOptions();
+ MarkerOptions markerOptions = new MarkerOptions().position(new LatLng());
Marker initialMarker = mMapboxMap.addMarker(markerOptions);
Marker retrievedMarker = (Marker) mMapboxMap.getAnnotation(0);
assertEquals("Markers should match", initialMarker, retrievedMarker);
@@ -814,7 +820,7 @@ public class MapboxMapTest {
@Test
public void testSelectMarker() {
mMapboxMap.setOnMarkerClickListener(mOnMarkerClickListener);
- MarkerOptions markerOptions = new MarkerOptions();
+ MarkerOptions markerOptions = new MarkerOptions().position(new LatLng());
Marker marker = mMapboxMap.addMarker(markerOptions);
when(mOnMarkerClickListener.onMarkerClick(marker)).thenReturn(true);
mMapboxMap.selectMarker(marker);
@@ -824,7 +830,7 @@ public class MapboxMapTest {
@Test
public void testDeselectMarker() {
mMapboxMap.setOnMarkerClickListener(mOnMarkerClickListener);
- MarkerOptions markerOptions = new MarkerOptions();
+ MarkerOptions markerOptions = new MarkerOptions().position(new LatLng());
Marker marker = mMapboxMap.addMarker(markerOptions);
when(mOnMarkerClickListener.onMarkerClick(marker)).thenReturn(true);
mMapboxMap.selectMarker(marker);
@@ -835,7 +841,7 @@ public class MapboxMapTest {
@Test
public void testDeselectMarkers() {
mMapboxMap.setOnMarkerClickListener(mOnMarkerClickListener);
- MarkerOptions markerOptions = new MarkerOptions();
+ MarkerOptions markerOptions = new MarkerOptions().position(new LatLng());
Marker marker1 = mMapboxMap.addMarker(markerOptions);
Marker marker2 = mMapboxMap.addMarker(markerOptions);
when(mOnMarkerClickListener.onMarkerClick(marker1)).thenReturn(true);
@@ -853,7 +859,7 @@ public class MapboxMapTest {
@Test
public void testOnMarkerClick() {
mMapboxMap.setOnMarkerClickListener(mOnMarkerClickListener);
- Marker marker = new MarkerOptions().getMarker();
+ Marker marker = new MarkerOptions().position(new LatLng()).getMarker();
when(mOnMarkerClickListener.onMarkerClick(marker)).thenReturn(true);
mMapboxMap.selectMarker(marker);
verify(mOnMarkerClickListener, times(1)).onMarkerClick(marker);
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/StyleInitializerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/StyleInitializerTest.java
deleted file mode 100644
index 71d61a3d4b..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/StyleInitializerTest.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package com.mapbox.mapboxsdk.maps;
-
-import android.content.Context;
-import android.content.res.Resources;
-
-import com.mapbox.mapboxsdk.testapp.R;
-import com.mapbox.mapboxsdk.testapp.model.constants.AppConstant;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.InjectMocks;
-import org.mockito.MockitoAnnotations;
-
-import java.util.Locale;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class StyleInitializerTest {
-
- @InjectMocks
- Context context = mock(Context.class);
-
- @InjectMocks
- Resources resources = mock(Resources.class);
-
- MapView.StyleInitializer initializer;
-
- @Before
- public void beforeTest() {
- MockitoAnnotations.initMocks(this);
- when(context.getResources()).thenReturn(resources);
- when(resources.getInteger(R.integer.style_version)).thenReturn(AppConstant.STYLE_VERSION);
- initializer = new MapView.StyleInitializer(context);
- }
-
- @Test
- public void testSanity() {
- assertNotNull("initializer should not be null", initializer);
- }
-
- @Test
- public void testDefaultStyle() {
- assertTrue(initializer.isDefaultStyle());
- assertEquals(String.format(Locale.US, "mapbox://styles/mapbox/streets-v%d", AppConstant.STYLE_VERSION), "mapbox://styles/mapbox/streets-v9");
- }
-
- @Test
- public void testUpdateStyle() {
- String customStyle = "test";
- initializer.setStyle(customStyle);
- assertFalse(initializer.isDefaultStyle());
- assertEquals(customStyle, initializer.getStyle());
- }
-
- @Test
- public void testUpdateStyleNull() {
- String customStyle = null;
- initializer.setStyle(customStyle);
- assertTrue(initializer.isDefaultStyle());
- assertEquals(String.format(Locale.US, "mapbox://styles/mapbox/streets-v%d", AppConstant.STYLE_VERSION), "mapbox://styles/mapbox/streets-v9");
- }
-
- @Test
- public void testOverrideDefaultStyle() {
- String customStyle = "test";
- initializer.setStyle(customStyle, true);
- assertTrue(initializer.isDefaultStyle());
- assertEquals(customStyle, initializer.getStyle());
- }
-}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettingsTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettingsTest.java
index a03eb6acae..fd70308931 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettingsTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettingsTest.java
@@ -16,6 +16,7 @@ import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
public class MyLocationViewSettingsTest {
@@ -41,6 +42,9 @@ public class MyLocationViewSettingsTest {
public void testForegroundDrawables() {
Drawable foregroundDrawable = mock(Drawable.class);
Drawable foregroundBearingDrawable = mock(Drawable.class);
+ Drawable.ConstantState constantState = mock(Drawable.ConstantState.class);
+ when(foregroundDrawable.getConstantState()).thenReturn(constantState);
+ when(constantState.newDrawable()).thenReturn(foregroundDrawable);
locationViewSettings.setForegroundDrawable(foregroundDrawable, foregroundBearingDrawable);
assertEquals("foreground should match", foregroundDrawable, locationViewSettings.getForegroundDrawable());
assertEquals("foreground bearing should match", foregroundBearingDrawable, locationViewSettings.getForegroundBearingDrawable());
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/style/layers/FilterTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/style/layers/FilterTest.java
new file mode 100644
index 0000000000..3e312d3b0a
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/style/layers/FilterTest.java
@@ -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"});
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/style/layers/FunctionTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/style/layers/FunctionTest.java
new file mode 100644
index 0000000000..1106009ea8
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/style/layers/FunctionTest.java
@@ -0,0 +1,29 @@
+package com.mapbox.mapboxsdk.style.layers;
+
+import org.junit.Test;
+
+import static com.mapbox.mapboxsdk.style.layers.Function.*;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.*;
+
+import static org.junit.Assert.*;
+
+/**
+ * Tests Function
+ */
+public class FunctionTest {
+
+ @Test
+ public void testZoomFunction() {
+ Function zoomF = zoom(
+ stop(1f, lineBlur(1f)),
+ stop(10f, lineBlur(20f))
+ );
+
+ assertNotNull(zoomF.toValueObject());
+ assertArrayEquals(
+ new Object[]{new Object[]{1f, 1f}, new Object[]{10f, 20f}},
+ (Object[]) zoomF.toValueObject().get("stops")
+ );
+ }
+
+}
diff --git a/platform/android/bitrise.yml b/platform/android/bitrise.yml
index 3c06a04675..5eb5cfa508 100644
--- a/platform/android/bitrise.yml
+++ b/platform/android/bitrise.yml
@@ -75,7 +75,7 @@ workflows:
signing.secretKeyRingFile=secring.gpg" >> platform/android/MapboxGLAndroidSDK/gradle.properties
export BUILDTYPE=Release
- make apackage -j4
+ make apackage
cd platform/android
./gradlew uploadArchives
diff --git a/platform/android/build.gradle b/platform/android/build.gradle
index 23aef9d1e6..c99fc67a61 100644
--- a/platform/android/build.gradle
+++ b/platform/android/build.gradle
@@ -7,7 +7,7 @@ buildscript {
maven { url 'https://jitpack.io' }
}
dependencies {
- classpath 'com.android.tools.build:gradle:2.1.0'
+ classpath 'com.android.tools.build:gradle:2.1.2'
classpath 'com.github.JakeWharton:sdk-manager-plugin:220bf7a88a7072df3ed16dc8466fb144f2817070'
// NOTE: Do not place your application dependencies here; they belong
diff --git a/platform/android/platform.gyp b/platform/android/platform.gyp
index 964492a21e..f8e8b33b08 100644
--- a/platform/android/platform.gyp
+++ b/platform/android/platform.gyp
@@ -1,6 +1,7 @@
{
'variables': {
'loop_lib': 'android',
+ 'OS': 'android',
'headless_lib': 'none',
'coverage': 0,
},
@@ -26,11 +27,23 @@
'sources': [
'src/native_map_view.cpp',
'src/jni.cpp',
+ 'src/java_types.cpp',
'src/attach_env.cpp',
'src/log_android.cpp',
'src/http_file_source.cpp',
'src/asset_file_source.cpp',
- '../default/thread.cpp',
+ 'src/thread.cpp',
+ 'src/style/value.cpp',
+ 'src/style/sources/sources.cpp',
+ 'src/style/layers/layers.cpp',
+ 'src/style/layers/layer.cpp',
+ 'src/style/layers/background_layer.cpp',
+ 'src/style/layers/circle_layer.cpp',
+ 'src/style/layers/fill_layer.cpp',
+ 'src/style/layers/line_layer.cpp',
+ 'src/style/layers/raster_layer.cpp',
+ 'src/style/layers/symbol_layer.cpp',
+ 'src/style/layers/custom_layer.cpp',
'../default/string_stdlib.cpp',
'../default/image.cpp',
'../default/png_reader.cpp',
@@ -49,6 +62,7 @@
'cflags_cc': [
'<@(boost_cflags)',
+ '<@(geojson_cflags)',
'<@(rapidjson_cflags)',
'<@(nunicode_cflags)',
'<@(sqlite_cflags)',
@@ -78,6 +92,7 @@
'<@(libpng_ldflags)',
'<@(libjpeg-turbo_static_libs)',
'<@(libjpeg-turbo_ldflags)',
+ '<@(geojson_static_libs)'
],
},
},
diff --git a/platform/android/scripts/configure.sh b/platform/android/scripts/configure.sh
index 2bbc134597..1c26108e11 100644
--- a/platform/android/scripts/configure.sh
+++ b/platform/android/scripts/configure.sh
@@ -9,8 +9,11 @@ SQLITE_VERSION=3.9.1
ZLIB_VERSION=system
NUNICODE_VERSION=1.6
LIBZIP_VERSION=0.11.2
-GEOMETRY_VERSION=0.5.0
-GEOJSONVT_VERSION=4.1.2
+GEOMETRY_VERSION=0.8.0
+GEOJSON_VERSION=0.1.4
+GEOJSONVT_VERSION=6.1.2
+SUPERCLUSTER_VERSION=0.2.0
+KDBUSH_VERSION=0.1.1
VARIANT_VERSION=1.1.0
RAPIDJSON_VERSION=1.0.2
JNI_HPP_VERSION=2.0.0
diff --git a/platform/android/scripts/debug.sh b/platform/android/scripts/debug.sh
index ade9ab2d6f..efed96969a 100755
--- a/platform/android/scripts/debug.sh
+++ b/platform/android/scripts/debug.sh
@@ -11,7 +11,7 @@ export PATH="${MASON_DIR}:${PATH}"
export MASON_ANDROID_ABI=x86
export MASON_ANDROID_ARCH=x86
export MASON_ANDROID_PLATFORM=9
-export MASON_NDK_PACKAGE_VERSION=${MASON_ANDROID_ARCH}-${MASON_ANDROID_PLATFORM}-r10e
+export MASON_NDK_PACKAGE_VERSION=${MASON_ANDROID_ARCH}-${MASON_ANDROID_PLATFORM}-r12b
if [[ $1 == '--prepare' ]]; then
mkdir -p ~/.android/debugging/{vendor,system}_lib
diff --git a/platform/android/scripts/generate-style-code.js b/platform/android/scripts/generate-style-code.js
new file mode 100644
index 0000000000..0abc4969be
--- /dev/null
+++ b/platform/android/scripts/generate-style-code.js
@@ -0,0 +1,206 @@
+'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 snakeCaseUpper(str) {
+ return str.replace(/-/g, "_").toUpperCase();
+}
+
+global.propertyType = function propertyType(property) {
+ 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.propertyJNIType = function propertyJNIType(property) {
+ switch (property.type) {
+ case 'boolean':
+ return 'jboolean';
+ case 'jfloat':
+ return 'Float';
+ case 'String':
+ return 'String';
+ case 'enum':
+ return 'String';
+ case 'color':
+ return 'String';
+ case 'array':
+ return `jarray<${propertyType({type:property.value})}[]>`;
+ default:
+ return 'jobject*';
+ }
+}
+
+global.propertyNativeType = function (property) {
+ if (/-translate-anchor$/.test(property.name)) {
+ return 'TranslateAnchorType';
+ }
+ if (/-(rotation|pitch)-alignment$/.test(property.name)) {
+ return 'AlignmentType';
+ }
+ switch (property.type) {
+ case 'boolean':
+ return 'bool';
+ case 'number':
+ return 'float';
+ case 'string':
+ return 'std::string';
+ case 'enum':
+ return `${camelize(property.name)}Type`;
+ case 'color':
+ return `Color`;
+ case 'array':
+ if (property.length) {
+ return `std::array<${propertyType({type: property.value})}, ${property.length}>`;
+ } else {
+ return `std::vector<${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 "";
+ }
+};
+
+global.defaultValueJava = function(property) {
+ if(property.name.endsWith("-pattern")) {
+ return '"pedestrian-polygon"';
+ }
+ if(property.name.endsWith("-font")) {
+ return 'new String[]{"Open Sans Regular", "Arial Unicode MS Regular"}';
+ }
+ switch (property.type) {
+ case 'boolean':
+ return 'true';
+ case 'number':
+ return '0.3f';
+ case 'string':
+ return '"' + property['default'] + '"';
+ case 'enum':
+ return snakeCaseUpper(property.name) + "_" + snakeCaseUpper(property.values[0]);
+ case 'color':
+ return '"rgba(0, 0, 0, 1)"';
+ case 'array':
+ switch (property.value) {
+ case 'string':
+ return '[' + property['default'] + "]";
+ case 'number':
+ var result ='new Float[]{';
+ for (var i = 0; i < property.length; i++) {
+ result += "0f";
+ if (i +1 != property.length) {
+ result += ",";
+ }
+ }
+ return result + "}";
+ }
+ default: throw new Error(`unknown type for ${property.name}`)
+ }
+}
+
+//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,
+ properties: layoutProperties.concat(paintProperties)
+ };
+});
+
+const layerHpp = ejs.compile(fs.readFileSync('platform/android/src/style/layers/layer.hpp.ejs', 'utf8'), {strict: true});
+const layerCpp = ejs.compile(fs.readFileSync('platform/android/src/style/layers/layer.cpp.ejs', 'utf8'), {strict: true});
+const layerJava = ejs.compile(fs.readFileSync('platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/layer.java.ejs', 'utf8'), {strict: true});
+const layerJavaUnitTests = ejs.compile(fs.readFileSync('platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/layer.junit.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));
+ fs.writeFileSync(`platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/style/${camelize(layer.type)}LayerTest.java`, layerJavaUnitTests(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/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/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 enumPropertyJavaTemplate = ejs.compile(fs.readFileSync('platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property.java.ejs', 'utf8'), {strict: true});
+fs.writeFileSync(
+ `platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java`,
+ enumPropertyJavaTemplate({properties: enumProperties})
+);
+
+//De-dup types before generating cpp headers
+const enumPropertiesDeDup = _(enumProperties).uniq(global.propertyNativeType).value();
+const enumPropertyHppTypeStringValueTemplate = ejs.compile(fs.readFileSync('platform/android/src/style/conversion/types_string_values.hpp.ejs', 'utf8'), {strict: true});
+fs.writeFileSync(
+ `platform/android/src/style/conversion/types_string_values.hpp`,
+ enumPropertyHppTypeStringValueTemplate({properties: enumPropertiesDeDup})
+);
+
+const enumPropertyHppTypeTemplate = ejs.compile(fs.readFileSync('platform/android/src/style/conversion/types.hpp.ejs', 'utf8'), {strict: true});
+fs.writeFileSync(
+ `platform/android/src/style/conversion/types.hpp`,
+ enumPropertyHppTypeTemplate({properties: enumPropertiesDeDup})
+);
diff --git a/platform/android/src/asset_file_source.cpp b/platform/android/src/asset_file_source.cpp
index 2babe7db41..ec4925a02e 100644
--- a/platform/android/src/asset_file_source.cpp
+++ b/platform/android/src/asset_file_source.cpp
@@ -100,7 +100,7 @@ private:
AssetFileSource::AssetFileSource(const std::string& root)
: thread(std::make_unique<util::Thread<Impl>>(
- util::ThreadContext{"AssetFileSource"},
+ util::ThreadContext{"AssetFileSource", util::ThreadPriority::Low},
root)) {
}
diff --git a/platform/android/src/async_task.cpp b/platform/android/src/async_task.cpp
index 6a9263baff..7b78eadb0c 100644
--- a/platform/android/src/async_task.cpp
+++ b/platform/android/src/async_task.cpp
@@ -1,9 +1,9 @@
#include "run_loop_impl.hpp"
#include <mbgl/util/async_task.hpp>
-#include <mbgl/util/atomic.hpp>
#include <mbgl/util/run_loop.hpp>
+#include <atomic>
#include <functional>
namespace mbgl {
@@ -45,7 +45,7 @@ private:
// TODO: Use std::atomic_flag if we ever drop
// support for ARMv5
- util::Atomic<bool> queued;
+ std::atomic<bool> queued;
std::function<void()> task;
};
diff --git a/platform/android/src/conversion/constant.hpp b/platform/android/src/conversion/constant.hpp
new file mode 100644
index 0000000000..9a570d3717
--- /dev/null
+++ b/platform/android/src/conversion/constant.hpp
@@ -0,0 +1,95 @@
+#pragma once
+
+#include "conversion.hpp"
+
+#include <mbgl/util/optional.hpp>
+#include <jni/jni.hpp>
+
+#include <string>
+#include <array>
+#include <vector>
+#include <sstream>
+
+namespace mbgl {
+namespace android {
+namespace conversion {
+
+template <>
+struct Converter<jni::jobject*, bool> {
+ Result<jni::jobject*> operator()(jni::JNIEnv& env, const bool& value) const {
+ static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/Boolean")).release();
+ static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "(Z)V");
+ return {&jni::NewObject(env, *javaClass, *constructor, (jboolean) value)};
+ }
+};
+
+template <>
+struct Converter<jni::jobject*, float> {
+ Result<jni::jobject*> operator()(jni::JNIEnv& env, const float& value) const {
+ static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/Float")).release();
+ static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "(F)V");
+ return {&jni::NewObject(env, *javaClass, *constructor, (jfloat) value)};
+ }
+};
+
+template <>
+struct Converter<jni::jobject*, std::string> {
+ Result<jni::jobject*> operator()(jni::JNIEnv& env, const std::string& value) const {
+ return {jni::Make<jni::String>(env, value).Get()};
+ }
+};
+
+template <>
+struct Converter<jni::jobject*, Color> {
+ Result<jni::jobject*> operator()(jni::JNIEnv& env, const Color& value) const {
+ std::stringstream sstream;
+ sstream << "rgba(" << value.r << ", " << value.g << ", " << value.b << ", " << value.a << ")";
+ std::string result = sstream.str();
+ return convert<jni::jobject*, std::string>(env, result);
+ }
+};
+
+template <std::size_t N>
+struct Converter<jni::jobject*, std::array<float, N>> {
+ Result<jni::jobject*> operator()(jni::JNIEnv& env, const std::array<float, N>& value) const {
+ std::vector<float> v;
+ for (const float& id : value) {
+ v.push_back(id);
+ }
+ return convert<jni::jobject*, std::vector<float>>(env, v);
+ }
+};
+
+template <>
+struct Converter<jni::jobject*, std::vector<std::string>> {
+ Result<jni::jobject*> operator()(jni::JNIEnv& env, const std::vector<std::string>& value) const {
+ static jni::jclass* stringCass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/String")).release();
+ jni::jarray<jni::jobject>& jarray = jni::NewObjectArray(env, value.size(), *stringCass);
+
+ for(size_t i = 0; i < value.size(); i = i + 1) {
+ Result<jni::jobject*> converted = convert<jni::jobject*, std::string>(env, value.at(i));
+ jni::SetObjectArrayElement(env, jarray, i, *converted);
+ }
+
+ return &jarray;
+ }
+};
+
+template <>
+struct Converter<jni::jobject*, std::vector<float>> {
+ Result<jni::jobject*> operator()(jni::JNIEnv& env, const std::vector<float>& value) const {
+ static jni::jclass* floatClass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/Float")).release();
+ jni::jarray<jni::jobject>& jarray = jni::NewObjectArray(env, value.size(), *floatClass);
+
+ for(size_t i = 0; i < value.size(); i = i + 1) {
+ Result<jni::jobject*> converted = convert<jni::jobject*, float>(env, value.at(i));
+ jni::SetObjectArrayElement(env, jarray, i, *converted);
+ }
+
+ return &jarray;
+ }
+};
+
+} // namespace conversion
+} // namespace style
+} // namespace mbgl
diff --git a/platform/android/src/conversion/conversion.hpp b/platform/android/src/conversion/conversion.hpp
new file mode 100644
index 0000000000..ea8a31bcf2
--- /dev/null
+++ b/platform/android/src/conversion/conversion.hpp
@@ -0,0 +1,50 @@
+#pragma once
+
+#include <mbgl/util/variant.hpp>
+
+#include <jni/jni.hpp>
+
+#include <string>
+
+namespace mbgl {
+namespace android {
+namespace conversion {
+
+struct Error { std::string message; };
+
+template <class T>
+class Result : private variant<T, Error> {
+public:
+ using variant<T, Error>::variant;
+
+ explicit operator bool() const {
+ return this->template is<T>();
+ }
+
+ T& operator*() {
+ assert(this->template is<T>());
+ return this->template get<T>();
+ }
+
+ const T& operator*() const {
+ assert(this->template is<T>());
+ return this->template get<T>();
+ }
+
+ const Error& error() const {
+ assert(this->template is<Error>());
+ return this->template get<Error>();
+ }
+};
+
+template <class T, class V>
+struct Converter;
+
+template <class T, typename V, class...Args>
+Result<T> convert(jni::JNIEnv& env, const V& value, Args&&...args) {
+ return Converter<T, V>()(env, value, std::forward<Args>(args)...);
+}
+
+} // namespace conversion
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/java_types.cpp b/platform/android/src/java_types.cpp
new file mode 100644
index 0000000000..6383426387
--- /dev/null
+++ b/platform/android/src/java_types.cpp
@@ -0,0 +1,37 @@
+#include "java_types.hpp"
+
+namespace mbgl {
+namespace android {
+namespace java {
+
+ jni::jclass* ObjectArray::jclass;
+
+ jni::jclass* String::jclass;
+
+ jni::jclass* Boolean::jclass;
+ jni::jmethodID* Boolean::booleanValueMethodId;
+
+ jni::jclass* Number::jclass;
+ jni::jmethodID* Number::floatValueMethodId;
+
+ jni::jclass* Map::jclass;
+ jni::jmethodID* Map::getMethodId;
+
+ void registerNatives(JNIEnv& env) {
+ ObjectArray::jclass = jni::NewGlobalRef(env, &jni::FindClass(env, "[Ljava/lang/Object;")).release();
+
+ String::jclass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/String")).release();
+
+ Boolean::jclass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/Boolean")).release();
+ Boolean::booleanValueMethodId = &jni::GetMethodID(env, *Boolean::jclass, "booleanValue", "()Z");
+
+ Number::jclass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/Number")).release();
+ Number::floatValueMethodId = &jni::GetMethodID(env, *Number::jclass, "floatValue", "()F");
+
+ Map::jclass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/util/Map")).release();
+ Map::getMethodId = &jni::GetMethodID(env, *Map::jclass, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
+ }
+
+}
+}
+}
diff --git a/platform/android/src/java_types.hpp b/platform/android/src/java_types.hpp
new file mode 100644
index 0000000000..2e2c5fc2d6
--- /dev/null
+++ b/platform/android/src/java_types.hpp
@@ -0,0 +1,35 @@
+#pragma once
+
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+namespace java {
+
+ struct ObjectArray {
+ static jni::jclass* jclass;
+ };
+
+ struct String {
+ static jni::jclass* jclass;
+ };
+
+ struct Boolean {
+ static jni::jclass* jclass;
+ static jni::jmethodID* booleanValueMethodId;
+ };
+
+ struct Number {
+ static jni::jclass* jclass;
+ static jni::jmethodID* floatValueMethodId;
+ };
+
+ struct Map {
+ static jni::jclass* jclass;
+ static jni::jmethodID* getMethodId;
+ };
+
+ void registerNatives(JNIEnv&);
+}
+}
+} \ No newline at end of file
diff --git a/platform/android/src/jni.cpp b/platform/android/src/jni.cpp
index e79689d7ad..5907a0ff9d 100755
--- a/platform/android/src/jni.cpp
+++ b/platform/android/src/jni.cpp
@@ -9,12 +9,15 @@
#include <sys/system_properties.h>
#include "jni.hpp"
+#include "java_types.hpp"
#include "native_map_view.hpp"
+#include "style/layers/layers.hpp"
+#include "style/sources/sources.hpp"
#include <mbgl/map/map.hpp>
#include <mbgl/map/camera.hpp>
#include <mbgl/annotation/annotation.hpp>
-#include <mbgl/style/layers/custom_layer.hpp>
+#include <mbgl/style/layer.hpp>
#include <mbgl/sprite/sprite_image.hpp>
#include <mbgl/platform/event.hpp>
#include <mbgl/platform/log.hpp>
@@ -42,6 +45,7 @@ std::string androidRelease;
jni::jmethodID* onInvalidateId = nullptr;
jni::jmethodID* onMapChangedId = nullptr;
jni::jmethodID* onFpsChangedId = nullptr;
+jni::jmethodID* onSnapshotReadyId = nullptr;
jni::jclass* latLngClass = nullptr;
jni::jmethodID* latLngConstructorId = nullptr;
@@ -98,13 +102,6 @@ jni::jfieldID* rectFTopId = nullptr;
jni::jfieldID* rectFRightId = nullptr;
jni::jfieldID* rectFBottomId = nullptr;
-jni::jclass* customLayerClass = nullptr;
-jni::jfieldID* customLayerIdId = nullptr;
-jni::jfieldID* customLayerContextId = nullptr;
-jni::jfieldID* customLayerInitializeFunctionId = nullptr;
-jni::jfieldID* customLayerRenderFunctionId = nullptr;
-jni::jfieldID* customLayerDeinitializeFunctionId = nullptr;
-
// Offline declarations start
jni::jfieldID* offlineManagerClassPtrId = nullptr;
@@ -478,15 +475,10 @@ void nativeMoveBy(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdoubl
nativeMapView->getMap().moveBy(center, mbgl::Milliseconds(duration));
}
-void nativeSetLatLng(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jobject* latLng,
- jlong duration) {
+void nativeSetLatLng(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble latitude, jdouble longitude, jlong duration) {
mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetLatLng");
assert(nativeMapViewPtr != 0);
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- jdouble latitude = jni::GetField<jdouble>(*env, latLng, *latLngLatitudeId);
- jdouble longitude = jni::GetField<jdouble>(*env, latLng, *latLngLongitudeId);
-
nativeMapView->getMap().setLatLng(mbgl::LatLng(latitude, longitude), nativeMapView->getInsets(), mbgl::Duration(duration));
}
@@ -660,29 +652,16 @@ void nativeResetNorth(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
nativeMapView->getMap().resetNorth();
}
-void nativeUpdateMarker(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jobject* marker) {
+void nativeUpdateMarker(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jlong markerId, jdouble lat, jdouble lon, jni::jstring* jid) {
mbgl::Log::Debug(mbgl::Event::JNI, "nativeUpdateMarker");
assert(nativeMapViewPtr != 0);
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- jlong markerId = jni::GetField<jlong>(*env, marker, *markerIdId);
if (markerId == -1) {
return;
}
-
- jni::jobject* position = jni::GetField<jni::jobject*>(*env, marker, *markerPositionId);
- jni::jobject* icon = jni::GetField<jni::jobject*>(*env, marker, *markerIconId);
-
- jni::jstring* jid = reinterpret_cast<jni::jstring*>(jni::GetField<jni::jobject*>(*env, icon, *iconIdId));
std::string iconId = std_string_from_jstring(env, jid);
-
- jdouble latitude = jni::GetField<jdouble>(*env, position, *latLngLatitudeId);
- jdouble longitude = jni::GetField<jdouble>(*env, position, *latLngLongitudeId);
-
- nativeMapView->getMap().updateAnnotation(markerId, mbgl::SymbolAnnotation {
- mbgl::Point<double>(longitude, latitude),
- iconId
- });
+ // Because Java only has int, not unsigned int, we need to bump the annotation id up to a long.
+ nativeMapView->getMap().updateAnnotation(markerId, mbgl::SymbolAnnotation { mbgl::Point<double>(lon, lat), iconId });
}
jni::jarray<jlong>* nativeAddMarkers(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jarray<jni::jobject>* jarray) {
@@ -724,7 +703,7 @@ static mbgl::Color toColor(jint color) {
float g = (color >> 8) & 0xFF;
float b = (color) & 0xFF;
float a = (color >> 24) & 0xFF;
- return {{ r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f }};
+ return { r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f };
}
template <class Geometry>
@@ -734,10 +713,12 @@ Geometry toGeometry(JNIEnv *env, jni::jobject* jlist) {
reinterpret_cast<jni::jarray<jni::jobject>*>(jni::CallMethod<jni::jobject*>(*env, jlist, *listToArrayId));
NullCheck(*env, jarray);
+ std::size_t size = jni::GetArrayLength(*env, *jarray);
+
Geometry geometry;
- geometry.reserve(jni::GetArrayLength(*env, *jarray));
+ geometry.reserve(size);
- for (std::size_t i = 0; i < geometry.size(); i++) {
+ for (std::size_t i = 0; i < size; i++) {
jni::jobject* latLng = reinterpret_cast<jni::jobject*>(jni::GetObjectArrayElement(*env, *jarray, i));
NullCheck(*env, latLng);
@@ -770,9 +751,9 @@ jni::jarray<jlong>* nativeAddPolylines(JNIEnv *env, jni::jobject* obj, jlong nat
jni::jobject* points = jni::GetField<jni::jobject*>(*env, polyline, *polylinePointsId);
mbgl::LineAnnotation annotation { toGeometry<mbgl::LineString<double>>(env, points) };
- annotation.opacity = jni::GetField<jfloat>(*env, polyline, *polylineAlphaId);
- annotation.color = toColor(jni::GetField<jint>(*env, polyline, *polylineColorId));
- annotation.width = jni::GetField<jfloat>(*env, polyline, *polylineWidthId);
+ annotation.opacity = { jni::GetField<jfloat>(*env, polyline, *polylineAlphaId) };
+ annotation.color = { toColor(jni::GetField<jint>(*env, polyline, *polylineColorId)) };
+ annotation.width = { jni::GetField<jfloat>(*env, polyline, *polylineWidthId) };
ids.push_back(nativeMapView->getMap().addAnnotation(annotation));
jni::DeleteLocalRef(*env, polyline);
@@ -797,9 +778,9 @@ jni::jarray<jlong>* nativeAddPolygons(JNIEnv *env, jni::jobject* obj, jlong nati
jni::jobject* points = jni::GetField<jni::jobject*>(*env, polygon, *polygonPointsId);
mbgl::FillAnnotation annotation { mbgl::Polygon<double> { toGeometry<mbgl::LinearRing<double>>(env, points) } };
- annotation.opacity = jni::GetField<jfloat>(*env, polygon, *polygonAlphaId);
- annotation.outlineColor = toColor(jni::GetField<jint>(*env, polygon, *polygonStrokeColorId));
- annotation.color = toColor(jni::GetField<jint>(*env, polygon, *polygonFillColorId));
+ annotation.opacity = { jni::GetField<jfloat>(*env, polygon, *polygonAlphaId) };
+ annotation.outlineColor = { toColor(jni::GetField<jint>(*env, polygon, *polygonStrokeColorId)) };
+ annotation.color = { toColor(jni::GetField<jint>(*env, polygon, *polygonFillColorId)) };
ids.push_back(nativeMapView->getMap().addAnnotation(annotation));
jni::DeleteLocalRef(*env, polygon);
@@ -808,6 +789,42 @@ jni::jarray<jlong>* nativeAddPolygons(JNIEnv *env, jni::jobject* obj, jlong nati
return std_vector_uint_to_jobject(env, ids);
}
+jlong nativeUpdatePolygon(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jlong polygonId, jni::jobject* polygon) {
+ mbgl::Log::Debug(mbgl::Event::JNI, "nativeUpdatePolygon");
+ assert(nativeMapViewPtr != 0);
+ NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
+ if (polygonId == -1) {
+ return polygonId;
+ }
+ jni::jobject* points = jni::GetField<jni::jobject*>(*env, polygon, *polygonPointsId);
+
+ mbgl::FillAnnotation annotation { mbgl::Polygon<double> { toGeometry<mbgl::LinearRing<double>>(env, points) } };
+ annotation.opacity = { jni::GetField<jfloat>(*env, polygon, *polygonAlphaId) };
+ annotation.outlineColor = { toColor(jni::GetField<jint>(*env, polygon, *polygonStrokeColorId)) };
+ annotation.color = { toColor(jni::GetField<jint>(*env, polygon, *polygonFillColorId)) };
+ //TODO replace remove add with updateAnnotation, https://github.com/mapbox/mapbox-gl-native/issues/5844
+ nativeMapView->getMap().removeAnnotation(polygonId);
+ return nativeMapView->getMap().addAnnotation(annotation);
+}
+
+jlong nativeUpdatePolyline(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jlong polylineId, jni::jobject* polyline) {
+ mbgl::Log::Debug(mbgl::Event::JNI, "nativeUpdatePolyline");
+ assert(nativeMapViewPtr != 0);
+ NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
+ if (polylineId == -1) {
+ return polylineId;
+ }
+ jni::jobject* points = jni::GetField<jni::jobject*>(*env, polyline, *polylinePointsId);
+
+ mbgl::LineAnnotation annotation { toGeometry<mbgl::LineString<double>>(env, points) };
+ annotation.opacity = { jni::GetField<jfloat>(*env, polyline, *polylineAlphaId) };
+ annotation.color = { toColor(jni::GetField<jint>(*env, polyline, *polylineColorId)) };
+ annotation.width = { jni::GetField<jfloat>(*env, polyline, *polylineWidthId) };
+ //TODO replace remove add with updateAnnotation, https://github.com/mapbox/mapbox-gl-native/issues/5844
+ nativeMapView->getMap().removeAnnotation(polylineId);
+ return nativeMapView->getMap().addAnnotation(annotation);
+}
+
void nativeRemoveAnnotations(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jarray<jlong>* jarray) {
mbgl::Log::Debug(mbgl::Event::JNI, "nativeRemoveAnnotations");
assert(nativeMapViewPtr != 0);
@@ -902,7 +919,7 @@ void nativeSetVisibleCoordinateBounds(JNIEnv *env, jni::jobject* obj, jlong nati
if (duration > 0) {
animationOptions.duration.emplace(mbgl::Milliseconds(duration));
// equivalent to kCAMediaTimingFunctionDefault in iOS
- animationOptions.easing = mbgl::util::UnitBezier(0.25, 0.1, 0.25, 0.1);
+ animationOptions.easing.emplace(mbgl::util::UnitBezier { 0.25, 0.1, 0.25, 0.1 });
}
nativeMapView->getMap().easeTo(cameraOptions, animationOptions);
@@ -963,50 +980,34 @@ jdouble nativeGetMetersPerPixelAtLatitude(JNIEnv *env, jni::jobject* obj, jlong
return nativeMapView->getMap().getMetersPerPixelAtLatitude(lat, zoom);
}
-jni::jobject* nativeProjectedMetersForLatLng(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jobject* latLng) {
+jni::jobject* nativeProjectedMetersForLatLng(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble latitude, jdouble longitude) {
mbgl::Log::Debug(mbgl::Event::JNI, "nativeProjectedMetersForLatLng");
assert(nativeMapViewPtr != 0);
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- jdouble latitude = jni::GetField<jdouble>(*env, latLng, *latLngLatitudeId);
- jdouble longitude = jni::GetField<jdouble>(*env, latLng, *latLngLongitudeId);
-
mbgl::ProjectedMeters projectedMeters = nativeMapView->getMap().projectedMetersForLatLng(mbgl::LatLng(latitude, longitude));
return &jni::NewObject(*env, *projectedMetersClass, *projectedMetersConstructorId, projectedMeters.northing, projectedMeters.easting);
}
-jni::jobject* nativeLatLngForProjectedMeters(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jobject* projectedMeters) {
+jni::jobject* nativeLatLngForProjectedMeters(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble northing, jdouble easting) {
mbgl::Log::Debug(mbgl::Event::JNI, "nativeLatLngForProjectedMeters");
assert(nativeMapViewPtr != 0);
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- jdouble northing = jni::GetField<jdouble>(*env, projectedMeters, *projectedMetersNorthingId);
- jdouble easting = jni::GetField<jdouble>(*env, projectedMeters, *projectedMetersEastingId);
-
mbgl::LatLng latLng = nativeMapView->getMap().latLngForProjectedMeters(mbgl::ProjectedMeters(northing, easting));
return &jni::NewObject(*env, *latLngClass, *latLngConstructorId, latLng.latitude, latLng.longitude);
}
-jni::jobject* nativePixelForLatLng(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jobject* latLng) {
+jni::jobject* nativePixelForLatLng(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble latitude, jdouble longitude) {
mbgl::Log::Debug(mbgl::Event::JNI, "nativePixelForLatLng");
assert(nativeMapViewPtr != 0);
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- jdouble latitude = jni::GetField<jdouble>(*env, latLng, *latLngLatitudeId);
- jdouble longitude = jni::GetField<jdouble>(*env, latLng, *latLngLongitudeId);
-
mbgl::ScreenCoordinate pixel = nativeMapView->getMap().pixelForLatLng(mbgl::LatLng(latitude, longitude));
return &jni::NewObject(*env, *pointFClass, *pointFConstructorId, static_cast<jfloat>(pixel.x), static_cast<jfloat>(pixel.y));
}
-jni::jobject* nativeLatLngForPixel(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jobject* pixel) {
+jni::jobject* nativeLatLngForPixel(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jfloat x, jfloat y) {
mbgl::Log::Debug(mbgl::Event::JNI, "nativeLatLngForPixel");
assert(nativeMapViewPtr != 0);
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- jfloat x = jni::GetField<jfloat>(*env, pixel, *pointFXId);
- jfloat y = jni::GetField<jfloat>(*env, pixel, *pointFYId);
-
mbgl::LatLng latLng = nativeMapView->getMap().latLngForPixel(mbgl::ScreenCoordinate(x, y));
return &jni::NewObject(*env, *latLngClass, *latLngConstructorId, latLng.latitude, latLng.longitude);
}
@@ -1018,14 +1019,11 @@ jdouble nativeGetTopOffsetPixelsForAnnotationSymbol(JNIEnv *env, jni::jobject* o
return nativeMapView->getMap().getTopOffsetPixelsForAnnotationIcon(std_string_from_jstring(env, symbolName));
}
-void nativeJumpTo(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble angle, jni::jobject* centerLatLng, jdouble pitch, jdouble zoom) {
+void nativeJumpTo(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble angle, jdouble latitude, jdouble longitude, jdouble pitch, jdouble zoom) {
mbgl::Log::Debug(mbgl::Event::JNI, "nativeJumpTo");
assert(nativeMapViewPtr != 0);
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- jdouble latitude = jni::GetField<jdouble>(*env, centerLatLng, *latLngLatitudeId);
- jdouble longitude = jni::GetField<jdouble>(*env, centerLatLng, *latLngLongitudeId);
-
mbgl::CameraOptions options;
if (angle != -1) {
options.angle = angle;
@@ -1042,14 +1040,11 @@ void nativeJumpTo(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdoubl
nativeMapView->getMap().jumpTo(options);
}
-void nativeEaseTo(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble angle, jni::jobject* centerLatLng, jlong duration, jdouble pitch, jdouble zoom, jboolean easing) {
+void nativeEaseTo(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble angle, jdouble latitude, jdouble longitude, jlong duration, jdouble pitch, jdouble zoom, jboolean easing) {
mbgl::Log::Debug(mbgl::Event::JNI, "nativeEaseTo");
assert(nativeMapViewPtr != 0);
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- jdouble latitude = jni::GetField<jdouble>(*env, centerLatLng, *latLngLatitudeId);
- jdouble longitude = jni::GetField<jdouble>(*env, centerLatLng, *latLngLongitudeId);
-
mbgl::CameraOptions cameraOptions;
if (angle != -1) {
cameraOptions.angle = angle;
@@ -1067,7 +1062,7 @@ void nativeEaseTo(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdoubl
if (!easing) {
// add a linear interpolator instead of easing
- animationOptions.easing = mbgl::util::UnitBezier(0, 0, 1, 1);
+ animationOptions.easing.emplace(mbgl::util::UnitBezier { 0, 0, 1, 1 });
}
nativeMapView->getMap().easeTo(cameraOptions, animationOptions);
@@ -1080,14 +1075,11 @@ void nativeSetContentPadding(JNIEnv *env, jni::jobject* obj,long nativeMapViewPt
nativeMapView->setInsets({top, left, bottom, right});
}
-void nativeFlyTo(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble angle, jni::jobject* centerLatLng, jlong duration, jdouble pitch, jdouble zoom) {
+void nativeFlyTo(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble angle, jdouble latitude, jdouble longitude, jlong duration, jdouble pitch, jdouble zoom) {
mbgl::Log::Debug(mbgl::Event::JNI, "nativeFlyTo");
assert(nativeMapViewPtr != 0);
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- jdouble latitude = jni::GetField<jdouble>(*env, centerLatLng, *latLngLatitudeId);
- jdouble longitude = jni::GetField<jdouble>(*env, centerLatLng, *latLngLongitudeId);
-
mbgl::CameraOptions cameraOptions;
if (angle != -1) {
cameraOptions.angle = angle;
@@ -1106,24 +1098,86 @@ void nativeFlyTo(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble
nativeMapView->getMap().flyTo(cameraOptions, animationOptions);
}
-void nativeAddCustomLayer(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jobject* customLayer, jni::jstring* before) {
- mbgl::Log::Debug(mbgl::Event::JNI, "nativeAddCustomLayer");
+jni::jobject* nativeGetLayer(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* layerId) {
+ mbgl::Log::Debug(mbgl::Event::JNI, "nativeGetLayer");
+
+ assert(env);
assert(nativeMapViewPtr != 0);
+
+ //Get the native map peer
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().addLayer(std::make_unique<mbgl::style::CustomLayer>(
- std_string_from_jstring(env, reinterpret_cast<jni::jstring*>(jni::GetField<jni::jobject*>(*env, customLayer, *customLayerIdId))),
- reinterpret_cast<mbgl::style::CustomLayerInitializeFunction>(jni::GetField<jlong>(*env, customLayer, *customLayerInitializeFunctionId)),
- reinterpret_cast<mbgl::style::CustomLayerRenderFunction>(jni::GetField<jlong>(*env, customLayer, *customLayerRenderFunctionId)),
- reinterpret_cast<mbgl::style::CustomLayerDeinitializeFunction>(jni::GetField<jlong>(*env, customLayer, *customLayerDeinitializeFunctionId)),
- reinterpret_cast<void*>(jni::GetField<jlong>(*env, customLayer, *customLayerContextId))),
- before ? mbgl::optional<std::string>(std_string_from_jstring(env, before)) : mbgl::optional<std::string>());
+
+ //Find the layer
+ mbgl::style::Layer* coreLayer = nativeMapView->getMap().getLayer(std_string_from_jstring(env, layerId));
+ if (!coreLayer) {
+ mbgl::Log::Debug(mbgl::Event::JNI, "No layer found");
+ return jni::Object<Layer>();
+ }
+
+ //Create and return the layer's native peer
+ return createJavaLayerPeer(*env, nativeMapView->getMap(), *coreLayer);
}
-void nativeRemoveCustomLayer(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* id) {
- mbgl::Log::Debug(mbgl::Event::JNI, "nativeRemoveCustomLayer");
+void nativeAddLayer(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jlong nativeLayerPtr, jni::jstring* before) {
+ mbgl::Log::Debug(mbgl::Event::JNI, "nativeAddLayer");
assert(nativeMapViewPtr != 0);
+ assert(nativeLayerPtr != 0);
+
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().removeLayer(std_string_from_jstring(env, id));
+ Layer *layer = reinterpret_cast<Layer *>(nativeLayerPtr);
+
+ nativeMapView->getMap().addLayer(
+ layer->releaseCoreLayer(),
+ before ? mbgl::optional<std::string>(std_string_from_jstring(env, before)) : mbgl::optional<std::string>()
+ );
+}
+
+void nativeRemoveLayer(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* id) {
+ mbgl::Log::Debug(mbgl::Event::JNI, "nativeRemoveLayer");
+ assert(nativeMapViewPtr != 0);
+ NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
+ try {
+ nativeMapView->getMap().removeLayer(std_string_from_jstring(env, id));
+ } catch (const std::runtime_error& error) {
+ jni::ThrowNew(*env, jni::FindClass(*env, "com/mapbox/mapboxsdk/style/layers/NoSuchLayerException"), error.what());
+ }
+}
+
+void nativeAddSource(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* id, jni::jobject* jsource) {
+ mbgl::Log::Debug(mbgl::Event::JNI, "nativeAddSource");
+ assert(nativeMapViewPtr != 0);
+ assert(id != nullptr);
+ assert(jsource != nullptr);
+
+ //Convert
+ mbgl::optional<std::unique_ptr<mbgl::style::Source>> source = convertToNativeSource(
+ *env,
+ jni::Object<jni::jobject>(jsource), jni::String(id)
+ );
+
+ //Add to map view
+ if (source) {
+ NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
+ nativeMapView->getMap().addSource(std::move(*source));
+ }
+}
+
+void nativeRemoveSource(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* id) {
+ mbgl::Log::Debug(mbgl::Event::JNI, "nativeRemoveSource");
+ assert(nativeMapViewPtr != 0);
+ NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
+ try {
+ nativeMapView->getMap().removeSource(std_string_from_jstring(env, id));
+ } catch (const std::runtime_error& error) {
+ jni::ThrowNew(*env, jni::FindClass(*env, "com/mapbox/mapboxsdk/style/layers/NoSuchSourceException"), error.what());
+ }
+}
+
+void nativeScheduleTakeSnapshot(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
+ mbgl::Log::Error(mbgl::Event::JNI, "nativeRenderToOffscreen");
+ assert(nativeMapViewPtr != 0);
+ NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
+ nativeMapView->scheduleTakeSnapshot();
}
// Offline calls begin
@@ -1183,12 +1237,15 @@ void listOfflineRegions(JNIEnv *env, jni::jobject* obj, jlong defaultFileSourceP
std::size_t index = 0;
jni::jarray<jni::jobject>* jregions = &jni::NewObjectArray(*env2, regions->size(), *offlineRegionClass, NULL);
for (auto& region : *regions) {
+ // Create a new local reference frame (capacity 2 for the NewObject allocations below)
+ // to avoid a local reference table overflow (#5629)
+ jni::UniqueLocalFrame frame = jni::PushLocalFrame(*env2, 2);
+
// Build the Region object
jni::jobject* jregion = &jni::NewObject(*env2, *offlineRegionClass, *offlineRegionConstructorId);
jni::SetField<jni::jobject*>(*env2, jregion, *offlineRegionOfflineManagerId, obj);
jni::SetField<jlong>(*env2, jregion, *offlineRegionIdId, region.getID());
-
// Definition object
mbgl::OfflineTilePyramidRegionDefinition definition = region.getDefinition();
jni::jobject* jdefinition = &jni::NewObject(*env2, *offlineRegionDefinitionClass, *offlineRegionDefinitionConstructorId);
@@ -1198,7 +1255,7 @@ void listOfflineRegions(JNIEnv *env, jni::jobject* obj, jlong defaultFileSourceP
jni::SetField<jdouble>(*env2, jdefinition, *offlineRegionDefinitionMaxZoomId, definition.maxZoom);
jni::SetField<jfloat>(*env2, jdefinition, *offlineRegionDefinitionPixelRatioId, definition.pixelRatio);
jni::SetField<jni::jobject*>(*env2, jregion, *offlineRegionDefinitionId, jdefinition);
-
+
// Metadata object
jni::jarray<jbyte>* metadata = metadata_from_native(env2, region.getMetadata());
jni::SetField<jni::jobject*>(*env2, jregion, *offlineRegionMetadataId, metadata);
@@ -1583,6 +1640,9 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
mbgl::android::RegisterNativeHTTPRequest(env);
+ java::registerNatives(env);
+ registerNativeLayers(env);
+
latLngClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/geometry/LatLng");
latLngClass = jni::NewGlobalRef(env, latLngClass).release();
latLngConstructorId = &jni::GetMethodID(env, *latLngClass, "<init>", "(DD)V");
@@ -1649,19 +1709,12 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
rectFTopId = &jni::GetFieldID(env, *rectFClass, "top", "F");
rectFBottomId = &jni::GetFieldID(env, *rectFClass, "bottom", "F");
- customLayerClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/layers/CustomLayer");
- customLayerClass = jni::NewGlobalRef(env, customLayerClass).release();
- customLayerIdId = &jni::GetFieldID(env, *customLayerClass, "mID", "Ljava/lang/String;");
- customLayerContextId = &jni::GetFieldID(env, *customLayerClass, "mContext", "J");
- customLayerInitializeFunctionId = &jni::GetFieldID(env, *customLayerClass, "mInitializeFunction", "J");
- customLayerRenderFunctionId = &jni::GetFieldID(env, *customLayerClass, "mRenderFunction", "J");
- customLayerDeinitializeFunctionId = &jni::GetFieldID(env, *customLayerClass, "mDeinitializeFunction", "J");
-
jni::jclass& nativeMapViewClass = jni::FindClass(env, "com/mapbox/mapboxsdk/maps/NativeMapView");
onInvalidateId = &jni::GetMethodID(env, nativeMapViewClass, "onInvalidate", "()V");
onMapChangedId = &jni::GetMethodID(env, nativeMapViewClass, "onMapChanged", "(I)V");
onFpsChangedId = &jni::GetMethodID(env, nativeMapViewClass, "onFpsChanged", "(D)V");
+ onSnapshotReadyId = &jni::GetMethodID(env, nativeMapViewClass, "onSnapshotReady","([B)V");
#define MAKE_NATIVE_METHOD(name, sig) jni::MakeNativeMethod<decltype(name), name>( #name, sig )
@@ -1691,7 +1744,7 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
MAKE_NATIVE_METHOD(nativeCancelTransitions, "(J)V"),
MAKE_NATIVE_METHOD(nativeSetGestureInProgress, "(JZ)V"),
MAKE_NATIVE_METHOD(nativeMoveBy, "(JDDJ)V"),
- MAKE_NATIVE_METHOD(nativeSetLatLng, "(JLcom/mapbox/mapboxsdk/geometry/LatLng;J)V"),
+ MAKE_NATIVE_METHOD(nativeSetLatLng, "(JDDJ)V"),
MAKE_NATIVE_METHOD(nativeGetLatLng, "(J)Lcom/mapbox/mapboxsdk/geometry/LatLng;"),
MAKE_NATIVE_METHOD(nativeResetPosition, "(J)V"),
MAKE_NATIVE_METHOD(nativeGetCameraValues, "(J)[D"),
@@ -1715,7 +1768,9 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
MAKE_NATIVE_METHOD(nativeAddMarkers, "(J[Lcom/mapbox/mapboxsdk/annotations/Marker;)[J"),
MAKE_NATIVE_METHOD(nativeAddPolylines, "(J[Lcom/mapbox/mapboxsdk/annotations/Polyline;)[J"),
MAKE_NATIVE_METHOD(nativeAddPolygons, "(J[Lcom/mapbox/mapboxsdk/annotations/Polygon;)[J"),
- MAKE_NATIVE_METHOD(nativeUpdateMarker, "(JLcom/mapbox/mapboxsdk/annotations/Marker;)V"),
+ MAKE_NATIVE_METHOD(nativeUpdateMarker, "(JJDDLjava/lang/String;)V"),
+ MAKE_NATIVE_METHOD(nativeUpdatePolygon, "(JJLcom/mapbox/mapboxsdk/annotations/Polygon;)J"),
+ MAKE_NATIVE_METHOD(nativeUpdatePolyline, "(JJLcom/mapbox/mapboxsdk/annotations/Polyline;)J"),
MAKE_NATIVE_METHOD(nativeRemoveAnnotations, "(J[J)V"),
MAKE_NATIVE_METHOD(nativeGetAnnotationsInBounds, "(JLcom/mapbox/mapboxsdk/geometry/LatLngBounds;)[J"),
MAKE_NATIVE_METHOD(nativeAddAnnotationIcon, "(JLjava/lang/String;IIF[B)V"),
@@ -1727,17 +1782,21 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
MAKE_NATIVE_METHOD(nativeIsFullyLoaded, "(J)Z"),
MAKE_NATIVE_METHOD(nativeSetReachability, "(JZ)V"),
MAKE_NATIVE_METHOD(nativeGetMetersPerPixelAtLatitude, "(JDD)D"),
- MAKE_NATIVE_METHOD(nativeProjectedMetersForLatLng, "(JLcom/mapbox/mapboxsdk/geometry/LatLng;)Lcom/mapbox/mapboxsdk/geometry/ProjectedMeters;"),
- MAKE_NATIVE_METHOD(nativeLatLngForProjectedMeters, "(JLcom/mapbox/mapboxsdk/geometry/ProjectedMeters;)Lcom/mapbox/mapboxsdk/geometry/LatLng;"),
- MAKE_NATIVE_METHOD(nativePixelForLatLng, "(JLcom/mapbox/mapboxsdk/geometry/LatLng;)Landroid/graphics/PointF;"),
- MAKE_NATIVE_METHOD(nativeLatLngForPixel, "(JLandroid/graphics/PointF;)Lcom/mapbox/mapboxsdk/geometry/LatLng;"),
+ MAKE_NATIVE_METHOD(nativeProjectedMetersForLatLng, "(JDD)Lcom/mapbox/mapboxsdk/geometry/ProjectedMeters;"),
+ MAKE_NATIVE_METHOD(nativeLatLngForProjectedMeters, "(JDD)Lcom/mapbox/mapboxsdk/geometry/LatLng;"),
+ MAKE_NATIVE_METHOD(nativePixelForLatLng, "(JDD)Landroid/graphics/PointF;"),
+ MAKE_NATIVE_METHOD(nativeLatLngForPixel, "(JFF)Lcom/mapbox/mapboxsdk/geometry/LatLng;"),
MAKE_NATIVE_METHOD(nativeGetTopOffsetPixelsForAnnotationSymbol, "(JLjava/lang/String;)D"),
- MAKE_NATIVE_METHOD(nativeJumpTo, "(JDLcom/mapbox/mapboxsdk/geometry/LatLng;DD)V"),
- MAKE_NATIVE_METHOD(nativeEaseTo, "(JDLcom/mapbox/mapboxsdk/geometry/LatLng;JDDZ)V"),
- MAKE_NATIVE_METHOD(nativeFlyTo, "(JDLcom/mapbox/mapboxsdk/geometry/LatLng;JDD)V"),
- MAKE_NATIVE_METHOD(nativeAddCustomLayer, "(JLcom/mapbox/mapboxsdk/layers/CustomLayer;Ljava/lang/String;)V"),
- MAKE_NATIVE_METHOD(nativeRemoveCustomLayer, "(JLjava/lang/String;)V"),
- MAKE_NATIVE_METHOD(nativeSetContentPadding, "(JDDDD)V")
+ MAKE_NATIVE_METHOD(nativeJumpTo, "(JDDDDD)V"),
+ MAKE_NATIVE_METHOD(nativeEaseTo, "(JDDDJDDZ)V"),
+ MAKE_NATIVE_METHOD(nativeFlyTo, "(JDDDJDD)V"),
+ MAKE_NATIVE_METHOD(nativeGetLayer, "(JLjava/lang/String;)Lcom/mapbox/mapboxsdk/style/layers/Layer;"),
+ MAKE_NATIVE_METHOD(nativeAddLayer, "(JJLjava/lang/String;)V"),
+ MAKE_NATIVE_METHOD(nativeRemoveLayer, "(JLjava/lang/String;)V"),
+ MAKE_NATIVE_METHOD(nativeAddSource, "(JLjava/lang/String;Lcom/mapbox/mapboxsdk/style/sources/Source;)V"),
+ MAKE_NATIVE_METHOD(nativeRemoveSource, "(JLjava/lang/String;)V"),
+ MAKE_NATIVE_METHOD(nativeSetContentPadding, "(JDDDD)V"),
+ MAKE_NATIVE_METHOD(nativeScheduleTakeSnapshot, "(J)V")
);
// Offline begin
diff --git a/platform/android/src/jni.hpp b/platform/android/src/jni.hpp
index 57f84f0ccc..0810ee656d 100644
--- a/platform/android/src/jni.hpp
+++ b/platform/android/src/jni.hpp
@@ -19,6 +19,7 @@ extern std::string androidRelease;
extern jmethodID onInvalidateId;
extern jmethodID onMapChangedId;
extern jmethodID onFpsChangedId;
+extern jmethodID onSnapshotReadyId;
extern bool attach_jni_thread(JavaVM* vm, JNIEnv** env, std::string threadName);
extern void detach_jni_thread(JavaVM* vm, JNIEnv** env, bool detach);
diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp
index 0b849976eb..578e5d0033 100755
--- a/platform/android/src/native_map_view.cpp
+++ b/platform/android/src/native_map_view.cpp
@@ -194,6 +194,35 @@ void NativeMapView::render() {
map->render();
+ if(snapshot){
+ snapshot = false;
+
+ // take snapshot
+ const unsigned int w = fbWidth;
+ const unsigned int h = fbHeight;
+ mbgl::PremultipliedImage image { w, h };
+ MBGL_CHECK_ERROR(glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, image.data.get()));
+ const size_t stride = image.stride();
+ auto tmp = std::make_unique<uint8_t[]>(stride);
+ uint8_t *rgba = image.data.get();
+ for (int i = 0, j = h - 1; i < j; i++, j--) {
+ std::memcpy(tmp.get(), rgba + i * stride, stride);
+ std::memcpy(rgba + i * stride, rgba + j * stride, stride);
+ std::memcpy(rgba + j * stride, tmp.get(), stride);
+ }
+
+ // encode and convert to jbytes
+ std::string string = encodePNG(image);
+ jbyteArray arr = env->NewByteArray(string.length());
+ env->SetByteArrayRegion(arr,0,string.length(),(jbyte*)string.c_str());
+
+ // invoke Mapview#OnSnapshotReady
+ env->CallVoidMethod(obj, onSnapshotReadyId, arr);
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ }
+ }
+
if ((display != EGL_NO_DISPLAY) && (surface != EGL_NO_SURFACE)) {
if (!eglSwapBuffers(display, surface)) {
mbgl::Log::Error(mbgl::Event::OpenGL, "eglSwapBuffers() returned error %d",
@@ -436,6 +465,10 @@ void NativeMapView::destroySurface() {
}
}
+void NativeMapView::scheduleTakeSnapshot() {
+ snapshot = true;
+}
+
// Speed
/*
typedef enum {
diff --git a/platform/android/src/native_map_view.hpp b/platform/android/src/native_map_view.hpp
index 40cb012b0b..9b5af76dfe 100755
--- a/platform/android/src/native_map_view.hpp
+++ b/platform/android/src/native_map_view.hpp
@@ -49,6 +49,8 @@ public:
mbgl::EdgeInsets getInsets() { return insets;}
void setInsets(mbgl::EdgeInsets insets_);
+ void scheduleTakeSnapshot();
+
private:
EGLConfig chooseConfig(const EGLConfig configs[], EGLint numConfigs);
@@ -79,6 +81,7 @@ private:
bool firstTime = false;
bool fpsEnabled = false;
bool sizeChanged = false;
+ bool snapshot = false;
double fps = 0.0;
int width = 0;
diff --git a/platform/android/src/run_loop.cpp b/platform/android/src/run_loop.cpp
index 7a28a6139c..1e5fc9b4ba 100644
--- a/platform/android/src/run_loop.cpp
+++ b/platform/android/src/run_loop.cpp
@@ -1,13 +1,16 @@
#include "run_loop_impl.hpp"
+#include <mbgl/platform/platform.hpp>
#include <mbgl/util/thread_context.hpp>
#include <mbgl/util/thread_local.hpp>
+#include <mbgl/util/timer.hpp>
#include <android/looper.h>
#include <algorithm>
#include <cassert>
#include <functional>
+#include <memory>
#include <stdexcept>
#include <vector>
@@ -36,9 +39,15 @@ int looperCallbackDefault(int fd, int, void* data) {
int buffer[1];
while (read(fd, buffer, sizeof(buffer)) > 0) {}
- auto runLoop = reinterpret_cast<RunLoop*>(data);
+ auto runLoopImpl = reinterpret_cast<RunLoop::Impl*>(data);
+ auto runLoop = runLoopImpl->runLoop;
+
runLoop->runOnce();
+ if (!runLoopImpl->running) {
+ ALooper_wake(runLoopImpl->loop);
+ }
+
return 1;
}
@@ -47,9 +56,27 @@ int looperCallbackDefault(int fd, int, void* data) {
namespace mbgl {
namespace util {
-RunLoop::Impl::Impl(RunLoop* runLoop, RunLoop::Type type) {
+// This is needed only for the RunLoop living on the main thread because of
+// how we implement timers. We sleep on `ALooper_pollAll` until the next
+// timeout, but on the main thread `ALooper_pollAll` is called by the activity
+// automatically, thus we cannot set the timeout. Instead we wake the loop
+// with an external file descriptor event coming from this thread.
+class Alarm {
+public:
+ Alarm(RunLoop::Impl* loop_) : loop(loop_) {}
+
+ void set(const Milliseconds& timeout) {
+ alarm.start(timeout, mbgl::Duration::zero(), [this]() { loop->wake(); });
+ }
+
+private:
+ Timer alarm;
+ RunLoop::Impl* loop;
+};
+
+RunLoop::Impl::Impl(RunLoop* runLoop_, RunLoop::Type type) : runLoop(runLoop_) {
using namespace mbgl::android;
- detach = attach_jni_thread(theJVM, &env, "");
+ detach = attach_jni_thread(theJVM, &env, platform::getCurrentThreadName());
loop = ALooper_prepare(0);
assert(loop);
@@ -73,7 +100,9 @@ RunLoop::Impl::Impl(RunLoop* runLoop, RunLoop::Type type) {
break;
case Type::Default:
ret = ALooper_addFd(loop, fds[PIPE_OUT], ALOOPER_POLL_CALLBACK,
- ALOOPER_EVENT_INPUT, looperCallbackDefault, runLoop);
+ ALOOPER_EVENT_INPUT, looperCallbackDefault, this);
+ alarm = std::make_unique<Thread<Alarm>>(ThreadContext{"Alarm"}, this);
+ running = true;
break;
}
@@ -83,6 +112,8 @@ RunLoop::Impl::Impl(RunLoop* runLoop, RunLoop::Type type) {
}
RunLoop::Impl::~Impl() {
+ alarm.reset();
+
if (ALooper_removeFd(loop, fds[PIPE_OUT]) != 1) {
throw std::runtime_error("Failed to remove file descriptor from Looper.");
}
@@ -117,10 +148,16 @@ void RunLoop::Impl::addRunnable(Runnable* runnable) {
void RunLoop::Impl::removeRunnable(Runnable* runnable) {
std::lock_guard<std::recursive_mutex> lock(mtx);
- if (runnable->iter != runnables.end()) {
- runnables.erase(runnable->iter);
- runnable->iter = runnables.end();
+ if (runnable->iter == runnables.end()) {
+ return;
+ }
+
+ if (nextRunnable == runnable->iter) {
+ ++nextRunnable;
}
+
+ runnables.erase(runnable->iter);
+ runnable->iter = runnables.end();
}
void RunLoop::Impl::initRunnable(Runnable* runnable) {
@@ -135,8 +172,8 @@ Milliseconds RunLoop::Impl::processRunnables() {
// O(N) but in the render thread where we get tons
// of messages, the size of the list is usually 1~2.
- for (auto iter = runnables.begin(); iter != runnables.end();) {
- Runnable* runnable = *(iter++);
+ for (nextRunnable = runnables.begin(); nextRunnable != runnables.end();) {
+ Runnable* runnable = *(nextRunnable++);
auto const dueTime = runnable->dueTime();
if (dueTime <= now) {
@@ -148,9 +185,14 @@ Milliseconds RunLoop::Impl::processRunnables() {
if (runnables.empty() || nextDue == TimePoint::max()) {
return Milliseconds(-1);
- } else {
- return std::chrono::duration_cast<Milliseconds>(nextDue - now);
}
+
+ auto timeout = std::chrono::duration_cast<Milliseconds>(nextDue - now);
+ if (alarm) {
+ alarm->invoke(&Alarm::set, timeout);
+ }
+
+ return timeout;
}
RunLoop* RunLoop::Get() {
@@ -197,8 +239,10 @@ void RunLoop::runOnce() {
}
void RunLoop::stop() {
- impl->running = false;
- impl->wake();
+ invoke([&] {
+ impl->running = false;
+ impl->wake();
+ });
}
void RunLoop::addWatch(int, Event, std::function<void(int, Event)>&&) {
diff --git a/platform/android/src/run_loop_impl.hpp b/platform/android/src/run_loop_impl.hpp
index d855728b60..a3efa92a83 100644
--- a/platform/android/src/run_loop_impl.hpp
+++ b/platform/android/src/run_loop_impl.hpp
@@ -2,10 +2,11 @@
#include "jni.hpp"
-#include <mbgl/util/atomic.hpp>
#include <mbgl/util/chrono.hpp>
#include <mbgl/util/run_loop.hpp>
+#include <mbgl/util/thread.hpp>
+#include <atomic>
#include <list>
#include <memory>
#include <mutex>
@@ -15,6 +16,8 @@ struct ALooper;
namespace mbgl {
namespace util {
+class Alarm;
+
class RunLoop::Impl {
public:
class Runnable {
@@ -38,6 +41,10 @@ public:
Milliseconds processRunnables();
+ ALooper* loop = nullptr;
+ RunLoop* runLoop = nullptr;
+ std::atomic<bool> running;
+
private:
friend RunLoop;
@@ -46,11 +53,11 @@ private:
JNIEnv *env = nullptr;
bool detach = false;
- ALooper* loop = nullptr;
- util::Atomic<bool> running;
+ std::unique_ptr<Thread<Alarm>> alarm;
std::recursive_mutex mtx;
std::list<Runnable*> runnables;
+ std::list<Runnable*>::iterator nextRunnable;
};
} // namespace util
diff --git a/platform/android/src/style/android_conversion.hpp b/platform/android/src/style/android_conversion.hpp
new file mode 100644
index 0000000000..0ccb704c0a
--- /dev/null
+++ b/platform/android/src/style/android_conversion.hpp
@@ -0,0 +1,91 @@
+#pragma once
+
+#include "value.hpp"
+
+#include <mbgl/platform/log.hpp>
+#include <mbgl/style/conversion.hpp>
+#include <mbgl/util/feature.hpp>
+#include <mbgl/util/optional.hpp>
+
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace style {
+namespace conversion {
+
+inline bool isUndefined(const mbgl::android::Value& value) {
+ return value.isNull();
+}
+
+inline bool isArray(const mbgl::android::Value& value) {
+ return value.isArray();
+}
+
+inline bool isObject(const mbgl::android::Value& value) {
+ return value.isObject();
+}
+
+inline std::size_t arrayLength(const mbgl::android::Value& value) {
+ return value.getLength();;
+}
+
+inline mbgl::android::Value arrayMember(const mbgl::android::Value& value, std::size_t i) {
+ return value.get(i);
+}
+
+inline optional<mbgl::android::Value> objectMember(const mbgl::android::Value& value, const char* key) {
+ mbgl::android::Value member = value.get(key);
+
+ if (!member.isNull()) {
+ return member;
+ } else {
+ return {};
+ }
+}
+
+template <class Fn>
+optional<Error> eachMember(const mbgl::android::Value&, Fn&&) {
+ //TODO
+ mbgl::Log::Warning(mbgl::Event::Android, "eachMember not implemented");
+ return {};
+}
+
+inline optional<bool> toBool(const mbgl::android::Value& value) {
+ if (value.isBool()) {
+ return value.toBool();
+ } else {
+ return {};
+ }
+}
+
+inline optional<float> toNumber(const mbgl::android::Value& value) {
+ if (value.isNumber()) {
+ return value.toNumber();
+ } else {
+ return {};
+ }
+}
+
+inline optional<std::string> toString(const mbgl::android::Value& value) {
+ if (value.isString()) {
+ return value.toString();
+ } else {
+ return {};
+ }
+}
+
+inline optional<Value> toValue(const mbgl::android::Value& value) {
+ if (value.isBool()) {
+ return { value.toBool() };
+ } else if (value.isString()) {
+ return { value.toString() };
+ } else if (value.isNumber()) {
+ return { value.toNumber() };
+ } else {
+ return {};
+ }
+}
+
+} // namespace conversion
+} // namespace style
+} // namespace mbgl
diff --git a/platform/android/src/style/android_geojson.hpp b/platform/android/src/style/android_geojson.hpp
new file mode 100644
index 0000000000..b2e0ca0a4a
--- /dev/null
+++ b/platform/android/src/style/android_geojson.hpp
@@ -0,0 +1,48 @@
+#pragma once
+
+#include "value.hpp"
+
+#include <mapbox/geojson.hpp>
+#include <mbgl/style/conversion.hpp>
+#include <mbgl/style/conversion/geojson.hpp>
+#include <mbgl/util/rapidjson.hpp>
+#include <mbgl/platform/log.hpp>
+#include <jni/jni.hpp>
+
+#include <sstream>
+#include <string>
+
+namespace mbgl {
+namespace style {
+namespace conversion {
+
+template <>
+Result<GeoJSON> convertGeoJSON(const mbgl::android::Value& value) {
+
+ //Value should be a string wrapped in an object
+ mbgl::android::Value jsonValue = value.get("data");
+ if(value.isNull()) {
+ return Error { "no json data found" };
+ }
+ std::string jsonString = value.get("data").toString();
+
+ rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::CrtAllocator> d;
+ d.Parse(jsonString.c_str());
+
+ if (d.HasParseError()) {
+ std::stringstream message;
+ message << d.GetErrorOffset() << " - " << rapidjson::GetParseError_En(d.GetParseError());
+ return Error { message.str() };
+ }
+
+ conversion::Result<GeoJSON> geoJSON = conversion::convertGeoJSON<JSValue>(d);
+ if (!geoJSON) {
+ return Error { geoJSON.error().message };
+ }
+
+ return geoJSON;
+}
+
+} // namespace conversion
+} // namespace style
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/style/conversion/function.hpp b/platform/android/src/style/conversion/function.hpp
new file mode 100644
index 0000000000..ad09ce02d2
--- /dev/null
+++ b/platform/android/src/style/conversion/function.hpp
@@ -0,0 +1,52 @@
+#pragma once
+
+#include <mbgl/style/property_value.hpp>
+#include "../../conversion/conversion.hpp"
+#include "../../conversion/constant.hpp"
+#include "types.hpp"
+#include "function.hpp"
+
+#include <jni/jni.hpp>
+
+#include <tuple>
+#include <vector>
+
+namespace mbgl {
+namespace android {
+namespace conversion {
+
+template <class T>
+inline jni::jobject* toFunctionStopJavaArray(jni::JNIEnv& env, std::vector<std::pair<float, T>> value) {
+ static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/mapboxsdk/style/layers/Function$Stop")).release();
+ static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "(Ljava/lang/Object;Ljava/lang/Object;)V");
+
+ jni::jarray<jni::jobject>& jarray = jni::NewObjectArray(env, value.size(), *javaClass);
+
+ for(size_t i = 0; i < value.size(); i = i + 1) {
+ jni::SetObjectArrayElement(env, jarray, i, &jni::NewObject(env, *javaClass, *constructor, value[i].first, *convert<jni::jobject*, T>(env, value[i].second)));
+ }
+
+ return &jarray;
+}
+
+template <class T>
+struct Converter<jni::jobject*, mbgl::style::Function<T>> {
+
+ Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::Function<T>& value) const {
+ static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/mapboxsdk/style/layers/Function")).release();
+ static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "([Lcom/mapbox/mapboxsdk/style/layers/Function$Stop;)V");
+ static jni::jmethodID* withBase = &jni::GetMethodID(env, *javaClass, "withBase", "(F)Lcom/mapbox/mapboxsdk/style/layers/Function;");
+
+ //Create object
+ jni::jobject* jfunction = &jni::NewObject(env, *javaClass, *constructor, *toFunctionStopJavaArray(env, value.getStops()));
+
+ //Set base
+ jni::CallMethod<jni::jobject*>(env, jfunction, *withBase, value.getBase());
+
+ return {jfunction};
+ }
+};
+
+} // namespace conversion
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/style/conversion/property_value.hpp b/platform/android/src/style/conversion/property_value.hpp
new file mode 100644
index 0000000000..4121192f3f
--- /dev/null
+++ b/platform/android/src/style/conversion/property_value.hpp
@@ -0,0 +1,38 @@
+#pragma once
+
+#include <mbgl/style/property_value.hpp>
+#include "../../conversion/conversion.hpp"
+#include "../../conversion/constant.hpp"
+#include "types.hpp"
+#include "function.hpp"
+
+namespace mbgl {
+namespace android {
+namespace conversion {
+
+template <class T>
+struct Converter<jni::jobject*, mbgl::style::PropertyValue<T>> {
+
+ Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::PropertyValue<T>& value) const {
+
+ if(value.isUndefined()) {
+ //Return a nullptr representing a Java null value
+ return {nullptr};
+ } else if (value.isConstant()) {
+ //Time to convert the constant value
+ Result<jni::jobject*> result = convert<jni::jobject*, T>(env, value.asConstant());
+ return {*result};
+ //return converted;
+ } else if (value.isFunction()) {
+ //Must be a function than
+ return convert<jni::jobject*, mbgl::style::Function<T>>(env, value.asFunction());
+ } else {
+ throw std::runtime_error("Unknown property value type");
+ }
+
+ }
+};
+
+} // namespace conversion
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/style/conversion/types.hpp b/platform/android/src/style/conversion/types.hpp
new file mode 100644
index 0000000000..d3c12ff89a
--- /dev/null
+++ b/platform/android/src/style/conversion/types.hpp
@@ -0,0 +1,98 @@
+// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make style-code-android`.
+#pragma once
+
+#include "types_string_values.hpp"
+#include "../../conversion/conversion.hpp"
+#include "../../conversion/constant.hpp"
+
+#include <mbgl/style/types.hpp>
+#include <mbgl/util/optional.hpp>
+#include <jni/jni.hpp>
+
+#include <string>
+
+namespace mbgl {
+namespace android {
+namespace conversion {
+
+template <>
+struct Converter<jni::jobject*, mbgl::style::VisibilityType> {
+ Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::VisibilityType& value) const {
+ return convert<jni::jobject*, std::string>(env, toString(value));
+ }
+};
+
+template <>
+struct Converter<jni::jobject*, mbgl::style::LineCapType> {
+ Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::LineCapType& value) const {
+ return convert<jni::jobject*, std::string>(env, toString(value));
+ }
+};
+
+template <>
+struct Converter<jni::jobject*, mbgl::style::LineJoinType> {
+ Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::LineJoinType& value) const {
+ return convert<jni::jobject*, std::string>(env, toString(value));
+ }
+};
+
+template <>
+struct Converter<jni::jobject*, mbgl::style::SymbolPlacementType> {
+ Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::SymbolPlacementType& value) const {
+ return convert<jni::jobject*, std::string>(env, toString(value));
+ }
+};
+
+template <>
+struct Converter<jni::jobject*, mbgl::style::AlignmentType> {
+ Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::AlignmentType& value) const {
+ return convert<jni::jobject*, std::string>(env, toString(value));
+ }
+};
+
+template <>
+struct Converter<jni::jobject*, mbgl::style::IconTextFitType> {
+ Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::IconTextFitType& value) const {
+ return convert<jni::jobject*, std::string>(env, toString(value));
+ }
+};
+
+template <>
+struct Converter<jni::jobject*, mbgl::style::TextJustifyType> {
+ Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::TextJustifyType& value) const {
+ return convert<jni::jobject*, std::string>(env, toString(value));
+ }
+};
+
+template <>
+struct Converter<jni::jobject*, mbgl::style::TextAnchorType> {
+ Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::TextAnchorType& value) const {
+ return convert<jni::jobject*, std::string>(env, toString(value));
+ }
+};
+
+template <>
+struct Converter<jni::jobject*, mbgl::style::TextTransformType> {
+ Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::TextTransformType& value) const {
+ return convert<jni::jobject*, std::string>(env, toString(value));
+ }
+};
+
+template <>
+struct Converter<jni::jobject*, mbgl::style::TranslateAnchorType> {
+ Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::TranslateAnchorType& value) const {
+ return convert<jni::jobject*, std::string>(env, toString(value));
+ }
+};
+
+template <>
+struct Converter<jni::jobject*, mbgl::style::CirclePitchScaleType> {
+ Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::CirclePitchScaleType& value) const {
+ return convert<jni::jobject*, std::string>(env, toString(value));
+ }
+};
+
+
+} // namespace conversion
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/style/conversion/types.hpp.ejs b/platform/android/src/style/conversion/types.hpp.ejs
new file mode 100644
index 0000000000..de26d061f7
--- /dev/null
+++ b/platform/android/src/style/conversion/types.hpp.ejs
@@ -0,0 +1,40 @@
+<%
+ const properties = locals.properties;
+-%>
+// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make style-code-android`.
+#pragma once
+
+#include "types_string_values.hpp"
+#include "../../conversion/conversion.hpp"
+#include "../../conversion/constant.hpp"
+
+#include <mbgl/style/types.hpp>
+#include <mbgl/util/optional.hpp>
+#include <jni/jni.hpp>
+
+#include <string>
+
+namespace mbgl {
+namespace android {
+namespace conversion {
+
+template <>
+struct Converter<jni::jobject*, mbgl::style::VisibilityType> {
+ Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::VisibilityType& value) const {
+ return convert<jni::jobject*, std::string>(env, toString(value));
+ }
+};
+
+<% for (const property of properties) { -%>
+template <>
+struct Converter<jni::jobject*, mbgl::style::<%- propertyNativeType(property) %>> {
+ Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::<%- propertyNativeType(property) %>& value) const {
+ return convert<jni::jobject*, std::string>(env, toString(value));
+ }
+};
+
+<% } -%>
+
+} // namespace conversion
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/style/conversion/types_string_values.hpp b/platform/android/src/style/conversion/types_string_values.hpp
new file mode 100644
index 0000000000..35cdb1cbc9
--- /dev/null
+++ b/platform/android/src/style/conversion/types_string_values.hpp
@@ -0,0 +1,209 @@
+// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make style-code-android`.
+#pragma once
+
+#include <mbgl/style/types.hpp>
+
+#include <string>
+#include <stdexcept>
+
+namespace mbgl {
+namespace android {
+namespace conversion {
+
+ //visibility
+ inline std::string toString(mbgl::style::VisibilityType value) {
+ switch (value) {
+ case mbgl::style::VisibilityType::Visible:
+ return "visible";
+ break;
+ case mbgl::style::VisibilityType::None:
+ return "none";
+ break;
+ default:
+ throw std::runtime_error("Not implemented");
+ }
+ }
+
+ //line-cap
+ inline std::string toString(mbgl::style::LineCapType value) {
+ switch (value) {
+ case mbgl::style::LineCapType::Butt:
+ return "butt";
+ break;
+ case mbgl::style::LineCapType::Round:
+ return "round";
+ break;
+ case mbgl::style::LineCapType::Square:
+ return "square";
+ break;
+ default:
+ throw std::runtime_error("Not implemented");
+ }
+ }
+
+ //line-join
+ inline std::string toString(mbgl::style::LineJoinType value) {
+ switch (value) {
+ case mbgl::style::LineJoinType::Bevel:
+ return "bevel";
+ break;
+ case mbgl::style::LineJoinType::Round:
+ return "round";
+ break;
+ case mbgl::style::LineJoinType::Miter:
+ return "miter";
+ break;
+ default:
+ throw std::runtime_error("Not implemented");
+ }
+ }
+
+ //symbol-placement
+ inline std::string toString(mbgl::style::SymbolPlacementType value) {
+ switch (value) {
+ case mbgl::style::SymbolPlacementType::Point:
+ return "point";
+ break;
+ case mbgl::style::SymbolPlacementType::Line:
+ return "line";
+ break;
+ default:
+ throw std::runtime_error("Not implemented");
+ }
+ }
+
+ //icon-rotation-alignment
+ inline std::string toString(mbgl::style::AlignmentType value) {
+ switch (value) {
+ case mbgl::style::AlignmentType::Map:
+ return "map";
+ break;
+ case mbgl::style::AlignmentType::Viewport:
+ return "viewport";
+ break;
+ default:
+ throw std::runtime_error("Not implemented");
+ }
+ }
+
+ //icon-text-fit
+ inline std::string toString(mbgl::style::IconTextFitType value) {
+ switch (value) {
+ case mbgl::style::IconTextFitType::None:
+ return "none";
+ break;
+ case mbgl::style::IconTextFitType::Both:
+ return "both";
+ break;
+ case mbgl::style::IconTextFitType::Width:
+ return "width";
+ break;
+ case mbgl::style::IconTextFitType::Height:
+ return "height";
+ break;
+ default:
+ throw std::runtime_error("Not implemented");
+ }
+ }
+
+ //text-justify
+ inline std::string toString(mbgl::style::TextJustifyType value) {
+ switch (value) {
+ case mbgl::style::TextJustifyType::Left:
+ return "left";
+ break;
+ case mbgl::style::TextJustifyType::Center:
+ return "center";
+ break;
+ case mbgl::style::TextJustifyType::Right:
+ return "right";
+ break;
+ default:
+ throw std::runtime_error("Not implemented");
+ }
+ }
+
+ //text-anchor
+ inline std::string toString(mbgl::style::TextAnchorType value) {
+ switch (value) {
+ case mbgl::style::TextAnchorType::Center:
+ return "center";
+ break;
+ case mbgl::style::TextAnchorType::Left:
+ return "left";
+ break;
+ case mbgl::style::TextAnchorType::Right:
+ return "right";
+ break;
+ case mbgl::style::TextAnchorType::Top:
+ return "top";
+ break;
+ case mbgl::style::TextAnchorType::Bottom:
+ return "bottom";
+ break;
+ case mbgl::style::TextAnchorType::TopLeft:
+ return "top-left";
+ break;
+ case mbgl::style::TextAnchorType::TopRight:
+ return "top-right";
+ break;
+ case mbgl::style::TextAnchorType::BottomLeft:
+ return "bottom-left";
+ break;
+ case mbgl::style::TextAnchorType::BottomRight:
+ return "bottom-right";
+ break;
+ default:
+ throw std::runtime_error("Not implemented");
+ }
+ }
+
+ //text-transform
+ inline std::string toString(mbgl::style::TextTransformType value) {
+ switch (value) {
+ case mbgl::style::TextTransformType::None:
+ return "none";
+ break;
+ case mbgl::style::TextTransformType::Uppercase:
+ return "uppercase";
+ break;
+ case mbgl::style::TextTransformType::Lowercase:
+ return "lowercase";
+ break;
+ default:
+ throw std::runtime_error("Not implemented");
+ }
+ }
+
+ //fill-translate-anchor
+ inline std::string toString(mbgl::style::TranslateAnchorType value) {
+ switch (value) {
+ case mbgl::style::TranslateAnchorType::Map:
+ return "map";
+ break;
+ case mbgl::style::TranslateAnchorType::Viewport:
+ return "viewport";
+ break;
+ default:
+ throw std::runtime_error("Not implemented");
+ }
+ }
+
+ //circle-pitch-scale
+ inline std::string toString(mbgl::style::CirclePitchScaleType value) {
+ switch (value) {
+ case mbgl::style::CirclePitchScaleType::Map:
+ return "map";
+ break;
+ case mbgl::style::CirclePitchScaleType::Viewport:
+ return "viewport";
+ break;
+ default:
+ throw std::runtime_error("Not implemented");
+ }
+ }
+
+
+} // namespace conversion
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/style/conversion/types_string_values.hpp.ejs b/platform/android/src/style/conversion/types_string_values.hpp.ejs
new file mode 100644
index 0000000000..db90a614f5
--- /dev/null
+++ b/platform/android/src/style/conversion/types_string_values.hpp.ejs
@@ -0,0 +1,48 @@
+<%
+ const properties = locals.properties;
+-%>
+// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make style-code-android`.
+#pragma once
+
+#include <mbgl/style/types.hpp>
+
+#include <string>
+#include <stdexcept>
+
+namespace mbgl {
+namespace android {
+namespace conversion {
+
+ //visibility
+ inline std::string toString(mbgl::style::VisibilityType value) {
+ switch (value) {
+ case mbgl::style::VisibilityType::Visible:
+ return "visible";
+ break;
+ case mbgl::style::VisibilityType::None:
+ return "none";
+ break;
+ default:
+ throw std::runtime_error("Not implemented");
+ }
+ }
+
+<% for (const property of properties) { -%>
+ //<%- property.name %>
+ inline std::string toString(mbgl::style::<%- propertyNativeType(property) %> value) {
+ switch (value) {
+<% for (const value of property.values) { -%>
+ case mbgl::style::<%- propertyNativeType(property) %>::<%- camelize(value) %>:
+ return "<%- value %>";
+ break;
+<% } -%>
+ default:
+ throw std::runtime_error("Not implemented");
+ }
+ }
+
+<% } -%>
+
+} // namespace conversion
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/style/layers/background_layer.cpp b/platform/android/src/style/layers/background_layer.cpp
new file mode 100644
index 0000000000..25526a07fa
--- /dev/null
+++ b/platform/android/src/style/layers/background_layer.cpp
@@ -0,0 +1,67 @@
+// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make style-code-android`.
+
+#include "background_layer.hpp"
+
+#include <string>
+
+#include "../conversion/property_value.hpp"
+
+namespace mbgl {
+namespace android {
+
+ BackgroundLayer::BackgroundLayer(jni::JNIEnv& env, jni::String layerId)
+ : Layer(env, std::make_unique<mbgl::style::BackgroundLayer>(jni::Make<std::string>(env, layerId))) {
+ }
+
+ BackgroundLayer::BackgroundLayer(mbgl::Map& map, mbgl::style::BackgroundLayer& coreLayer)
+ : Layer(map, coreLayer) {
+ }
+
+ BackgroundLayer::~BackgroundLayer() = default;
+
+ // Property getters
+
+ jni::Object<jni::ObjectTag> BackgroundLayer::getBackgroundColor(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::BackgroundLayer>()->BackgroundLayer::getBackgroundColor());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> BackgroundLayer::getBackgroundPattern(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::BackgroundLayer>()->BackgroundLayer::getBackgroundPattern());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> BackgroundLayer::getBackgroundOpacity(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::BackgroundLayer>()->BackgroundLayer::getBackgroundOpacity());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Class<BackgroundLayer> BackgroundLayer::javaClass;
+
+ jni::jobject* BackgroundLayer::createJavaPeer(jni::JNIEnv& env) {
+ static auto constructor = BackgroundLayer::javaClass.template GetConstructor<jni::jlong>(env);
+ return BackgroundLayer::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this));
+ }
+
+ void BackgroundLayer::registerNative(jni::JNIEnv& env) {
+ //Lookup the class
+ BackgroundLayer::javaClass = *jni::Class<BackgroundLayer>::Find(env).NewGlobalRef(env).release();
+
+ #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
+
+ //Register the peer
+ jni::RegisterNativePeer<BackgroundLayer>(
+ env, BackgroundLayer::javaClass, "nativePtr",
+ std::make_unique<BackgroundLayer, JNIEnv&, jni::String>,
+ "initialize",
+ "finalize",
+ METHOD(&BackgroundLayer::getBackgroundColor, "nativeGetBackgroundColor"),
+ METHOD(&BackgroundLayer::getBackgroundPattern, "nativeGetBackgroundPattern"),
+ METHOD(&BackgroundLayer::getBackgroundOpacity, "nativeGetBackgroundOpacity"));
+ }
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/layers/background_layer.hpp b/platform/android/src/style/layers/background_layer.hpp
new file mode 100644
index 0000000000..f201213e46
--- /dev/null
+++ b/platform/android/src/style/layers/background_layer.hpp
@@ -0,0 +1,39 @@
+// 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/background_layer.hpp>
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class BackgroundLayer : public Layer {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/BackgroundLayer"; };
+
+ static jni::Class<BackgroundLayer> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+ BackgroundLayer(jni::JNIEnv&, jni::String);
+
+ BackgroundLayer(mbgl::Map&, mbgl::style::BackgroundLayer&);
+
+ ~BackgroundLayer();
+
+ // Property getters
+ jni::Object<jni::ObjectTag> getBackgroundColor(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getBackgroundPattern(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getBackgroundOpacity(jni::JNIEnv&);
+
+ jni::jobject* createJavaPeer(jni::JNIEnv&);
+
+}; // class BackgroundLayer
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/layers/circle_layer.cpp b/platform/android/src/style/layers/circle_layer.cpp
new file mode 100644
index 0000000000..c2d6ff06d1
--- /dev/null
+++ b/platform/android/src/style/layers/circle_layer.cpp
@@ -0,0 +1,95 @@
+// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make style-code-android`.
+
+#include "circle_layer.hpp"
+
+#include <string>
+
+#include "../conversion/property_value.hpp"
+
+namespace mbgl {
+namespace android {
+
+ CircleLayer::CircleLayer(jni::JNIEnv& env, jni::String layerId, jni::String sourceId)
+ : Layer(env, std::make_unique<mbgl::style::CircleLayer>(jni::Make<std::string>(env, layerId), jni::Make<std::string>(env, sourceId))) {
+ }
+
+ CircleLayer::CircleLayer(mbgl::Map& map, mbgl::style::CircleLayer& coreLayer)
+ : Layer(map, coreLayer) {
+ }
+
+ CircleLayer::~CircleLayer() = default;
+
+ // Property getters
+
+ jni::Object<jni::ObjectTag> CircleLayer::getCircleRadius(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::CircleLayer>()->CircleLayer::getCircleRadius());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> CircleLayer::getCircleColor(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::CircleLayer>()->CircleLayer::getCircleColor());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> CircleLayer::getCircleBlur(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::CircleLayer>()->CircleLayer::getCircleBlur());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> CircleLayer::getCircleOpacity(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::CircleLayer>()->CircleLayer::getCircleOpacity());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> CircleLayer::getCircleTranslate(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::CircleLayer>()->CircleLayer::getCircleTranslate());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> CircleLayer::getCircleTranslateAnchor(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::CircleLayer>()->CircleLayer::getCircleTranslateAnchor());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> CircleLayer::getCirclePitchScale(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::CircleLayer>()->CircleLayer::getCirclePitchScale());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Class<CircleLayer> CircleLayer::javaClass;
+
+ jni::jobject* CircleLayer::createJavaPeer(jni::JNIEnv& env) {
+ static auto constructor = CircleLayer::javaClass.template GetConstructor<jni::jlong>(env);
+ return CircleLayer::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this));
+ }
+
+ void CircleLayer::registerNative(jni::JNIEnv& env) {
+ //Lookup the class
+ CircleLayer::javaClass = *jni::Class<CircleLayer>::Find(env).NewGlobalRef(env).release();
+
+ #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
+
+ //Register the peer
+ jni::RegisterNativePeer<CircleLayer>(
+ env, CircleLayer::javaClass, "nativePtr",
+ std::make_unique<CircleLayer, JNIEnv&, jni::String, jni::String>,
+ "initialize",
+ "finalize",
+ METHOD(&CircleLayer::getCircleRadius, "nativeGetCircleRadius"),
+ METHOD(&CircleLayer::getCircleColor, "nativeGetCircleColor"),
+ METHOD(&CircleLayer::getCircleBlur, "nativeGetCircleBlur"),
+ METHOD(&CircleLayer::getCircleOpacity, "nativeGetCircleOpacity"),
+ METHOD(&CircleLayer::getCircleTranslate, "nativeGetCircleTranslate"),
+ METHOD(&CircleLayer::getCircleTranslateAnchor, "nativeGetCircleTranslateAnchor"),
+ METHOD(&CircleLayer::getCirclePitchScale, "nativeGetCirclePitchScale"));
+ }
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/layers/circle_layer.hpp b/platform/android/src/style/layers/circle_layer.hpp
new file mode 100644
index 0000000000..91c99c686e
--- /dev/null
+++ b/platform/android/src/style/layers/circle_layer.hpp
@@ -0,0 +1,47 @@
+// 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/circle_layer.hpp>
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class CircleLayer : public Layer {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/CircleLayer"; };
+
+ static jni::Class<CircleLayer> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+ CircleLayer(jni::JNIEnv&, jni::String, jni::String);
+
+ CircleLayer(mbgl::Map&, mbgl::style::CircleLayer&);
+
+ ~CircleLayer();
+
+ // Property getters
+ jni::Object<jni::ObjectTag> getCircleRadius(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getCircleColor(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getCircleBlur(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getCircleOpacity(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getCircleTranslate(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getCircleTranslateAnchor(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getCirclePitchScale(jni::JNIEnv&);
+
+ jni::jobject* createJavaPeer(jni::JNIEnv&);
+
+}; // class CircleLayer
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/layers/custom_layer.cpp b/platform/android/src/style/layers/custom_layer.cpp
new file mode 100644
index 0000000000..4be6f3800d
--- /dev/null
+++ b/platform/android/src/style/layers/custom_layer.cpp
@@ -0,0 +1,57 @@
+#include "custom_layer.hpp"
+
+#include <string>
+
+#include <mbgl/platform/log.hpp>
+
+namespace mbgl {
+namespace android {
+
+ CustomLayer::CustomLayer(jni::JNIEnv& env, jni::String layerId, jni::jlong initializeFunction, jni::jlong renderFunction, jni::jlong deinitializeFunction, jni::jlong context)
+ : Layer(env, std::make_unique<mbgl::style::CustomLayer>(
+ jni::Make<std::string>(env, layerId),
+ reinterpret_cast<mbgl::style::CustomLayerInitializeFunction>(initializeFunction),
+ reinterpret_cast<mbgl::style::CustomLayerRenderFunction>(renderFunction),
+ reinterpret_cast<mbgl::style::CustomLayerDeinitializeFunction>(deinitializeFunction),
+ reinterpret_cast<void*>(context))
+ ) {
+ }
+
+ CustomLayer::CustomLayer(mbgl::Map& map, mbgl::style::CustomLayer& coreLayer)
+ : Layer(map, coreLayer) {
+ }
+
+ CustomLayer::~CustomLayer() = default;
+
+ void CustomLayer::update(jni::JNIEnv&) {
+ if (map) {
+ map->update(mbgl::Update::Repaint);
+ } else {
+ Log::Error(mbgl::Event::JNI, "No map reference, cannot update");
+ }
+ }
+
+ jni::Class<CustomLayer> CustomLayer::javaClass;
+
+ jni::jobject* CustomLayer::createJavaPeer(jni::JNIEnv& env) {
+ static auto constructor = CustomLayer::javaClass.template GetConstructor<jni::jlong>(env);
+ return CustomLayer::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this));
+ }
+
+ void CustomLayer::registerNative(jni::JNIEnv& env) {
+ //Lookup the class
+ CustomLayer::javaClass = *jni::Class<CustomLayer>::Find(env).NewGlobalRef(env).release();
+
+ #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
+
+ //Register the peer
+ jni::RegisterNativePeer<CustomLayer>(
+ env, CustomLayer::javaClass, "nativePtr",
+ std::make_unique<CustomLayer, JNIEnv&, jni::String, jni::jlong, jni::jlong, jni::jlong, jni::jlong>,
+ "initialize",
+ "finalize",
+ METHOD(&CustomLayer::update, "nativeUpdate"));
+ }
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/layers/custom_layer.hpp b/platform/android/src/style/layers/custom_layer.hpp
new file mode 100644
index 0000000000..1173d21bfd
--- /dev/null
+++ b/platform/android/src/style/layers/custom_layer.hpp
@@ -0,0 +1,32 @@
+#pragma once
+
+#include "layer.hpp"
+#include <mbgl/style/layers/custom_layer.hpp>
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class CustomLayer : public Layer {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/CustomLayer"; };
+
+ static jni::Class<CustomLayer> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+ CustomLayer(jni::JNIEnv&, jni::String, jni::jlong, jni::jlong, jni::jlong, jni::jlong);
+
+ CustomLayer(mbgl::Map&, mbgl::style::CustomLayer&);
+
+ ~CustomLayer();
+
+ void update(jni::JNIEnv&);
+
+ jni::jobject* createJavaPeer(jni::JNIEnv&);
+
+}; // class CustomLayer
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/layers/fill_layer.cpp b/platform/android/src/style/layers/fill_layer.cpp
new file mode 100644
index 0000000000..8cb96c9cd3
--- /dev/null
+++ b/platform/android/src/style/layers/fill_layer.cpp
@@ -0,0 +1,95 @@
+// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make style-code-android`.
+
+#include "fill_layer.hpp"
+
+#include <string>
+
+#include "../conversion/property_value.hpp"
+
+namespace mbgl {
+namespace android {
+
+ FillLayer::FillLayer(jni::JNIEnv& env, jni::String layerId, jni::String sourceId)
+ : Layer(env, std::make_unique<mbgl::style::FillLayer>(jni::Make<std::string>(env, layerId), jni::Make<std::string>(env, sourceId))) {
+ }
+
+ FillLayer::FillLayer(mbgl::Map& map, mbgl::style::FillLayer& coreLayer)
+ : Layer(map, coreLayer) {
+ }
+
+ FillLayer::~FillLayer() = default;
+
+ // Property getters
+
+ jni::Object<jni::ObjectTag> FillLayer::getFillAntialias(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::FillLayer>()->FillLayer::getFillAntialias());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> FillLayer::getFillOpacity(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::FillLayer>()->FillLayer::getFillOpacity());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> FillLayer::getFillColor(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::FillLayer>()->FillLayer::getFillColor());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> FillLayer::getFillOutlineColor(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::FillLayer>()->FillLayer::getFillOutlineColor());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> FillLayer::getFillTranslate(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::FillLayer>()->FillLayer::getFillTranslate());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> FillLayer::getFillTranslateAnchor(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::FillLayer>()->FillLayer::getFillTranslateAnchor());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> FillLayer::getFillPattern(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::FillLayer>()->FillLayer::getFillPattern());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Class<FillLayer> FillLayer::javaClass;
+
+ jni::jobject* FillLayer::createJavaPeer(jni::JNIEnv& env) {
+ static auto constructor = FillLayer::javaClass.template GetConstructor<jni::jlong>(env);
+ return FillLayer::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this));
+ }
+
+ void FillLayer::registerNative(jni::JNIEnv& env) {
+ //Lookup the class
+ FillLayer::javaClass = *jni::Class<FillLayer>::Find(env).NewGlobalRef(env).release();
+
+ #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
+
+ //Register the peer
+ jni::RegisterNativePeer<FillLayer>(
+ env, FillLayer::javaClass, "nativePtr",
+ std::make_unique<FillLayer, JNIEnv&, jni::String, jni::String>,
+ "initialize",
+ "finalize",
+ METHOD(&FillLayer::getFillAntialias, "nativeGetFillAntialias"),
+ METHOD(&FillLayer::getFillOpacity, "nativeGetFillOpacity"),
+ METHOD(&FillLayer::getFillColor, "nativeGetFillColor"),
+ METHOD(&FillLayer::getFillOutlineColor, "nativeGetFillOutlineColor"),
+ METHOD(&FillLayer::getFillTranslate, "nativeGetFillTranslate"),
+ METHOD(&FillLayer::getFillTranslateAnchor, "nativeGetFillTranslateAnchor"),
+ METHOD(&FillLayer::getFillPattern, "nativeGetFillPattern"));
+ }
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/layers/fill_layer.hpp b/platform/android/src/style/layers/fill_layer.hpp
new file mode 100644
index 0000000000..5dbd7a3412
--- /dev/null
+++ b/platform/android/src/style/layers/fill_layer.hpp
@@ -0,0 +1,47 @@
+// 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/fill_layer.hpp>
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class FillLayer : public Layer {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/FillLayer"; };
+
+ static jni::Class<FillLayer> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+ FillLayer(jni::JNIEnv&, jni::String, jni::String);
+
+ FillLayer(mbgl::Map&, mbgl::style::FillLayer&);
+
+ ~FillLayer();
+
+ // Property getters
+ jni::Object<jni::ObjectTag> getFillAntialias(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getFillOpacity(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getFillColor(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getFillOutlineColor(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getFillTranslate(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getFillTranslateAnchor(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getFillPattern(jni::JNIEnv&);
+
+ jni::jobject* createJavaPeer(jni::JNIEnv&);
+
+}; // class FillLayer
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/layers/layer.cpp b/platform/android/src/style/layers/layer.cpp
new file mode 100644
index 0000000000..4d5f90f67e
--- /dev/null
+++ b/platform/android/src/style/layers/layer.cpp
@@ -0,0 +1,171 @@
+#include "layer.hpp"
+#include "../android_conversion.hpp"
+
+#include <jni/jni.hpp>
+
+#include <mbgl/platform/log.hpp>
+
+//Java -> C++ conversion
+#include <mbgl/style/conversion.hpp>
+#include <mbgl/style/conversion/layer.hpp>
+#include <mbgl/style/conversion/source.hpp>
+
+//C++ -> Java conversion
+#include "../conversion/property_value.hpp"
+
+#include <string>
+
+namespace mbgl {
+namespace android {
+
+ /**
+ * Invoked when the construction is initiated from the jvm through a subclass
+ */
+ Layer::Layer(jni::JNIEnv&, std::unique_ptr<mbgl::style::Layer> coreLayer)
+ : ownedLayer(std::move(coreLayer))
+ , layer(*ownedLayer) {
+ }
+
+ Layer::Layer(mbgl::Map& coreMap, mbgl::style::Layer& coreLayer) : layer(coreLayer) , map(&coreMap) {
+ }
+
+ Layer::~Layer() {
+ }
+
+ jni::String Layer::getId(jni::JNIEnv& env) {
+ return jni::Make<jni::String>(env, layer.getID());
+ }
+
+ std::unique_ptr<mbgl::style::Layer> Layer::releaseCoreLayer() {
+ assert(ownedLayer != nullptr);
+ return std::move(ownedLayer);
+ }
+
+ void Layer::setLayoutProperty(jni::JNIEnv& env, jni::String jname, jni::Object<> jvalue) {
+ Value value(env, jvalue);
+
+ //Convert and set property
+ optional<mbgl::style::conversion::Error> error = mbgl::style::conversion::setLayoutProperty(layer, jni::Make<std::string>(env, jname), value);
+ if (error) {
+ mbgl::Log::Error(mbgl::Event::JNI, "Error setting property: " + jni::Make<std::string>(env, jname) + " " + error->message);
+ return;
+ }
+ }
+
+ void Layer::setPaintProperty(jni::JNIEnv& env, jni::String jname, jni::Object<> jvalue) {
+ Value value(env, jvalue);
+
+ //Convert and set property
+ optional<mbgl::style::conversion::Error> error = mbgl::style::conversion::setPaintProperty(layer, jni::Make<std::string>(env, jname), value, mbgl::optional<std::string>());
+ if (error) {
+ mbgl::Log::Error(mbgl::Event::JNI, "Error setting property: " + jni::Make<std::string>(env, jname) + " " + error->message);
+ return;
+ }
+ }
+
+ void Layer::updateStyle(jni::JNIEnv&, jni::jboolean updateClasses) {
+ //Update the style only if attached
+ if (ownedLayer == nullptr) {
+ Update flags = mbgl::Update::RecalculateStyle;
+ if(updateClasses) {
+ flags = flags | mbgl::Update::Classes;
+ }
+ map->update(flags);
+ } else {
+ mbgl::Log::Debug(mbgl::Event::JNI, "Not updating as layer is not attached to map (yet)");
+ }
+ }
+
+ void Layer::setFilter(jni::JNIEnv& env, jni::Array<jni::Object<>> jfilter) {
+ using namespace mbgl::style;
+ using namespace mbgl::style::conversion;
+
+ Value wrapped(env, jfilter);
+ Filter filter;
+
+ Result<Filter> converted = convert<Filter>(wrapped);
+ if (!converted) {
+ mbgl::Log::Error(mbgl::Event::JNI, "Error setting filter: " + converted.error().message);
+ return;
+ }
+ filter = std::move(*converted);
+
+ if (layer.is<FillLayer>()) {
+ layer.as<FillLayer>()->setFilter(filter);
+ } else if (layer.is<LineLayer>()) {
+ layer.as<LineLayer>()->setFilter(filter);
+ } else if (layer.is<SymbolLayer>()) {
+ layer.as<SymbolLayer>()->setFilter(filter);
+ } else if (layer.is<CircleLayer>()) {
+ layer.as<CircleLayer>()->setFilter(filter);
+ } else {
+ mbgl::Log::Warning(mbgl::Event::JNI, "Layer doesn't support filters");
+ }
+ }
+
+ void Layer::setSourceLayer(jni::JNIEnv& env, jni::String sourceLayer) {
+ using namespace mbgl::style;
+
+ std::string layerId = jni::Make<std::string>(env, sourceLayer);
+
+ if (layer.is<FillLayer>()) {
+ layer.as<FillLayer>()->setSourceLayer(layerId);
+ } else if (layer.is<LineLayer>()) {
+ layer.as<LineLayer>()->setSourceLayer(layerId);
+ } else if (layer.is<SymbolLayer>()) {
+ layer.as<SymbolLayer>()->setSourceLayer(layerId);
+ } else if (layer.is<CircleLayer>()) {
+ layer.as<CircleLayer>()->setSourceLayer(layerId);
+ } else {
+ mbgl::Log::Warning(mbgl::Event::JNI, "Layer doesn't support source layer");
+ }
+ }
+
+ jni::jfloat Layer::getMinZoom(jni::JNIEnv&){
+ return layer.getMinZoom();
+ }
+
+ jni::jfloat Layer::getMaxZoom(jni::JNIEnv&) {
+ return layer.getMaxZoom();
+ }
+
+ void Layer::setMinZoom(jni::JNIEnv&, jni::jfloat zoom) {
+ layer.setMinZoom(zoom);
+ }
+
+ void Layer::setMaxZoom(jni::JNIEnv&, jni::jfloat zoom) {
+ layer.setMaxZoom(zoom);
+ }
+
+ jni::Object<jni::ObjectTag> Layer::getVisibility(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ return jni::Object<jni::ObjectTag>(*convert<jni::jobject*>(env, layer.getVisibility()));
+ }
+
+ jni::Class<Layer> Layer::javaClass;
+
+ void Layer::registerNative(jni::JNIEnv& env) {
+ //Lookup the class
+ Layer::javaClass = *jni::Class<Layer>::Find(env).NewGlobalRef(env).release();
+
+ #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
+
+ //Register the peer
+ jni::RegisterNativePeer<Layer>(env, Layer::javaClass, "nativePtr",
+ METHOD(&Layer::getId, "nativeGetId"),
+ METHOD(&Layer::setLayoutProperty, "nativeSetLayoutProperty"),
+ METHOD(&Layer::setPaintProperty, "nativeSetPaintProperty"),
+ METHOD(&Layer::updateStyle, "nativeUpdateStyle"),
+ METHOD(&Layer::setFilter, "nativeSetFilter"),
+ METHOD(&Layer::setSourceLayer, "nativeSetSourceLayer"),
+ METHOD(&Layer::getMinZoom, "nativeGetMinZoom"),
+ METHOD(&Layer::getMaxZoom, "nativeGetMaxZoom"),
+ METHOD(&Layer::setMinZoom, "nativeSetMinZoom"),
+ METHOD(&Layer::setMaxZoom, "nativeSetMaxZoom"),
+ METHOD(&Layer::getVisibility, "nativeGetVisibility")
+ );
+
+ }
+
+} //android
+} //mbgl \ No newline at end of file
diff --git a/platform/android/src/style/layers/layer.cpp.ejs b/platform/android/src/style/layers/layer.cpp.ejs
new file mode 100644
index 0000000000..68dd27b801
--- /dev/null
+++ b/platform/android/src/style/layers/layer.cpp.ejs
@@ -0,0 +1,69 @@
+<%
+ const type = locals.type;
+ const properties = locals.properties;
+-%>
+// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make style-code-android`.
+
+#include "<%- type %>_layer.hpp"
+
+#include <string>
+
+#include "../conversion/property_value.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))) {
+<% } -%>
+ }
+
+ <%- camelize(type) %>Layer::<%- camelize(type) %>Layer(mbgl::Map& map, mbgl::style::<%- camelize(type) %>Layer& coreLayer)
+ : Layer(map, coreLayer) {
+ }
+
+ <%- camelize(type) %>Layer::~<%- camelize(type) %>Layer() = default;
+
+ // Property getters
+
+<% for (const property of properties) { -%>
+ jni::Object<jni::ObjectTag> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::<%- camelize(type) %>Layer>()-><%- camelize(type) %>Layer::get<%- camelize(property.name) %>());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+<% } -%>
+ 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) {
+ //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",<% for(var i = 0; i < properties.length; i++) {%>
+ METHOD(&<%- camelize(type) %>Layer::get<%- camelize(properties[i].name) %>, "nativeGet<%- camelize(properties[i].name) %>")<% if(i != (properties.length -1)) {-%>,<% } -%>
+<% } -%>);
+ }
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/layers/layer.hpp b/platform/android/src/style/layers/layer.hpp
new file mode 100644
index 0000000000..37eb34cdd7
--- /dev/null
+++ b/platform/android/src/style/layers/layer.hpp
@@ -0,0 +1,80 @@
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/map/map.hpp>
+#include <mbgl/style/layer.hpp>
+
+#include "../value.hpp"
+
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class Layer : private mbgl::util::noncopyable {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/Layer"; };
+
+ static jni::Class<Layer> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+ /*
+ * Called when a Java object is created on the c++ side
+ */
+ Layer(mbgl::Map&, mbgl::style::Layer&);
+
+ /*
+ * Called when a Java object was created from the jvm side
+ */
+ Layer(jni::JNIEnv&, std::unique_ptr<mbgl::style::Layer>);
+
+ virtual ~Layer();
+
+ virtual jni::jobject* createJavaPeer(jni::JNIEnv&) = 0;
+
+ jni::String getId(jni::JNIEnv&);
+
+ //Release the owned view and return it
+ std::unique_ptr<mbgl::style::Layer> releaseCoreLayer();
+
+ void setLayoutProperty(jni::JNIEnv&, jni::String, jni::Object<> value);
+
+ void setPaintProperty(jni::JNIEnv&, jni::String, jni::Object<> value);
+
+ void updateStyle(jni::JNIEnv&, jni::jboolean updateClasses);
+
+ //Zoom
+
+ jni::jfloat getMinZoom(jni::JNIEnv&);
+
+ jni::jfloat getMaxZoom(jni::JNIEnv&);
+
+ void setMinZoom(jni::JNIEnv&, jni::jfloat zoom);
+
+ void setMaxZoom(jni::JNIEnv&, jni::jfloat zoom);
+
+ /* common properties, but not shared by all */
+
+ void setFilter(jni::JNIEnv& env, jni::Array<jni::Object<>> jfilter);
+
+ void setSourceLayer(jni::JNIEnv& env, jni::String sourceLayer);
+
+ //Property getters
+
+ jni::Object<jni::ObjectTag> getVisibility(jni::JNIEnv&);
+
+protected:
+ std::unique_ptr<mbgl::style::Layer> ownedLayer;
+ mbgl::style::Layer& layer;
+ mbgl::Map* map;
+
+};
+
+} //android
+} //mbgl
+
+
+
+
diff --git a/platform/android/src/style/layers/layer.hpp.ejs b/platform/android/src/style/layers/layer.hpp.ejs
new file mode 100644
index 0000000000..826e133fca
--- /dev/null
+++ b/platform/android/src/style/layers/layer.hpp.ejs
@@ -0,0 +1,45 @@
+<%
+ const type = locals.type;
+ const properties = locals.properties;
+-%>
+// 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();
+
+ // Property getters
+<% for (const property of properties) { -%>
+ jni::Object<jni::ObjectTag> get<%- camelize(property.name) %>(jni::JNIEnv&);
+
+<% } -%>
+ jni::jobject* createJavaPeer(jni::JNIEnv&);
+
+}; // class <%- camelize(type) %>Layer
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/layers/layers.cpp b/platform/android/src/style/layers/layers.cpp
new file mode 100644
index 0000000000..57dbf6f4b1
--- /dev/null
+++ b/platform/android/src/style/layers/layers.cpp
@@ -0,0 +1,64 @@
+#include "layers.hpp"
+
+#include <mbgl/style/layers/background_layer.hpp>
+#include <mbgl/style/layers/circle_layer.hpp>
+#include <mbgl/style/layers/fill_layer.hpp>
+#include <mbgl/style/layers/line_layer.hpp>
+#include <mbgl/style/layers/raster_layer.hpp>
+#include <mbgl/style/layers/symbol_layer.hpp>
+#include <mbgl/style/layers/custom_layer.hpp>
+
+#include "background_layer.hpp"
+#include "circle_layer.hpp"
+#include "fill_layer.hpp"
+#include "line_layer.hpp"
+#include "raster_layer.hpp"
+#include "symbol_layer.hpp"
+#include "custom_layer.hpp"
+
+namespace mbgl {
+namespace android {
+
+Layer* initializeLayerPeer(mbgl::Map& map, mbgl::style::Layer& coreLayer) {
+ Layer* layer;
+ if (coreLayer.is<mbgl::style::BackgroundLayer>()) {
+ layer = new BackgroundLayer(map, *coreLayer.as<mbgl::style::BackgroundLayer>());
+ } else if (coreLayer.is<mbgl::style::CircleLayer>()) {
+ layer = new CircleLayer(map, *coreLayer.as<mbgl::style::CircleLayer>());
+ } else if (coreLayer.is<mbgl::style::FillLayer>()) {
+ layer = new FillLayer(map, *coreLayer.as<mbgl::style::FillLayer>());
+ } else if (coreLayer.is<mbgl::style::LineLayer>()) {
+ layer = new LineLayer(map, *coreLayer.as<mbgl::style::LineLayer>());
+ } else if (coreLayer.is<mbgl::style::RasterLayer>()) {
+ layer = new RasterLayer(map, *coreLayer.as<mbgl::style::RasterLayer>());
+ } else if (coreLayer.is<mbgl::style::SymbolLayer>()) {
+ layer = new SymbolLayer(map, *coreLayer.as<mbgl::style::SymbolLayer>());
+ } else if (coreLayer.is<mbgl::style::CustomLayer>()) {
+ layer = new CustomLayer(map, *coreLayer.as<mbgl::style::CustomLayer>());
+ } else {
+ throw new std::runtime_error("Layer type not implemented");
+ }
+
+ return layer;
+}
+
+jni::jobject* createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, mbgl::style::Layer& coreLayer) {
+ std::unique_ptr<Layer> peerLayer = std::unique_ptr<Layer>(initializeLayerPeer(map, coreLayer));
+ jni::jobject* result = peerLayer->createJavaPeer(env);
+ peerLayer.release();
+ return result;
+}
+
+void registerNativeLayers(jni::JNIEnv& env) {
+ Layer::registerNative(env);
+ BackgroundLayer::registerNative(env);
+ CircleLayer::registerNative(env);
+ FillLayer::registerNative(env);
+ LineLayer::registerNative(env);
+ RasterLayer::registerNative(env);
+ SymbolLayer::registerNative(env);
+ CustomLayer::registerNative(env);
+}
+
+} //android
+} //mbgl \ No newline at end of file
diff --git a/platform/android/src/style/layers/layers.hpp b/platform/android/src/style/layers/layers.hpp
new file mode 100644
index 0000000000..0c979ec2cf
--- /dev/null
+++ b/platform/android/src/style/layers/layers.hpp
@@ -0,0 +1,20 @@
+#pragma once
+
+#include <mbgl/map/map.hpp>
+#include <mbgl/style/layer.hpp>
+
+#include "layer.hpp"
+
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+mbgl::android::Layer* initializeLayerPeer(mbgl::Map&, mbgl::style::Layer&);
+
+jni::jobject* createJavaLayerPeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Layer&);
+
+void registerNativeLayers(jni::JNIEnv&);
+
+}
+} \ No newline at end of file
diff --git a/platform/android/src/style/layers/line_layer.cpp b/platform/android/src/style/layers/line_layer.cpp
new file mode 100644
index 0000000000..91d3e4a1cd
--- /dev/null
+++ b/platform/android/src/style/layers/line_layer.cpp
@@ -0,0 +1,144 @@
+// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make style-code-android`.
+
+#include "line_layer.hpp"
+
+#include <string>
+
+#include "../conversion/property_value.hpp"
+
+namespace mbgl {
+namespace android {
+
+ LineLayer::LineLayer(jni::JNIEnv& env, jni::String layerId, jni::String sourceId)
+ : Layer(env, std::make_unique<mbgl::style::LineLayer>(jni::Make<std::string>(env, layerId), jni::Make<std::string>(env, sourceId))) {
+ }
+
+ LineLayer::LineLayer(mbgl::Map& map, mbgl::style::LineLayer& coreLayer)
+ : Layer(map, coreLayer) {
+ }
+
+ LineLayer::~LineLayer() = default;
+
+ // Property getters
+
+ jni::Object<jni::ObjectTag> LineLayer::getLineCap(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::LineLayer>()->LineLayer::getLineCap());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> LineLayer::getLineJoin(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::LineLayer>()->LineLayer::getLineJoin());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> LineLayer::getLineMiterLimit(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::LineLayer>()->LineLayer::getLineMiterLimit());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> LineLayer::getLineRoundLimit(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::LineLayer>()->LineLayer::getLineRoundLimit());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> LineLayer::getLineOpacity(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::LineLayer>()->LineLayer::getLineOpacity());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> LineLayer::getLineColor(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::LineLayer>()->LineLayer::getLineColor());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> LineLayer::getLineTranslate(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::LineLayer>()->LineLayer::getLineTranslate());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> LineLayer::getLineTranslateAnchor(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::LineLayer>()->LineLayer::getLineTranslateAnchor());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> LineLayer::getLineWidth(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::LineLayer>()->LineLayer::getLineWidth());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> LineLayer::getLineGapWidth(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::LineLayer>()->LineLayer::getLineGapWidth());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> LineLayer::getLineOffset(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::LineLayer>()->LineLayer::getLineOffset());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> LineLayer::getLineBlur(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::LineLayer>()->LineLayer::getLineBlur());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> LineLayer::getLineDasharray(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::LineLayer>()->LineLayer::getLineDasharray());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> LineLayer::getLinePattern(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::LineLayer>()->LineLayer::getLinePattern());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Class<LineLayer> LineLayer::javaClass;
+
+ jni::jobject* LineLayer::createJavaPeer(jni::JNIEnv& env) {
+ static auto constructor = LineLayer::javaClass.template GetConstructor<jni::jlong>(env);
+ return LineLayer::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this));
+ }
+
+ void LineLayer::registerNative(jni::JNIEnv& env) {
+ //Lookup the class
+ LineLayer::javaClass = *jni::Class<LineLayer>::Find(env).NewGlobalRef(env).release();
+
+ #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
+
+ //Register the peer
+ jni::RegisterNativePeer<LineLayer>(
+ env, LineLayer::javaClass, "nativePtr",
+ std::make_unique<LineLayer, JNIEnv&, jni::String, jni::String>,
+ "initialize",
+ "finalize",
+ METHOD(&LineLayer::getLineCap, "nativeGetLineCap"),
+ METHOD(&LineLayer::getLineJoin, "nativeGetLineJoin"),
+ METHOD(&LineLayer::getLineMiterLimit, "nativeGetLineMiterLimit"),
+ METHOD(&LineLayer::getLineRoundLimit, "nativeGetLineRoundLimit"),
+ METHOD(&LineLayer::getLineOpacity, "nativeGetLineOpacity"),
+ METHOD(&LineLayer::getLineColor, "nativeGetLineColor"),
+ METHOD(&LineLayer::getLineTranslate, "nativeGetLineTranslate"),
+ METHOD(&LineLayer::getLineTranslateAnchor, "nativeGetLineTranslateAnchor"),
+ METHOD(&LineLayer::getLineWidth, "nativeGetLineWidth"),
+ METHOD(&LineLayer::getLineGapWidth, "nativeGetLineGapWidth"),
+ METHOD(&LineLayer::getLineOffset, "nativeGetLineOffset"),
+ METHOD(&LineLayer::getLineBlur, "nativeGetLineBlur"),
+ METHOD(&LineLayer::getLineDasharray, "nativeGetLineDasharray"),
+ METHOD(&LineLayer::getLinePattern, "nativeGetLinePattern"));
+ }
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/layers/line_layer.hpp b/platform/android/src/style/layers/line_layer.hpp
new file mode 100644
index 0000000000..da9b564325
--- /dev/null
+++ b/platform/android/src/style/layers/line_layer.hpp
@@ -0,0 +1,61 @@
+// 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/line_layer.hpp>
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class LineLayer : public Layer {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/LineLayer"; };
+
+ static jni::Class<LineLayer> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+ LineLayer(jni::JNIEnv&, jni::String, jni::String);
+
+ LineLayer(mbgl::Map&, mbgl::style::LineLayer&);
+
+ ~LineLayer();
+
+ // Property getters
+ jni::Object<jni::ObjectTag> getLineCap(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getLineJoin(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getLineMiterLimit(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getLineRoundLimit(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getLineOpacity(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getLineColor(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getLineTranslate(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getLineTranslateAnchor(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getLineWidth(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getLineGapWidth(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getLineOffset(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getLineBlur(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getLineDasharray(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getLinePattern(jni::JNIEnv&);
+
+ jni::jobject* createJavaPeer(jni::JNIEnv&);
+
+}; // class LineLayer
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/layers/raster_layer.cpp b/platform/android/src/style/layers/raster_layer.cpp
new file mode 100644
index 0000000000..da78ccb8e3
--- /dev/null
+++ b/platform/android/src/style/layers/raster_layer.cpp
@@ -0,0 +1,95 @@
+// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make style-code-android`.
+
+#include "raster_layer.hpp"
+
+#include <string>
+
+#include "../conversion/property_value.hpp"
+
+namespace mbgl {
+namespace android {
+
+ RasterLayer::RasterLayer(jni::JNIEnv& env, jni::String layerId, jni::String sourceId)
+ : Layer(env, std::make_unique<mbgl::style::RasterLayer>(jni::Make<std::string>(env, layerId), jni::Make<std::string>(env, sourceId))) {
+ }
+
+ RasterLayer::RasterLayer(mbgl::Map& map, mbgl::style::RasterLayer& coreLayer)
+ : Layer(map, coreLayer) {
+ }
+
+ RasterLayer::~RasterLayer() = default;
+
+ // Property getters
+
+ jni::Object<jni::ObjectTag> RasterLayer::getRasterOpacity(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::RasterLayer>()->RasterLayer::getRasterOpacity());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> RasterLayer::getRasterHueRotate(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::RasterLayer>()->RasterLayer::getRasterHueRotate());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> RasterLayer::getRasterBrightnessMin(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::RasterLayer>()->RasterLayer::getRasterBrightnessMin());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> RasterLayer::getRasterBrightnessMax(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::RasterLayer>()->RasterLayer::getRasterBrightnessMax());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> RasterLayer::getRasterSaturation(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::RasterLayer>()->RasterLayer::getRasterSaturation());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> RasterLayer::getRasterContrast(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::RasterLayer>()->RasterLayer::getRasterContrast());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> RasterLayer::getRasterFadeDuration(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::RasterLayer>()->RasterLayer::getRasterFadeDuration());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Class<RasterLayer> RasterLayer::javaClass;
+
+ jni::jobject* RasterLayer::createJavaPeer(jni::JNIEnv& env) {
+ static auto constructor = RasterLayer::javaClass.template GetConstructor<jni::jlong>(env);
+ return RasterLayer::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this));
+ }
+
+ void RasterLayer::registerNative(jni::JNIEnv& env) {
+ //Lookup the class
+ RasterLayer::javaClass = *jni::Class<RasterLayer>::Find(env).NewGlobalRef(env).release();
+
+ #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
+
+ //Register the peer
+ jni::RegisterNativePeer<RasterLayer>(
+ env, RasterLayer::javaClass, "nativePtr",
+ std::make_unique<RasterLayer, JNIEnv&, jni::String, jni::String>,
+ "initialize",
+ "finalize",
+ METHOD(&RasterLayer::getRasterOpacity, "nativeGetRasterOpacity"),
+ METHOD(&RasterLayer::getRasterHueRotate, "nativeGetRasterHueRotate"),
+ METHOD(&RasterLayer::getRasterBrightnessMin, "nativeGetRasterBrightnessMin"),
+ METHOD(&RasterLayer::getRasterBrightnessMax, "nativeGetRasterBrightnessMax"),
+ METHOD(&RasterLayer::getRasterSaturation, "nativeGetRasterSaturation"),
+ METHOD(&RasterLayer::getRasterContrast, "nativeGetRasterContrast"),
+ METHOD(&RasterLayer::getRasterFadeDuration, "nativeGetRasterFadeDuration"));
+ }
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/layers/raster_layer.hpp b/platform/android/src/style/layers/raster_layer.hpp
new file mode 100644
index 0000000000..e59cd05f87
--- /dev/null
+++ b/platform/android/src/style/layers/raster_layer.hpp
@@ -0,0 +1,47 @@
+// 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/raster_layer.hpp>
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class RasterLayer : public Layer {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/RasterLayer"; };
+
+ static jni::Class<RasterLayer> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+ RasterLayer(jni::JNIEnv&, jni::String, jni::String);
+
+ RasterLayer(mbgl::Map&, mbgl::style::RasterLayer&);
+
+ ~RasterLayer();
+
+ // Property getters
+ jni::Object<jni::ObjectTag> getRasterOpacity(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getRasterHueRotate(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getRasterBrightnessMin(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getRasterBrightnessMax(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getRasterSaturation(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getRasterContrast(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getRasterFadeDuration(jni::JNIEnv&);
+
+ jni::jobject* createJavaPeer(jni::JNIEnv&);
+
+}; // class RasterLayer
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/layers/symbol_layer.cpp b/platform/android/src/style/layers/symbol_layer.cpp
new file mode 100644
index 0000000000..fd69b6591f
--- /dev/null
+++ b/platform/android/src/style/layers/symbol_layer.cpp
@@ -0,0 +1,382 @@
+// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make style-code-android`.
+
+#include "symbol_layer.hpp"
+
+#include <string>
+
+#include "../conversion/property_value.hpp"
+
+namespace mbgl {
+namespace android {
+
+ SymbolLayer::SymbolLayer(jni::JNIEnv& env, jni::String layerId, jni::String sourceId)
+ : Layer(env, std::make_unique<mbgl::style::SymbolLayer>(jni::Make<std::string>(env, layerId), jni::Make<std::string>(env, sourceId))) {
+ }
+
+ SymbolLayer::SymbolLayer(mbgl::Map& map, mbgl::style::SymbolLayer& coreLayer)
+ : Layer(map, coreLayer) {
+ }
+
+ SymbolLayer::~SymbolLayer() = default;
+
+ // Property getters
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getSymbolPlacement(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getSymbolPlacement());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getSymbolSpacing(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getSymbolSpacing());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getSymbolAvoidEdges(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getSymbolAvoidEdges());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getIconAllowOverlap(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getIconAllowOverlap());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getIconIgnorePlacement(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getIconIgnorePlacement());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getIconOptional(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getIconOptional());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getIconRotationAlignment(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getIconRotationAlignment());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getIconSize(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getIconSize());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getIconTextFit(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getIconTextFit());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getIconTextFitPadding(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getIconTextFitPadding());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getIconImage(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getIconImage());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getIconRotate(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getIconRotate());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getIconPadding(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getIconPadding());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getIconKeepUpright(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getIconKeepUpright());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getIconOffset(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getIconOffset());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getTextPitchAlignment(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getTextPitchAlignment());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getTextRotationAlignment(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getTextRotationAlignment());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getTextField(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getTextField());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getTextFont(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getTextFont());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getTextSize(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getTextSize());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getTextMaxWidth(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getTextMaxWidth());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getTextLineHeight(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getTextLineHeight());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getTextLetterSpacing(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getTextLetterSpacing());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getTextJustify(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getTextJustify());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getTextAnchor(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getTextAnchor());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getTextMaxAngle(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getTextMaxAngle());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getTextRotate(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getTextRotate());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getTextPadding(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getTextPadding());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getTextKeepUpright(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getTextKeepUpright());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getTextTransform(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getTextTransform());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getTextOffset(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getTextOffset());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getTextAllowOverlap(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getTextAllowOverlap());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getTextIgnorePlacement(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getTextIgnorePlacement());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getTextOptional(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getTextOptional());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getIconOpacity(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getIconOpacity());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getIconColor(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getIconColor());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getIconHaloColor(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getIconHaloColor());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getIconHaloWidth(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getIconHaloWidth());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getIconHaloBlur(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getIconHaloBlur());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getIconTranslate(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getIconTranslate());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getIconTranslateAnchor(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getIconTranslateAnchor());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getTextOpacity(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getTextOpacity());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getTextColor(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getTextColor());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getTextHaloColor(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getTextHaloColor());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getTextHaloWidth(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getTextHaloWidth());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getTextHaloBlur(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getTextHaloBlur());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getTextTranslate(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getTextTranslate());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> SymbolLayer::getTextTranslateAnchor(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getTextTranslateAnchor());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Class<SymbolLayer> SymbolLayer::javaClass;
+
+ jni::jobject* SymbolLayer::createJavaPeer(jni::JNIEnv& env) {
+ static auto constructor = SymbolLayer::javaClass.template GetConstructor<jni::jlong>(env);
+ return SymbolLayer::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this));
+ }
+
+ void SymbolLayer::registerNative(jni::JNIEnv& env) {
+ //Lookup the class
+ SymbolLayer::javaClass = *jni::Class<SymbolLayer>::Find(env).NewGlobalRef(env).release();
+
+ #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
+
+ //Register the peer
+ jni::RegisterNativePeer<SymbolLayer>(
+ env, SymbolLayer::javaClass, "nativePtr",
+ std::make_unique<SymbolLayer, JNIEnv&, jni::String, jni::String>,
+ "initialize",
+ "finalize",
+ METHOD(&SymbolLayer::getSymbolPlacement, "nativeGetSymbolPlacement"),
+ METHOD(&SymbolLayer::getSymbolSpacing, "nativeGetSymbolSpacing"),
+ METHOD(&SymbolLayer::getSymbolAvoidEdges, "nativeGetSymbolAvoidEdges"),
+ METHOD(&SymbolLayer::getIconAllowOverlap, "nativeGetIconAllowOverlap"),
+ METHOD(&SymbolLayer::getIconIgnorePlacement, "nativeGetIconIgnorePlacement"),
+ METHOD(&SymbolLayer::getIconOptional, "nativeGetIconOptional"),
+ METHOD(&SymbolLayer::getIconRotationAlignment, "nativeGetIconRotationAlignment"),
+ METHOD(&SymbolLayer::getIconSize, "nativeGetIconSize"),
+ METHOD(&SymbolLayer::getIconTextFit, "nativeGetIconTextFit"),
+ METHOD(&SymbolLayer::getIconTextFitPadding, "nativeGetIconTextFitPadding"),
+ METHOD(&SymbolLayer::getIconImage, "nativeGetIconImage"),
+ METHOD(&SymbolLayer::getIconRotate, "nativeGetIconRotate"),
+ METHOD(&SymbolLayer::getIconPadding, "nativeGetIconPadding"),
+ METHOD(&SymbolLayer::getIconKeepUpright, "nativeGetIconKeepUpright"),
+ METHOD(&SymbolLayer::getIconOffset, "nativeGetIconOffset"),
+ METHOD(&SymbolLayer::getTextPitchAlignment, "nativeGetTextPitchAlignment"),
+ METHOD(&SymbolLayer::getTextRotationAlignment, "nativeGetTextRotationAlignment"),
+ METHOD(&SymbolLayer::getTextField, "nativeGetTextField"),
+ METHOD(&SymbolLayer::getTextFont, "nativeGetTextFont"),
+ METHOD(&SymbolLayer::getTextSize, "nativeGetTextSize"),
+ METHOD(&SymbolLayer::getTextMaxWidth, "nativeGetTextMaxWidth"),
+ METHOD(&SymbolLayer::getTextLineHeight, "nativeGetTextLineHeight"),
+ METHOD(&SymbolLayer::getTextLetterSpacing, "nativeGetTextLetterSpacing"),
+ METHOD(&SymbolLayer::getTextJustify, "nativeGetTextJustify"),
+ METHOD(&SymbolLayer::getTextAnchor, "nativeGetTextAnchor"),
+ METHOD(&SymbolLayer::getTextMaxAngle, "nativeGetTextMaxAngle"),
+ METHOD(&SymbolLayer::getTextRotate, "nativeGetTextRotate"),
+ METHOD(&SymbolLayer::getTextPadding, "nativeGetTextPadding"),
+ METHOD(&SymbolLayer::getTextKeepUpright, "nativeGetTextKeepUpright"),
+ METHOD(&SymbolLayer::getTextTransform, "nativeGetTextTransform"),
+ METHOD(&SymbolLayer::getTextOffset, "nativeGetTextOffset"),
+ METHOD(&SymbolLayer::getTextAllowOverlap, "nativeGetTextAllowOverlap"),
+ METHOD(&SymbolLayer::getTextIgnorePlacement, "nativeGetTextIgnorePlacement"),
+ METHOD(&SymbolLayer::getTextOptional, "nativeGetTextOptional"),
+ METHOD(&SymbolLayer::getIconOpacity, "nativeGetIconOpacity"),
+ METHOD(&SymbolLayer::getIconColor, "nativeGetIconColor"),
+ METHOD(&SymbolLayer::getIconHaloColor, "nativeGetIconHaloColor"),
+ METHOD(&SymbolLayer::getIconHaloWidth, "nativeGetIconHaloWidth"),
+ METHOD(&SymbolLayer::getIconHaloBlur, "nativeGetIconHaloBlur"),
+ METHOD(&SymbolLayer::getIconTranslate, "nativeGetIconTranslate"),
+ METHOD(&SymbolLayer::getIconTranslateAnchor, "nativeGetIconTranslateAnchor"),
+ METHOD(&SymbolLayer::getTextOpacity, "nativeGetTextOpacity"),
+ METHOD(&SymbolLayer::getTextColor, "nativeGetTextColor"),
+ METHOD(&SymbolLayer::getTextHaloColor, "nativeGetTextHaloColor"),
+ METHOD(&SymbolLayer::getTextHaloWidth, "nativeGetTextHaloWidth"),
+ METHOD(&SymbolLayer::getTextHaloBlur, "nativeGetTextHaloBlur"),
+ METHOD(&SymbolLayer::getTextTranslate, "nativeGetTextTranslate"),
+ METHOD(&SymbolLayer::getTextTranslateAnchor, "nativeGetTextTranslateAnchor"));
+ }
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/layers/symbol_layer.hpp b/platform/android/src/style/layers/symbol_layer.hpp
new file mode 100644
index 0000000000..f5165327bf
--- /dev/null
+++ b/platform/android/src/style/layers/symbol_layer.hpp
@@ -0,0 +1,129 @@
+// 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/symbol_layer.hpp>
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class SymbolLayer : public Layer {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/SymbolLayer"; };
+
+ static jni::Class<SymbolLayer> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+ SymbolLayer(jni::JNIEnv&, jni::String, jni::String);
+
+ SymbolLayer(mbgl::Map&, mbgl::style::SymbolLayer&);
+
+ ~SymbolLayer();
+
+ // Property getters
+ jni::Object<jni::ObjectTag> getSymbolPlacement(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getSymbolSpacing(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getSymbolAvoidEdges(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getIconAllowOverlap(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getIconIgnorePlacement(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getIconOptional(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getIconRotationAlignment(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getIconSize(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getIconTextFit(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getIconTextFitPadding(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getIconImage(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getIconRotate(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getIconPadding(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getIconKeepUpright(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getIconOffset(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getTextPitchAlignment(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getTextRotationAlignment(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getTextField(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getTextFont(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getTextSize(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getTextMaxWidth(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getTextLineHeight(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getTextLetterSpacing(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getTextJustify(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getTextAnchor(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getTextMaxAngle(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getTextRotate(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getTextPadding(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getTextKeepUpright(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getTextTransform(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getTextOffset(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getTextAllowOverlap(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getTextIgnorePlacement(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getTextOptional(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getIconOpacity(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getIconColor(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getIconHaloColor(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getIconHaloWidth(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getIconHaloBlur(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getIconTranslate(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getIconTranslateAnchor(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getTextOpacity(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getTextColor(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getTextHaloColor(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getTextHaloWidth(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getTextHaloBlur(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getTextTranslate(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getTextTranslateAnchor(jni::JNIEnv&);
+
+ jni::jobject* createJavaPeer(jni::JNIEnv&);
+
+}; // class SymbolLayer
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/sources/sources.cpp b/platform/android/src/style/sources/sources.cpp
new file mode 100644
index 0000000000..47c9757e9d
--- /dev/null
+++ b/platform/android/src/style/sources/sources.cpp
@@ -0,0 +1,28 @@
+#include "sources.hpp"
+
+#include "../value.hpp"
+#include "../android_conversion.hpp"
+#include "../android_geojson.hpp"
+
+#include <mbgl/util/constants.hpp>
+#include <mbgl/style/conversion.hpp>
+#include <mbgl/style/conversion/source.hpp>
+
+#include <string>
+
+namespace mbgl {
+namespace android {
+
+ mbgl::optional<std::unique_ptr<mbgl::style::Source>> convertToNativeSource(jni::JNIEnv& env, jni::Object<jni::jobject> jvalue, jni::String id) {
+ using namespace mbgl::style;
+
+ Value value(env, jvalue);
+ conversion::Result<std::unique_ptr<Source>> source = conversion::convert<std::unique_ptr<Source>>(value, jni::Make<std::string>(env, id));
+ if (!source) {
+ mbgl::Log::Error(mbgl::Event::JNI, "Unable to add source: " + source.error().message);
+ return {};
+ }
+ return std::move(*source);
+ }
+}
+} \ No newline at end of file
diff --git a/platform/android/src/style/sources/sources.hpp b/platform/android/src/style/sources/sources.hpp
new file mode 100644
index 0000000000..b967685dfb
--- /dev/null
+++ b/platform/android/src/style/sources/sources.hpp
@@ -0,0 +1,14 @@
+#pragma once
+
+#include <mbgl/style/source.hpp>
+#include <mbgl/util/optional.hpp>
+
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+ mbgl::optional<std::unique_ptr<mbgl::style::Source>> convertToNativeSource(jni::JNIEnv& env, jni::Object<jni::jobject> jsource, jni::String id);
+
+}
+} \ No newline at end of file
diff --git a/platform/android/src/style/value.cpp b/platform/android/src/style/value.cpp
new file mode 100644
index 0000000000..daad3e998d
--- /dev/null
+++ b/platform/android/src/style/value.cpp
@@ -0,0 +1,67 @@
+#include "value.hpp"
+
+#include "../java_types.hpp"
+
+namespace mbgl {
+namespace android {
+
+ //Instance
+
+ Value::Value(jni::JNIEnv& env, jni::jobject* _value) : jenv(env), value(_value) {}
+
+ Value::~Value() {}
+
+ bool Value::isNull() const {
+ return value == nullptr;
+ }
+
+ bool Value::isArray() const {
+ return jni::IsInstanceOf(jenv, value, *java::ObjectArray::jclass);
+ }
+
+ bool Value::isObject() const {
+ return jni::IsInstanceOf(jenv, value, *java::Map::jclass);;
+ }
+
+ bool Value::isString() const {
+ return jni::IsInstanceOf(jenv, value, *java::String::jclass);
+ }
+
+ bool Value::isBool() const {
+ return jni::IsInstanceOf(jenv, value, *java::Boolean::jclass);
+ }
+
+ bool Value::isNumber() const {
+ return jni::IsInstanceOf(jenv, value, *java::Number::jclass);
+ }
+
+ std::string Value::toString() const {
+ jni::jstring* string = reinterpret_cast<jni::jstring*>(value);
+ return jni::Make<std::string>(jenv, jni::String(string));
+ }
+
+ float Value::toNumber() const {
+ return jni::CallMethod<jni::jfloat>(jenv, value, *java::Number::floatValueMethodId);
+ }
+
+ bool Value::toBool() const {
+ return jni::CallMethod<jni::jboolean>(jenv, value, *java::Boolean::booleanValueMethodId);
+ }
+
+ Value Value::get(const char* key) const {
+ jni::jobject* member = jni::CallMethod<jni::jobject*>(jenv, value, *java::Map::getMethodId, jni::Make<jni::String>(jenv, std::string(key)).Get());
+ return Value(jenv, member);
+ }
+
+ int Value::getLength() const {
+ auto array = (jni::jarray<jni::jobject>*) value;
+ return jni::GetArrayLength(jenv, *array);
+ }
+
+ Value Value::get(const int index ) const {
+ auto array = (jni::jarray<jni::jobject>*) value;
+ return Value(jenv, jni::GetObjectArrayElement(jenv, *array, index));
+ }
+}
+}
+
diff --git a/platform/android/src/style/value.hpp b/platform/android/src/style/value.hpp
new file mode 100644
index 0000000000..2f0b1d9706
--- /dev/null
+++ b/platform/android/src/style/value.hpp
@@ -0,0 +1,35 @@
+#pragma once
+
+#include <jni/jni.hpp>
+
+#include <string>
+
+namespace mbgl {
+namespace android {
+
+class Value {
+public:
+
+ Value(jni::JNIEnv&, jni::jobject*);
+ virtual ~Value();
+
+ bool isNull() const;
+ bool isArray() const;
+ bool isObject() const;
+ bool isString() const;
+ bool isBool() const;
+ bool isNumber() const;
+
+ std::string toString() const;
+ float toNumber() const;
+ bool toBool() const;
+ Value get(const char* key) const;
+ int getLength() const;
+ Value get(const int index ) const;
+
+ jni::JNIEnv& jenv;
+ jni::jobject* value;
+};
+
+}
+}
diff --git a/platform/android/src/thread.cpp b/platform/android/src/thread.cpp
new file mode 100644
index 0000000000..77f9815866
--- /dev/null
+++ b/platform/android/src/thread.cpp
@@ -0,0 +1,37 @@
+#include <mbgl/platform/log.hpp>
+#include <mbgl/platform/platform.hpp>
+
+#include <sys/prctl.h>
+#include <sys/resource.h>
+
+// Implementation based on Chromium's platform_thread_android.cc.
+
+namespace mbgl {
+namespace platform {
+
+std::string getCurrentThreadName() {
+ char name[32] = "unknown";
+
+ if (prctl(PR_GET_NAME, name) == -1) {
+ Log::Warning(Event::General, "Couldn't get thread name");
+ }
+
+ return name;
+}
+
+void setCurrentThreadName(const std::string& name) {
+ if (prctl(PR_SET_NAME, name.c_str()) == -1) {
+ Log::Warning(Event::General, "Couldn't set thread name");
+ }
+}
+
+void makeThreadLowPriority() {
+ // ANDROID_PRIORITY_LOWEST = 19
+ //
+ // Supposedly would set the priority for the whole process, but
+ // on Linux/Android it only sets for the current thread.
+ setpriority(PRIO_PROCESS, 0, 19);
+}
+
+} // namespace platform
+} // namespace mbgl
diff --git a/platform/android/src/timer.cpp b/platform/android/src/timer.cpp
index 741005df23..7057d6de70 100644
--- a/platform/android/src/timer.cpp
+++ b/platform/android/src/timer.cpp
@@ -29,14 +29,13 @@ public:
}
void stop() {
- task = nullptr;
loop->removeRunnable(this);
}
void reschedule() {
if (repeat != Duration::zero()) {
due = Clock::now() + repeat;
- loop->addRunnable(this);
+ loop->wake();
} else {
stop();
}
@@ -47,8 +46,8 @@ public:
}
void runTask() override {
- task();
reschedule();
+ task();
}
private:
diff --git a/platform/darwin/src/MGLFeature.h b/platform/darwin/src/MGLFeature.h
index 69cff6b054..1ab587ede5 100644
--- a/platform/darwin/src/MGLFeature.h
+++ b/platform/darwin/src/MGLFeature.h
@@ -29,13 +29,23 @@ NS_ASSUME_NONNULL_BEGIN
An object that uniquely identifies the feature in its containing
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile source</a>.
- The value of this property is currently always an `NSNumber` object but may in
- the future be an instance of another class, such as `NSString`.
-
The identifier corresponds to the
<a href="https://github.com/mapbox/vector-tile-spec/tree/master/2.1#42-features">feature identifier</a>
(`id`) in the tile source. If the source does not specify the feature’s
- identifier, the value of this property is `nil`.
+ identifier, the value of this property is `nil`. If specified, the identifier
+ may be an integer, floating-point number, or string. These data types are
+ mapped to instances of the following Foundation classes:
+
+ <table>
+ <thead>
+ <tr><th>In the tile source</th><th>This property</th></tr>
+ </thead>
+ <tbody>
+ <tr><td>Integer</td> <td><code>NSNumber</code> (use the <code>unsignedLongLongValue</code> or <code>longLongValue</code> property)</td></tr>
+ <tr><td>Floating-point number</td> <td><code>NSNumber</code> (use the <code>doubleValue</code> property)</td></tr>
+ <tr><td>String</td> <td><code>NSString</code></td></tr>
+ </tbody>
+ </table>
For details about the identifiers used in most Mapbox-provided styles, consult
the
diff --git a/platform/darwin/src/MGLFeature.mm b/platform/darwin/src/MGLFeature.mm
index 777b296303..3bf1e61153 100644
--- a/platform/darwin/src/MGLFeature.mm
+++ b/platform/darwin/src/MGLFeature.mm
@@ -118,7 +118,7 @@
*/
class PropertyValueEvaluator {
public:
- id operator()(const std::nullptr_t &) const {
+ id operator()(const mbgl::NullValue &) const {
return [NSNull null];
}
@@ -260,7 +260,7 @@ NS_ARRAY_OF(MGLShape <MGLFeature> *) *MGLFeaturesFromMBGLFeatures(const std::vec
GeometryEvaluator<double> evaluator;
MGLShape <MGLFeaturePrivate> *shape = mapbox::geometry::geometry<double>::visit(feature.geometry, evaluator);
if (feature.id) {
- shape.identifier = @(*feature.id);
+ shape.identifier = mbgl::FeatureIdentifier::visit(*feature.id, PropertyValueEvaluator());
}
shape.attributes = attributes;
[shapes addObject:shape];
diff --git a/platform/darwin/src/MGLMultiPoint.mm b/platform/darwin/src/MGLMultiPoint.mm
index 6084535d05..a5b9eb8efc 100644
--- a/platform/darwin/src/MGLMultiPoint.mm
+++ b/platform/darwin/src/MGLMultiPoint.mm
@@ -5,11 +5,11 @@
mbgl::Color MGLColorObjectFromCGColorRef(CGColorRef cgColor) {
if (!cgColor) {
- return {{ 0, 0, 0, 0 }};
+ return { 0, 0, 0, 0 };
}
NSCAssert(CGColorGetNumberOfComponents(cgColor) >= 4, @"Color must have at least 4 components");
const CGFloat *components = CGColorGetComponents(cgColor);
- return {{ (float)components[0], (float)components[1], (float)components[2], (float)components[3] }};
+ return { (float)components[0], (float)components[1], (float)components[2], (float)components[3] };
}
@implementation MGLMultiPoint
diff --git a/platform/darwin/src/MGLPolygon.mm b/platform/darwin/src/MGLPolygon.mm
index c009d9e3d6..b8f02b6406 100644
--- a/platform/darwin/src/MGLPolygon.mm
+++ b/platform/darwin/src/MGLPolygon.mm
@@ -44,9 +44,9 @@
}
mbgl::FillAnnotation annotation { geometry };
- annotation.opacity = [delegate alphaForShapeAnnotation:self];
- annotation.outlineColor = [delegate strokeColorForShapeAnnotation:self];
- annotation.color = [delegate fillColorForPolygonAnnotation:self];
+ annotation.opacity = { static_cast<float>([delegate alphaForShapeAnnotation:self]) };
+ annotation.outlineColor = { [delegate strokeColorForShapeAnnotation:self] };
+ annotation.color = { [delegate fillColorForPolygonAnnotation:self] };
return annotation;
}
diff --git a/platform/darwin/src/MGLPolyline.mm b/platform/darwin/src/MGLPolyline.mm
index 15ea5a0952..b81147a3ba 100644
--- a/platform/darwin/src/MGLPolyline.mm
+++ b/platform/darwin/src/MGLPolyline.mm
@@ -24,9 +24,9 @@
}
mbgl::LineAnnotation annotation { geometry };
- annotation.opacity = [delegate alphaForShapeAnnotation:self];
- annotation.color = [delegate strokeColorForShapeAnnotation:self];
- annotation.width = [delegate lineWidthForPolylineAnnotation:self];
+ annotation.opacity = { static_cast<float>([delegate alphaForShapeAnnotation:self]) };
+ annotation.color = { [delegate strokeColorForShapeAnnotation:self] };
+ annotation.width = { static_cast<float>([delegate lineWidthForPolylineAnnotation:self]) };
return annotation;
}
diff --git a/platform/darwin/src/headless_view_cgl.cpp b/platform/darwin/src/headless_view_cgl.cpp
index a4f809a250..dc58463b5d 100644
--- a/platform/darwin/src/headless_view_cgl.cpp
+++ b/platform/darwin/src/headless_view_cgl.cpp
@@ -19,7 +19,7 @@ gl::glProc HeadlessView::initializeExtension(const char* name) {
}
void HeadlessView::createContext() {
- CGLError error = CGLCreateContext(display->pixelFormat, NULL, &glContext);
+ CGLError error = CGLCreateContext(display->pixelFormat, nullptr, &glContext);
if (error != kCGLNoError) {
throw std::runtime_error(std::string("Error creating GL context object:") + CGLErrorString(error) + "\n");
}
diff --git a/platform/darwin/src/log_nslog.mm b/platform/darwin/src/log_nslog.mm
index a2e31968ab..49583ae3c4 100644
--- a/platform/darwin/src/log_nslog.mm
+++ b/platform/darwin/src/log_nslog.mm
@@ -1,4 +1,5 @@
#include <mbgl/platform/log.hpp>
+#include <mbgl/util/enum.hpp>
#import <Foundation/Foundation.h>
@@ -7,7 +8,7 @@ namespace mbgl {
void Log::platformRecord(EventSeverity severity, const std::string &msg) {
NSString *message =
[[NSString alloc] initWithBytes:msg.data() length:msg.size() encoding:NSUTF8StringEncoding];
- NSLog(@"[%s] %@", EventSeverityClass(severity).c_str(), message);
+ NSLog(@"[%s] %@", Enum<EventSeverity>::toString(severity), message);
}
}
diff --git a/platform/darwin/src/nsthread.mm b/platform/darwin/src/nsthread.mm
index 9ac1d2caa0..eee6d6991b 100644
--- a/platform/darwin/src/nsthread.mm
+++ b/platform/darwin/src/nsthread.mm
@@ -2,9 +2,22 @@
#include <mbgl/platform/platform.hpp>
+#include <pthread.h>
+
namespace mbgl {
namespace platform {
+std::string getCurrentThreadName() {
+ char name[32] = "unknown";
+ pthread_getname_np(pthread_self(), name, sizeof(name));
+
+ return name;
+}
+
+void setCurrentThreadName(const std::string& name) {
+ pthread_setname_np(name.c_str());
+}
+
void makeThreadLowPriority() {
[[NSThread currentThread] setThreadPriority:0.0];
}
diff --git a/platform/darwin/src/settings_nsuserdefaults.mm b/platform/darwin/src/settings_nsuserdefaults.mm
deleted file mode 100644
index 548ee9b220..0000000000
--- a/platform/darwin/src/settings_nsuserdefaults.mm
+++ /dev/null
@@ -1,60 +0,0 @@
-#import <Foundation/Foundation.h>
-
-#include <mbgl/platform/darwin/settings_nsuserdefaults.hpp>
-
-using namespace mbgl;
-
-Settings_NSUserDefaults::Settings_NSUserDefaults()
-{
- [[NSUserDefaults standardUserDefaults] registerDefaults:@{
- @"longitude" : @(longitude),
- @"latitude" : @(latitude),
- @"zoom" : @(zoom),
- @"bearing" : @(bearing),
- @"pitch" : @(pitch),
- @"userTrackingMode" : @(userTrackingMode),
- @"showsUserLocation" : @(showsUserLocation),
- @"debug" : @(debug),
- }];
- load();
-}
-
-void Settings_NSUserDefaults::load()
-{
- NSDictionary *settings = [[NSUserDefaults standardUserDefaults] dictionaryRepresentation];
-
- longitude = [settings[@"longitude"] doubleValue];
- latitude = [settings[@"latitude"] doubleValue];
- zoom = [settings[@"zoom"] doubleValue];
- bearing = [settings[@"bearing"] doubleValue];
- pitch = [settings[@"pitch"] doubleValue];
- debug = [settings[@"debug"] boolValue];
-
- unsigned uncheckedTrackingMode = [settings[@"userTrackingMode"] unsignedIntValue];
- if (uncheckedTrackingMode > MGLUserTrackingModeNone &&
- uncheckedTrackingMode <= MGLUserTrackingModeFollowWithCourse)
- {
- userTrackingMode = (MGLUserTrackingMode)uncheckedTrackingMode;
- }
- showsUserLocation = [settings[@"showsUserLocation"] boolValue];
-}
-
-void Settings_NSUserDefaults::save()
-{
- [[NSUserDefaults standardUserDefaults] setValuesForKeysWithDictionary:@{
- @"longitude" : @(longitude),
- @"latitude" : @(latitude),
- @"zoom" : @(zoom),
- @"bearing" : @(bearing),
- @"pitch" : @(pitch),
- @"userTrackingMode" : @(userTrackingMode),
- @"showsUserLocation" : @(showsUserLocation),
- @"debug" : @(debug),
- }];
- [[NSUserDefaults standardUserDefaults] synchronize];
-}
-
-void Settings_NSUserDefaults::clear()
-{
- [NSUserDefaults resetStandardUserDefaults];
-}
diff --git a/platform/darwin/test/MGLFeatureTests.mm b/platform/darwin/test/MGLFeatureTests.mm
index 6cf038d4fb..1b1722f172 100644
--- a/platform/darwin/test/MGLFeatureTests.mm
+++ b/platform/darwin/test/MGLFeatureTests.mm
@@ -1,6 +1,7 @@
#import <Mapbox/Mapbox.h>
#import <XCTest/XCTest.h>
+#import <mbgl/util/geometry.hpp>
#import "../../darwin/src/MGLFeature_Private.h"
@interface MGLFeatureTests : XCTestCase
@@ -12,16 +13,16 @@
- (void)testGeometryConversion {
std::vector<mbgl::Feature> features;
- mapbox::geometry::point<double> point = { -90.066667, 29.95 };
- features.emplace_back(point);
+ mbgl::Point<double> point = { -90.066667, 29.95 };
+ features.push_back(mbgl::Feature { point });
- mapbox::geometry::line_string<double> lineString = {
+ mbgl::LineString<double> lineString = {
{ -84.516667, 39.1 },
{ -90.066667, 29.95 },
};
- features.emplace_back(lineString);
+ features.push_back(mbgl::Feature { lineString });
- mapbox::geometry::polygon<double> polygon = {
+ mbgl::Polygon<double> polygon = {
{
{ 1, 1 },
{ 4, 1 },
@@ -35,7 +36,7 @@
{ 2, 3 },
},
};
- features.emplace_back(polygon);
+ features.push_back(mbgl::Feature { polygon });
NS_ARRAY_OF(MGLShape <MGLFeature> *) *shapes = MGLFeaturesFromMBGLFeatures(features);
XCTAssertEqual(shapes.count, 3, @"All features should be converted into shapes");
@@ -87,9 +88,9 @@
- (void)testPropertyConversion {
std::vector<mbgl::Feature> features;
- mapbox::geometry::point<double> point = { -90.066667, 29.95 };
- mbgl::Feature pointFeature(point);
- pointFeature.id = UINT64_MAX;
+ mbgl::Point<double> point = { -90.066667, 29.95 };
+ mbgl::Feature pointFeature { point };
+ pointFeature.id = { UINT64_MAX };
pointFeature.properties["null"] = nullptr;
pointFeature.properties["bool"] = true;
pointFeature.properties["unsigned int"] = UINT64_MAX;
diff --git a/platform/default/asset_file_source.cpp b/platform/default/asset_file_source.cpp
index 3a47f349fe..2872c6bb3a 100644
--- a/platform/default/asset_file_source.cpp
+++ b/platform/default/asset_file_source.cpp
@@ -14,8 +14,8 @@ namespace mbgl {
class AssetFileSource::Impl {
public:
- Impl(const std::string& root_)
- : root(root_) {
+ Impl(std::string root_)
+ : root(std::move(root_)) {
}
void request(const std::string& url, FileSource::Callback callback) {
@@ -57,7 +57,7 @@ private:
AssetFileSource::AssetFileSource(const std::string& root)
: thread(std::make_unique<util::Thread<Impl>>(
- util::ThreadContext{"AssetFileSource"},
+ util::ThreadContext{"AssetFileSource", util::ThreadPriority::Low},
root)) {
}
diff --git a/platform/default/glfw_view.cpp b/platform/default/glfw_view.cpp
index 67e9748a70..863f42ec76 100644
--- a/platform/default/glfw_view.cpp
+++ b/platform/default/glfw_view.cpp
@@ -23,7 +23,7 @@ GLFWView::GLFWView(bool fullscreen_, bool benchmark_)
: fullscreen(fullscreen_), benchmark(benchmark_) {
glfwSetErrorCallback(glfwError);
- std::srand(std::time(0));
+ std::srand(std::time(nullptr));
if (!glfwInit()) {
mbgl::Log::Error(mbgl::Event::OpenGL, "failed to initialize glfw");
@@ -55,7 +55,7 @@ GLFWView::GLFWView(bool fullscreen_, bool benchmark_)
glfwWindowHint(GLFW_STENCIL_BITS, 8);
glfwWindowHint(GLFW_DEPTH_BITS, 16);
- window = glfwCreateWindow(width, height, "Mapbox GL", monitor, NULL);
+ window = glfwCreateWindow(width, height, "Mapbox GL", monitor, nullptr);
if (!window) {
glfwTerminate();
mbgl::Log::Error(mbgl::Event::OpenGL, "failed to initialize window");
@@ -103,6 +103,7 @@ GLFWView::GLFWView(bool fullscreen_, bool benchmark_)
printf("\n");
printf("- Press `Q` to remove annotations\n");
printf("- Press `P` to add a random custom runtime imagery annotation\n");
+ printf("- Press `L` to add a random line annotation\n");
printf("- Press `W` to pop the last-added annotation off\n");
printf("\n");
printf("- `Control` + mouse drag to rotate\n");
@@ -164,9 +165,12 @@ void GLFWView::onKey(GLFWwindow *window, int key, int /*scancode*/, int action,
case GLFW_KEY_Q:
view->clearAnnotations();
break;
- case GLFW_KEY_P: {
+ case GLFW_KEY_P:
view->addRandomCustomPointAnnotations(1);
- } break;
+ break;
+ case GLFW_KEY_L:
+ view->addRandomLineAnnotations(1);
+ break;
case GLFW_KEY_A: {
// XXX Fix precision loss in flyTo:
// https://github.com/mapbox/mapbox-gl-native/issues/4298
@@ -207,6 +211,13 @@ void GLFWView::onKey(GLFWwindow *window, int key, int /*scancode*/, int action,
}
}
+mbgl::Color GLFWView::makeRandomColor() const {
+ const float r = 1.0f * (float(std::rand()) / RAND_MAX);
+ const float g = 1.0f * (float(std::rand()) / RAND_MAX);
+ const float b = 1.0f * (float(std::rand()) / RAND_MAX);
+ return { r, g, b, 1.0f };
+}
+
mbgl::Point<double> GLFWView::makeRandomPoint() const {
const double x = width * double(std::rand()) / RAND_MAX;
const double y = height * double(std::rand()) / RAND_MAX;
@@ -264,16 +275,26 @@ void GLFWView::addRandomCustomPointAnnotations(int count) {
}
void GLFWView::addRandomPointAnnotations(int count) {
- for (int i = 0; i < count; i++) {
+ for (int i = 0; i < count; ++i) {
annotationIDs.push_back(map->addAnnotation(mbgl::SymbolAnnotation { makeRandomPoint(), "default_marker" }));
}
}
+void GLFWView::addRandomLineAnnotations(int count) {
+ for (int i = 0; i < count; ++i) {
+ mbgl::LineString<double> lineString;
+ for (int j = 0; j < 3; ++j) {
+ lineString.push_back(makeRandomPoint());
+ }
+ annotationIDs.push_back(map->addAnnotation(mbgl::LineAnnotation { lineString, 1.0f, 2.0f, { makeRandomColor() } }));
+ }
+}
+
void GLFWView::addRandomShapeAnnotations(int count) {
- for (int i = 0; i < count; i++) {
+ for (int i = 0; i < count; ++i) {
mbgl::Polygon<double> triangle;
triangle.push_back({ makeRandomPoint(), makeRandomPoint(), makeRandomPoint() });
- annotationIDs.push_back(map->addAnnotation(mbgl::FillAnnotation { triangle, .1 }));
+ annotationIDs.push_back(map->addAnnotation(mbgl::FillAnnotation { triangle, 0.5f, { makeRandomColor() }, { makeRandomColor() } }));
}
}
diff --git a/platform/default/headless_view_glx.cpp b/platform/default/headless_view_glx.cpp
index 3b719ab43a..55d9313f99 100644
--- a/platform/default/headless_view_glx.cpp
+++ b/platform/default/headless_view_glx.cpp
@@ -23,12 +23,12 @@ void HeadlessView::createContext() {
if (!glXIsDirect(xDisplay, glContext)) {
Log::Error(Event::OpenGL, "failed to create direct OpenGL Legacy context");
glXDestroyContext(xDisplay, glContext);
- glContext = 0;
+ glContext = nullptr;
}
}
}
- if (glContext == 0) {
+ if (glContext == nullptr) {
throw std::runtime_error("Error creating GL context object.");
}
diff --git a/platform/default/http_file_source.cpp b/platform/default/http_file_source.cpp
index e83ecfbfc9..17e06a6c0f 100644
--- a/platform/default/http_file_source.cpp
+++ b/platform/default/http_file_source.cpp
@@ -63,8 +63,8 @@ public:
class HTTPRequest : public AsyncRequest {
public:
- HTTPRequest(HTTPFileSource::Impl*, const Resource&, FileSource::Callback);
- ~HTTPRequest();
+ HTTPRequest(HTTPFileSource::Impl*, Resource, FileSource::Callback);
+ ~HTTPRequest() override;
void handleResult(CURLcode code);
@@ -219,10 +219,10 @@ int HTTPFileSource::Impl::startTimeout(CURLM * /* multi */, long timeout_ms, voi
return 0;
}
-HTTPRequest::HTTPRequest(HTTPFileSource::Impl* context_, const Resource& resource_, FileSource::Callback callback_)
+HTTPRequest::HTTPRequest(HTTPFileSource::Impl* context_, Resource resource_, FileSource::Callback callback_)
: context(context_),
- resource(resource_),
- callback(callback_),
+ resource(std::move(resource_)),
+ callback(std::move(callback_)),
handle(context->getHandle()) {
// If there's already a response, set the correct etags/modified headers to make sure we are
diff --git a/platform/default/image.cpp b/platform/default/image.cpp
index 988d2f4a4e..890d442683 100644
--- a/platform/default/image.cpp
+++ b/platform/default/image.cpp
@@ -5,7 +5,7 @@
#include <png.h>
template<size_t max, typename... Args>
-inline static std::string sprintf(const char *msg, Args... args) {
+static std::string sprintf(const char *msg, Args... args) {
char res[max];
int len = snprintf(res, sizeof(res), msg, args...);
return std::string(res, len);
@@ -30,15 +30,15 @@ std::string encodePNG(const PremultipliedImage& pre) {
UnassociatedImage src = util::unpremultiply(std::move(copy));
- png_voidp error_ptr = 0;
- png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, error_ptr, NULL, NULL);
+ png_voidp error_ptr = nullptr;
+ png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, error_ptr, nullptr, nullptr);
if (!png_ptr) {
throw std::runtime_error("couldn't create png_ptr");
}
png_infop info_ptr = png_create_info_struct(png_ptr);
if (!png_ptr) {
- png_destroy_write_struct(&png_ptr, (png_infopp)0);
+ png_destroy_write_struct(&png_ptr, (png_infopp)nullptr);
throw std::runtime_error("couldn't create info_ptr");
}
@@ -55,7 +55,7 @@ std::string encodePNG(const PremultipliedImage& pre) {
png_set_write_fn(png_ptr, &result, [](png_structp png_ptr_, png_bytep data, png_size_t length) {
std::string *out = static_cast<std::string *>(png_get_io_ptr(png_ptr_));
out->append(reinterpret_cast<char *>(data), length);
- }, NULL);
+ }, nullptr);
struct ptrs {
ptrs(size_t count) : rows(new png_bytep[count]) {}
@@ -68,7 +68,7 @@ std::string encodePNG(const PremultipliedImage& pre) {
}
png_set_rows(png_ptr, info_ptr, pointers.rows);
- png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
+ png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, nullptr);
png_destroy_write_struct(&png_ptr, &info_ptr);
return result;
@@ -112,4 +112,4 @@ PremultipliedImage decodeImage(const std::string& string) {
throw std::runtime_error("unsupported image type");
}
-}
+} // namespace mbgl
diff --git a/platform/default/jpeg_reader.cpp b/platform/default/jpeg_reader.cpp
index b9518c71bc..9bcf3c6bc1 100644
--- a/platform/default/jpeg_reader.cpp
+++ b/platform/default/jpeg_reader.cpp
@@ -1,14 +1,9 @@
#include <mbgl/util/image.hpp>
+#include <mbgl/util/char_array_buffer.hpp>
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wunknown-pragmas"
-#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
-#pragma GCC diagnostic ignored "-Wshadow"
-#include <boost/iostreams/stream.hpp>
-#pragma GCC diagnostic pop
-
-#include <boost/iostreams/device/file.hpp>
-#include <boost/iostreams/device/array.hpp>
+#include <istream>
+#include <sstream>
+#include <array>
extern "C"
{
@@ -17,27 +12,24 @@ extern "C"
namespace mbgl {
-using source_type = boost::iostreams::array_source;
-using input_stream = boost::iostreams::stream<source_type>;
-
const static unsigned BUF_SIZE = 4096;
struct jpeg_stream_wrapper {
jpeg_source_mgr manager;
- input_stream * stream;
- JOCTET buffer[BUF_SIZE];
+ std::istream* stream;
+ std::array<JOCTET, BUF_SIZE> buffer;
};
static void init_source(j_decompress_ptr cinfo) {
jpeg_stream_wrapper* wrap = reinterpret_cast<jpeg_stream_wrapper*>(cinfo->src);
- wrap->stream->seekg(0,std::ios_base::beg);
+ wrap->stream->seekg(0, std::ios_base::beg);
}
static boolean fill_input_buffer(j_decompress_ptr cinfo) {
jpeg_stream_wrapper* wrap = reinterpret_cast<jpeg_stream_wrapper*>(cinfo->src);
- wrap->stream->read(reinterpret_cast<char*>(&wrap->buffer[0]),BUF_SIZE);
+ wrap->stream->read(reinterpret_cast<char*>(&wrap->buffer[0]), BUF_SIZE);
std::streamsize size = wrap->stream->gcount();
- wrap->manager.next_input_byte = wrap->buffer;
+ wrap->manager.next_input_byte = wrap->buffer.data();
wrap->manager.bytes_in_buffer = BUF_SIZE;
return (size > 0) ? TRUE : FALSE;
}
@@ -55,15 +47,15 @@ static void skip(j_decompress_ptr cinfo, long count) {
{
wrap->stream->seekg(count - wrap->manager.bytes_in_buffer, std::ios_base::cur);
// trigger buffer fill
- wrap->manager.next_input_byte = 0;
+ wrap->manager.next_input_byte = nullptr;
wrap->manager.bytes_in_buffer = 0; //bytes_in_buffer may be zero on return.
}
}
static void term(j_decompress_ptr) {}
-static void attach_stream(j_decompress_ptr cinfo, input_stream* in) {
- if (cinfo->src == 0) {
+static void attach_stream(j_decompress_ptr cinfo, std::istream* in) {
+ if (cinfo->src == nullptr) {
cinfo->src = (struct jpeg_source_mgr *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(jpeg_stream_wrapper));
}
@@ -74,7 +66,7 @@ static void attach_stream(j_decompress_ptr cinfo, input_stream* in) {
src->manager.resync_to_restart = jpeg_resync_to_restart;
src->manager.term_source = term;
src->manager.bytes_in_buffer = 0;
- src->manager.next_input_byte = 0;
+ src->manager.next_input_byte = nullptr;
src->stream = in;
}
@@ -98,8 +90,8 @@ struct jpeg_info_guard {
};
PremultipliedImage decodeJPEG(const uint8_t* data, size_t size) {
- source_type source(reinterpret_cast<const char*>(data), size);
- input_stream stream(source);
+ util::CharArrayBuffer dataBuffer { reinterpret_cast<const char*>(data), size };
+ std::istream stream(&dataBuffer);
jpeg_decompress_struct cinfo;
jpeg_info_guard iguard(&cinfo);
@@ -156,4 +148,4 @@ PremultipliedImage decodeJPEG(const uint8_t* data, size_t size) {
return image;
}
-}
+} // namespace mbgl
diff --git a/platform/default/log_stderr.cpp b/platform/default/log_stderr.cpp
index 536841617a..145cdeda03 100644
--- a/platform/default/log_stderr.cpp
+++ b/platform/default/log_stderr.cpp
@@ -1,11 +1,12 @@
#include <mbgl/platform/log.hpp>
+#include <mbgl/util/enum.hpp>
#include <iostream>
namespace mbgl {
void Log::platformRecord(EventSeverity severity, const std::string &msg) {
- std::cerr << "[" << severity << "] " << msg << std::endl;
+ std::cerr << "[" << Enum<EventSeverity>::toString(severity) << "] " << msg << std::endl;
}
} // namespace mbgl
diff --git a/platform/default/mbgl/storage/offline.cpp b/platform/default/mbgl/storage/offline.cpp
index d8e0357ae2..fd2d47819b 100644
--- a/platform/default/mbgl/storage/offline.cpp
+++ b/platform/default/mbgl/storage/offline.cpp
@@ -11,9 +11,9 @@
namespace mbgl {
OfflineTilePyramidRegionDefinition::OfflineTilePyramidRegionDefinition(
- const std::string& styleURL_, const LatLngBounds& bounds_, double minZoom_, double maxZoom_, float pixelRatio_)
- : styleURL(styleURL_),
- bounds(bounds_),
+ std::string styleURL_, LatLngBounds bounds_, double minZoom_, double maxZoom_, float pixelRatio_)
+ : styleURL(std::move(styleURL_)),
+ bounds(std::move(bounds_)),
minZoom(minZoom_),
maxZoom(maxZoom_),
pixelRatio(pixelRatio_) {
@@ -23,9 +23,9 @@ OfflineTilePyramidRegionDefinition::OfflineTilePyramidRegionDefinition(
}
}
-std::vector<CanonicalTileID> OfflineTilePyramidRegionDefinition::tileCover(SourceType type, uint16_t tileSize, const Tileset& tileset) const {
- double minZ = std::max<double>(util::coveringZoomLevel(minZoom, type, tileSize), tileset.minZoom);
- double maxZ = std::min<double>(util::coveringZoomLevel(maxZoom, type, tileSize), tileset.maxZoom);
+std::vector<CanonicalTileID> OfflineTilePyramidRegionDefinition::tileCover(SourceType type, uint16_t tileSize, const Range<uint8_t>& zoomRange) const {
+ double minZ = std::max<double>(util::coveringZoomLevel(minZoom, type, tileSize), zoomRange.min);
+ double maxZ = std::min<double>(util::coveringZoomLevel(maxZoom, type, tileSize), zoomRange.max);
assert(minZ >= 0);
assert(maxZ >= 0);
@@ -97,11 +97,11 @@ std::string encodeOfflineRegionDefinition(const OfflineRegionDefinition& region)
}
OfflineRegion::OfflineRegion(int64_t id_,
- const OfflineRegionDefinition& definition_,
- const OfflineRegionMetadata& metadata_)
+ OfflineRegionDefinition definition_,
+ OfflineRegionMetadata metadata_)
: id(id_),
- definition(definition_),
- metadata(metadata_) {
+ definition(std::move(definition_)),
+ metadata(std::move(metadata_)) {
}
OfflineRegion::OfflineRegion(OfflineRegion&&) = default;
diff --git a/platform/default/mbgl/storage/offline_database.cpp b/platform/default/mbgl/storage/offline_database.cpp
index 3193909294..46a2c2bc25 100644
--- a/platform/default/mbgl/storage/offline_database.cpp
+++ b/platform/default/mbgl/storage/offline_database.cpp
@@ -11,15 +11,13 @@
namespace mbgl {
-using namespace mapbox::sqlite;
-
OfflineDatabase::Statement::~Statement() {
stmt.reset();
stmt.clearBindings();
}
-OfflineDatabase::OfflineDatabase(const std::string& path_, uint64_t maximumCacheSize_)
- : path(path_),
+OfflineDatabase::OfflineDatabase(std::string path_, uint64_t maximumCacheSize_)
+ : path(std::move(path_)),
maximumCacheSize(maximumCacheSize_) {
ensureSchema();
}
@@ -36,7 +34,7 @@ OfflineDatabase::~OfflineDatabase() {
}
void OfflineDatabase::connect(int flags) {
- db = std::make_unique<Database>(path.c_str(), flags);
+ db = std::make_unique<mapbox::sqlite::Database>(path.c_str(), flags);
db->setBusyTimeout(Milliseconds::max());
db->exec("PRAGMA foreign_keys = ON");
}
@@ -44,7 +42,7 @@ void OfflineDatabase::connect(int flags) {
void OfflineDatabase::ensureSchema() {
if (path != ":memory:") {
try {
- connect(ReadWrite);
+ connect(mapbox::sqlite::ReadWrite);
switch (userVersion()) {
case 0: break; // cache-only database; ok to delete
@@ -55,7 +53,7 @@ void OfflineDatabase::ensureSchema() {
}
removeExisting();
- connect(ReadWrite | Create);
+ connect(mapbox::sqlite::ReadWrite | mapbox::sqlite::Create);
} catch (mapbox::sqlite::Exception& ex) {
if (ex.code != SQLITE_CANTOPEN && ex.code != SQLITE_NOTADB) {
Log::Error(Event::Database, "Unexpected error connecting to database: %s", ex.what());
@@ -66,7 +64,7 @@ void OfflineDatabase::ensureSchema() {
if (ex.code == SQLITE_NOTADB) {
removeExisting();
}
- connect(ReadWrite | Create);
+ connect(mapbox::sqlite::ReadWrite | mapbox::sqlite::Create);
} catch (...) {
Log::Error(Event::Database, "Unexpected error creating database: %s", util::toString(std::current_exception()).c_str());
throw;
@@ -77,7 +75,7 @@ void OfflineDatabase::ensureSchema() {
try {
#include "offline_schema.cpp.include"
- connect(ReadWrite | Create);
+ connect(mapbox::sqlite::ReadWrite | mapbox::sqlite::Create);
// If you change the schema you must write a migration from the previous version.
db->exec("PRAGMA auto_vacuum = INCREMENTAL");
@@ -178,18 +176,22 @@ std::pair<bool, uint64_t> OfflineDatabase::putInternal(const Resource& resource,
}
optional<std::pair<Response, uint64_t>> OfflineDatabase::getResource(const Resource& resource) {
+ // clang-format off
Statement accessedStmt = getStatement(
"UPDATE resources SET accessed = ?1 WHERE url = ?2");
+ // clang-format on
accessedStmt->bind(1, util::now());
accessedStmt->bind(2, resource.url);
accessedStmt->run();
+ // clang-format off
Statement stmt = getStatement(
// 0 1 2 3 4
"SELECT etag, expires, modified, data, compressed "
"FROM resources "
"WHERE url = ?");
+ // clang-format on
stmt->bind(1, resource.url);
@@ -223,11 +225,13 @@ bool OfflineDatabase::putResource(const Resource& resource,
const std::string& data,
bool compressed) {
if (response.notModified) {
+ // clang-format off
Statement update = getStatement(
"UPDATE resources "
"SET accessed = ?1, "
" expires = ?2 "
"WHERE url = ?3 ");
+ // clang-format on
update->bind(1, util::now());
update->bind(2, response.expires);
@@ -240,8 +244,9 @@ bool OfflineDatabase::putResource(const Resource& resource,
// Begin an immediate-mode transaction to ensure that two writers do not attempt
// to INSERT a resource at the same moment.
- Transaction transaction(*db, Transaction::Immediate);
+ mapbox::sqlite::Transaction transaction(*db, mapbox::sqlite::Transaction::Immediate);
+ // clang-format off
Statement update = getStatement(
"UPDATE resources "
"SET kind = ?1, "
@@ -252,6 +257,7 @@ bool OfflineDatabase::putResource(const Resource& resource,
" data = ?6, "
" compressed = ?7 "
"WHERE url = ?8 ");
+ // clang-format on
update->bind(1, int(resource.kind));
update->bind(2, response.etag);
@@ -274,9 +280,11 @@ bool OfflineDatabase::putResource(const Resource& resource,
return false;
}
+ // clang-format off
Statement insert = getStatement(
"INSERT INTO resources (url, kind, etag, expires, modified, accessed, data, compressed) "
"VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8) ");
+ // clang-format on
insert->bind(1, resource.url);
insert->bind(2, int(resource.kind));
@@ -300,6 +308,7 @@ bool OfflineDatabase::putResource(const Resource& resource,
}
optional<std::pair<Response, uint64_t>> OfflineDatabase::getTile(const Resource::TileData& tile) {
+ // clang-format off
Statement accessedStmt = getStatement(
"UPDATE tiles "
"SET accessed = ?1 "
@@ -308,6 +317,7 @@ optional<std::pair<Response, uint64_t>> OfflineDatabase::getTile(const Resource:
" AND x = ?4 "
" AND y = ?5 "
" AND z = ?6 ");
+ // clang-format on
accessedStmt->bind(1, util::now());
accessedStmt->bind(2, tile.urlTemplate);
@@ -317,6 +327,7 @@ optional<std::pair<Response, uint64_t>> OfflineDatabase::getTile(const Resource:
accessedStmt->bind(6, tile.z);
accessedStmt->run();
+ // clang-format off
Statement stmt = getStatement(
// 0 1 2 3 4
"SELECT etag, expires, modified, data, compressed "
@@ -326,6 +337,7 @@ optional<std::pair<Response, uint64_t>> OfflineDatabase::getTile(const Resource:
" AND x = ?3 "
" AND y = ?4 "
" AND z = ?5 ");
+ // clang-format on
stmt->bind(1, tile.urlTemplate);
stmt->bind(2, tile.pixelRatio);
@@ -363,6 +375,7 @@ bool OfflineDatabase::putTile(const Resource::TileData& tile,
const std::string& data,
bool compressed) {
if (response.notModified) {
+ // clang-format off
Statement update = getStatement(
"UPDATE tiles "
"SET accessed = ?1, "
@@ -372,6 +385,7 @@ bool OfflineDatabase::putTile(const Resource::TileData& tile,
" AND x = ?5 "
" AND y = ?6 "
" AND z = ?7 ");
+ // clang-format on
update->bind(1, util::now());
update->bind(2, response.expires);
@@ -388,8 +402,9 @@ bool OfflineDatabase::putTile(const Resource::TileData& tile,
// Begin an immediate-mode transaction to ensure that two writers do not attempt
// to INSERT a resource at the same moment.
- Transaction transaction(*db, Transaction::Immediate);
+ mapbox::sqlite::Transaction transaction(*db, mapbox::sqlite::Transaction::Immediate);
+ // clang-format off
Statement update = getStatement(
"UPDATE tiles "
"SET modified = ?1, "
@@ -403,6 +418,7 @@ bool OfflineDatabase::putTile(const Resource::TileData& tile,
" AND x = ?9 "
" AND y = ?10 "
" AND z = ?11 ");
+ // clang-format on
update->bind(1, response.modified);
update->bind(2, response.etag);
@@ -428,9 +444,11 @@ bool OfflineDatabase::putTile(const Resource::TileData& tile,
return false;
}
+ // clang-format off
Statement insert = getStatement(
"INSERT INTO tiles (url_template, pixel_ratio, x, y, z, modified, etag, expires, accessed, data, compressed) "
"VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11) ");
+ // clang-format on
insert->bind(1, tile.urlTemplate);
insert->bind(2, tile.pixelRatio);
@@ -457,8 +475,10 @@ bool OfflineDatabase::putTile(const Resource::TileData& tile,
}
std::vector<OfflineRegion> OfflineDatabase::listRegions() {
+ // clang-format off
Statement stmt = getStatement(
"SELECT id, definition, description FROM regions");
+ // clang-format on
std::vector<OfflineRegion> result;
@@ -474,9 +494,11 @@ std::vector<OfflineRegion> OfflineDatabase::listRegions() {
OfflineRegion OfflineDatabase::createRegion(const OfflineRegionDefinition& definition,
const OfflineRegionMetadata& metadata) {
+ // clang-format off
Statement stmt = getStatement(
"INSERT INTO regions (definition, description) "
"VALUES (?1, ?2) ");
+ // clang-format on
stmt->bind(1, encodeOfflineRegionDefinition(definition));
stmt->bindBlob(2, metadata);
@@ -486,8 +508,10 @@ OfflineRegion OfflineDatabase::createRegion(const OfflineRegionDefinition& defin
}
void OfflineDatabase::deleteRegion(OfflineRegion&& region) {
+ // clang-format off
Statement stmt = getStatement(
"DELETE FROM regions WHERE id = ?");
+ // clang-format on
stmt->bind(1, region.getID());
stmt->run();
@@ -525,6 +549,7 @@ uint64_t OfflineDatabase::putRegionResource(int64_t regionID, const Resource& re
bool OfflineDatabase::markUsed(int64_t regionID, const Resource& resource) {
if (resource.kind == Resource::Kind::Tile) {
+ // clang-format off
Statement insert = getStatement(
"INSERT OR IGNORE INTO region_tiles (region_id, tile_id) "
"SELECT ?1, tiles.id "
@@ -534,6 +559,7 @@ bool OfflineDatabase::markUsed(int64_t regionID, const Resource& resource) {
" AND x = ?4 "
" AND y = ?5 "
" AND z = ?6 ");
+ // clang-format on
const Resource::TileData& tile = *resource.tileData;
insert->bind(1, regionID);
@@ -548,6 +574,7 @@ bool OfflineDatabase::markUsed(int64_t regionID, const Resource& resource) {
return false;
}
+ // clang-format off
Statement select = getStatement(
"SELECT region_id "
"FROM region_tiles, tiles "
@@ -558,6 +585,7 @@ bool OfflineDatabase::markUsed(int64_t regionID, const Resource& resource) {
" AND y = ?5 "
" AND z = ?6 "
"LIMIT 1 ");
+ // clang-format on
select->bind(1, regionID);
select->bind(2, tile.urlTemplate);
@@ -567,11 +595,13 @@ bool OfflineDatabase::markUsed(int64_t regionID, const Resource& resource) {
select->bind(6, tile.z);
return !select->run();
} else {
+ // clang-format off
Statement insert = getStatement(
"INSERT OR IGNORE INTO region_resources (region_id, resource_id) "
"SELECT ?1, resources.id "
"FROM resources "
"WHERE resources.url = ?2 ");
+ // clang-format on
insert->bind(1, regionID);
insert->bind(2, resource.url);
@@ -581,12 +611,14 @@ bool OfflineDatabase::markUsed(int64_t regionID, const Resource& resource) {
return false;
}
+ // clang-format off
Statement select = getStatement(
"SELECT region_id "
"FROM region_resources, resources "
"WHERE region_id != ?1 "
" AND resources.url = ?2 "
"LIMIT 1 ");
+ // clang-format on
select->bind(1, regionID);
select->bind(2, resource.url);
@@ -595,8 +627,10 @@ bool OfflineDatabase::markUsed(int64_t regionID, const Resource& resource) {
}
OfflineRegionDefinition OfflineDatabase::getRegionDefinition(int64_t regionID) {
+ // clang-format off
Statement stmt = getStatement(
"SELECT definition FROM regions WHERE id = ?1");
+ // clang-format on
stmt->bind(1, regionID);
stmt->run();
@@ -619,22 +653,26 @@ OfflineRegionStatus OfflineDatabase::getRegionCompletedStatus(int64_t regionID)
}
std::pair<int64_t, int64_t> OfflineDatabase::getCompletedResourceCountAndSize(int64_t regionID) {
+ // clang-format off
Statement stmt = getStatement(
"SELECT COUNT(*), SUM(LENGTH(data)) "
"FROM region_resources, resources "
"WHERE region_id = ?1 "
"AND resource_id = resources.id ");
+ // clang-format on
stmt->bind(1, regionID);
stmt->run();
return { stmt->get<int64_t>(0), stmt->get<int64_t>(1) };
}
std::pair<int64_t, int64_t> OfflineDatabase::getCompletedTileCountAndSize(int64_t regionID) {
+ // clang-format off
Statement stmt = getStatement(
"SELECT COUNT(*), SUM(LENGTH(data)) "
"FROM region_tiles, tiles "
"WHERE region_id = ?1 "
"AND tile_id = tiles.id ");
+ // clang-format on
stmt->bind(1, regionID);
stmt->run();
return { stmt->get<int64_t>(0), stmt->get<int64_t>(1) };
@@ -668,6 +706,7 @@ bool OfflineDatabase::evict(uint64_t neededFreeSize) {
// The addition of pageSize is a fudge factor to account for non `data` column
// size, and because pages can get fragmented on the database.
while (usedSize() + neededFreeSize + pageSize > maximumCacheSize) {
+ // clang-format off
Statement stmt1 = getStatement(
"DELETE FROM resources "
"WHERE id IN ( "
@@ -677,10 +716,12 @@ bool OfflineDatabase::evict(uint64_t neededFreeSize) {
" WHERE resource_id IS NULL "
" ORDER BY accessed ASC LIMIT ?1 "
") ");
+ // clang-format on
stmt1->bind(1, 50);
stmt1->run();
uint64_t changes1 = db->changes();
+ // clang-format off
Statement stmt2 = getStatement(
"DELETE FROM tiles "
"WHERE id IN ( "
@@ -690,6 +731,7 @@ bool OfflineDatabase::evict(uint64_t neededFreeSize) {
" WHERE tile_id IS NULL "
" ORDER BY accessed ASC LIMIT ?1 "
") ");
+ // clang-format on
stmt2->bind(1, 50);
stmt2->run();
uint64_t changes2 = db->changes();
@@ -727,11 +769,13 @@ uint64_t OfflineDatabase::getOfflineMapboxTileCount() {
return *offlineMapboxTileCount;
}
+ // clang-format off
Statement stmt = getStatement(
"SELECT COUNT(DISTINCT id) "
"FROM region_tiles, tiles "
"WHERE tile_id = tiles.id "
"AND url_template LIKE 'mapbox://%' ");
+ // clang-format on
stmt->run();
diff --git a/platform/default/mbgl/storage/offline_database.hpp b/platform/default/mbgl/storage/offline_database.hpp
index 1706c6ba5a..55cb7ad2fa 100644
--- a/platform/default/mbgl/storage/offline_database.hpp
+++ b/platform/default/mbgl/storage/offline_database.hpp
@@ -15,8 +15,8 @@ namespace mapbox {
namespace sqlite {
class Database;
class Statement;
-}
-}
+} // namespace sqlite
+} // namespace mapbox
namespace mbgl {
@@ -27,8 +27,7 @@ class OfflineDatabase : private util::noncopyable {
public:
// Limits affect ambient caching (put) only; resources required by offline
// regions are exempt.
- OfflineDatabase(const std::string& path,
- uint64_t maximumCacheSize = util::DEFAULT_MAX_CACHE_SIZE);
+ OfflineDatabase(std::string path, uint64_t maximumCacheSize = util::DEFAULT_MAX_CACHE_SIZE);
~OfflineDatabase();
optional<Response> get(const Resource&);
diff --git a/platform/default/mbgl/storage/offline_download.cpp b/platform/default/mbgl/storage/offline_download.cpp
index 11ca862925..dd66abf982 100644
--- a/platform/default/mbgl/storage/offline_download.cpp
+++ b/platform/default/mbgl/storage/offline_download.cpp
@@ -1,13 +1,16 @@
-#include <mbgl/storage/offline_download.hpp>
-#include <mbgl/storage/offline_database.hpp>
#include <mbgl/storage/file_source.hpp>
+#include <mbgl/storage/offline_database.hpp>
+#include <mbgl/storage/offline_download.hpp>
#include <mbgl/storage/resource.hpp>
#include <mbgl/storage/response.hpp>
#include <mbgl/style/parser.hpp>
+#include <mbgl/style/sources/geojson_source_impl.hpp>
+#include <mbgl/style/tile_source_impl.hpp>
#include <mbgl/text/glyph.hpp>
-#include <mbgl/util/tile_cover.hpp>
#include <mbgl/util/mapbox.hpp>
#include <mbgl/util/run_loop.hpp>
+#include <mbgl/util/tile_cover.hpp>
+#include <mbgl/util/tileset.hpp>
#include <set>
@@ -63,7 +66,8 @@ std::vector<Resource> OfflineDownload::glyphResources(const style::Parser& parse
if (!parser.glyphURL.empty()) {
for (const auto& fontStack : parser.fontStacks()) {
for (uint32_t i = 0; i < 256; i++) {
- result.push_back(Resource::glyphs(parser.glyphURL, fontStack, getGlyphRange(i * 256)));
+ result.push_back(
+ Resource::glyphs(parser.glyphURL, fontStack, getGlyphRange(i * 256)));
}
}
}
@@ -71,11 +75,13 @@ std::vector<Resource> OfflineDownload::glyphResources(const style::Parser& parse
return result;
}
-std::vector<Resource> OfflineDownload::tileResources(SourceType type, uint16_t tileSize, const Tileset& tileset) const {
+std::vector<Resource>
+OfflineDownload::tileResources(SourceType type, uint16_t tileSize, const Tileset& tileset) const {
std::vector<Resource> result;
- for (const auto& tile : definition.tileCover(type, tileSize, tileset)) {
- result.push_back(Resource::tile(tileset.tiles[0], definition.pixelRatio, tile.x, tile.y, tile.z));
+ for (const auto& tile : definition.tileCover(type, tileSize, tileset.zoomRange)) {
+ result.push_back(
+ Resource::tile(tileset.tiles[0], definition.pixelRatio, tile.x, tile.y, tile.z));
}
return result;
@@ -100,28 +106,45 @@ OfflineRegionStatus OfflineDownload::getStatus() const {
result.requiredResourceCountIsPrecise = true;
for (const auto& source : parser.sources) {
- switch (source->type) {
+ switch (source->baseImpl->type) {
case SourceType::Vector:
- case SourceType::Raster:
- if (source->getTileset()) {
- result.requiredResourceCount += tileResources(source->type, source->tileSize, *source->getTileset()).size();
+ case SourceType::Raster: {
+ style::TileSourceImpl* tileSource =
+ static_cast<style::TileSourceImpl*>(source->baseImpl.get());
+ const variant<std::string, Tileset>& urlOrTileset = tileSource->getURLOrTileset();
+
+ if (urlOrTileset.is<Tileset>()) {
+ result.requiredResourceCount +=
+ tileResources(source->baseImpl->type, tileSource->getTileSize(),
+ urlOrTileset.get<Tileset>())
+ .size();
} else {
result.requiredResourceCount += 1;
- optional<Response> sourceResponse = offlineDatabase.get(Resource::source(source->url));
+ const std::string& url = urlOrTileset.get<std::string>();
+ optional<Response> sourceResponse = offlineDatabase.get(Resource::source(url));
if (sourceResponse) {
- result.requiredResourceCount += tileResources(source->type, source->tileSize,
- *style::parseTileJSON(*sourceResponse->data, source->url, source->type, source->tileSize)).size();
+ result.requiredResourceCount +=
+ tileResources(source->baseImpl->type, tileSource->getTileSize(),
+ style::TileSourceImpl::parseTileJSON(
+ *sourceResponse->data, url, source->baseImpl->type,
+ tileSource->getTileSize()))
+ .size();
} else {
result.requiredResourceCountIsPrecise = false;
}
}
break;
+ }
+
+ case SourceType::GeoJSON: {
+ style::GeoJSONSource::Impl* geojsonSource =
+ static_cast<style::GeoJSONSource::Impl*>(source->baseImpl.get());
- case SourceType::GeoJSON:
- if (!source->url.empty()) {
+ if (!geojsonSource->loaded) {
result.requiredResourceCount += 1;
}
break;
+ }
case SourceType::Video:
case SourceType::Annotations:
@@ -141,28 +164,33 @@ void OfflineDownload::activateDownload() {
requiredSourceURLs.clear();
- ensureResource(Resource::style(definition.styleURL), [&] (Response styleResponse) {
+ ensureResource(Resource::style(definition.styleURL), [&](Response styleResponse) {
status.requiredResourceCountIsPrecise = true;
style::Parser parser;
parser.parse(*styleResponse.data);
for (const auto& source : parser.sources) {
- SourceType type = source->type;
- uint16_t tileSize = source->tileSize;
- std::string url = source->url;
+ SourceType type = source->baseImpl->type;
switch (type) {
case SourceType::Vector:
- case SourceType::Raster:
- if (source->getTileset()) {
- ensureTiles(type, tileSize, *source->getTileset());
+ case SourceType::Raster: {
+ const style::TileSourceImpl* tileSource =
+ static_cast<style::TileSourceImpl*>(source->baseImpl.get());
+ const variant<std::string, Tileset>& urlOrTileset = tileSource->getURLOrTileset();
+ const uint16_t tileSize = tileSource->getTileSize();
+
+ if (urlOrTileset.is<Tileset>()) {
+ ensureTiles(type, tileSize, urlOrTileset.get<Tileset>());
} else {
+ const std::string& url = urlOrTileset.get<std::string>();
status.requiredResourceCountIsPrecise = false;
requiredSourceURLs.insert(url);
- ensureResource(Resource::source(url), [=] (Response sourceResponse) {
- ensureTiles(type, tileSize, *style::parseTileJSON(*sourceResponse.data, url, type, tileSize));
+ ensureResource(Resource::source(url), [=](Response sourceResponse) {
+ ensureTiles(type, tileSize, style::TileSourceImpl::parseTileJSON(
+ *sourceResponse.data, url, type, tileSize));
requiredSourceURLs.erase(url);
if (requiredSourceURLs.empty()) {
@@ -171,19 +199,24 @@ void OfflineDownload::activateDownload() {
});
}
break;
+ }
- case SourceType::GeoJSON:
- if (!source->url.empty()) {
- ensureResource(Resource::source(source->url));
+ case SourceType::GeoJSON: {
+ style::GeoJSONSource::Impl* geojsonSource =
+ static_cast<style::GeoJSONSource::Impl*>(source->baseImpl.get());
+
+ if (!geojsonSource->loaded) {
+ ensureResource(Resource::source(geojsonSource->getURL()));
}
break;
+ }
case SourceType::Video:
case SourceType::Annotations:
break;
}
}
-
+
for (const auto& resource : spriteResources(parser)) {
ensureResource(resource);
}
@@ -204,14 +237,16 @@ void OfflineDownload::ensureTiles(SourceType type, uint16_t tileSize, const Tile
}
}
-void OfflineDownload::ensureResource(const Resource& resource, std::function<void (Response)> callback) {
+void OfflineDownload::ensureResource(const Resource& resource,
+ std::function<void(Response)> callback) {
status.requiredResourceCount++;
auto workRequestsIt = requests.insert(requests.begin(), nullptr);
- *workRequestsIt = util::RunLoop::Get()->invokeCancellable([=] () {
+ *workRequestsIt = util::RunLoop::Get()->invokeCancellable([=]() {
requests.erase(workRequestsIt);
- optional<std::pair<Response, uint64_t>> offlineResponse = offlineDatabase.getRegionResource(id, resource);
+ optional<std::pair<Response, uint64_t>> offlineResponse =
+ offlineDatabase.getRegionResource(id, resource);
if (offlineResponse) {
if (callback) {
callback(offlineResponse->first);
@@ -220,24 +255,25 @@ void OfflineDownload::ensureResource(const Resource& resource, std::function<voi
status.completedResourceCount++;
status.completedResourceSize += offlineResponse->second;
if (resource.kind == Resource::Kind::Tile) {
+ status.completedTileCount += 1;
status.completedTileSize += offlineResponse->second;
}
-
+
observer->statusChanged(status);
-
+
if (status.complete()) {
setState(OfflineRegionDownloadState::Inactive);
}
return;
}
-
+
if (checkTileCountLimit(resource)) {
return;
}
auto fileRequestsIt = requests.insert(requests.begin(), nullptr);
- *fileRequestsIt = onlineFileSource.request(resource, [=] (Response onlineResponse) {
+ *fileRequestsIt = onlineFileSource.request(resource, [=](Response onlineResponse) {
if (onlineResponse.error) {
observer->responseError(*onlineResponse.error);
return;
@@ -253,15 +289,16 @@ void OfflineDownload::ensureResource(const Resource& resource, std::function<voi
uint64_t resourceSize = offlineDatabase.putRegionResource(id, resource, onlineResponse);
status.completedResourceSize += resourceSize;
if (resource.kind == Resource::Kind::Tile) {
+ status.completedTileCount += 1;
status.completedTileSize += resourceSize;
}
observer->statusChanged(status);
-
+
if (checkTileCountLimit(resource)) {
return;
}
-
+
if (status.complete()) {
setState(OfflineRegionDownloadState::Inactive);
}
@@ -270,14 +307,13 @@ void OfflineDownload::ensureResource(const Resource& resource, std::function<voi
}
bool OfflineDownload::checkTileCountLimit(const Resource& resource) {
- if (resource.kind == Resource::Kind::Tile
- && util::mapbox::isMapboxURL(resource.url)
- && offlineDatabase.offlineMapboxTileCountLimitExceeded()) {
+ if (resource.kind == Resource::Kind::Tile && util::mapbox::isMapboxURL(resource.url) &&
+ offlineDatabase.offlineMapboxTileCountLimitExceeded()) {
observer->mapboxTileCountLimitExceeded(offlineDatabase.getOfflineMapboxTileCountLimit());
setState(OfflineRegionDownloadState::Inactive);
return true;
}
-
+
return false;
}
diff --git a/platform/default/mbgl/storage/offline_download.hpp b/platform/default/mbgl/storage/offline_download.hpp
index 1a0d7536d8..27c5f0b139 100644
--- a/platform/default/mbgl/storage/offline_download.hpp
+++ b/platform/default/mbgl/storage/offline_download.hpp
@@ -17,7 +17,7 @@ class Tileset;
namespace style {
class Parser;
-}
+} // namespace style
/**
* Coordinates the request and storage of all resources for an offline region.
diff --git a/platform/default/online_file_source.cpp b/platform/default/online_file_source.cpp
index a4ac2c2b2b..b7d658694c 100644
--- a/platform/default/online_file_source.cpp
+++ b/platform/default/online_file_source.cpp
@@ -26,8 +26,8 @@ class OnlineFileRequest : public AsyncRequest {
public:
using Callback = std::function<void (Response)>;
- OnlineFileRequest(const Resource&, Callback, OnlineFileSource::Impl&);
- ~OnlineFileRequest();
+ OnlineFileRequest(Resource, Callback, OnlineFileSource::Impl&);
+ ~OnlineFileRequest() override;
void networkIsReachableAgain();
void schedule(optional<Timestamp> expires);
@@ -182,9 +182,9 @@ std::unique_ptr<AsyncRequest> OnlineFileSource::request(const Resource& resource
return std::make_unique<OnlineFileRequest>(res, callback, *impl);
}
-OnlineFileRequest::OnlineFileRequest(const Resource& resource_, Callback callback_, OnlineFileSource::Impl& impl_)
+OnlineFileRequest::OnlineFileRequest(Resource resource_, Callback callback_, OnlineFileSource::Impl& impl_)
: impl(impl_),
- resource(resource_),
+ resource(std::move(resource_)),
callback(std::move(callback_)) {
impl.add(this);
diff --git a/platform/default/png_reader.cpp b/platform/default/png_reader.cpp
index 096596ee2e..0461ec61a6 100644
--- a/platform/default/png_reader.cpp
+++ b/platform/default/png_reader.cpp
@@ -1,16 +1,10 @@
#include <mbgl/util/image.hpp>
#include <mbgl/util/premultiply.hpp>
+#include <mbgl/util/char_array_buffer.hpp>
#include <mbgl/platform/log.hpp>
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wunknown-pragmas"
-#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
-#pragma GCC diagnostic ignored "-Wshadow"
-#include <boost/iostreams/stream.hpp>
-#pragma GCC diagnostic pop
-
-#include <boost/iostreams/device/file.hpp>
-#include <boost/iostreams/device/array.hpp>
+#include <istream>
+#include <sstream>
extern "C"
{
@@ -19,9 +13,6 @@ extern "C"
namespace mbgl {
-using source_type = boost::iostreams::array_source;
-using input_stream = boost::iostreams::stream<source_type>;
-
static void user_error_fn(png_structp, png_const_charp error_msg) {
throw std::runtime_error(std::string("failed to read invalid png: '") + error_msg + "'");
}
@@ -31,7 +22,7 @@ static void user_warning_fn(png_structp, png_const_charp warning_msg) {
}
static void png_read_data(png_structp png_ptr, png_bytep data, png_size_t length) {
- input_stream * fin = reinterpret_cast<input_stream*>(png_get_io_ptr(png_ptr));
+ std::istream* fin = reinterpret_cast<std::istream*>(png_get_io_ptr(png_ptr));
fin->read(reinterpret_cast<char*>(data), length);
std::streamsize read_count = fin->gcount();
if (read_count < 0 || static_cast<png_size_t>(read_count) != length)
@@ -46,7 +37,7 @@ struct png_struct_guard {
i_(info_ptr_ptr) {}
~png_struct_guard() {
- png_destroy_read_struct(p_,i_,0);
+ png_destroy_read_struct(p_,i_,nullptr);
}
png_structpp p_;
@@ -54,8 +45,8 @@ struct png_struct_guard {
};
PremultipliedImage decodePNG(const uint8_t* data, size_t size) {
- source_type source(reinterpret_cast<const char*>(data), size);
- input_stream stream(source);
+ util::CharArrayBuffer dataBuffer { reinterpret_cast<const char*>(data), size };
+ std::istream stream(&dataBuffer);
png_byte header[8] = { 0 };
stream.read(reinterpret_cast<char*>(header), 8);
@@ -66,7 +57,7 @@ PremultipliedImage decodePNG(const uint8_t* data, size_t size) {
if (!is_png)
throw std::runtime_error("File or stream is not a png");
- png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
+ png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
if (!png_ptr)
throw std::runtime_error("failed to allocate png_ptr");
@@ -87,7 +78,7 @@ PremultipliedImage decodePNG(const uint8_t* data, size_t size) {
png_uint_32 height = 0;
int bit_depth = 0;
int color_type = 0;
- png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0);
+ png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, nullptr, nullptr, nullptr);
UnassociatedImage image { width, height };
@@ -125,9 +116,9 @@ PremultipliedImage decodePNG(const uint8_t* data, size_t size) {
rows[row] = image.data.get() + row * width * 4;
png_read_image(png_ptr, rows.get());
- png_read_end(png_ptr, 0);
+ png_read_end(png_ptr, nullptr);
return util::premultiply(std::move(image));
}
-}
+} // namespace mbgl
diff --git a/platform/default/run_loop.cpp b/platform/default/run_loop.cpp
index 6230e8f1ab..1ebbade7ab 100644
--- a/platform/default/run_loop.cpp
+++ b/platform/default/run_loop.cpp
@@ -14,9 +14,9 @@ using namespace mbgl::util;
static ThreadLocal<RunLoop>& current = *new ThreadLocal<RunLoop>;
#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
-void dummyCallback(uv_async_t*, int) {};
+void dummyCallback(uv_async_t*, int) {}
#else
-void dummyCallback(uv_async_t*) {};
+void dummyCallback(uv_async_t*) {}
#endif
} // namespace
@@ -158,7 +158,7 @@ void RunLoop::run() {
void RunLoop::runOnce() {
MBGL_VERIFY_THREAD(tid);
- uv_run(impl->loop, UV_RUN_ONCE);
+ uv_run(impl->loop, UV_RUN_NOWAIT);
}
void RunLoop::stop() {
diff --git a/platform/default/settings_json.cpp b/platform/default/settings_json.cpp
index 2c1bb3d242..ef53aa83e7 100644
--- a/platform/default/settings_json.cpp
+++ b/platform/default/settings_json.cpp
@@ -1,7 +1,7 @@
#include <mbgl/platform/default/settings_json.hpp>
#include <fstream>
-using namespace mbgl;
+namespace mbgl {
Settings_JSON::Settings_JSON() { load(); }
@@ -37,3 +37,5 @@ void Settings_JSON::clear() {
pitch = 0;
debug = 0;
}
+
+} // namespace mbgl
diff --git a/platform/default/sqlite3.hpp b/platform/default/sqlite3.hpp
index 57ee18e9f3..cdc6f87380 100644
--- a/platform/default/sqlite3.hpp
+++ b/platform/default/sqlite3.hpp
@@ -22,8 +22,8 @@ enum OpenFlag : int {
};
struct Exception : std::runtime_error {
- inline Exception(int err, const char *msg) : std::runtime_error(msg), code(err) {}
- inline Exception(int err, const std::string& msg) : std::runtime_error(msg), code(err) {}
+ Exception(int err, const char *msg) : std::runtime_error(msg), code(err) {}
+ Exception(int err, const std::string& msg) : std::runtime_error(msg), code(err) {}
const int code = 0;
};
diff --git a/platform/default/string_stdlib.cpp b/platform/default/string_stdlib.cpp
index ac4c26234c..90a75c1738 100644
--- a/platform/default/string_stdlib.cpp
+++ b/platform/default/string_stdlib.cpp
@@ -11,17 +11,17 @@ namespace mbgl { namespace platform {
std::string uppercase(const std::string& str)
{
std::stringstream output;
- char const *itr = str.c_str(), *nitr = itr;
+ char const *itr = str.c_str(), *nitr;
char const *end = itr + str.length();
char lo[5] = { 0 };
for (; itr < end; itr = nitr)
{
uint32_t code_point = 0;
- char const* buf = 0;
+ char const* buf = nullptr;
- nitr = _nu_toupper(itr, end, nu_utf8_read, &code_point, &buf, 0);
- if (buf != 0)
+ nitr = _nu_toupper(itr, end, nu_utf8_read, &code_point, &buf, nullptr);
+ if (buf != nullptr)
{
do
{
@@ -44,17 +44,17 @@ std::string uppercase(const std::string& str)
std::string lowercase(const std::string& str)
{
std::stringstream output;
- char const *itr = str.c_str(), *nitr = itr;
+ char const *itr = str.c_str(), *nitr;
char const *end = itr + str.length();
char lo[5] = { 0 };
for (; itr < end; itr = nitr)
{
uint32_t code_point = 0;
- char const* buf = 0;
+ char const* buf = nullptr;
- nitr = _nu_tolower(itr, end, nu_utf8_read, &code_point, &buf, 0);
- if (buf != 0)
+ nitr = _nu_tolower(itr, end, nu_utf8_read, &code_point, &buf, nullptr);
+ if (buf != nullptr)
{
do
{
@@ -73,4 +73,5 @@ std::string lowercase(const std::string& str)
return output.str();
}
-}}
+} // namespace platform
+} // namespace mbgl
diff --git a/platform/default/thread.cpp b/platform/default/thread.cpp
index 3ef3257923..f4d0b9a855 100644
--- a/platform/default/thread.cpp
+++ b/platform/default/thread.cpp
@@ -1,27 +1,36 @@
#include <mbgl/platform/platform.hpp>
-
#include <mbgl/platform/log.hpp>
+#include <string>
+
#include <pthread.h>
-#ifdef __linux__
-#include <linux/sched.h>
-#endif
#include <sched.h>
namespace mbgl {
namespace platform {
+std::string getCurrentThreadName() {
+ char name[32] = "unknown";
+ pthread_getname_np(pthread_self(), name, sizeof(name));
+
+ return name;
+}
+
+void setCurrentThreadName(const std::string& name) {
+ if (name.size() > 15) { // Linux hard limit (see manpages).
+ pthread_setname_np(pthread_self(), name.substr(0, 15).c_str());
+ } else {
+ pthread_setname_np(pthread_self(), name.c_str());
+ }
+}
+
void makeThreadLowPriority() {
-#ifdef SCHED_IDLE
struct sched_param param;
param.sched_priority = 0;
- int status = sched_setscheduler(0, SCHED_IDLE, &param);
- if (status != 0) {
+
+ if (sched_setscheduler(0, SCHED_IDLE, &param) != 0) {
Log::Warning(Event::General, "Couldn't set thread scheduling policy");
}
-#else
-#pragma message("Building without thread priority control")
-#endif
}
} // namespace platform
diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md
index 1b90d20999..89f301ea37 100644
--- a/platform/ios/CHANGELOG.md
+++ b/platform/ios/CHANGELOG.md
@@ -2,17 +2,29 @@
Mapbox welcomes participation and contributions from everyone. Please read [CONTRIBUTING.md](../../CONTRIBUTING.md) to get started.
-## 3.3.3
+## master
+
+* As the user zooms in, tiles from lower zoom levels are scaled up until tiles for higher zoom levels are loaded. ([#5143](https://github.com/mapbox/mapbox-gl-native/pull/5143))
+* Added [quadkey](https://msdn.microsoft.com/en-us/library/bb259689.aspx) support and limited WMS support in raster tile URL templates. ([#5628](https://github.com/mapbox/mapbox-gl-native/pull/5628))
+* The `text-pitch-alignment` property is now supported in stylesheets for improved street label legibility on a tilted map. ([#5288](https://github.com/mapbox/mapbox-gl-native/pull/5288))
+* The `icon-text-fit` and `icon-text-fit-padding` properties are now supported in stylesheets, allowing the background of a shield to automatically resize to fit the shield’s text. ([#5334](https://github.com/mapbox/mapbox-gl-native/pull/5334))
+* Improved the performance of relocating a non-view-backed point annotation by changing its `coordinate` property. ([#5385](https://github.com/mapbox/mapbox-gl-native/pull/5385))
+* MGLMapDebugOverdrawVisualizationMask does nothing in Release builds of the SDK. This is disabled for performance reasons. ([#5555](https://github.com/mapbox/mapbox-gl-native/pull/5555))
+* Include simulator architecture slices in the dSYM file that is generated for release builds. ([#5740](https://github.com/mapbox/mapbox-gl-native/pull/5740))
+* Fixed an issue where annotation views could be assigned to multipoint annotations. ([#5770](https://github.com/mapbox/mapbox-gl-native/pull/5770))
+* Fixed the static only framework build. ([#5782](https://github.com/mapbox/mapbox-gl-native/issues/5782))
+
+## 3.3.3 - July 29, 2016
* Fixes an issue where the style zoom levels were not respected when deciding when to render a layer. ([#5811](https://github.com/mapbox/mapbox-gl-native/issues/5811))
-## 3.3.2
+## 3.3.2 - July 28, 2016
* Speculatively fixed a crash that occurred when initializing an MGLMapView on iOS 7.x. ([#5791](https://github.com/mapbox/mapbox-gl-native/pull/5791))
* View-backed annotations no longer prevent the user from starting to pan the map. ([#5813](https://github.com/mapbox/mapbox-gl-native/pull/5813))
* Fixed an issue that caused the user dot to be selected when tapping an annotation that lies within the user dot’s accuracy circle. ([#5816](https://github.com/mapbox/mapbox-gl-native/pull/5816))
-## 3.3.1
+## 3.3.1 - July 19, 2016
* Fixed a crash that occurred when a sprite URL lacks a file extension. See [this comment](https://github.com/mapbox/mapbox-gl-native/issues/5722#issuecomment-233701251) to determine who may be affected by this bug. ([#5723](https://github.com/mapbox/mapbox-gl-native/pull/5723))
* Fixed an issue causing overlapping polylines and polygons to be drawn in undefined z-order. Shapes are always drawn in the order they are added to the map, from the oldest on the bottom to the newest on the top. ([#5710](https://github.com/mapbox/mapbox-gl-native/pull/5710))
@@ -23,7 +35,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CON
* The compass, Mapbox logo, and attribution button now accommodate the containing map view’s content insets. If your interface elements partially overlap the map view but do not affect the top and bottom layout guides, set the `automaticallyAdjustsScrollViewInsets` property to `NO` and set the `contentInset` property to a suitable value. ([#5671](https://github.com/mapbox/mapbox-gl-native/pull/5671))
* Added a property to MGLOfflineStorage, `countOfBytesCompleted`, that indicates the disk space occupied by all cached and offline resources. ([#5585](https://github.com/mapbox/mapbox-gl-native/pull/5585))
-## 3.3.0
+## 3.3.0 - July 14, 2016
### Styles and data
@@ -78,25 +90,25 @@ Mapbox welcomes participation and contributions from everyone. Please read [CON
- Added NSFormatter subclasses for converting geographic coordinates and directions into display strings. ([#4802](https://github.com/mapbox/mapbox-gl-native/pull/4802))
- Added `MGLCoordinateInCoordinateBounds()`, a function that tests whether or not a coordinate is in a given bounds. ([#5053](https://github.com/mapbox/mapbox-gl-native/pull/5053))
-## 3.2.3
+## 3.2.3 - June 7, 2016
- Fixed an issue preventing `-[MGLMapViewDelegate mapViewDidFinishLoadingMap:]` from being called when returning to the view controller containing the map view from another view controller. ([#5164](https://github.com/mapbox/mapbox-gl-native/pull/5164))
- Declarations in the API documentation are shown in both Objective-C and Swift. ([realm/jazzy#530](https://github.com/realm/jazzy/pull/530))
-## 3.2.2
+## 3.2.2 - May 10, 2016
- Existing MGLStyle class methods that return default style URLs have been deprecated in favor of new methods that require an explicit style version parameter. The deprecated, unversioned methods continue to return version 8 of the respective styles and will not be updated as new versions of the styles are released. ([#4759](https://github.com/mapbox/mapbox-gl-native/pull/4759))
- Deprecated `+[MGLStyle emeraldStyleURL]` with no replacement method. To use the Emerald style going forward, we recommend that you use the underlying URL. ([#4759](https://github.com/mapbox/mapbox-gl-native/pull/4759))
- Added `+[MGLStyle outdoorsStyleURLWithVersion:]` for the new Outdoors style. ([#4759](https://github.com/mapbox/mapbox-gl-native/pull/4759))
- The Hybrid style is now called Satellite Streets. ([#4759](https://github.com/mapbox/mapbox-gl-native/pull/4759))
-## 3.2.1
+## 3.2.1 - April 20, 2016
- Fixed a hang that could occur if the host application attempts to set user defaults on a background queue. ([#4745](https://github.com/mapbox/mapbox-gl-native/pull/4745))
- User location heading updates now resume properly when an app becomes active again. ([#4674](https://github.com/mapbox/mapbox-gl-native/pull/4674))
- Fixed an issue causing hyperlinks in the documentation to be displayed as raw Markdown syntax when viewed in Xcode’s Quick Help popover or sidebar. ([#4760](https://github.com/mapbox/mapbox-gl-native/pull/4760))
-## 3.2.0
+## 3.2.0 - April 5, 2016
- If you’ve previously installed the SDK as a static framework, the installation workflow has changed to address issues when submitting your application to the App Store or installing it on a device. Upon upgrading to this version of the SDK, you’ll need to add Mapbox.bundle to the Copy Bundle Resources build phase and remove Mapbox.framework from the Embed Frameworks build phase. ([#4455](https://github.com/mapbox/mapbox-gl-native/pull/4455))
- Offline packs can now be downloaded to allow users to view specific regions of the map offline. A new MGLOfflineStorage class provides APIs for managing MGLOfflinePacks. ([#4221](https://github.com/mapbox/mapbox-gl-native/pull/4221))
@@ -117,12 +129,12 @@ Mapbox welcomes participation and contributions from everyone. Please read [CON
- The Improve This Map tool now uses the same zoom level that is currently being shown in the map view. ([#4068](https://github.com/mapbox/mapbox-gl-native/pull/4068))
- Fixed a formatting issue in the documentation for `MGLCoordinateBoundsIsEmpty()`. ([#3958](https://github.com/mapbox/mapbox-gl-native/pull/3958))
-## 3.1.2
+## 3.1.2 - February 22, 2016
- You can once again install the static framework without manually linking several framework and library dependencies. ([#4029](https://github.com/mapbox/mapbox-gl-native/pull/4029))
- The location manager used by MGLMapView to show the user’s location is now paused when the application is sent to the background. ([#4034](https://github.com/mapbox/mapbox-gl-native/pull/4034))
-## 3.1.1
+## 3.1.1 - February 15, 2016
- Corrected the dynamic framework’s minimum deployment target to iOS 8.0. ([#3872](https://github.com/mapbox/mapbox-gl-native/pull/3872))
- Fixed Fabric compatibility. ([#3847](https://github.com/mapbox/mapbox-gl-native/pull/3847))
@@ -131,7 +143,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CON
- Fixed an issue that incorrectly expanded the tappable area of an annotation and prevented the annotation’s alignment rect insets from having any effect on the tappable area. ([#3898](https://github.com/mapbox/mapbox-gl-native/pull/3898))
- Fixed an issue preventing `-[MGLMapViewDelegate mapView:tapOnCalloutForAnnotation:]` from being called when a non-custom callout view is tapped. ([#3875](https://github.com/mapbox/mapbox-gl-native/pull/3875))
-## 3.1.0
+## 3.1.0 - February 5, 2016
- The SDK is now distributed as a dynamic framework instead of a static library, resulting in a simpler installation workflow and significantly reduced download size. The framework contains both simulator and device content. If you install the dynamic framework manually, you’ll need to strip out the simulator content before submitting your application to the App Store due to [an Xcode bug](http://www.openradar.me/radar?id=6409498411401216); see the installation instructions included with the framework for details. ([#3183](https://github.com/mapbox/mapbox-gl-native/pull/3183))
- Fixed an issue causing the entire MGLMapView to leak. ([#3448](https://github.com/mapbox/mapbox-gl-native/pull/3448))
@@ -160,13 +172,13 @@ Mapbox welcomes participation and contributions from everyone. Please read [CON
- Avoids triggering the blue background location status bar when user has granted "when in use" permission. ([#3671](https://github.com/mapbox/mapbox-gl-native/issues/3671))
- Deprecated the `debugActive` property and `-toggleDebug` method on MGLMapView in favor of a new `debugMask` property that exposes individual style debugging options. ([#3742](https://github.com/mapbox/mapbox-gl-native/pull/3742))
-## 3.0.1
+## 3.0.1 - December 7, 2015
- Fixed CoreTelephony.framework crash. ([#3170](https://github.com/mapbox/mapbox-gl-native/pull/3170))
- Fixed an issue preventing the compass from responding to taps after the compass is moved programmatically. ([#3117](https://github.com/mapbox/mapbox-gl-native/pull/3117))
- CocoaPods is now distributed via a (static) framework. ([#3181](https://github.com/mapbox/mapbox-gl-native/issues/3181))
-## 3.0.0
+## 3.0.0 - November 23, 2015
- If you install this SDK via CocoaPods, CocoaPods version 0.38.0 or above is required. ([#2132](https://github.com/mapbox/mapbox-gl-native/pull/2132))
- The `styleID` property has been removed from MGLMapView. Instead, set the `styleURL` property to an NSURL in the form `mapbox://styles/STYLE_ID`. If you previously set the style ID in Interface Builder’s Attributes inspector, delete the `styleID` entry from the User Defined Runtime Attributes section of the Identity inspector, then set the new “Style URL” inspectable to a value in the form `mapbox://styles/STYLE_ID`. ([#2632](https://github.com/mapbox/mapbox-gl-native/pull/2632))
@@ -191,15 +203,15 @@ Mapbox welcomes participation and contributions from everyone. Please read [CON
- Removed CoreTelephony.framework dependency. ([#2581](https://github.com/mapbox/mapbox-gl-native/pull/2581))
- Improved user location annotation responsiveness. ([#2643](https://github.com/mapbox/mapbox-gl-native/pull/2643))
-## 2.1.2
+## 2.1.2 - September 15, 2015
- Built with Xcode 6.4 to not yet trigger Bitcode compatibility until Xcode 7 stabilizes. ([#2332](https://github.com/mapbox/mapbox-gl-native/issues/2332))
-## 2.1.1
+## 2.1.1 - September 15, 2015
- Fixes for Xcode 7 and Bitcode. ([#2238](https://github.com/mapbox/mapbox-gl-native/pull/2238))
-## 2.1.0
+## 2.1.0 - September 14, 2015
- A two-finger vertical swipe now tilts the map into perspective mode. ([#2116](https://github.com/mapbox/mapbox-gl-native/pull/2116))
- A new `MGLMapCamera` API allows you to transition multiple viewpoint properties, including rotation and pitch, simultaneously with an optional custom duration and timing function. ([#2193](https://github.com/mapbox/mapbox-gl-native/pull/2193))
@@ -218,21 +230,21 @@ Mapbox welcomes participation and contributions from everyone. Please read [CON
- Minor style updates. ([#1910](https://github.com/mapbox/mapbox-gl-native/pull/1910))
- The CocoaPods pod now contains a `README.md` file. ([#1886](https://github.com/mapbox/mapbox-gl-native/pull/1886))
-## 2.0.0
+## 2.0.0 - August 21, 2015
Repackaging 2.0.0-pre.1 as it contained no issues.
-## 2.0.0-pre.1
+## 2.0.0-pre.1 - August 21, 2015
Repackaging 0.5.1 as the Mapbox iOS SDK 2.0.0 series.
-## 0.5.1
+## 0.5.1 - July 13, 2015
### iOS
- Added support for CocoaPods 0.38.0. ([#1876](https://github.com/mapbox/mapbox-gl-native/pull/1876))
-## 0.5.0
+## 0.5.0 - July 9, 2015
### Core
@@ -261,7 +273,7 @@ Repackaging 0.5.1 as the Mapbox iOS SDK 2.0.0 series.
- Fixed an issue in which `-[MGLMapView direction]` would sometimes return 360 instead of 0. ([#1829](https://github.com/mapbox/mapbox-gl-native/pull/1829))
- Build against iOS 8.4. ([#1868](https://github.com/mapbox/mapbox-gl-native/pull/1868))
-## 0.4.0
+## 0.4.0 - June 19, 2015
### Core
@@ -285,11 +297,11 @@ Repackaging 0.5.1 as the Mapbox iOS SDK 2.0.0 series.
- Internal use of the Reachability library has been cleaned up so that your app can include its own copy of Reachability. ([#1718](https://github.com/mapbox/mapbox-gl-native/issues/1718))
- Now distribute a binary stripped of debugging symbols by default with an optional, secondary symbols build. ([#1650](https://github.com/mapbox/mapbox-gl-native/issues/1650))
-## 0.3.1
+## 0.3.1 - May 15, 2015
- Temporarily removed `IBDesignable` support on iOS.
-## 0.3.0
+## 0.3.0 - May 14, 2015
- Initial iOS beta release.
diff --git a/platform/ios/DEVELOPING.md b/platform/ios/DEVELOPING.md
index 4efc6af480..d78518eddd 100644
--- a/platform/ios/DEVELOPING.md
+++ b/platform/ios/DEVELOPING.md
@@ -63,6 +63,21 @@ The products of these build commands can be found in the `build/ios/pkg` folder
## Contributing
+### Making any symbol public
+
+To add any Objective-C type, constant, or member to the iOS SDK’s public interface:
+
+1. Ensure that the symbol is pure Objective-C and does not rely on any language features specific to Objective-C++ or the C11 dialect of C – so no namespaced types or classes named with emoji! 🙃 Most projects that depend on this SDK are either written in pure Objective-C (GNU99 dialect) or Swift, which cannot yet bridge C++ types.
+1. Name the symbol according to [Cocoa naming conventions](https://developer.apple.com/library/prerelease/content/documentation/Cocoa/Conceptual/CodingGuidelines/CodingGuidelines.html#//apple_ref/doc/uid/10000146i). Use the `MGL` class prefix to avoid conflicts with client code. If the symbol has an analogue in MapKit, name the symbol according to MapKit.
+1. Provide full documentation comments. We use [jazzy](https://github.com/realm/jazzy/) to produce the documentation found in the SDK distribution and [on the Mapbox iOS SDK website](https://www.mapbox.com/ios-sdk/api/). We also recognize that many developers rely on Xcode’s Quick Help feature. jazzy supports Markdown formatting; however, Quick Help supports only [HeaderDoc](https://developer.apple.com/legacy/library/documentation/DeveloperTools/Conceptual/HeaderDoc/intro/intro.html) syntax and a subset of Doxygen syntax. For hyperlinks, use HTML syntax, which is recognized by both tools.
+
+### Making a type or constant public
+
+To add an Objective-C class, protocol, category, typedef, enumeration, or global constant to the iOS SDK’s public interface:
+
+1. _(Optional.)_ Add the type or constant’s name to the relevant category in the `custom_categories` section of [the jazzy configuration file](./jazzy.yml). This is required for classes and protocols and also recommended for any other type that is strongly associated with a particular class or protocol. If you leave out this step, the symbol will appear in an “Other” section in the generated HTML documentation’s table of contents.
+1. _(Optional.)_ If the symbol would also be publicly exposed in the macOS SDK, consult [the companion macOS document](../macos/DEVELOPING.md#making-a-type-or-constant-public) for further instructions.
+
### Adding a source code file
To add an Objective-C header or implementation file to the iOS SDK:
diff --git a/platform/ios/Mapbox.playground/Contents.swift b/platform/ios/Mapbox.playground/Contents.swift
index b1b11e5e34..1f368be73b 100644
--- a/platform/ios/Mapbox.playground/Contents.swift
+++ b/platform/ios/Mapbox.playground/Contents.swift
@@ -1,5 +1,9 @@
import UIKit
-import XCPlayground
+#if swift(>=3)
+ import PlaygroundSupport
+#else
+ import XCPlayground
+#endif
import Mapbox
let width: CGFloat = 700
@@ -9,7 +13,11 @@ class Responder: NSObject {
var mapView: MGLMapView?
func togglePitch(sender: UISwitch) {
let camera = mapView!.camera
- camera.pitch = sender.on ? 60 : 0
+ #if swift(>=3)
+ camera.pitch = sender.isOn ? 60 : 0
+ #else
+ camera.pitch = sender.on ? 60 : 0
+ #endif
mapView!.setCamera(camera, animated: false)
}
}
@@ -18,7 +26,11 @@ class Responder: NSObject {
let panelWidth: CGFloat = 200
let panel = UIView(frame: CGRect(x: width - panelWidth, y: 0, width: 200, height: 100))
panel.alpha = 0.8
-panel.backgroundColor = UIColor.whiteColor()
+#if swift(>=3)
+ panel.backgroundColor = .white
+#else
+ panel.backgroundColor = UIColor.whiteColor()
+#endif
// Delete markers
let deleteSwitchLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 100, height: 30))
@@ -41,7 +53,11 @@ let pitchLabel = UILabel(frame: CGRect(x: 0, y: 60, width: 100, height: 30))
pitchLabel.text = "Pitch"
let pitchSwitch = UISwitch(frame: CGRect(x: panelWidth-panelWidth / 2.0, y: 60, width: 100, height: 50))
let responder = Responder()
-pitchSwitch.addTarget(responder, action: #selector(responder.togglePitch(_:)), forControlEvents: .ValueChanged)
+#if swift(>=3)
+ pitchSwitch.addTarget(responder, action: #selector(responder.togglePitch(sender:)), for: .valueChanged)
+#else
+ pitchSwitch.addTarget(responder, action: #selector(responder.togglePitch(_:)), forControlEvents: .ValueChanged)
+#endif
panel.addSubview(pitchLabel)
panel.addSubview(pitchSwitch)
@@ -56,7 +72,11 @@ MGLAccountManager.setAccessToken(accessToken)
class PlaygroundAnnotationView: MGLAnnotationView {
override func prepareForReuse() {
- hidden = hideMarkerSwitchView.on
+ #if swift(>=3)
+ isHidden = hideMarkerSwitchView.isOn
+ #else
+ hidden = hideMarkerSwitchView.on
+ #endif
}
}
@@ -67,6 +87,29 @@ class MapDelegate: NSObject, MGLMapViewDelegate {
var annotationViewByAnnotation = [MGLPointAnnotation: PlaygroundAnnotationView]()
+ #if swift(>=3)
+ func mapView(_ mapView: MGLMapView, viewFor annotation: MGLAnnotation) -> MGLAnnotationView? {
+
+ var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: "annotation") as? PlaygroundAnnotationView
+
+ if (annotationView == nil) {
+ let av = PlaygroundAnnotationView(reuseIdentifier: "annotation")
+ av.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
+ av.centerOffset = CGVector(dx: -15, dy: -15)
+ let centerView = UIView(frame: av.bounds.insetBy(dx: 3, dy: 3))
+ centerView.backgroundColor = .white
+ av.addSubview(centerView)
+ av.backgroundColor = .purple
+ annotationView = av
+ } else {
+ annotationView!.subviews.first?.backgroundColor = .green
+ }
+
+ annotationViewByAnnotation[annotation as! MGLPointAnnotation] = annotationView
+
+ return annotationView
+ }
+ #else
func mapView(mapView: MGLMapView, viewForAnnotation annotation: MGLAnnotation) -> MGLAnnotationView? {
var annotationView = mapView.dequeueReusableAnnotationViewWithIdentifier("annotation") as? PlaygroundAnnotationView
@@ -83,12 +126,40 @@ class MapDelegate: NSObject, MGLMapViewDelegate {
} else {
annotationView!.subviews.first?.backgroundColor = UIColor.greenColor()
}
-
+
annotationViewByAnnotation[annotation as! MGLPointAnnotation] = annotationView
return annotationView
}
+ #endif
+ #if swift(>=3)
+ func mapView(_ mapView: MGLMapView, didSelect annotation: MGLAnnotation) {
+ let pointAnnotation = annotation as! MGLPointAnnotation
+ let annotationView: PlaygroundAnnotationView = annotationViewByAnnotation[pointAnnotation]!
+
+ for view in annotationViewByAnnotation.values {
+ view.layer.zPosition = -1
+ }
+
+ annotationView.layer.zPosition = 1
+
+ UIView.animate(withDuration: 1.25, delay: 0, usingSpringWithDamping: 0.4, initialSpringVelocity: 0.6, options: .curveEaseOut, animations: {
+ annotationView.transform = CGAffineTransform(scaleX: 1.8, y: 1.8)
+ }) { _ in
+ annotationView.transform = CGAffineTransform(scaleX: 1, y: 1)
+
+ if deleteMarkerSwitchView.isOn {
+ mapView.removeAnnotation(pointAnnotation)
+ return
+ }
+
+ if hideMarkerSwitchView.isOn {
+ annotationView.isHidden = true
+ }
+ }
+ }
+ #else
func mapView(mapView: MGLMapView, didSelectAnnotation annotation: MGLAnnotation) {
let pointAnnotation = annotation as! MGLPointAnnotation
let annotationView: PlaygroundAnnotationView = annotationViewByAnnotation[pointAnnotation]!
@@ -114,15 +185,25 @@ class MapDelegate: NSObject, MGLMapViewDelegate {
}
}
}
+ #endif
func handleTap(press: UILongPressGestureRecognizer) {
let mapView: MGLMapView = press.view as! MGLMapView
- if (press.state == .Recognized) {
- let coordiante: CLLocationCoordinate2D = mapView.convertPoint(press.locationInView(mapView), toCoordinateFromView: mapView)
+ #if swift(>=3)
+ let isRecognized = press.state == .recognized
+ #else
+ let isRecognized = press.state == .Recognized
+ #endif
+ if (isRecognized) {
+ #if swift(>=3)
+ let coordinate: CLLocationCoordinate2D = mapView.convert(press.location(in: mapView), toCoordinateFrom: mapView)
+ #else
+ let coordinate: CLLocationCoordinate2D = mapView.convertPoint(press.locationInView(mapView), toCoordinateFromView: mapView)
+ #endif
let annotation = MGLPointAnnotation()
annotation.title = "Dropped Marker"
- annotation.coordinate = coordiante
+ annotation.coordinate = coordinate
mapView.addAnnotation(annotation)
mapView.showAnnotations([annotation], animated: true)
}
@@ -132,14 +213,16 @@ class MapDelegate: NSObject, MGLMapViewDelegate {
//: Create a map and its delegate
-let lat: CLLocationDegrees = 37.174057
-let lng: CLLocationDegrees = -104.490984
-let centerCoordinate = CLLocationCoordinate2D(latitude: lat, longitude: lng)
+let centerCoordinate = CLLocationCoordinate2D(latitude: 37.174057, longitude: -104.490984)
let mapView = MGLMapView(frame: CGRect(x: 0, y: 0, width: width, height: height))
mapView.frame = CGRect(x: 0, y: 0, width: width, height: height)
-XCPlaygroundPage.currentPage.liveView = mapView
+#if swift(>=3)
+ PlaygroundPage.current.liveView = mapView
+#else
+ XCPlaygroundPage.currentPage.liveView = mapView
+#endif
let mapDelegate = MapDelegate()
mapView.delegate = mapDelegate
@@ -150,7 +233,11 @@ mapView.addGestureRecognizer(tapGesture)
//: Zoom in to a location
-mapView.setCenterCoordinate(centerCoordinate, zoomLevel: 12, animated: false)
+#if swift(>=3)
+ mapView.setCenter(centerCoordinate, zoomLevel: 12, animated: false)
+#else
+ mapView.setCenterCoordinate(centerCoordinate, zoomLevel: 12, animated: false)
+#endif
//: Add control panel
diff --git a/platform/ios/app/MBXAppDelegate.h b/platform/ios/app/MBXAppDelegate.h
index 8145d3b8ca..7ff321b6c7 100644
--- a/platform/ios/app/MBXAppDelegate.h
+++ b/platform/ios/app/MBXAppDelegate.h
@@ -6,4 +6,4 @@ extern NSString * const MBXMapboxAccessTokenDefaultsKey;
@property (strong, nonatomic) UIWindow *window;
-@end \ No newline at end of file
+@end
diff --git a/platform/ios/app/MBXViewController.m b/platform/ios/app/MBXViewController.m
index 789ee00372..ef91c847be 100644
--- a/platform/ios/app/MBXViewController.m
+++ b/platform/ios/app/MBXViewController.m
@@ -30,6 +30,12 @@ static NSString * const MBXViewControllerAnnotationViewReuseIdentifer = @"MBXVie
@implementation MBXCustomCalloutAnnotation
@end
+@interface MBXSpriteBackedAnnotation : MGLPointAnnotation
+@end
+
+@implementation MBXSpriteBackedAnnotation
+@end
+
@interface MBXViewController () <UIActionSheetDelegate, MGLMapViewDelegate>
@property (nonatomic) IBOutlet MGLMapView *mapView;
@@ -184,9 +190,12 @@ static NSString * const MBXViewControllerAnnotationViewReuseIdentifer = @"MBXVie
((debugMask & MGLMapDebugOverdrawVisualizationMask)
? @"Hide Overdraw Visualization"
: @"Show Overdraw Visualization"),
- @"Add 100 Points",
- @"Add 1,000 Points",
- @"Add 10,000 Points",
+ @"Add 100 Views",
+ @"Add 1,000 Views",
+ @"Add 10,000 Views",
+ @"Add 100 Sprites",
+ @"Add 1,000 Sprites",
+ @"Add 10,000 Sprites",
@"Add Test Shapes",
@"Start World Tour",
@"Add Custom Callout Point",
@@ -230,109 +239,42 @@ static NSString * const MBXViewControllerAnnotationViewReuseIdentifer = @"MBXVie
}
else if (buttonIndex == actionSheet.firstOtherButtonIndex + 6)
{
- [self parseFeaturesAddingCount:100];
+ [self parseFeaturesAddingCount:100 usingViews:YES];
}
else if (buttonIndex == actionSheet.firstOtherButtonIndex + 7)
{
- [self parseFeaturesAddingCount:1000];
+ [self parseFeaturesAddingCount:1000 usingViews:YES];
}
else if (buttonIndex == actionSheet.firstOtherButtonIndex + 8)
{
- [self parseFeaturesAddingCount:10000];
+ [self parseFeaturesAddingCount:10000 usingViews:YES];
}
else if (buttonIndex == actionSheet.firstOtherButtonIndex + 9)
{
- // PNW triangle
- //
- CLLocationCoordinate2D triangleCoordinates[3] =
- {
- CLLocationCoordinate2DMake(44, -122),
- CLLocationCoordinate2DMake(46, -122),
- CLLocationCoordinate2DMake(46, -121)
- };
-
- MGLPolygon *triangle = [MGLPolygon polygonWithCoordinates:triangleCoordinates count:3];
-
- [self.mapView addAnnotation:triangle];
-
- // Orcas Island hike
- //
- NSDictionary *hike = [NSJSONSerialization JSONObjectWithData:
- [NSData dataWithContentsOfFile:
- [[NSBundle mainBundle] pathForResource:@"polyline" ofType:@"geojson"]]
- options:0
- error:nil];
-
- NSArray *hikeCoordinatePairs = hike[@"features"][0][@"geometry"][@"coordinates"];
-
- CLLocationCoordinate2D *polylineCoordinates = (CLLocationCoordinate2D *)malloc([hikeCoordinatePairs count] * sizeof(CLLocationCoordinate2D));
-
- for (NSUInteger i = 0; i < [hikeCoordinatePairs count]; i++)
- {
- polylineCoordinates[i] = CLLocationCoordinate2DMake([hikeCoordinatePairs[i][1] doubleValue], [hikeCoordinatePairs[i][0] doubleValue]);
- }
-
- MGLPolyline *polyline = [MGLPolyline polylineWithCoordinates:polylineCoordinates
- count:[hikeCoordinatePairs count]];
-
- [self.mapView addAnnotation:polyline];
-
- free(polylineCoordinates);
-
- // PA/NJ/DE polys
- //
- NSDictionary *threestates = [NSJSONSerialization JSONObjectWithData:
- [NSData dataWithContentsOfFile:
- [[NSBundle mainBundle] pathForResource:@"threestates" ofType:@"geojson"]]
- options:0
- error:nil];
-
- for (NSDictionary *feature in threestates[@"features"])
- {
- NSArray *stateCoordinatePairs = feature[@"geometry"][@"coordinates"];
-
- while ([stateCoordinatePairs count] == 1) stateCoordinatePairs = stateCoordinatePairs[0];
-
- CLLocationCoordinate2D *polygonCoordinates = (CLLocationCoordinate2D *)malloc([stateCoordinatePairs count] * sizeof(CLLocationCoordinate2D));
-
- for (NSUInteger i = 0; i < [stateCoordinatePairs count]; i++)
- {
- polygonCoordinates[i] = CLLocationCoordinate2DMake([stateCoordinatePairs[i][1] doubleValue], [stateCoordinatePairs[i][0] doubleValue]);
- }
-
- MGLPolygon *polygon = [MGLPolygon polygonWithCoordinates:polygonCoordinates count:[stateCoordinatePairs count]];
-
- [self.mapView addAnnotation:polygon];
-
- free(polygonCoordinates);
- }
-
- CLLocationCoordinate2D innerCoordinates[] = {
- CLLocationCoordinate2DMake(-5, -5),
- CLLocationCoordinate2DMake(-5, 5),
- CLLocationCoordinate2DMake(5, 5),
- CLLocationCoordinate2DMake(5, -5),
- };
- MGLPolygon *innerPolygon = [MGLPolygon polygonWithCoordinates:innerCoordinates count:sizeof(innerCoordinates) / sizeof(innerCoordinates[0])];
- CLLocationCoordinate2D outerCoordinates[] = {
- CLLocationCoordinate2DMake(-10, -20),
- CLLocationCoordinate2DMake(-10, 10),
- CLLocationCoordinate2DMake(10, 10),
- CLLocationCoordinate2DMake(10, -10),
- };
- MGLPolygon *outerPolygon = [MGLPolygon polygonWithCoordinates:outerCoordinates count:sizeof(outerCoordinates) / sizeof(outerCoordinates[0]) interiorPolygons:@[innerPolygon]];
- [self.mapView addAnnotation:outerPolygon];
+ [self parseFeaturesAddingCount:100 usingViews:NO];
}
else if (buttonIndex == actionSheet.firstOtherButtonIndex + 10)
{
- [self startWorldTour:actionSheet];
+ [self parseFeaturesAddingCount:1000 usingViews:NO];
}
else if (buttonIndex == actionSheet.firstOtherButtonIndex + 11)
{
- [self presentAnnotationWithCustomCallout];
+ [self parseFeaturesAddingCount:10000 usingViews:NO];
}
else if (buttonIndex == actionSheet.firstOtherButtonIndex + 12)
{
+ [self addTestShapes];
+ }
+ else if (buttonIndex == actionSheet.firstOtherButtonIndex + 13)
+ {
+ [self startWorldTour:actionSheet];
+ }
+ else if (buttonIndex == actionSheet.firstOtherButtonIndex + 14)
+ {
+ [self presentAnnotationWithCustomCallout];
+ }
+ else if (buttonIndex == actionSheet.firstOtherButtonIndex + 15)
+ {
[self.mapView removeAnnotations:self.mapView.annotations];
}
else if (buttonIndex == actionSheet.numberOfButtons - 2 && self.debugLoggingEnabled)
@@ -355,7 +297,7 @@ static NSString * const MBXViewControllerAnnotationViewReuseIdentifer = @"MBXVie
}
}
-- (void)parseFeaturesAddingCount:(NSUInteger)featuresCount
+- (void)parseFeaturesAddingCount:(NSUInteger)featuresCount usingViews:(BOOL)useViews
{
[self.mapView removeAnnotations:self.mapView.annotations];
@@ -377,7 +319,8 @@ static NSString * const MBXViewControllerAnnotationViewReuseIdentifer = @"MBXVie
[feature[@"geometry"][@"coordinates"][0] doubleValue]);
NSString *title = feature[@"properties"][@"NAME"];
- MGLPointAnnotation *annotation = [MGLPointAnnotation new];
+ MGLPointAnnotation *annotation = (useViews ? [MGLPointAnnotation new] : [MBXSpriteBackedAnnotation new]);
+
annotation.coordinate = coordinate;
annotation.title = title;
@@ -395,6 +338,92 @@ static NSString * const MBXViewControllerAnnotationViewReuseIdentifer = @"MBXVie
});
}
+- (void)addTestShapes
+{
+ // Pacific Northwest triangle
+ //
+ CLLocationCoordinate2D triangleCoordinates[3] =
+ {
+ CLLocationCoordinate2DMake(44, -122),
+ CLLocationCoordinate2DMake(46, -122),
+ CLLocationCoordinate2DMake(46, -121)
+ };
+
+ MGLPolygon *triangle = [MGLPolygon polygonWithCoordinates:triangleCoordinates count:3];
+
+ [self.mapView addAnnotation:triangle];
+
+ // Orcas Island, WA hike polyline
+ //
+ NSDictionary *hike = [NSJSONSerialization JSONObjectWithData:
+ [NSData dataWithContentsOfFile:
+ [[NSBundle mainBundle] pathForResource:@"polyline" ofType:@"geojson"]]
+ options:0
+ error:nil];
+
+ NSArray *hikeCoordinatePairs = hike[@"features"][0][@"geometry"][@"coordinates"];
+
+ CLLocationCoordinate2D *polylineCoordinates = (CLLocationCoordinate2D *)malloc([hikeCoordinatePairs count] * sizeof(CLLocationCoordinate2D));
+
+ for (NSUInteger i = 0; i < [hikeCoordinatePairs count]; i++)
+ {
+ polylineCoordinates[i] = CLLocationCoordinate2DMake([hikeCoordinatePairs[i][1] doubleValue], [hikeCoordinatePairs[i][0] doubleValue]);
+ }
+
+ MGLPolyline *polyline = [MGLPolyline polylineWithCoordinates:polylineCoordinates
+ count:[hikeCoordinatePairs count]];
+
+ [self.mapView addAnnotation:polyline];
+
+ free(polylineCoordinates);
+
+ // PA/NJ/DE polygons
+ //
+ NSDictionary *threestates = [NSJSONSerialization JSONObjectWithData:
+ [NSData dataWithContentsOfFile:
+ [[NSBundle mainBundle] pathForResource:@"threestates" ofType:@"geojson"]]
+ options:0
+ error:nil];
+
+ for (NSDictionary *feature in threestates[@"features"])
+ {
+ NSArray *stateCoordinatePairs = feature[@"geometry"][@"coordinates"];
+
+ while ([stateCoordinatePairs count] == 1) stateCoordinatePairs = stateCoordinatePairs[0];
+
+ CLLocationCoordinate2D *polygonCoordinates = (CLLocationCoordinate2D *)malloc([stateCoordinatePairs count] * sizeof(CLLocationCoordinate2D));
+
+ for (NSUInteger i = 0; i < [stateCoordinatePairs count]; i++)
+ {
+ polygonCoordinates[i] = CLLocationCoordinate2DMake([stateCoordinatePairs[i][1] doubleValue], [stateCoordinatePairs[i][0] doubleValue]);
+ }
+
+ MGLPolygon *polygon = [MGLPolygon polygonWithCoordinates:polygonCoordinates count:[stateCoordinatePairs count]];
+
+ [self.mapView addAnnotation:polygon];
+
+ free(polygonCoordinates);
+ }
+
+ // Null Island polygon with an interior hole
+ //
+ CLLocationCoordinate2D innerCoordinates[] = {
+ CLLocationCoordinate2DMake(-5, -5),
+ CLLocationCoordinate2DMake(-5, 5),
+ CLLocationCoordinate2DMake(5, 5),
+ CLLocationCoordinate2DMake(5, -5),
+ };
+ MGLPolygon *innerPolygon = [MGLPolygon polygonWithCoordinates:innerCoordinates count:sizeof(innerCoordinates) / sizeof(innerCoordinates[0])];
+ CLLocationCoordinate2D outerCoordinates[] = {
+ CLLocationCoordinate2DMake(-10, -10),
+ CLLocationCoordinate2DMake(-10, 10),
+ CLLocationCoordinate2DMake(10, 10),
+ CLLocationCoordinate2DMake(10, -10),
+ };
+ MGLPolygon *outerPolygon = [MGLPolygon polygonWithCoordinates:outerCoordinates count:sizeof(outerCoordinates) / sizeof(outerCoordinates[0]) interiorPolygons:@[innerPolygon]];
+ [self.mapView addAnnotation:outerPolygon];
+}
+
- (void)presentAnnotationWithCustomCallout
{
[self.mapView removeAnnotations:self.mapView.annotations];
@@ -575,7 +604,7 @@ static NSString * const MBXViewControllerAnnotationViewReuseIdentifer = @"MBXVie
- (MGLAnnotationView *)mapView:(MGLMapView *)mapView viewForAnnotation:(id<MGLAnnotation>)annotation
{
// Use GL backed pins for dropped pin annotations
- if ([annotation isKindOfClass:[MBXDroppedPinAnnotation class]])
+ if ([annotation isKindOfClass:[MBXDroppedPinAnnotation class]] || [annotation isKindOfClass:[MBXSpriteBackedAnnotation class]])
{
return nil;
}
@@ -603,6 +632,73 @@ static NSString * const MBXViewControllerAnnotationViewReuseIdentifer = @"MBXVie
return annotationView;
}
+- (MGLAnnotationImage *)mapView:(MGLMapView * __nonnull)mapView imageForAnnotation:(id <MGLAnnotation> __nonnull)annotation
+{
+ if ([annotation isKindOfClass:[MBXDroppedPinAnnotation class]] || [annotation isKindOfClass:[MBXCustomCalloutAnnotation class]])
+ {
+ return nil; // use default marker
+ }
+
+ NSAssert([annotation isKindOfClass:[MBXSpriteBackedAnnotation class]], @"Annotations should be sprite-backed.");
+
+ NSString *title = [(MGLPointAnnotation *)annotation title];
+ if (!title.length) return nil;
+ NSString *lastTwoCharacters = [title substringFromIndex:title.length - 2];
+
+ MGLAnnotationImage *annotationImage = [mapView dequeueReusableAnnotationImageWithIdentifier:lastTwoCharacters];
+
+ if ( ! annotationImage)
+ {
+ UIColor *color;
+
+ // make every tenth annotation blue
+ if ([lastTwoCharacters hasSuffix:@"0"]) {
+ color = [UIColor blueColor];
+ } else {
+ color = [UIColor redColor];
+ }
+
+ UIImage *image = [self imageWithText:lastTwoCharacters backgroundColor:color];
+ annotationImage = [MGLAnnotationImage annotationImageWithImage:image reuseIdentifier:lastTwoCharacters];
+
+ // don't allow touches on blue annotations
+ if ([color isEqual:[UIColor blueColor]]) annotationImage.enabled = NO;
+ }
+
+ return annotationImage;
+}
+
+
+- (UIImage *)imageWithText:(NSString *)text backgroundColor:(UIColor *)color
+{
+ CGRect rect = CGRectMake(0, 0, 20, 15);
+
+ UIGraphicsBeginImageContextWithOptions(rect.size, NO, [[UIScreen mainScreen] scale]);
+
+ CGContextRef ctx = UIGraphicsGetCurrentContext();
+
+ CGContextSetFillColorWithColor(ctx, [[color colorWithAlphaComponent:0.75] CGColor]);
+ CGContextFillRect(ctx, rect);
+
+ CGContextSetStrokeColorWithColor(ctx, [[UIColor blackColor] CGColor]);
+ CGContextStrokeRectWithWidth(ctx, rect, 2);
+
+ NSAttributedString *drawString = [[NSAttributedString alloc] initWithString:text attributes:@{
+ NSFontAttributeName: [UIFont fontWithName:@"Arial-BoldMT" size:12],
+ NSForegroundColorAttributeName: [UIColor whiteColor],
+ }];
+ CGSize stringSize = drawString.size;
+ CGRect stringRect = CGRectMake((rect.size.width - stringSize.width) / 2,
+ (rect.size.height - stringSize.height) / 2,
+ stringSize.width,
+ stringSize.height);
+ [drawString drawInRect:stringRect];
+
+ UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
+ UIGraphicsEndImageContext();
+ return image;
+}
+
- (BOOL)mapView:(__unused MGLMapView *)mapView annotationCanShowCallout:(__unused id <MGLAnnotation>)annotation
{
return YES;
diff --git a/platform/ios/benchmark/MBXBenchAppDelegate.h b/platform/ios/benchmark/MBXBenchAppDelegate.h
index e89add93fd..6ae9cdf27c 100644
--- a/platform/ios/benchmark/MBXBenchAppDelegate.h
+++ b/platform/ios/benchmark/MBXBenchAppDelegate.h
@@ -6,4 +6,4 @@ extern NSString * const MBXMapboxAccessTokenDefaultsKey;
@property (strong, nonatomic) UIWindow *window;
-@end \ No newline at end of file
+@end
diff --git a/platform/ios/docs/doc-README.md b/platform/ios/docs/doc-README.md
index 057dbe719c..22493b1502 100644
--- a/platform/ios/docs/doc-README.md
+++ b/platform/ios/docs/doc-README.md
@@ -1,6 +1,6 @@
# [Mapbox iOS SDK](https://www.mapbox.com/ios-sdk/)
-The Mapbox iOS SDK is an open-source framework for embedding interactive map views with scalable, customizable vector maps into Cocoa Touch applications on iOS 7.0 and above using Objective-C, Swift, or Interface Builder. It takes stylesheets that conform to the [Mapbox GL Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/), applies them to vector tiles that conform to the [Mapbox Vector Tile Specification](https://www.mapbox.com/developers/vector-tiles/), and renders them using OpenGL.
+The Mapbox iOS SDK is an open-source framework for embedding interactive map views with scalable, customizable vector maps into Cocoa Touch applications on iOS 7.0 and above using Objective-C, Swift, or Interface Builder. It takes stylesheets that conform to the [Mapbox Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/), applies them to vector tiles that conform to the [Mapbox Vector Tile Specification](https://www.mapbox.com/developers/vector-tiles/), and renders them using OpenGL.
![Mapbox iOS SDK screenshots](screenshot.png)
diff --git a/platform/ios/docs/pod-README.md b/platform/ios/docs/pod-README.md
index 1633c7d126..93aa18bc65 100644
--- a/platform/ios/docs/pod-README.md
+++ b/platform/ios/docs/pod-README.md
@@ -1,6 +1,6 @@
# [Mapbox iOS SDK](https://www.mapbox.com/ios-sdk/)
-The Mapbox iOS SDK is an open-source framework for embedding interactive map views with scalable, customizable vector maps into Cocoa Touch applications on iOS 7.0 and above using Objective-C, Swift, or Interface Builder. It takes stylesheets that conform to the [Mapbox GL Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/), applies them to vector tiles that conform to the [Mapbox Vector Tile Specification](https://www.mapbox.com/developers/vector-tiles/), and renders them using OpenGL.
+The Mapbox iOS SDK is an open-source framework for embedding interactive map views with scalable, customizable vector maps into Cocoa Touch applications on iOS 7.0 and above using Objective-C, Swift, or Interface Builder. It takes stylesheets that conform to the [Mapbox Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/), applies them to vector tiles that conform to the [Mapbox Vector Tile Specification](https://www.mapbox.com/developers/vector-tiles/), and renders them using OpenGL.
For more information, check out the [Mapbox iOS SDK homepage](https://www.mapbox.com/ios-sdk/) and the [full changelog](https://github.com/mapbox/mapbox-gl-native/blob/master/platform/ios/CHANGELOG.md) online.
diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj
index 83ae3e6406..bfd5a5e8a9 100644
--- a/platform/ios/ios.xcodeproj/project.pbxproj
+++ b/platform/ios/ios.xcodeproj/project.pbxproj
@@ -13,6 +13,8 @@
353794D01D22B3BD002C281C /* NSData+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 35305D461D22AA450007D005 /* NSData+MGLAdditions.h */; settings = {ATTRIBUTES = (Private, ); }; };
353D23961D0B0DFE002BE09D /* MGLAnnotationViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 353D23951D0B0DFE002BE09D /* MGLAnnotationViewTests.m */; };
35E208A71D24210F00EC9A46 /* MGLNSDataAdditionsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 35E208A61D24210F00EC9A46 /* MGLNSDataAdditionsTests.m */; };
+ 36F1153D1D46080700878E1A /* libmbgl-core.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 36F1153B1D46080700878E1A /* libmbgl-core.a */; };
+ 36F1153E1D46080700878E1A /* libmbgl-platform-ios.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 36F1153C1D46080700878E1A /* libmbgl-platform-ios.a */; };
4018B1C71CDC287F00F666AF /* MGLAnnotationView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4018B1C41CDC277F00F666AF /* MGLAnnotationView.mm */; };
4018B1C81CDC287F00F666AF /* MGLAnnotationView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4018B1C41CDC277F00F666AF /* MGLAnnotationView.mm */; };
4018B1C91CDC288A00F666AF /* MGLAnnotationView_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 4018B1C31CDC277F00F666AF /* MGLAnnotationView_Private.h */; };
@@ -22,6 +24,7 @@
40EDA1C11CFE0E0500D9EA68 /* MGLAnnotationContainerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 40EDA1BE1CFE0D4A00D9EA68 /* MGLAnnotationContainerView.m */; };
40EDA1C21CFE0E0500D9EA68 /* MGLAnnotationContainerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 40EDA1BE1CFE0D4A00D9EA68 /* MGLAnnotationContainerView.m */; };
40FDA76B1CCAAA6800442548 /* MBXAnnotationView.m in Sources */ = {isa = PBXBuildFile; fileRef = 40FDA76A1CCAAA6800442548 /* MBXAnnotationView.m */; };
+ 554180421D2E97DE00012372 /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 554180411D2E97DE00012372 /* OpenGLES.framework */; };
DA0CD5901CF56F6A00A5F5A5 /* MGLFeatureTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA0CD58F1CF56F6A00A5F5A5 /* MGLFeatureTests.mm */; };
DA17BE301CC4BAC300402C41 /* MGLMapView_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = DA17BE2F1CC4BAC300402C41 /* MGLMapView_Internal.h */; };
DA17BE311CC4BDAA00402C41 /* MGLMapView_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = DA17BE2F1CC4BAC300402C41 /* MGLMapView_Internal.h */; };
@@ -335,6 +338,8 @@
35305D471D22AA450007D005 /* NSData+MGLAdditions.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSData+MGLAdditions.mm"; sourceTree = "<group>"; };
353D23951D0B0DFE002BE09D /* MGLAnnotationViewTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLAnnotationViewTests.m; sourceTree = "<group>"; };
35E208A61D24210F00EC9A46 /* MGLNSDataAdditionsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLNSDataAdditionsTests.m; sourceTree = "<group>"; };
+ 36F1153B1D46080700878E1A /* libmbgl-core.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libmbgl-core.a"; path = "build/Debug-iphoneos/libmbgl-core.a"; sourceTree = "<group>"; };
+ 36F1153C1D46080700878E1A /* libmbgl-platform-ios.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libmbgl-platform-ios.a"; path = "build/Debug-iphoneos/libmbgl-platform-ios.a"; sourceTree = "<group>"; };
4018B1C31CDC277F00F666AF /* MGLAnnotationView_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAnnotationView_Private.h; sourceTree = "<group>"; };
4018B1C41CDC277F00F666AF /* MGLAnnotationView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLAnnotationView.mm; sourceTree = "<group>"; };
4018B1C51CDC277F00F666AF /* MGLAnnotationView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAnnotationView.h; sourceTree = "<group>"; };
@@ -343,6 +348,7 @@
40EDA1BE1CFE0D4A00D9EA68 /* MGLAnnotationContainerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLAnnotationContainerView.m; sourceTree = "<group>"; };
40FDA7691CCAAA6800442548 /* MBXAnnotationView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MBXAnnotationView.h; sourceTree = "<group>"; };
40FDA76A1CCAAA6800442548 /* MBXAnnotationView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MBXAnnotationView.m; sourceTree = "<group>"; };
+ 554180411D2E97DE00012372 /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; };
DA0CD58F1CF56F6A00A5F5A5 /* MGLFeatureTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLFeatureTests.mm; path = ../../darwin/test/MGLFeatureTests.mm; sourceTree = "<group>"; };
DA17BE2F1CC4BAC300402C41 /* MGLMapView_Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLMapView_Internal.h; sourceTree = "<group>"; };
DA1DC94A1CB6C1C2006E619F /* Mapbox GL.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Mapbox GL.app"; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -516,6 +522,7 @@
buildActionMask = 2147483647;
files = (
DA8847D91CBAF91600AB86E3 /* Mapbox.framework in Frameworks */,
+ 554180421D2E97DE00012372 /* OpenGLES.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -543,6 +550,8 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ 36F1153D1D46080700878E1A /* libmbgl-core.a in Frameworks */,
+ 36F1153E1D46080700878E1A /* libmbgl-platform-ios.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -631,6 +640,9 @@
DA1DC9921CB6DF24006E619F /* Frameworks */ = {
isa = PBXGroup;
children = (
+ 36F1153B1D46080700878E1A /* libmbgl-core.a */,
+ 36F1153C1D46080700878E1A /* libmbgl-platform-ios.a */,
+ 554180411D2E97DE00012372 /* OpenGLES.framework */,
DAABF73B1CBC59BB005B1825 /* libmbgl-core.a */,
DAABF73C1CBC59BB005B1825 /* libmbgl-platform-ios.a */,
DAA4E4021CBB5C2F00178DFB /* CoreGraphics.framework */,
@@ -1701,6 +1713,7 @@
"$(OTHER_CFLAGS)",
"$(variant_cflags)",
"$(geometry_cflags)",
+ "$(geojson_cflags)",
);
PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.test;
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -1719,6 +1732,7 @@
"$(OTHER_CFLAGS)",
"$(variant_cflags)",
"$(geometry_cflags)",
+ "$(geojson_cflags)",
);
PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.test;
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -1751,12 +1765,13 @@
"$(rapidjson_cflags)",
"$(variant_cflags)",
"$(geometry_cflags)",
+ "$(geojson_cflags)",
);
OTHER_LDFLAGS = (
"$(sqlite_ldflags)",
"$(zlib_ldflags)",
"$(opengl_ldflags)",
- "$(geojsonvt_static_libs)",
+ "$(geojson_static_libs)",
);
PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.sdk.ios;
PRODUCT_NAME = Mapbox;
@@ -1792,12 +1807,13 @@
"$(rapidjson_cflags)",
"$(variant_cflags)",
"$(geometry_cflags)",
+ "$(geojson_cflags)",
);
OTHER_LDFLAGS = (
"$(sqlite_ldflags)",
"$(zlib_ldflags)",
"$(opengl_ldflags)",
- "$(geojsonvt_static_libs)",
+ "$(geojson_static_libs)",
);
PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.sdk.ios;
PRODUCT_NAME = Mapbox;
@@ -1839,6 +1855,10 @@
../../include,
../../src,
);
+ LIBRARY_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(PROJECT_DIR)/build/Debug-iphoneos",
+ );
OTHER_CPLUSPLUSFLAGS = (
"$(OTHER_CFLAGS)",
"$(sqlite_cflags)",
@@ -1846,13 +1866,14 @@
"$(rapidjson_cflags)",
"$(variant_cflags)",
"$(geometry_cflags)",
+ "$(geojson_cflags)",
);
OTHER_LDFLAGS = (
"-ObjC",
"$(sqlite_ldflags)",
"$(zlib_ldflags)",
"$(opengl_ldflags)",
- "$(geojsonvt_static_libs)",
+ "$(geojson_static_libs)",
);
PRODUCT_NAME = Mapbox;
PUBLIC_HEADERS_FOLDER_PATH = Headers;
@@ -1870,6 +1891,10 @@
../../include,
../../src,
);
+ LIBRARY_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(PROJECT_DIR)/build/Debug-iphoneos",
+ );
OTHER_CPLUSPLUSFLAGS = (
"$(OTHER_CFLAGS)",
"$(sqlite_cflags)",
@@ -1877,13 +1902,14 @@
"$(rapidjson_cflags)",
"$(variant_cflags)",
"$(geometry_cflags)",
+ "$(geojson_cflags)",
);
OTHER_LDFLAGS = (
"-ObjC",
"$(sqlite_ldflags)",
"$(zlib_ldflags)",
"$(opengl_ldflags)",
- "$(geojsonvt_static_libs)",
+ "$(geojson_static_libs)",
);
PRODUCT_NAME = Mapbox;
PUBLIC_HEADERS_FOLDER_PATH = Headers;
diff --git a/platform/ios/scripts/configure.sh b/platform/ios/scripts/configure.sh
index 408180881c..82599f0fe9 100644
--- a/platform/ios/scripts/configure.sh
+++ b/platform/ios/scripts/configure.sh
@@ -5,8 +5,11 @@ PROTOZERO_VERSION=1.3.0
BOOST_VERSION=1.60.0
SQLITE_VERSION=system
ZLIB_VERSION=system
-GEOMETRY_VERSION=0.5.0
-GEOJSONVT_VERSION=4.1.2
+GEOMETRY_VERSION=0.8.0
+GEOJSON_VERSION=0.1.4
+GEOJSONVT_VERSION=6.1.2
+SUPERCLUSTER_VERSION=0.2.0
+KDBUSH_VERSION=0.1.1
VARIANT_VERSION=1.1.0
RAPIDJSON_VERSION=1.0.2
GTEST_VERSION=1.7.0
diff --git a/platform/ios/scripts/package.sh b/platform/ios/scripts/package.sh
index c753c63dfd..c012934203 100755
--- a/platform/ios/scripts/package.sh
+++ b/platform/ios/scripts/package.sh
@@ -108,7 +108,7 @@ if [[ ${BUILD_FOR_DEVICE} == true ]]; then
-jobs ${JOBS} | xcpretty
fi
-LIBS=(Mapbox.a mbgl-core.a mbgl-platform-ios.a)
+LIBS=(Mapbox.a)
# https://medium.com/@syshen/create-an-ios-universal-framework-148eb130a46c
if [[ "${BUILD_FOR_DEVICE}" == true ]]; then
@@ -119,7 +119,7 @@ if [[ "${BUILD_FOR_DEVICE}" == true ]]; then
-o ${OUTPUT}/static/${NAME}.framework/${NAME} \
${LIBS[@]/#/${PRODUCTS}/${BUILDTYPE}-iphoneos/lib} \
${LIBS[@]/#/${PRODUCTS}/${BUILDTYPE}-iphonesimulator/lib} \
- `find mason_packages/ios-${IOS_SDK_VERSION} -type f -name libgeojsonvt.a`
+ `find mason_packages/ios-${IOS_SDK_VERSION} -type f -name libgeojson.a`
cp -rv ${PRODUCTS}/${BUILDTYPE}-iphoneos/${NAME}.bundle ${STATIC_BUNDLE_DIR}
fi
@@ -129,9 +129,19 @@ if [[ "${BUILD_FOR_DEVICE}" == true ]]; then
cp -r \
${PRODUCTS}/${BUILDTYPE}-iphoneos/${NAME}.framework \
${OUTPUT}/dynamic/
+
if [[ -e ${PRODUCTS}/${BUILDTYPE}-iphoneos/${NAME}.framework.dSYM ]]; then
+ step "Copying dSYM"
cp -r ${PRODUCTS}/${BUILDTYPE}-iphoneos/${NAME}.framework.dSYM \
- ${OUTPUT}/dynamic/
+ ${OUTPUT}/dynamic/
+ if [[ -e ${PRODUCTS}/${BUILDTYPE}-iphonesimulator/${NAME}.framework.dSYM ]]; then
+ step "Merging device and simulator dSYMs…"
+ lipo \
+ ${PRODUCTS}/${BUILDTYPE}-iphoneos/${NAME}.framework.dSYM/Contents/Resources/DWARF/${NAME} \
+ ${PRODUCTS}/${BUILDTYPE}-iphonesimulator/${NAME}.framework.dSYM/Contents/Resources/DWARF/${NAME} \
+ -create -output ${OUTPUT}/dynamic/${NAME}.framework.dSYM/Contents/Resources/DWARF/${NAME}
+ lipo -info ${OUTPUT}/dynamic/${NAME}.framework.dSYM/Contents/Resources/DWARF/${NAME}
+ fi
fi
step "Merging simulator dynamic library into device dynamic library…"
@@ -149,7 +159,7 @@ else
libtool -static -no_warning_for_no_symbols \
-o ${OUTPUT}/static/${NAME}.framework/${NAME} \
${LIBS[@]/#/${PRODUCTS}/${BUILDTYPE}-iphonesimulator/lib} \
- `find mason_packages/ios-${IOS_SDK_VERSION} -type f -name libgeojsonvt.a`
+ `find mason_packages/ios-${IOS_SDK_VERSION} -type f -name libgeojson.a`
cp -rv ${PRODUCTS}/${BUILDTYPE}-iphonesimulator/${NAME}.bundle ${STATIC_BUNDLE_DIR}
fi
@@ -160,6 +170,7 @@ else
${PRODUCTS}/${BUILDTYPE}-iphonesimulator/${NAME}.framework \
${OUTPUT}/dynamic/${NAME}.framework
if [[ -e ${PRODUCTS}/${BUILDTYPE}-iphonesimulator/${NAME}.framework.dSYM ]]; then
+ step "Copying dSYM"
cp -r ${PRODUCTS}/${BUILDTYPE}-iphonesimulator/${NAME}.framework.dSYM \
${OUTPUT}/dynamic/
fi
diff --git a/platform/ios/src/MGLAnnotationImage.h b/platform/ios/src/MGLAnnotationImage.h
index fa2adb3830..5ded4016f7 100644
--- a/platform/ios/src/MGLAnnotationImage.h
+++ b/platform/ios/src/MGLAnnotationImage.h
@@ -4,7 +4,12 @@
NS_ASSUME_NONNULL_BEGIN
-/** The MGLAnnotationImage class is responsible for presenting point-based annotations visually on a map view. Annotation image objects wrap `UIImage` objects and may be recycled later and put into a reuse queue that is maintained by the map view. */
+/**
+ The `MGLAnnotationImage` class is responsible for presenting point-based
+ annotations visually on a map view. Annotation image objects wrap `UIImage`
+ objects and may be recycled later and put into a reuse queue that is maintained
+ by the map view.
+ */
@interface MGLAnnotationImage : NSObject
#pragma mark Initializing and Preparing the Image Object
@@ -13,8 +18,10 @@ NS_ASSUME_NONNULL_BEGIN
Initializes and returns a new annotation image object.
@param image The image to be displayed for the annotation.
- @param reuseIdentifier The string that identifies that this annotation image is reusable.
- @return The initialized annotation image object or `nil` if there was a problem initializing the object.
+ @param reuseIdentifier The string that identifies that this annotation image is
+ reusable.
+ @return The initialized annotation image object or `nil` if there was a problem
+ initializing the object.
*/
+ (instancetype)annotationImageWithImage:(UIImage *)image reuseIdentifier:(NSString *)reuseIdentifier;
@@ -26,16 +33,21 @@ NS_ASSUME_NONNULL_BEGIN
/**
The string that identifies that this annotation image is reusable. (read-only)
- You specify the reuse identifier when you create the image object. You use this type later to retrieve an annotation image object that was created previously but which is currently unused because its annotation is not on screen.
+ You specify the reuse identifier when you create the image object. You use this
+ type later to retrieve an annotation image object that was created previously
+ but which is currently unused because its annotation is not on screen.
- If you define distinctly different types of annotations (with distinctly different annotation images to go with them), you can differentiate between the annotation types by specifying different reuse identifiers for each one.
+ If you define distinctly different types of annotations (with distinctly
+ different annotation images to go with them), you can differentiate between the
+ annotation types by specifying different reuse identifiers for each one.
*/
@property (nonatomic, readonly) NSString *reuseIdentifier;
/**
A Boolean value indicating whether the annotation is enabled.
- The default value of this property is `YES`. If the value of this property is `NO`, the annotation image ignores touch events and cannot be selected.
+ The default value of this property is `YES`. If the value of this property is
+ `NO`, the annotation image ignores touch events and cannot be selected.
*/
@property (nonatomic, getter=isEnabled) BOOL enabled;
diff --git a/platform/ios/src/MGLCalloutView.h b/platform/ios/src/MGLCalloutView.h
index 641976dfee..27d173b230 100644
--- a/platform/ios/src/MGLCalloutView.h
+++ b/platform/ios/src/MGLCalloutView.h
@@ -8,32 +8,38 @@ NS_ASSUME_NONNULL_BEGIN
@protocol MGLAnnotation;
/**
- A protocol for a `UIView` subclass that displays information about a selected annotation near that annotation.
+ A protocol for a `UIView` subclass that displays information about a selected
+ annotation near that annotation.
*/
@protocol MGLCalloutView <NSObject>
/**
- An object conforming to the `MGLAnnotation` protocol whose details this callout view displays.
+ An object conforming to the `MGLAnnotation` protocol whose details this callout
+ view displays.
*/
@property (nonatomic, strong) id <MGLAnnotation> representedObject;
/**
- A view that the user may tap to perform an action. This view is conventionally positioned on the left side of the callout view.
+ A view that the user may tap to perform an action. This view is conventionally
+ positioned on the left side of the callout view.
*/
@property (nonatomic, strong) UIView *leftAccessoryView;
/**
- A view that the user may tap to perform an action. This view is conventionally positioned on the right side of the callout view.
+ A view that the user may tap to perform an action. This view is conventionally
+ positioned on the right side of the callout view.
*/
@property (nonatomic, strong) UIView *rightAccessoryView;
/**
- An object conforming to the `MGLCalloutViewDelegate` method that receives messages related to the callout view’s interactive subviews.
+ An object conforming to the `MGLCalloutViewDelegate` method that receives
+ messages related to the callout view’s interactive subviews.
*/
@property (nonatomic, weak) id<MGLCalloutViewDelegate> delegate;
/**
- Presents a callout view by adding it to `inView` and pointing at the given rect of `inView`’s bounds. Constrains the callout to the bounds of the given view.
+ Presents a callout view by adding it to `view` and pointing at the given rect
+ of `view`’s bounds. Constrains the callout to the bounds of the given view.
*/
- (void)presentCalloutFromRect:(CGRect)rect inView:(UIView *)view constrainedToView:(UIView *)constrainedView animated:(BOOL)animated;
@@ -45,15 +51,21 @@ NS_ASSUME_NONNULL_BEGIN
@end
/**
- The MGLCalloutViewDelegate protocol defines a set of optional methods that you can use to receive messages from an object that conforms to the MGLCalloutView protocol. The callout view uses these methods to inform the delegate that the user has interacted with the the callout view.
+ The `MGLCalloutViewDelegate` protocol defines a set of optional methods that
+ you can use to receive messages from an object that conforms to the
+ `MGLCalloutView` protocol. The callout view uses these methods to inform the
+ delegate that the user has interacted with the the callout view.
*/
@protocol MGLCalloutViewDelegate <NSObject>
@optional
/**
- Returns a Boolean value indicating whether the entire callout view “highlights” when tapped. The default value is `YES`, which means the callout view highlights when tapped.
+ Returns a Boolean value indicating whether the entire callout view “highlights”
+ when tapped. The default value is `YES`, which means the callout view
+ highlights when tapped.
- The return value of this method is ignored unless the delegate also responds to the `-calloutViewTapped` method.
+ The return value of this method is ignored unless the delegate also responds to
+ the `-calloutViewTapped` method.
*/
- (BOOL)calloutViewShouldHighlight:(UIView<MGLCalloutView> *)calloutView;
@@ -63,12 +75,14 @@ NS_ASSUME_NONNULL_BEGIN
- (void)calloutViewTapped:(UIView<MGLCalloutView> *)calloutView;
/**
- Called before the callout view appears on screen, or before the appearance animation will start.
+ Called before the callout view appears on screen, or before the appearance
+ animation will start.
*/
- (void)calloutViewWillAppear:(UIView<MGLCalloutView> *)calloutView;
/**
- Called after the callout view appears on screen, or after the appearance animation is complete.
+ Called after the callout view appears on screen, or after the appearance
+ animation is complete.
*/
- (void)calloutViewDidAppear:(UIView<MGLCalloutView> *)calloutView;
diff --git a/platform/ios/src/MGLCompactCalloutView.h b/platform/ios/src/MGLCompactCalloutView.h
index ebe27c842c..56c48a99e5 100644
--- a/platform/ios/src/MGLCompactCalloutView.h
+++ b/platform/ios/src/MGLCompactCalloutView.h
@@ -2,7 +2,10 @@
#import "MGLCalloutView.h"
/**
- A concrete implementation of `MGLCalloutView` based on <a href="https://github.com/nfarina/calloutview">SMCalloutView</a>. This callout view displays the represented annotation’s title, subtitle, and accessory views in a compact, two-line layout.
+ A concrete implementation of `MGLCalloutView` based on
+ <a href="https://github.com/nfarina/calloutview">SMCalloutView</a>. This
+ callout view displays the represented annotation’s title, subtitle, and
+ accessory views in a compact, two-line layout.
*/
@interface MGLCompactCalloutView : SMCalloutView <MGLCalloutView>
diff --git a/platform/ios/src/MGLMapView.h b/platform/ios/src/MGLMapView.h
index a70b603f02..56236c54d8 100644
--- a/platform/ios/src/MGLMapView.h
+++ b/platform/ios/src/MGLMapView.h
@@ -43,7 +43,7 @@ typedef NS_ENUM(NSUInteger, MGLAnnotationVerticalAlignment) {
MGLAnnotationVerticalAlignmentBottom,
};
-/** Options for enabling debugging features in an MGLMapView instance. */
+/** Options for enabling debugging features in an `MGLMapView` instance. */
typedef NS_OPTIONS(NSUInteger, MGLMapDebugMaskOptions) {
/** Edges of tile boundaries are shown as thick, red lines to help diagnose
tile clipping issues. */
@@ -57,13 +57,14 @@ typedef NS_OPTIONS(NSUInteger, MGLMapDebugMaskOptions) {
MGLMapDebugCollisionBoxesMask = 1 << 4,
/** Each drawing operation is replaced by a translucent fill. Overlapping
drawing operations appear more prominent to help diagnose overdrawing.
+ @note This option does nothing in Release builds of the SDK.
*/
MGLMapDebugOverdrawVisualizationMask = 1 << 5,
};
/**
An interactive, customizable map view with an interface similar to the one
- provided by Apple's MapKit.
+ provided by Apple’s MapKit.
Using `MGLMapView`, you can embed the map inside a view, allow users to
manipulate it with standard gestures, animate the map between different
@@ -72,7 +73,7 @@ typedef NS_OPTIONS(NSUInteger, MGLMapDebugMaskOptions) {
The map view loads scalable vector tiles that conform to the
<a href="https://github.com/mapbox/vector-tile-spec">Mapbox Vector Tile Specification</a>.
It styles them with a style that conforms to the
- <a href="https://www.mapbox.com/mapbox-gl-style-spec/">Mapbox GL style specification</a>.
+ <a href="https://www.mapbox.com/mapbox-gl-style-spec/">Mapbox Style Specification</a>.
Such styles can be designed in
<a href="https://www.mapbox.com/studio/">Mapbox Studio</a> and hosted on
mapbox.com.
@@ -86,7 +87,7 @@ typedef NS_OPTIONS(NSUInteger, MGLMapDebugMaskOptions) {
Mapbox-hosted vector tiles and styles require an API access token, which you
can obtain from the
<a href="https://www.mapbox.com/studio/account/tokens/">Mapbox account page</a>.
- Access tokens associate requests to Mapbox's vector tile and style APIs with
+ Access tokens associate requests to Mapbox’s vector tile and style APIs with
your Mapbox account. They also deter other developers from using your styles
without your permission.
@@ -113,9 +114,9 @@ IB_DESIGNABLE
@param frame The frame for the view, measured in points.
@param styleURL URL of the map style to display. The URL may be a full HTTP
- or HTTPS URL, a Mapbox URL indicating the style's map ID
+ or HTTPS URL, a Mapbox URL indicating the style’s map ID
(`mapbox://styles/{user}/{style}`), or a path to a local file relative
- to the application's resource path. Specify `nil` for the default style.
+ to the application’s resource path. Specify `nil` for the default style.
@return An initialized map view.
*/
- (instancetype)initWithFrame:(CGRect)frame styleURL:(nullable NSURL *)styleURL;
@@ -123,7 +124,7 @@ IB_DESIGNABLE
#pragma mark Accessing the Delegate
/**
- The receiver's delegate.
+ The receiver’s delegate.
A map view sends messages to its delegate to notify it of changes to its
contents or the viewpoint. The delegate also provides information about
@@ -132,7 +133,7 @@ IB_DESIGNABLE
*/
@property(nonatomic, weak, nullable) IBOutlet id<MGLMapViewDelegate> delegate;
-#pragma mark Configuring the Map's Appearance
+#pragma mark Configuring the Map’s Appearance
/**
URLs of the styles bundled with the library.
@@ -145,12 +146,12 @@ IB_DESIGNABLE
/**
URL of the style currently displayed in the receiver.
- The URL may be a full HTTP or HTTPS URL, a Mapbox URL indicating the style's
+ The URL may be a full HTTP or HTTPS URL, a Mapbox URL indicating the style’s
map ID (`mapbox://styles/{user}/{style}`), or a path to a local file
- relative to the application's resource path.
+ relative to the application’s resource path.
If you set this property to `nil`, the receiver will use the default style
- and this property will automatically be set to that style's URL.
+ and this property will automatically be set to that style’s URL.
*/
@property (nonatomic, null_resettable) NSURL *styleURL;
@@ -169,7 +170,7 @@ IB_DESIGNABLE
- (IBAction)reloadStyle:(id)sender;
/**
- A control indicating the map's direction and allowing the user to manipulate
+ A control indicating the map’s direction and allowing the user to manipulate
the direction, positioned in the upper-right corner.
*/
@property (nonatomic, readonly) UIImageView *compassView;
@@ -235,18 +236,18 @@ IB_DESIGNABLE
*/
- (void)removeStyleClass:(NSString *)styleClass;
-#pragma mark Displaying the User's Location
+#pragma mark Displaying the User’s Location
/**
A Boolean value indicating whether the map may display the user location.
Setting this property to `YES` causes the map view to use the Core Location
framework to find the current location. As long as this property is `YES`, the
- map view continues to track the user's location and update it periodically.
+ map view continues to track the user’s location and update it periodically.
- This property does not indicate whether the user's position is actually visible
+ This property does not indicate whether the user’s position is actually visible
on the map, only whether the map view is allowed to display it. To determine
- whether the user's position is visible, use the `userLocationVisible` property.
+ whether the user’s position is visible, use the `userLocationVisible` property.
The default value of this property is `NO`.
On iOS 8 and above, your app must specify a value for
@@ -257,7 +258,7 @@ IB_DESIGNABLE
@property (nonatomic, assign) BOOL showsUserLocation;
/**
- A Boolean value indicating whether the device's current location is visible in
+ A Boolean value indicating whether the device’s current location is visible in
the map view.
Use `showsUserLocation` to control the visibility of the on-screen user
@@ -266,7 +267,7 @@ IB_DESIGNABLE
@property (nonatomic, assign, readonly, getter=isUserLocationVisible) BOOL userLocationVisible;
/**
- Returns the annotation object indicating the user's current location.
+ Returns the annotation object indicating the user’s current location.
*/
@property (nonatomic, readonly, nullable) MGLUserLocation *userLocation;
@@ -577,7 +578,7 @@ IB_DESIGNABLE
- (IBAction)resetNorth;
/**
- The coordinate bounds visible in the receiver's viewport.
+ The coordinate bounds visible in the receiver’s viewport.
Changing the value of this property updates the receiver immediately. If you
want to animate the change, call `-setVisibleCoordinateBounds:animated:`
@@ -596,7 +597,7 @@ IB_DESIGNABLE
- (void)setVisibleCoordinateBounds:(MGLCoordinateBounds)bounds animated:(BOOL)animated;
/**
- Changes the receiver's viewport to fit the given coordinate bounds and
+ Changes the receiver’s viewport to fit the given coordinate bounds and
optionally some additional padding on each side.
@param bounds The bounds that the viewport will show in its entirety.
@@ -608,7 +609,7 @@ IB_DESIGNABLE
- (void)setVisibleCoordinateBounds:(MGLCoordinateBounds)bounds edgePadding:(UIEdgeInsets)insets animated:(BOOL)animated;
/**
- Changes the receiver's viewport to fit all of the given coordinates and
+ Changes the receiver’s viewport to fit all of the given coordinates and
optionally some additional padding on each side.
@param coordinates The coordinates that the viewport will show.
@@ -622,7 +623,7 @@ IB_DESIGNABLE
- (void)setVisibleCoordinates:(CLLocationCoordinate2D *)coordinates count:(NSUInteger)count edgePadding:(UIEdgeInsets)insets animated:(BOOL)animated;
/**
- Changes the receiver's viewport to fit all of the given coordinates and
+ Changes the receiver’s viewport to fit all of the given coordinates and
optionally some additional padding on each side.
@param coordinates The coordinates that the viewport will show.
@@ -656,7 +657,7 @@ IB_DESIGNABLE
Sets the visible region so that the map displays the specified annotations with
the specified amount of padding on each side.
- Calling this method updates the value in the visibleCoordinateBounds property
+ Calling this method updates the value in the `visibleCoordinateBounds` property
and potentially other properties to reflect the new map region.
@param annotations The annotations that you want to be visible in the map.
@@ -787,7 +788,7 @@ IB_DESIGNABLE
- (MGLMapCamera *)cameraThatFitsCoordinateBounds:(MGLCoordinateBounds)bounds edgePadding:(UIEdgeInsets)insets;
/**
- Returns the point in this view's coordinate system on which to "anchor" in
+ Returns the point in this view’s coordinate system on which to "anchor" in
response to a user-initiated gesture.
For example, a pinch-to-zoom gesture would anchor the map at the midpoint of
@@ -797,7 +798,7 @@ IB_DESIGNABLE
user annotation is used as the anchor point.
Subclasses may override this method to provide specialized behavior - for
- example, anchoring on the map's center point to provide a "locked" zooming
+ example, anchoring on the map’s center point to provide a "locked" zooming
mode.
@param gesture An anchorable user gesture.
@@ -849,7 +850,7 @@ IB_DESIGNABLE
#pragma mark Converting Geographic Coordinates
/**
- Converts a point in the given view's coordinate system to a geographic
+ Converts a point in the given view’s coordinate system to a geographic
coordinate.
@param point The point to convert.
@@ -859,13 +860,13 @@ IB_DESIGNABLE
- (CLLocationCoordinate2D)convertPoint:(CGPoint)point toCoordinateFromView:(nullable UIView *)view;
/**
- Converts a geographic coordinate to a point in the given view's coordinate
+ Converts a geographic coordinate to a point in the given view’s coordinate
system.
@param coordinate The geographic coordinate to convert.
@param view The view in whose coordinate system the returned point should be
expressed. If this parameter is `nil`, the returned point is expressed
- in the window's coordinate system. If `view` is not `nil`, it must
+ in the window’s coordinate system. If `view` is not `nil`, it must
belong to the same window as the map view.
@return The point (in the appropriate view or window coordinate system)
corresponding to the given geographic coordinate.
@@ -895,7 +896,7 @@ IB_DESIGNABLE
- (CGRect)convertCoordinateBounds:(MGLCoordinateBounds)bounds toRectToView:(nullable UIView *)view;
/**
- Returns the distance spanned by one point in the map view's coordinate system
+ Returns the distance spanned by one point in the map view’s coordinate system
at the given latitude and current zoom level.
The distance between points decreases as the latitude approaches the poles.
diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm
index 4ec3619189..b0c213ebfb 100644
--- a/platform/ios/src/MGLMapView.mm
+++ b/platform/ios/src/MGLMapView.mm
@@ -134,11 +134,11 @@ mbgl::Color MGLColorObjectFromUIColor(UIColor *color)
{
if (!color)
{
- return {{ 0, 0, 0, 0 }};
+ return { 0, 0, 0, 0 };
}
CGFloat r, g, b, a;
[color getRed:&r green:&g blue:&b alpha:&a];
- return {{ (float)r, (float)g, (float)b, (float)a }};
+ return { (float)r, (float)g, (float)b, (float)a };
}
@interface MGLAnnotationAccessibilityElement : UIAccessibilityElement
@@ -1815,7 +1815,7 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
{
mask |= MGLMapDebugCollisionBoxesMask;
}
- if (options & mbgl::MapDebugOptions::Wireframe)
+ if (options & mbgl::MapDebugOptions::Overdraw)
{
mask |= MGLMapDebugOverdrawVisualizationMask;
}
@@ -1843,7 +1843,7 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
}
if (debugMask & MGLMapDebugOverdrawVisualizationMask)
{
- options |= mbgl::MapDebugOptions::Wireframe;
+ options |= mbgl::MapDebugOptions::Overdraw;
}
_mbglMap->setDebug(options);
}
@@ -2182,8 +2182,8 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
mbgl::AnimationOptions animationOptions;
if (duration)
{
- animationOptions.duration = MGLDurationInSeconds(duration);
- animationOptions.easing = MGLUnitBezierForMediaTimingFunction(function);
+ animationOptions.duration.emplace(MGLDurationInSeconds(duration));
+ animationOptions.easing.emplace(MGLUnitBezierForMediaTimingFunction(function));
}
if (completion)
{
@@ -2335,8 +2335,8 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
mbgl::AnimationOptions animationOptions;
if (duration > 0)
{
- animationOptions.duration = MGLDurationInSeconds(duration);
- animationOptions.easing = MGLUnitBezierForMediaTimingFunction(function);
+ animationOptions.duration.emplace(MGLDurationInSeconds(duration));
+ animationOptions.easing.emplace(MGLUnitBezierForMediaTimingFunction(function));
}
if (completion)
{
@@ -2442,8 +2442,8 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
mbgl::AnimationOptions animationOptions;
if (duration > 0)
{
- animationOptions.duration = MGLDurationInSeconds(duration);
- animationOptions.easing = MGLUnitBezierForMediaTimingFunction(function);
+ animationOptions.duration.emplace(MGLDurationInSeconds(duration));
+ animationOptions.easing.emplace(MGLUnitBezierForMediaTimingFunction(function));
}
if (completion)
{
@@ -4556,7 +4556,13 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
MGLAnnotationContext &annotationContext = pair.second;
MGLAnnotationView *annotationView = annotationContext.annotationView;
-
+
+ // Defer to the shape/polygon styling delegate methods
+ if ([annotationContext.annotation isKindOfClass:[MGLMultiPoint class]])
+ {
+ continue;
+ }
+
if (!annotationView)
{
MGLAnnotationView *annotationView = [self annotationViewForAnnotation:annotationContext.annotation];
diff --git a/platform/ios/src/MGLMapViewDelegate.h b/platform/ios/src/MGLMapViewDelegate.h
index 12a0658a51..db1327685a 100644
--- a/platform/ios/src/MGLMapViewDelegate.h
+++ b/platform/ios/src/MGLMapViewDelegate.h
@@ -204,12 +204,12 @@ NS_ASSUME_NONNULL_BEGIN
/**
Returns the alpha value to use when rendering a shape annotation.
- A value of 0.0 results in a completely transparent shape. A value of 1.0, the
- default, results in a completely opaque shape.
+ A value of `0.0` results in a completely transparent shape. A value of `1.0`,
+ the default, results in a completely opaque shape.
@param mapView The map view rendering the shape annotation.
@param annotation The annotation being rendered.
- @return An alpha value between 0 and 1.0.
+ @return An alpha value between `0` and `1.0`.
*/
- (CGFloat)mapView:(MGLMapView *)mapView alphaForShapeAnnotation:(MGLShape *)annotation;
@@ -241,7 +241,7 @@ NS_ASSUME_NONNULL_BEGIN
Returns the line width in points to use when rendering the outline of a
polyline annotation.
- By default, the polyline is outlined with a line 3.0 points wide.
+ By default, the polyline is outlined with a line `3.0` points wide.
@param mapView The map view rendering the polygon annotation.
@param annotation The annotation being rendered.
diff --git a/platform/ios/src/MGLUserLocation.h b/platform/ios/src/MGLUserLocation.h
index 6160413510..81f9557b16 100644
--- a/platform/ios/src/MGLUserLocation.h
+++ b/platform/ios/src/MGLUserLocation.h
@@ -7,7 +7,12 @@
NS_ASSUME_NONNULL_BEGIN
-/** The MGLUserLocation class defines a specific type of annotation that identifies the user’s current location. You do not create instances of this class directly. Instead, you retrieve an existing MGLUserLocation object from the userLocation property of the map view displayed in your application. */
+/**
+ The MGLUserLocation class defines a specific type of annotation that identifies
+ the user’s current location. You do not create instances of this class
+ directly. Instead, you retrieve an existing MGLUserLocation object from the
+ `userLocation` property of the map view displayed in your application.
+ */
@interface MGLUserLocation : NSObject <MGLAnnotation>
#pragma mark Determining the User’s Position
@@ -15,17 +20,22 @@ NS_ASSUME_NONNULL_BEGIN
/**
The current location of the device. (read-only)
- This property contains `nil` if the map view is not currently showing the user location or if the user’s location has not yet been determined.
+ This property contains `nil` if the map view is not currently showing the user
+ location or if the user’s location has not yet been determined.
*/
@property (nonatomic, readonly, nullable) CLLocation *location;
-/** A Boolean value indicating whether the user’s location is currently being updated. (read-only) */
+/**
+ A Boolean value indicating whether the user’s location is currently being
+ updated. (read-only)
+ */
@property (nonatomic, readonly, getter=isUpdating) BOOL updating;
/**
The heading of the user location. (read-only)
- This property is `nil` if the user location tracking mode is not `MGLUserTrackingModeFollowWithHeading`.
+ This property is `nil` if the user location tracking mode is not
+ `MGLUserTrackingModeFollowWithHeading`.
*/
@property (nonatomic, readonly, nullable) CLHeading *heading;
diff --git a/platform/ios/src/MGLUserLocationAnnotationView.h b/platform/ios/src/MGLUserLocationAnnotationView.h
index 1eb50b7740..40432581fd 100644
--- a/platform/ios/src/MGLUserLocationAnnotationView.h
+++ b/platform/ios/src/MGLUserLocationAnnotationView.h
@@ -8,7 +8,7 @@ NS_ASSUME_NONNULL_BEGIN
@class MGLMapView;
@class MGLUserLocation;
-/** View representing an MGLUserLocation on screen. */
+/** View representing an `MGLUserLocation` on screen. */
@interface MGLUserLocationAnnotationView : UIView
@property (nonatomic, weak) MGLMapView *mapView;
diff --git a/platform/linux/scripts/configure.sh b/platform/linux/scripts/configure.sh
index 8f041d589a..3d37994868 100644
--- a/platform/linux/scripts/configure.sh
+++ b/platform/linux/scripts/configure.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
-CXX11ABI=$(scripts/check-cxx11abi.sh)
+CXX11ABI=${CXX11ABI:-$(scripts/check-cxx11abi.sh)}
UNIQUE_RESOURCE_VERSION=dev
PROTOZERO_VERSION=1.3.0
@@ -14,8 +14,11 @@ SQLITE_VERSION=3.9.1
LIBUV_VERSION=1.7.5
ZLIB_VERSION=system
NUNICODE_VERSION=1.6
-GEOMETRY_VERSION=0.5.0
-GEOJSONVT_VERSION=4.1.2${CXX11ABI:-}
+GEOMETRY_VERSION=0.8.0
+GEOJSON_VERSION=0.1.4${CXX11ABI:-}
+GEOJSONVT_VERSION=6.1.2
+SUPERCLUSTER_VERSION=0.2.0
+KDBUSH_VERSION=0.1.1
VARIANT_VERSION=1.1.0
RAPIDJSON_VERSION=1.0.2
GTEST_VERSION=1.7.0${CXX11ABI:-}
diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md
index e09f1e5b5f..9bd4188552 100644
--- a/platform/macos/CHANGELOG.md
+++ b/platform/macos/CHANGELOG.md
@@ -2,24 +2,42 @@
## master
+* Added `showAnnotations:animated:` and `showAnnotations:edgePadding:animated:`, which moves the map viewport to show the specified annotations. ([#5749](https://github.com/mapbox/mapbox-gl-native/pull/5749))
+
+## 0.2.1 - July 19, 2016
+
* Fixed a crash that occurred when a sprite URL lacks a file extension. See [this comment](https://github.com/mapbox/mapbox-gl-native/issues/5722#issuecomment-233701251) to determine who may be affected by this bug. ([#5723](https://github.com/mapbox/mapbox-gl-native/pull/5723))
+* Right-clicking to open MGLMapView’s context menu no longer prevents the user from subsequently panning the map by clicking and dragging. ([#5593](https://github.com/mapbox/mapbox-gl-native/pull/5593))
* Fixed an issue causing overlapping polylines and polygons to be drawn in undefined z-order. Shapes are always drawn in the order they are added to the map, from the oldest on the bottom to the newest on the top. ([#5710](https://github.com/mapbox/mapbox-gl-native/pull/5710))
+* Improved the design of the generated API documentation. ([#5306](https://github.com/mapbox/mapbox-gl-native/pull/5306))
+* As the user zooms in, tiles from lower zoom levels are scaled up until tiles for higher zoom levels are loaded. ([#5143](https://github.com/mapbox/mapbox-gl-native/pull/5143))
+* Added [quadkey](https://msdn.microsoft.com/en-us/library/bb259689.aspx) support and limited WMS support in raster tile URL templates. ([#5628](https://github.com/mapbox/mapbox-gl-native/pull/5628))
+* Fixed a crash that occurred when a style or other resource URL has a query string. ([#5554](https://github.com/mapbox/mapbox-gl-native/pull/5554))
* Fixed an issue causing polyline and polygon annotations to disappear when the zoom level is one less than the maximum zoom level. ([#5418](https://github.com/mapbox/mapbox-gl-native/pull/5418))
* Added a property to MGLOfflineStorage, `countOfBytesCompleted`, that indicates the disk space occupied by all cached and offline resources. ([#5585](https://github.com/mapbox/mapbox-gl-native/pull/5585))
-* Fixed a crash that occurred when a style or other resource URL has a query string. ([#5554](https://github.com/mapbox/mapbox-gl-native/pull/5554))
+* The `text-pitch-alignment` property is now supported in stylesheets for improved street label legibility on a tilted map. ([#5288](https://github.com/mapbox/mapbox-gl-native/pull/5288))
+* The `icon-text-fit` and `icon-text-fit-padding` properties are now supported in stylesheets, allowing the background of a shield to automatically resize to fit the shield’s text. ([#5334](https://github.com/mapbox/mapbox-gl-native/pull/5334))
+* Improved the performance of relocating a point annotation by changing its `coordinate` property. ([#5385](https://github.com/mapbox/mapbox-gl-native/pull/5385))
* Replaced the wireframe debug mask with an overdraw visualization debug mask to match Mapbox GL JS’s overdraw inspector. ([#5403](https://github.com/mapbox/mapbox-gl-native/pull/5403))
-* Improved the design of the generated API documentation. ([#5306](https://github.com/mapbox/mapbox-gl-native/pull/5306))
+* MGLMapDebugOverdrawVisualizationMask and MGLMapDebugStencilBufferMask does nothing in Release builds of the SDK. These are disabled for performance reasons. ([#5555](https://github.com/mapbox/mapbox-gl-native/pull/5555))
-## 0.2.0
+## 0.2.0 - June 14, 2016
+* This version of the Mapbox macOS SDK roughly corresponds to version 3.3.0-beta.1 of the Mapbox iOS SDK. The two SDKs have very similar feature sets. The main differences are the lack of user location tracking and annotation views. Some APIs have been adapted to macOS conventions, particularly the use of NSPopover for callout views.
* Renamed the SDK to the Mapbox macOS SDK.
* Fixed an issue in which Mapbox.framework was nested inside another folder named Mapbox.framework. ([#4998](https://github.com/mapbox/mapbox-gl-native/pull/4998))
* Added methods to MGLMapView for obtaining the underlying map data rendered by the current style, along with additional classes to represent complex geometry in that data. ([#5110](https://github.com/mapbox/mapbox-gl-native/pull/5110))
* An MGLPolygon can now have interior polygons, representing holes knocked out of the overall shape. ([#5110](https://github.com/mapbox/mapbox-gl-native/pull/5110))
+* Fixed a vector tile parsing bug that sometimes caused properties in the vector tile source to be mismatched. ([#5183](https://github.com/mapbox/mapbox-gl-native/pull/5183))
* Fixed a crash passing a mixture of point and shape annotations into `-[MGLMapView addAnnotations:]`. ([#5097](https://github.com/mapbox/mapbox-gl-native/pull/5097))
-* Added new options to `MGLMapDebugMaskOptions` that show wireframes and the stencil buffer instead of the color buffer. ([#4359](https://github.com/mapbox/mapbox-gl-native/pull/4359))
+* Fixed an issue (speculatively) where the tile cache could be included in iCloud backups. ([#5124](https://github.com/mapbox/mapbox-gl-native/pull/5124))
+* Improved performance viewing regions with large landcover polygons when viewing a style that uses the Mapbox Streets source. ([#2444](https://github.com/mapbox/mapbox-gl-native/pull/2444))
* Fixed a memory leak when using raster resources. ([#5141](https://github.com/mapbox/mapbox-gl-native/pull/5141))
+* Added `MGLCoordinateInCoordinateBounds()`, a function that tests whether or not a coordinate is in a given bounds. ([#5053](https://github.com/mapbox/mapbox-gl-native/pull/5053))
+* Fixed an issue in which fade transitions (such as on street labels in some styles) lagged behind the map when quickly zooming in and out. ([#4579](https://github.com/mapbox/mapbox-gl-native/pull/4579))
+* Added new options to `MGLMapDebugMaskOptions` that show wireframes and the stencil buffer instead of the color buffer. ([#4359](https://github.com/mapbox/mapbox-gl-native/pull/4359))
+* Declarations in the API documentation are shown in both Objective-C and Swift. ([realm/jazzy#530](https://github.com/realm/jazzy/pull/530))
-## 0.1.0
+## 0.1.0 - May 10, 2016
* This version of the Mapbox OS X SDK roughly corresponds to version 3.3.0-alpha.2 of the Mapbox iOS SDK. The two SDKs have very similar feature sets. The main difference is the lack of user location tracking. Some APIs have been adapted to OS X conventions, particularly the use of NSPopover for callout views.
diff --git a/platform/macos/DEVELOPING.md b/platform/macos/DEVELOPING.md
index fc7b0330a3..5f437f4172 100644
--- a/platform/macos/DEVELOPING.md
+++ b/platform/macos/DEVELOPING.md
@@ -14,6 +14,21 @@ The Mapbox macOS SDK and the macosapp demo application run on macOS 10.10.0 and
## Contributing
+### Making any symbol public
+
+To add any Objective-C type, constant, or member to the iOS SDK’s public interface:
+
+1. Ensure that the symbol is pure Objective-C and does not rely on any language features specific to Objective-C++ or the C11 dialect of C – so no namespaced types or classes named with emoji! 🙃 Most projects that depend on this SDK are either written in pure Objective-C (GNU99 dialect) or Swift, which cannot yet bridge C++ types.
+1. Name the symbol according to [Cocoa naming conventions](https://developer.apple.com/library/prerelease/content/documentation/Cocoa/Conceptual/CodingGuidelines/CodingGuidelines.html#//apple_ref/doc/uid/10000146i). Use the `MGL` class prefix to avoid conflicts with client code. If the symbol has an analogue in MapKit, name the symbol according to MapKit.
+1. Provide full documentation comments. We use [jazzy](https://github.com/realm/jazzy/) to produce the documentation found in the SDK distribution. We also recognize that many developers rely on Xcode’s Quick Help feature. jazzy supports Markdown formatting; however, Quick Help supports only [HeaderDoc](https://developer.apple.com/legacy/library/documentation/DeveloperTools/Conceptual/HeaderDoc/intro/intro.html) syntax and a subset of Doxygen syntax. For hyperlinks, use HTML syntax, which is recognized by both tools.
+
+### Making a type or constant public
+
+To add an Objective-C class, protocol, category, typedef, enumeration, or global constant to the macOS SDK’s public interface:
+
+1. _(Optional.)_ Add the type or constant’s name to the relevant category in the `custom_categories` section of [the jazzy configuration file](./jazzy.yml). This is required for classes and protocols and also recommended for any other type that is strongly associated with a particular class or protocol. If you leave out this step, the symbol will appear in an “Other” section in the generated HTML documentation’s table of contents.
+1. _(Optional.)_ If the symbol would also be publicly exposed in the iOS SDK, consult [the companion iOS document](../ios/DEVELOPING.md#making-a-type-or-constant-public) for further instructions.
+
### Adding a source code file
To add an Objective-C header or implementation file to the macOS SDK:
diff --git a/platform/macos/INSTALL.md b/platform/macos/INSTALL.md
index 42896d380d..07aae88a2e 100644
--- a/platform/macos/INSTALL.md
+++ b/platform/macos/INSTALL.md
@@ -21,7 +21,15 @@ Grab a [prebuilt release](https://github.com/mapbox/mapbox-gl-native/releases/)
## Usage
-In a storyboard or XIB, add a view to your view controller. (Drag Custom View from the Object library to the View Controller scene on the Interface Builder canvas.) In the Identity inspector, set the view’s custom class to `MGLMapView`. If you need to manipulate the map view programmatically:
+In a storyboard or XIB:
+
+1. Add a view to your view controller or window. (Drag Custom View from the Object library to the View Controller scene on the Interface Builder canvas. In a XIB, drag it instead to the window on the canvas.)
+2. In the Identity inspector, set the view’s custom class to `MGLMapView`.
+3. MGLMapView needs to be layer-backed:
+ * You can make the window layer-backed by selecting the window and checking Full Size Content View in the Attributes inspector. This allows the map view to underlap the title bar and toolbar.
+ * Alternatively, if you don’t want the entire window to be layer-backed, you can make just the map view layer-backed by selecting it and checking its entry under the View Effects inspector’s Core Animation Layer section.
+
+If you need to manipulate the map view programmatically:
1. Switch to the Assistant Editor.
1. Import the `Mapbox` module.
@@ -47,4 +55,12 @@ class ViewController: NSViewController {
}
```
+```applescript
+-- AppDelegate.applescript
+script AppDelegate
+ property parent : class "NSObject"
+ property theMapView : missing value
+end script
+```
+
Run `make xdocument` to generate complete API documentation. The [Mapbox iOS SDK](https://www.mapbox.com/ios-sdk/)’s [API documentation](https://www.mapbox.com/ios-sdk/api/) and [online examples](https://www.mapbox.com/ios-sdk/examples/) apply to the Mapbox macOS SDK with few differences, mostly around unimplemented features like user location tracking.
diff --git a/platform/macos/app/AppDelegate.m b/platform/macos/app/AppDelegate.m
index b7860cf130..d3fe2d204e 100644
--- a/platform/macos/app/AppDelegate.m
+++ b/platform/macos/app/AppDelegate.m
@@ -53,6 +53,22 @@ NSString * const MGLLastMapDebugMaskDefaultsKey = @"MGLLastMapDebugMask";
return self.progress.countOfBytesCompleted;
}
++ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingCountOfTilesCompleted {
+ return [NSSet setWithObjects:@"progress", nil];
+}
+
+- (uint64_t)countOfTilesCompleted {
+ return self.progress.countOfTilesCompleted;
+}
+
++ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingCountOfTileBytesCompleted {
+ return [NSSet setWithObjects:@"progress", nil];
+}
+
+- (uint64_t)countOfTileBytesCompleted {
+ return self.progress.countOfTileBytesCompleted;
+}
+
@end
@interface AppDelegate ()
@@ -233,7 +249,7 @@ NSString * const MGLLastMapDebugMaskDefaultsKey = @"MGLLastMapDebugMask";
alert.informativeText = @"\
• To scroll, swipe with two fingers on a trackpad, or drag the cursor, or press the arrow keys.\n\
• To zoom in, pinch two fingers apart on a trackpad, or double-click, or hold down Shift while dragging the cursor down, or hold down Option while pressing the up key.\n\
-• To zoom out, pinch two fingers together on a trackpad, or double-tap on a mouse, or hold down Shift while dragging the cursor up, or hold down Option while pressing the down key.\n\
+• To zoom out, pinch two fingers together on a trackpad, or double-tap with two fingers on a trackpad, or double-tap on a mouse, or hold down Shift while dragging the cursor up, or hold down Option while pressing the down key.\n\
• To rotate, move two fingers opposite each other in a circle on a trackpad, or hold down Option while dragging the cursor left and right, or hold down Option while pressing the left and right arrow keys.\n\
• To tilt, hold down Option while dragging the cursor up and down.\n\
• To drop a pin, click and hold.\
diff --git a/platform/macos/app/Base.lproj/MainMenu.xib b/platform/macos/app/Base.lproj/MainMenu.xib
index 36fb02736c..4d81289314 100644
--- a/platform/macos/app/Base.lproj/MainMenu.xib
+++ b/platform/macos/app/Base.lproj/MainMenu.xib
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11129.15" systemVersion="15F34" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
+<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10117" systemVersion="15G26a" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
- <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11129.15"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10117"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
@@ -129,7 +129,6 @@
</menuItem>
<menuItem isSeparatorItem="YES" id="aJh-i4-bef"/>
<menuItem title="Page Setup…" keyEquivalent="P" id="qIS-W8-SiK">
- <modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
<connections>
<action selector="runPageLayout:" target="-1" id="Din-rz-gC5"/>
</connections>
@@ -437,45 +436,40 @@
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Debug" id="McE-ka-r79">
<items>
- <menuItem title="Show Tile Boundaries" id="rDE-dG-rTR">
- <modifierMask key="keyEquivalentModifierMask"/>
+ <menuItem title="Show Tile Boundaries" keyEquivalent="b" id="rDE-dG-rTR">
<connections>
<action selector="toggleTileBoundaries:" target="-1" id="LAO-88-F7h"/>
</connections>
</menuItem>
- <menuItem title="Show Tile Info" id="LoH-qD-kb0">
- <modifierMask key="keyEquivalentModifierMask"/>
+ <menuItem title="Show Tile Info" keyEquivalent="i" id="LoH-qD-kb0">
<connections>
<action selector="toggleTileInfo:" target="-1" id="KCn-0G-V87"/>
</connections>
</menuItem>
- <menuItem title="Show Tile Timestamps" id="bY0-2E-LZ7">
- <modifierMask key="keyEquivalentModifierMask"/>
+ <menuItem title="Show Tile Timestamps" keyEquivalent="t" id="bY0-2E-LZ7">
<connections>
<action selector="toggleTileTimestamps:" target="-1" id="tBs-2N-KEG"/>
</connections>
</menuItem>
- <menuItem title="Show Collision Boxes" id="Y0b-3K-mJE">
- <modifierMask key="keyEquivalentModifierMask"/>
+ <menuItem title="Show Collision Boxes" keyEquivalent="C" id="Y0b-3K-mJE">
<connections>
<action selector="toggleCollisionBoxes:" target="-1" id="EYa-7n-iWZ"/>
</connections>
</menuItem>
- <menuItem title="Show Overdraw Visualization" id="hSX-Be-8xC">
- <modifierMask key="keyEquivalentModifierMask"/>
+ <menuItem title="Show Overdraw Visualization" keyEquivalent="O" id="hSX-Be-8xC">
<connections>
<action selector="toggleOverdrawVisualization:" target="-1" id="usj-ug-upt"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="2EG-Hp-4FA"/>
- <menuItem title="Show Color Buffer" id="Eao-WE-BWz">
- <modifierMask key="keyEquivalentModifierMask"/>
+ <menuItem title="Color Buffer" keyEquivalent="c" id="Eao-WE-BWz">
+ <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="showColorBuffer:" target="-1" id="Nuq-Qs-98g"/>
</connections>
</menuItem>
- <menuItem title="Show Stencil Buffer" id="LlS-Yh-RkN">
- <modifierMask key="keyEquivalentModifierMask"/>
+ <menuItem title="Stencil Buffer" keyEquivalent="s" id="LlS-Yh-RkN">
+ <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="showStencilBuffer:" target="-1" id="WkN-t9-Mpv"/>
</connections>
@@ -494,27 +488,40 @@
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="Sl5-nE-kHd"/>
- <menuItem title="Blanket Map With Pins" id="LMZ-oe-Ngh">
- <modifierMask key="keyEquivalentModifierMask"/>
+ <menuItem title="Blanket Map With Pins" keyEquivalent="." id="LMZ-oe-Ngh">
+ <modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
<connections>
<action selector="dropManyPins:" target="-1" id="Rtv-8N-3Z8"/>
</connections>
</menuItem>
- <menuItem title="Add Polygon and Polyline" id="DVr-vT-lpe">
- <modifierMask key="keyEquivalentModifierMask"/>
+ <menuItem title="Add Polygon and Polyline" keyEquivalent="l" id="DVr-vT-lpe">
<connections>
<action selector="drawPolygonAndPolyLineAnnotations:" target="-1" id="EhT-CB-gee"/>
</connections>
</menuItem>
- <menuItem title="Remove All Annotations" id="6rC-68-vk0">
+ <menuItem title="Add Animated Annotation" id="Etf-JN-Aoc">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
+ <action selector="drawAnimatedAnnotation:" target="-1" id="CYM-WB-s97"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Show All Annnotations" keyEquivalent="A" id="yMj-uM-8SN">
+ <modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
+ <connections>
+ <action selector="showAllAnnotations:" target="-1" id="ahr-OR-Em2"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Remove All Annotations" id="6rC-68-vk0">
+ <string key="keyEquivalent" base64-UTF8="YES">
+CA
+</string>
+ <connections>
<action selector="removeAllAnnotations:" target="-1" id="6v3-0E-LsR"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="wQq-Mx-QY0"/>
<menuItem title="Start World Tour" id="VFo-Jh-2sw">
- <modifierMask key="keyEquivalentModifierMask"/>
+ <modifierMask key="keyEquivalentModifierMask" option="YES"/>
<connections>
<action selector="startWorldTour:" target="-1" id="66Y-Gm-Yn1"/>
</connections>
@@ -711,13 +718,13 @@
</connections>
</tableColumn>
<tableColumn editable="NO" width="50" minWidth="40" maxWidth="1000" id="pkI-c7-xoD">
- <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Downloaded">
+ <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Downloaded Resources">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Text Cell" id="WfC-qb-HsW">
- <numberFormatter key="formatter" formatterBehavior="default10_4" numberStyle="decimal" usesGroupingSeparator="NO" groupingSize="0" minimumIntegerDigits="0" maximumIntegerDigits="42" id="sNm-Qn-ne6"/>
+ <numberFormatter key="formatter" formatterBehavior="default10_4" numberStyle="decimal" minimumIntegerDigits="1" maximumIntegerDigits="2000000000" id="sNm-Qn-ne6"/>
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
@@ -728,13 +735,13 @@
</connections>
</tableColumn>
<tableColumn identifier="" editable="NO" width="50" minWidth="10" maxWidth="3.4028234663852886e+38" id="Rrd-A9-jqc">
- <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="Total">
+ <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="Total Resources">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" alignment="left" title="Text Cell" id="mHy-qJ-rOA">
- <numberFormatter key="formatter" formatterBehavior="default10_4" numberStyle="decimal" usesGroupingSeparator="NO" groupingSize="0" minimumIntegerDigits="0" maximumIntegerDigits="42" id="kyx-ZP-OBH"/>
+ <numberFormatter key="formatter" formatterBehavior="default10_4" numberStyle="decimal" minimumIntegerDigits="1" maximumIntegerDigits="2000000000" id="kyx-ZP-OBH"/>
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
@@ -744,14 +751,56 @@
<binding destination="dWe-R6-sRz" name="value" keyPath="arrangedObjects.countOfResourcesExpected" id="mh2-k0-vvB"/>
</connections>
</tableColumn>
+ <tableColumn editable="NO" width="50" minWidth="40" maxWidth="1000" id="kCO-Cd-bQt">
+ <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Downloaded Tiles">
+ <font key="font" metaFont="smallSystem"/>
+ <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
+ </tableHeaderCell>
+ <textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Text Cell" id="hUl-2C-sHr">
+ <numberFormatter key="formatter" formatterBehavior="default10_4" numberStyle="decimal" minimumIntegerDigits="1" maximumIntegerDigits="2000000000" id="KjY-J1-gSm"/>
+ <font key="font" metaFont="system"/>
+ <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ <tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
+ <connections>
+ <binding destination="dWe-R6-sRz" name="value" keyPath="arrangedObjects.countOfTilesCompleted" id="XHn-D7-zqf">
+ <dictionary key="options">
+ <bool key="NSConditionallySetsEditable" value="YES"/>
+ </dictionary>
+ </binding>
+ </connections>
+ </tableColumn>
+ <tableColumn editable="NO" width="60" minWidth="10" maxWidth="3.4028234663852886e+38" id="WO5-Ci-HgG">
+ <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="Downloaded Tiles Size">
+ <font key="font" metaFont="smallSystem"/>
+ <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
+ </tableHeaderCell>
+ <textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" alignment="left" title="Text Cell" id="cKy-kF-5Pv">
+ <byteCountFormatter key="formatter" allowsNonnumericFormatting="NO" includesActualByteCount="YES" id="bHS-Ch-aXU"/>
+ <font key="font" metaFont="system"/>
+ <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ <tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
+ <connections>
+ <binding destination="dWe-R6-sRz" name="value" keyPath="arrangedObjects.countOfTileBytesCompleted" id="Xpk-BZ-Xcr">
+ <dictionary key="options">
+ <bool key="NSConditionallySetsEditable" value="YES"/>
+ </dictionary>
+ </binding>
+ </connections>
+ </tableColumn>
<tableColumn identifier="" editable="NO" width="60" minWidth="10" maxWidth="3.4028234663852886e+38" id="h7m-6l-KaS">
- <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="Size">
+ <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="Downloaded Resources Size">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" alignment="left" title="Text Cell" id="701-bg-k6L">
- <byteCountFormatter key="formatter" allowsNonnumericFormatting="NO" id="IXV-J9-sP3"/>
+ <byteCountFormatter key="formatter" allowsNonnumericFormatting="NO" includesActualByteCount="YES" id="IXV-J9-sP3"/>
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
@@ -767,10 +816,9 @@
</connections>
</tableView>
</subviews>
- <color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</clipView>
- <scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="QLr-6P-Ogs">
- <rect key="frame" x="1" y="7" width="0.0" height="16"/>
+ <scroller key="horizontalScroller" verticalHuggingPriority="750" horizontal="YES" id="QLr-6P-Ogs">
+ <rect key="frame" x="1" y="264" width="400" height="16"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="NO" id="q0K-eE-mzL">
@@ -778,7 +826,7 @@
<autoresizingMask key="autoresizingMask"/>
</scroller>
<tableHeaderView key="headerView" id="MAZ-Iq-hBi">
- <rect key="frame" x="0.0" y="0.0" width="400" height="23"/>
+ <rect key="frame" x="0.0" y="0.0" width="423" height="23"/>
<autoresizingMask key="autoresizingMask"/>
</tableHeaderView>
</scrollView>
@@ -832,6 +880,8 @@ CA
<string>context</string>
<string>countOfResourcesCompleted</string>
<string>countOfResourcesExpected</string>
+ <string>countOfTilesCompleted</string>
+ <string>countOfTileBytesCompleted</string>
<string>countOfBytesCompleted</string>
<string>stateImage</string>
</declaredKeys>
diff --git a/platform/macos/app/MapDocument.m b/platform/macos/app/MapDocument.m
index 1b920a029b..81fd85e156 100644
--- a/platform/macos/app/MapDocument.m
+++ b/platform/macos/app/MapDocument.m
@@ -65,6 +65,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
BOOL _randomizesCursorsOnDroppedPins;
BOOL _isTouringWorld;
BOOL _isShowingPolygonAndPolylineAnnotations;
+ BOOL _isShowingAnimatedAnnotation;
}
#pragma mark Lifecycle
@@ -180,7 +181,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
- (IBAction)chooseCustomStyle:(id)sender {
NSAlert *alert = [[NSAlert alloc] init];
alert.messageText = @"Apply custom style";
- alert.informativeText = @"Enter the URL to a JSON file that conforms to the Mapbox GL style specification, such as a style designed in Mapbox Studio:";
+ alert.informativeText = @"Enter the URL to a JSON file that conforms to the Mapbox Style Specification, such as a style designed in Mapbox Studio:";
NSTextField *textField = [[NSTextField alloc] initWithFrame:NSZeroRect];
[textField sizeToFit];
NSRect textFieldFrame = textField.frame;
@@ -307,7 +308,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
}
}
- [NSTimer scheduledTimerWithTimeInterval:1/60
+ [NSTimer scheduledTimerWithTimeInterval:1.0/60.0
target:self
selector:@selector(dropOneOfManyPins:)
userInfo:annotations
@@ -329,9 +330,14 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
}
}
+- (IBAction)showAllAnnotations:(id)sender {
+ [self.mapView showAnnotations:self.mapView.annotations animated:YES];
+}
+
- (IBAction)removeAllAnnotations:(id)sender {
[self.mapView removeAnnotations:self.mapView.annotations];
_isShowingPolygonAndPolylineAnnotations = NO;
+ _isShowingAnimatedAnnotation = NO;
}
- (IBAction)startWorldTour:(id)sender {
@@ -405,6 +411,27 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
[self.mapView addAnnotation:line];
}
+- (IBAction)drawAnimatedAnnotation:(id)sender {
+ DroppedPinAnnotation *annotation = [[DroppedPinAnnotation alloc] init];
+ [self.mapView addAnnotation:annotation];
+
+ _isShowingAnimatedAnnotation = YES;
+
+ [NSTimer scheduledTimerWithTimeInterval:1.0/60.0
+ target:self
+ selector:@selector(updateAnimatedAnnotation:)
+ userInfo:annotation
+ repeats:YES];
+}
+
+- (void)updateAnimatedAnnotation:(NSTimer *)timer {
+ DroppedPinAnnotation *annotation = timer.userInfo;
+ double angle = timer.fireDate.timeIntervalSinceReferenceDate;
+ annotation.coordinate = CLLocationCoordinate2DMake(
+ sin(angle) * 20,
+ cos(angle) * 20);
+}
+
#pragma mark Offline packs
- (IBAction)addOfflinePack:(id)sender {
@@ -613,7 +640,13 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
if (menuItem.action == @selector(dropManyPins:)) {
return YES;
}
- if (menuItem.action == @selector(removeAllAnnotations:)) {
+ if (menuItem.action == @selector(drawPolygonAndPolyLineAnnotations:)) {
+ return !_isShowingPolygonAndPolylineAnnotations;
+ }
+ if (menuItem.action == @selector(drawAnimatedAnnotation:)) {
+ return !_isShowingAnimatedAnnotation;
+ }
+ if (menuItem.action == @selector(showAllAnnotations:) || menuItem.action == @selector(removeAllAnnotations:)) {
return self.mapView.annotations.count > 0;
}
if (menuItem.action == @selector(startWorldTour:)) {
@@ -622,9 +655,6 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
if (menuItem.action == @selector(stopWorldTour:)) {
return _isTouringWorld;
}
- if (menuItem.action == @selector(drawPolygonAndPolyLineAnnotations:)) {
- return !_isShowingPolygonAndPolylineAnnotations;
- }
if (menuItem.action == @selector(addOfflinePack:)) {
NSURL *styleURL = self.mapView.styleURL;
return !styleURL.isFileURL;
diff --git a/platform/macos/app/wms.json b/platform/macos/app/wms.json
new file mode 100644
index 0000000000..e5fb236259
--- /dev/null
+++ b/platform/macos/app/wms.json
@@ -0,0 +1,21 @@
+{
+ "version": 8,
+ "name": "WMS Test",
+ "sources": {
+ "wms-test": {
+ "type": "raster",
+ "tiles": [
+ "https://geodata.state.nj.us/imagerywms/Natural2015?bbox={bbox-epsg-3857}&format=image/png&service=WMS&version=1.1.1&request=GetMap&srs=EPSG:3857&width=256&height=256&layers=Natural2015"
+ ],
+ "tileSize": 256
+ }
+ },
+ "layers": [{
+ "id": "wms-test-layer",
+ "type": "raster",
+ "source": "wms-test",
+ "paint": {
+ "raster-fade-duration": 100
+ }
+ }]
+}
diff --git a/platform/macos/docs/doc-README.md b/platform/macos/docs/doc-README.md
index 58dc6001df..4aba26afd9 100644
--- a/platform/macos/docs/doc-README.md
+++ b/platform/macos/docs/doc-README.md
@@ -1,6 +1,6 @@
# [Mapbox macOS SDK](https://github.com/mapbox/mapbox-gl-native/tree/master/platform/macos/)
-The Mapbox macOS SDK is an open-source framework for embedding interactive map views with scalable, customizable vector maps into Cocoa applications on macOS 10.10.0 and above using Objective-C, Swift, or Interface Builder. It takes stylesheets that conform to the [Mapbox GL Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/), applies them to vector tiles that conform to the [Mapbox Vector Tile Specification](https://www.mapbox.com/developers/vector-tiles/), and renders them using OpenGL.
+The Mapbox macOS SDK is an open-source framework for embedding interactive map views with scalable, customizable vector maps into Cocoa applications on macOS 10.10.0 and above using Objective-C, Swift, or Interface Builder. It takes stylesheets that conform to the [Mapbox Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/), applies them to vector tiles that conform to the [Mapbox Vector Tile Specification](https://www.mapbox.com/developers/vector-tiles/), and renders them using OpenGL.
<img alt="Mapbox macOS SDK screenshot" src="screenshot.png" width="645">
diff --git a/platform/macos/docs/pod-README.md b/platform/macos/docs/pod-README.md
index 70d98ecdb9..b86ccfb897 100644
--- a/platform/macos/docs/pod-README.md
+++ b/platform/macos/docs/pod-README.md
@@ -1,6 +1,6 @@
# [Mapbox macOS SDK](https://github.com/mapbox/mapbox-gl-native/tree/master/platform/macos/)
-The Mapbox macOS SDK is an open-source framework for embedding interactive map views with scalable, customizable vector maps into Cocoa applications on macOS 10.10.0 and above using Objective-C, Swift, or Interface Builder. It takes stylesheets that conform to the [Mapbox GL Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/), applies them to vector tiles that conform to the [Mapbox Vector Tile Specification](https://www.mapbox.com/developers/vector-tiles/), and renders them using OpenGL.
+The Mapbox macOS SDK is an open-source framework for embedding interactive map views with scalable, customizable vector maps into Cocoa applications on macOS 10.10.0 and above using Objective-C, Swift, or Interface Builder. It takes stylesheets that conform to the [Mapbox Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/), applies them to vector tiles that conform to the [Mapbox Vector Tile Specification](https://www.mapbox.com/developers/vector-tiles/), and renders them using OpenGL.
<img alt="" src="https://raw.githubusercontent.com/mapbox/mapbox-gl-native/master/platform/macos/screenshot.png" width="645">
diff --git a/platform/macos/macos.xcodeproj/project.pbxproj b/platform/macos/macos.xcodeproj/project.pbxproj
index 7271356f2a..ed980294a9 100644
--- a/platform/macos/macos.xcodeproj/project.pbxproj
+++ b/platform/macos/macos.xcodeproj/project.pbxproj
@@ -20,6 +20,7 @@
DA35A2C21CCA9F4A00E826B2 /* MGLClockDirectionFormatterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DA35A2C11CCA9F4A00E826B2 /* MGLClockDirectionFormatterTests.m */; };
DA35A2CF1CCAAED300E826B2 /* NSValue+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = DA35A2CD1CCAAED300E826B2 /* NSValue+MGLAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; };
DA35A2D01CCAAED300E826B2 /* NSValue+MGLAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = DA35A2CE1CCAAED300E826B2 /* NSValue+MGLAdditions.m */; };
+ DA5589771D320C41006B7F64 /* wms.json in Resources */ = {isa = PBXBuildFile; fileRef = DA5589761D320C41006B7F64 /* wms.json */; };
DA839E971CC2E3400062CAFB /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DA839E961CC2E3400062CAFB /* AppDelegate.m */; };
DA839E9A1CC2E3400062CAFB /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DA839E991CC2E3400062CAFB /* main.m */; };
DA839E9D1CC2E3400062CAFB /* MapDocument.m in Sources */ = {isa = PBXBuildFile; fileRef = DA839E9C1CC2E3400062CAFB /* MapDocument.m */; };
@@ -159,6 +160,7 @@
DA35A2C11CCA9F4A00E826B2 /* MGLClockDirectionFormatterTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLClockDirectionFormatterTests.m; path = ../../darwin/test/MGLClockDirectionFormatterTests.m; sourceTree = "<group>"; };
DA35A2CD1CCAAED300E826B2 /* NSValue+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSValue+MGLAdditions.h"; sourceTree = "<group>"; };
DA35A2CE1CCAAED300E826B2 /* NSValue+MGLAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSValue+MGLAdditions.m"; sourceTree = "<group>"; };
+ DA5589761D320C41006B7F64 /* wms.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = wms.json; sourceTree = "<group>"; };
DA839E921CC2E3400062CAFB /* Mapbox GL.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Mapbox GL.app"; sourceTree = BUILT_PRODUCTS_DIR; };
DA839E951CC2E3400062CAFB /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
DA839E961CC2E3400062CAFB /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
@@ -334,6 +336,7 @@
DAE6C2EC1CC3050F00DB3429 /* TimeIntervalTransformer.m */,
DA839EA11CC2E3400062CAFB /* Assets.xcassets */,
DA839EA31CC2E3400062CAFB /* MainMenu.xib */,
+ DA5589761D320C41006B7F64 /* wms.json */,
DAE6C2E11CC304F900DB3429 /* Credits.rtf */,
DA839EA61CC2E3400062CAFB /* Info.plist */,
DA839E981CC2E3400062CAFB /* Supporting Files */,
@@ -721,6 +724,7 @@
DA839EA21CC2E3400062CAFB /* Assets.xcassets in Resources */,
DA839EA01CC2E3400062CAFB /* MapDocument.xib in Resources */,
DA839EA51CC2E3400062CAFB /* MainMenu.xib in Resources */,
+ DA5589771D320C41006B7F64 /* wms.json in Resources */,
DAE6C2E21CC304F900DB3429 /* Credits.rtf in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -1035,11 +1039,12 @@
"$(rapidjson_cflags)",
"$(variant_cflags)",
"$(geometry_cflags)",
+ "$(geojson_cflags)",
);
OTHER_LDFLAGS = (
"$(zlib_ldflags)",
"$(opengl_ldflags)",
- "$(geojsonvt_static_libs)",
+ "$(geojson_static_libs)",
);
PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.MapboxGL;
PRODUCT_NAME = Mapbox;
@@ -1074,11 +1079,12 @@
"$(rapidjson_cflags)",
"$(variant_cflags)",
"$(geometry_cflags)",
+ "$(geojson_cflags)",
);
OTHER_LDFLAGS = (
"$(zlib_ldflags)",
"$(opengl_ldflags)",
- "$(geojsonvt_static_libs)",
+ "$(geojson_static_libs)",
);
PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.MapboxGL;
PRODUCT_NAME = Mapbox;
@@ -1100,6 +1106,7 @@
"$(OTHER_CFLAGS)",
"$(variant_cflags)",
"$(geometry_cflags)",
+ "$(geojson_cflags)",
);
PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.test;
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -1118,6 +1125,7 @@
"$(OTHER_CFLAGS)",
"$(variant_cflags)",
"$(geometry_cflags)",
+ "$(geojson_cflags)",
);
PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.test;
PRODUCT_NAME = "$(TARGET_NAME)";
diff --git a/platform/macos/macos.xcworkspace/xcshareddata/xcschemes/test.xcscheme b/platform/macos/macos.xcworkspace/xcshareddata/xcschemes/test.xcscheme
index 20394eb258..bc8a3350f1 100644
--- a/platform/macos/macos.xcworkspace/xcshareddata/xcschemes/test.xcscheme
+++ b/platform/macos/macos.xcworkspace/xcshareddata/xcschemes/test.xcscheme
@@ -62,6 +62,12 @@
ReferencedContainer = "container:../../build/macos/platform/macos/platform.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
+ <CommandLineArguments>
+ <CommandLineArgument
+ argument = "--gtest_filter="
+ isEnabled = "NO">
+ </CommandLineArgument>
+ </CommandLineArguments>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
diff --git a/platform/macos/scripts/configure.sh b/platform/macos/scripts/configure.sh
index 2952ec2535..d408eef7e4 100644
--- a/platform/macos/scripts/configure.sh
+++ b/platform/macos/scripts/configure.sh
@@ -8,8 +8,11 @@ GLFW_VERSION=3.1.2
SQLITE_VERSION=3.9.1
ZLIB_VERSION=system
NUNICODE_VERSION=1.6
-GEOMETRY_VERSION=0.5.0
-GEOJSONVT_VERSION=4.1.2
+GEOMETRY_VERSION=0.8.0
+GEOJSON_VERSION=0.1.4
+GEOJSONVT_VERSION=6.1.2
+SUPERCLUSTER_VERSION=0.2.0
+KDBUSH_VERSION=0.1.1
VARIANT_VERSION=1.1.0
RAPIDJSON_VERSION=1.0.2
GTEST_VERSION=1.7.0
diff --git a/platform/macos/scripts/deploy-packages.sh b/platform/macos/scripts/deploy-packages.sh
new file mode 100755
index 0000000000..c137401748
--- /dev/null
+++ b/platform/macos/scripts/deploy-packages.sh
@@ -0,0 +1,83 @@
+#!/usr/bin/env bash
+
+set -e
+set -o pipefail
+set -u
+
+usage() {
+cat <<EOF
+# Usage: sh $0 version target_directory [argument]
+
+# version: The semver version plus optional alpha beta distinction (i.e. {major.minor.patch}{-alpha.N})
+# target_directory: The directory where build output should be placed
+
+# argument:
+# -g: Upload to github
+
+# environment variables and dependencies:
+# - You must run "mbx auth ..." before running
+# - Set GITHUB_TOKEN to a GitHub API access token in your environment to use GITHUB_RELEASE
+# - "wget" is required for downloading the zip files from s3
+# - The "github-release" gem is required to use GITHUB_RELEASE
+EOF
+}
+
+buildPackageStyle() {
+ local package=$1 style=""
+ if [[ ${#} -eq 2 ]]; then
+ style="$2"
+ fi
+ echo "make ${package} ${style}"
+ make ${package}
+ echo "publish ${package} with ${style}"
+ local file_name=""
+ if [ -z ${style} ]
+ then
+ file_name=mapbox-macos-sdk-${PUBLISH_VERSION}.zip
+ else
+ file_name=mapbox-macos-sdk-${PUBLISH_VERSION}-${style}.zip
+ fi
+ echo "compress ${file_name}"
+ cd build/macos/pkg
+ rm -f ../${file_name}
+ zip -r ../${file_name} *
+ cd -
+ if [[ "${GITHUB_RELEASE}" == true ]]; then
+ echo "publish ${file_name} to GitHub"
+ github-release --verbose upload --tag "macos-v${PUBLISH_VERSION}" --name ${file_name} --file "build/macos/${file_name}"
+ fi
+}
+
+if [ ${#} -eq 0 -o ${#} -gt 3 ]; then
+ usage
+ exit 1
+fi
+
+export TRAVIS_REPO_SLUG=mapbox-gl-native
+export PUBLISH_VERSION=$1
+export GITHUB_USER=mapbox
+export GITHUB_REPO=mapbox-gl-native
+export BUILDTYPE=Release
+
+BINARY_DIRECTORY=$2
+PUBLISH_PRE_FLAG=''
+GITHUB_RELEASE=false
+
+echo "Deploying version ${PUBLISH_VERSION}..."
+
+if [[ ${#} -eq 3 && $3 == "-g" ]]; then
+ GITHUB_RELEASE=true
+fi
+
+make clean && make distclean
+
+if [[ "${GITHUB_RELEASE}" == true ]]; then
+ echo "Create GitHub release..."
+ if [[ $( echo ${PUBLISH_VERSION} | awk '/[0-9]-/' ) ]]; then
+ PUBLISH_PRE_FLAG='--pre-release'
+ fi
+ github-release --verbose release --tag "macos-v${PUBLISH_VERSION}" --name "macos-v${PUBLISH_VERSION}" --draft ${PUBLISH_PRE_FLAG}
+fi
+
+buildPackageStyle "xpackage" "symbols"
+buildPackageStyle "xpackage SYMBOLS=NO"
diff --git a/platform/macos/scripts/package.sh b/platform/macos/scripts/package.sh
index a6952e8ab2..c2a015b346 100755
--- a/platform/macos/scripts/package.sh
+++ b/platform/macos/scripts/package.sh
@@ -38,7 +38,7 @@ xcodebuild \
step "Copying dynamic framework into place"
mkdir -p "${OUTPUT}/${NAME}.framework"
-cp -r ${PRODUCTS}/${BUILDTYPE}/${NAME}.framework/* "${OUTPUT}/${NAME}.framework"
+ditto ${PRODUCTS}/${BUILDTYPE}/${NAME}.framework "${OUTPUT}/${NAME}.framework"
if [[ -e ${PRODUCTS}/${BUILDTYPE}/${NAME}.framework.dSYM ]]; then
cp -r ${PRODUCTS}/${BUILDTYPE}/${NAME}.framework.dSYM "${OUTPUT}"
fi
diff --git a/platform/macos/src/MGLMapView.h b/platform/macos/src/MGLMapView.h
index 8f1fa40137..7c464fe83a 100644
--- a/platform/macos/src/MGLMapView.h
+++ b/platform/macos/src/MGLMapView.h
@@ -23,10 +23,13 @@ typedef NS_OPTIONS(NSUInteger, MGLMapDebugMaskOptions) {
/** Each drawing operation is replaced by a translucent fill. Overlapping
drawing operations appear more prominent to help diagnose overdrawing.
+ @note This option does nothing in Release builds of the SDK.
*/
MGLMapDebugOverdrawVisualizationMask = 1 << 5,
- /** The stencil buffer is shown instead of the color buffer. */
+ /** The stencil buffer is shown instead of the color buffer.
+ @note This option does nothing in Release builds of the SDK.
+ */
MGLMapDebugStencilBufferMask = 1 << 6,
};
@@ -49,7 +52,7 @@ typedef NS_OPTIONS(NSUInteger, MGLMapDebugMaskOptions) {
The map view loads scalable vector tiles that conform to the
<a href="https://github.com/mapbox/vector-tile-spec">Mapbox Vector Tile Specification</a>.
It styles them with a style that conforms to the
- <a href="https://www.mapbox.com/mapbox-gl-style-spec/">Mapbox GL style specification</a>.
+ <a href="https://www.mapbox.com/mapbox-gl-style-spec/">Mapbox Style Specification</a>.
Such styles can be designed in
<a href="https://www.mapbox.com/studio/">Mapbox Studio</a> and hosted on
mapbox.com.
@@ -384,6 +387,35 @@ IB_DESIGNABLE
- (void)setVisibleCoordinateBounds:(MGLCoordinateBounds)bounds edgePadding:(NSEdgeInsets)insets animated:(BOOL)animated;
/**
+ Sets the visible region so that the map displays the specified annotations.
+
+ Calling this method updates the value in the `visibleCoordinateBounds` property
+ and potentially other properties to reflect the new map region. A small amount
+ of padding is reserved around the edges of the map view. To specify a different
+ amount of padding, use the `-showAnnotations:edgePadding:animated:` method.
+
+ @param annotations The annotations that you want to be visible in the map.
+ @param animated `YES` if you want the map region change to be animated, or `NO`
+ if you want the map to display the new region immediately without animations.
+ */
+- (void)showAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations animated:(BOOL)animated;
+
+/**
+ Sets the visible region so that the map displays the specified annotations with
+ the specified amount of padding on each side.
+
+ Calling this method updates the value in the `visibleCoordinateBounds` property
+ and potentially other properties to reflect the new map region.
+
+ @param annotations The annotations that you want to be visible in the map.
+ @param insets The minimum padding (in screen points) around the edges of the
+ map view to keep clear of annotations.
+ @param animated `YES` if you want the map region change to be animated, or `NO`
+ if you want the map to display the new region immediately without animations.
+ */
+- (void)showAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations edgePadding:(NSEdgeInsets)insets animated:(BOOL)animated;
+
+/**
Returns the camera that best fits the given coordinate bounds.
@param bounds The coordinate bounds to fit to the receiver’s viewport.
diff --git a/platform/macos/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm
index e02a878bb1..7b0aad1db9 100644
--- a/platform/macos/src/MGLMapView.mm
+++ b/platform/macos/src/MGLMapView.mm
@@ -126,11 +126,11 @@ mbgl::util::UnitBezier MGLUnitBezierForMediaTimingFunction(CAMediaTimingFunction
/// Converts the given color into an mbgl::Color in calibrated RGB space.
mbgl::Color MGLColorObjectFromNSColor(NSColor *color) {
if (!color) {
- return {{ 0, 0, 0, 0 }};
+ return { 0, 0, 0, 0 };
}
CGFloat r, g, b, a;
[[color colorUsingColorSpaceName:NSCalibratedRGBColorSpace] getRed:&r green:&g blue:&b alpha:&a];
- return {{ (float)r, (float)g, (float)b, (float)a }};
+ return { (float)r, (float)g, (float)b, (float)a };
}
/// Lightweight container for metadata about an annotation, including the annotation itself.
@@ -395,6 +395,10 @@ public:
clickGestureRecognizer.delaysPrimaryMouseButtonEvents = NO;
[self addGestureRecognizer:clickGestureRecognizer];
+ NSClickGestureRecognizer *rightClickGestureRecognizer = [[NSClickGestureRecognizer alloc] initWithTarget:self action:@selector(handleRightClickGesture:)];
+ rightClickGestureRecognizer.buttonMask = 0x2;
+ [self addGestureRecognizer:rightClickGestureRecognizer];
+
NSClickGestureRecognizer *doubleClickGestureRecognizer = [[NSClickGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleClickGesture:)];
doubleClickGestureRecognizer.numberOfClicksRequired = 2;
doubleClickGestureRecognizer.delaysPrimaryMouseButtonEvents = NO;
@@ -1037,8 +1041,8 @@ public:
mbgl::CameraOptions cameraOptions = [self cameraOptionsObjectForAnimatingToCamera:camera];
mbgl::AnimationOptions animationOptions;
if (duration > 0) {
- animationOptions.duration = MGLDurationInSeconds(duration);
- animationOptions.easing = MGLUnitBezierForMediaTimingFunction(function);
+ animationOptions.duration.emplace(MGLDurationInSeconds(duration));
+ animationOptions.easing.emplace(MGLUnitBezierForMediaTimingFunction(function));
}
if (completion) {
animationOptions.transitionFinishFn = [completion]() {
@@ -1359,6 +1363,14 @@ public:
}
}
+/// Right-click to show the context menu.
+- (void)handleRightClickGesture:(NSClickGestureRecognizer *)gestureRecognizer {
+ NSMenu *menu = [self menuForEvent:[NSApp currentEvent]];
+ if (menu) {
+ [NSMenu popUpContextMenu:menu withEvent:[NSApp currentEvent] forView:self];
+ }
+}
+
/// Double-click or double-tap to zoom in.
- (void)handleDoubleClickGesture:(NSClickGestureRecognizer *)gestureRecognizer {
if (!self.zoomEnabled || gestureRecognizer.state != NSGestureRecognizerStateEnded
@@ -1986,6 +1998,38 @@ public:
}
}
+- (void)showAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations animated:(BOOL)animated {
+ CGFloat maximumPadding = 100;
+ CGFloat yPadding = (NSHeight(self.bounds) / 5 <= maximumPadding) ? (NSHeight(self.bounds) / 5) : maximumPadding;
+ CGFloat xPadding = (NSWidth(self.bounds) / 5 <= maximumPadding) ? (NSWidth(self.bounds) / 5) : maximumPadding;
+
+ NSEdgeInsets edgeInsets = NSEdgeInsetsMake(yPadding, xPadding, yPadding, xPadding);
+
+ [self showAnnotations:annotations edgePadding:edgeInsets animated:animated];
+}
+
+- (void)showAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations edgePadding:(NSEdgeInsets)insets animated:(BOOL)animated {
+ if ( ! annotations || ! annotations.count) return;
+
+ mbgl::LatLngBounds bounds = mbgl::LatLngBounds::empty();
+
+ for (id <MGLAnnotation> annotation in annotations)
+ {
+ if ([annotation conformsToProtocol:@protocol(MGLOverlay)])
+ {
+ bounds.extend(MGLLatLngBoundsFromCoordinateBounds(((id <MGLOverlay>)annotation).overlayBounds));
+ }
+ else
+ {
+ bounds.extend(MGLLatLngFromLocationCoordinate2D(annotation.coordinate));
+ }
+ }
+
+ [self setVisibleCoordinateBounds:MGLCoordinateBoundsFromLatLngBounds(bounds)
+ edgePadding:insets
+ animated:animated];
+}
+
/// Returns a popover detailing the annotation.
- (NSPopover *)calloutForAnnotation:(id <MGLAnnotation>)annotation {
NSPopover *callout = [[NSPopover alloc] init];
@@ -2398,7 +2442,7 @@ public:
if (options & mbgl::MapDebugOptions::Collision) {
mask |= MGLMapDebugCollisionBoxesMask;
}
- if (options & mbgl::MapDebugOptions::Wireframe) {
+ if (options & mbgl::MapDebugOptions::Overdraw) {
mask |= MGLMapDebugOverdrawVisualizationMask;
}
if (options & mbgl::MapDebugOptions::StencilClip) {
@@ -2422,7 +2466,7 @@ public:
options |= mbgl::MapDebugOptions::Collision;
}
if (debugMask & MGLMapDebugOverdrawVisualizationMask) {
- options |= mbgl::MapDebugOptions::Wireframe;
+ options |= mbgl::MapDebugOptions::Overdraw;
}
if (debugMask & MGLMapDebugStencilBufferMask) {
options |= mbgl::MapDebugOptions::StencilClip;
diff --git a/platform/node/CHANGELOG.md b/platform/node/CHANGELOG.md
index e1bff6cc28..e08c2fbc3f 100644
--- a/platform/node/CHANGELOG.md
+++ b/platform/node/CHANGELOG.md
@@ -1,25 +1,41 @@
-# 3.2.1
+# 3.3.2 - August 1, 2016
+
+- Fixes Node.js binary publishing to build with `BUILDTYPE=Release` ([#5838](https://github.com/mapbox/mapbox-gl-native/pull/5838))
+
+# 3.3.1 - July 29, 2016
+
+- Fixes `minzoom` and `maxzoom` properties ([#5828](https://github.com/mapbox/mapbox-gl-native/pull/5828))
+- Fixes `RunLoop::runOnce()` to use `UV_RUN_NOWAIT` instead of `UV_RUN_ONCE` (which can block the libuv threadpool) ([#5758](https://github.com/mapbox/mapbox-gl-native/pull/5758))
+- Map debug options 'overdraw' and 'stencil clip' are now disabled (no-ops) in release mode ([#5555](https://github.com/mapbox/mapbox-gl-native/pull/5555))
+
+# 3.3.0 - July 14, 2016
+
+- Adds runtime styling API ([#5318](https://github.com/mapbox/mapbox-gl-native/pull/5318), [#5380](https://github.com/mapbox/mapbox-gl-native/pull/5380), [#5428](https://github.com/mapbox/mapbox-gl-native/pull/5428), [#5429](https://github.com/mapbox/mapbox-gl-native/pull/5429), [#5462](https://github.com/mapbox/mapbox-gl-native/pull/5462), [#5614](https://github.com/mapbox/mapbox-gl-native/pull/5614), [#5670](https://github.com/mapbox/mapbox-gl-native/pull/5670))
+- Adds `BUILDTYPE=Debug` support to `make node` ([#5474](https://github.com/mapbox/mapbox-gl-native/pull/5474))
+- Fixes a memory leak in `NodeRequest` ([#5529](https://github.com/mapbox/mapbox-gl-native/pull/5529))
+
+# 3.2.1 - June 7, 2016
- Fixes a memory leak in raster image data ([#5269](https://github.com/mapbox/mapbox-gl-native/pull/5269))
-# 3.2.0
+# 3.2.0 - June 3, 2016
- Switches to [earcut.hpp](https://github.com/mapbox/earcut.hpp) for tessellation ([#2444](https://github.com/mapbox/mapbox-gl-native/pull/2444))
-# 3.1.3
+# 3.1.3 - May 27, 2016
- Fixes a leak in TexturePoolHolder ([#5141](https://github.com/mapbox/mapbox-gl-native/pull/5141))
- Fixes a bug where a callback would be fired after an AsyncRequest had been cancelled ([#5162](https://github.com/mapbox/mapbox-gl-native/pull/5162))
-# 3.1.2
+# 3.1.2 - April 26, 2016
- Fixes a race condition with animated transitions ([#4836](https://github.com/mapbox/mapbox-gl-native/pull/4836))
-# 3.1.1
+# 3.1.1 - April 11, 2016
- Moves node-pre-gyp from `bundledDependencies` to `preinstall` ([#4680](https://github.com/mapbox/mapbox-gl-native/pull/4680))
-# 3.1.0
+# 3.1.0 - April 8, 2016
- Adds debug render options ([#3840](https://github.com/mapbox/mapbox-gl-native/pull/3840))
- Fixes circle bucket rendering on tile boundaries ([#3764](https://github.com/mapbox/mapbox-gl-native/issues/3764))
@@ -29,45 +45,44 @@
- Fixes intermittent `stencil mask overflow` error ([#962](https://github.com/mapbox/mapbox-gl-native/issues/962))
- Drops support for Node.js v5.x prebuilt binaries due to ongoing npm3 instability ([#4370](https://github.com/mapbox/mapbox-gl-native/issues/4370))
-# 3.0.2
+# 3.0.2 - February 4, 2016
- Fixes a memory leak in `NodeMap::request` ([#3829](https://github.com/mapbox/mapbox-gl-native/pull/3829))
- Increases default max zoom level from 18 to 20 ([#3712](https://github.com/mapbox/mapbox-gl-native/pull/3712))
- Support tiles with non-4096 extents ([#3766](https://github.com/mapbox/mapbox-gl-native/pull/3766))
-# 3.0.1
+# 3.0.1 - January 26, 2016
- Fixes missing icon collision boxes ([#3672](https://github.com/mapbox/mapbox-gl-native/pull/3672))
- Fixes texture filtering to draw sharper icons ([#3669](https://github.com/mapbox/mapbox-gl-native/pull/3669))
-
-# 3.0.0
+# 3.0.0 - January 21, 2016
- Drops support for Node.js v0.10.x ([#3635](https://github.com/mapbox/mapbox-gl-native/pull/3635))
- Fixes label clipping issues with `symbol-avoid-edges` ([#3623](https://github.com/mapbox/mapbox-gl-native/pull/3623))
- Avoids label placement around sharp zig-zags ([#3640](https://github.com/mapbox/mapbox-gl-native/pull/3640))
-# 2.2.2
+# 2.2.2 - January 19, 2016
- Fixes a bug with non-deterministic label placement [#3543](https://github.com/mapbox/mapbox-gl-native/pull/3543)
-# 2.2.1
+# 2.2.1 - January 7, 2016
- Fixes a bug which clipped labels at tile boundaries [#2829](https://github.com/mapbox/mapbox-gl-native/pull/2829)
-# 2.2.0
+# 2.2.0 - December 16, 2015
- Adds support for GeoJSON sources [#2161](https://github.com/mapbox/mapbox-gl-native/pull/2161)
-# 2.1.0
+# 2.1.0 - December 8, 2015
- Adds [`line-offset`](https://github.com/mapbox/mapbox-gl/issues/3) style property support
-# 2.0.1
+# 2.0.1 - November 25, 2015
- Test and publish binaries for Node.js v5.x. ([#3129](https://github.com/mapbox/mapbox-gl-native/pull/3129))
-# 2.0.0
+# 2.0.0 - November 24, 2015
- Integrates Node.js bindings into core mapbox-gl-native project. ([#2179](https://github.com/mapbox/mapbox-gl-native/pull/2179))
- Adds Node.js v4.x and io.js v3.x support. ([#2261](https://github.com/mapbox/mapbox-gl-native/pull/2261))
@@ -89,11 +104,11 @@
- Fade transitions are now ignored to prevent half faded labels. ([#942](https://github.com/mapbox/mapbox-gl-native/pull/942))
- Labels can now line wrap on hyphens and other punctuation. ([#2598](https://github.com/mapbox/mapbox-gl-native/pull/2598))
-# 1.1.3
+# 1.1.3 - June 25, 2015
- Removes deprecated mbgl::Environment from NodeLogObserver.
-# 1.1.2
+# 1.1.2 - June 22, 2015
- Check libuv version semver-ishly, fixes segfaults in Node.js 0.12.x
and io.js.
@@ -101,11 +116,11 @@
render without first loading a style.
- Bumps mbgl submodule to v0.4.0
-# 1.1.1
+# 1.1.1 - June 16, 2015
- Bumps mbgl submodule to v0.3.5
-# 1.1.0
+# 1.1.0 - June 15, 2015
- Adds Node.js v0.12.x and io.js support.
- Adds `map.release()` method for manual cleanup of map resources.
@@ -121,23 +136,23 @@
- Fixes uncaught exception from missing sprites.
- Fixes Unicode glyph range end.
-# 1.0.3
+# 1.0.3 - April 3, 2015
- Fixes crash during garbage collection by assigning FileSource handle
to a v8::Persistent in NodeMap constructor.
-# 1.0.2
+# 1.0.2 - April 2, 2015
- Initialize shared display connection at module load time to avoid
race condition when display connection is initialized on-demand.
-# 1.0.1
+# 1.0.1 - March 19, 2015
- Adapts NodeFileSource around mbgl::Environment additions.
- Adapts to minor changes in mapbox-gl-test-suite.
- Adds tests for gzipped vector tile handling.
- Cleans up documentation.
-# 1.0.0
+# 1.0.0 - February 25, 2015
- Initial release.
diff --git a/platform/node/README.md b/platform/node/README.md
index 9e14d1bbd6..545d87861f 100644
--- a/platform/node/README.md
+++ b/platform/node/README.md
@@ -29,13 +29,25 @@ npm run test-suite
## Rendering a map tile
```js
+var fs = require('fs');
+var path = require('path');
var mbgl = require('mapbox-gl-native');
var sharp = require('sharp');
-var map = new mbgl.Map({ request: function() {} });
+
+var options = {
+ request: function(req, callback) {
+ fs.readFile(path.join(__dirname, 'test', req.url), function(err, data) {
+ callback(err, { data: data });
+ });
+ },
+ ratio: 1
+};
+
+var map = new mbgl.Map(options);
map.load(require('./test/fixtures/style.json'));
-map.render({}, function(err, buffer) {
+map.render({zoom: 0}, function(err, buffer) {
if (err) throw err;
map.release();
diff --git a/platform/node/scripts/after_script.sh b/platform/node/scripts/after_script.sh
index 905055ad11..311511726a 100755
--- a/platform/node/scripts/after_script.sh
+++ b/platform/node/scripts/after_script.sh
@@ -6,17 +6,19 @@ set -o pipefail
JOB=$1
TAG=$2
-if [ ! -z "${AWS_ACCESS_KEY_ID}" ] && [ ! -z "${AWS_SECRET_ACCESS_KEY}" ] ; then
- gzip --stdout node_modules/mapbox-gl-test-suite/render-tests/index.html | \
- aws s3 cp --acl public-read --content-encoding gzip --content-type text/html \
- - s3://mapbox/mapbox-gl-native/render-tests/$JOB/index.html
+if [[ ${PUBLISH} ]]; then
+ if [[ "$BUILDTYPE" == "Debug" ]]; then
+ echo "Please run this script in release mode (BUILDTYPE=Release)."
+ exit 1
+ else
+ ./node_modules/.bin/node-pre-gyp package publish info
+ fi
+else
+ if [ ! -z "${AWS_ACCESS_KEY_ID}" ] && [ ! -z "${AWS_SECRET_ACCESS_KEY}" ] ; then
+ gzip --stdout node_modules/mapbox-gl-test-suite/render-tests/index.html | \
+ aws s3 cp --acl public-read --content-encoding gzip --content-type text/html \
+ - s3://mapbox/mapbox-gl-native/render-tests/$JOB/index.html
- echo http://mapbox.s3.amazonaws.com/mapbox-gl-native/render-tests/$JOB/index.html
-fi
-
-PACKAGE_JSON_VERSION=$(node -e "console.log(require('./package.json').version)")
-
-if [[ $TAG == node-v${PACKAGE_JSON_VERSION} ]]; then
- ./node_modules/.bin/node-pre-gyp package
- ./node_modules/.bin/node-pre-gyp publish info
+ echo http://mapbox.s3.amazonaws.com/mapbox-gl-native/render-tests/$JOB/index.html
+ fi
fi
diff --git a/platform/node/src/node_conversion.hpp b/platform/node/src/node_conversion.hpp
new file mode 100644
index 0000000000..6ebc846d11
--- /dev/null
+++ b/platform/node/src/node_conversion.hpp
@@ -0,0 +1,113 @@
+#pragma once
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#pragma GCC diagnostic ignored "-Wshadow"
+#include <nan.h>
+#pragma GCC diagnostic pop
+
+#include <mbgl/util/optional.hpp>
+#include <mbgl/util/feature.hpp>
+#include <mbgl/style/conversion.hpp>
+
+namespace mbgl {
+namespace style {
+namespace conversion {
+
+inline bool isUndefined(v8::Local<v8::Value> value) {
+ Nan::HandleScope scope;
+ return value->IsUndefined() || value->IsNull();
+}
+
+inline bool isArray(v8::Local<v8::Value> value) {
+ Nan::HandleScope scope;
+ return value->IsArray();
+}
+
+inline std::size_t arrayLength(v8::Local<v8::Value> value) {
+ Nan::HandleScope scope;
+ return value.As<v8::Array>()->Length();
+}
+
+inline v8::Local<v8::Value> arrayMember(v8::Local<v8::Value> value, std::size_t i) {
+ Nan::EscapableHandleScope scope;
+ return scope.Escape(Nan::Get(value.As<v8::Array>(), i).ToLocalChecked());
+}
+
+inline bool isObject(v8::Local<v8::Value> value) {
+ Nan::HandleScope scope;
+ return value->IsObject();
+}
+
+inline optional<v8::Local<v8::Value>> objectMember(v8::Local<v8::Value> value, const char * name) {
+ Nan::EscapableHandleScope scope;
+ if (!Nan::Has(Nan::To<v8::Object>(value).ToLocalChecked(), Nan::New(name).ToLocalChecked()).FromJust()) {
+ return {};
+ }
+ Nan::MaybeLocal<v8::Value> result = Nan::Get(Nan::To<v8::Object>(value).ToLocalChecked(), Nan::New(name).ToLocalChecked());
+ if (result.IsEmpty()) {
+ return {};
+ }
+ return scope.Escape(result.ToLocalChecked());
+}
+
+template <class Fn>
+optional<Error> eachMember(v8::Local<v8::Value> value, Fn&& fn) {
+ Nan::HandleScope scope;
+ v8::Local<v8::Array> names = Nan::GetOwnPropertyNames(Nan::To<v8::Object>(value).ToLocalChecked()).ToLocalChecked();
+ for (uint32_t i = 0; i < names->Length(); ++i) {
+ v8::Local<v8::Value> k = Nan::Get(names, i).ToLocalChecked();
+ v8::Local<v8::Value> v = Nan::Get(Nan::To<v8::Object>(value).ToLocalChecked(), k).ToLocalChecked();
+ optional<Error> result = fn(*Nan::Utf8String(k), v);
+ if (result) {
+ return result;
+ }
+ }
+ return {};
+}
+
+inline optional<bool> toBool(v8::Local<v8::Value> value) {
+ Nan::HandleScope scope;
+ if (!value->IsBoolean()) {
+ return {};
+ }
+ return value->BooleanValue();
+}
+
+inline optional<float> toNumber(v8::Local<v8::Value> value) {
+ Nan::HandleScope scope;
+ if (!value->IsNumber()) {
+ return {};
+ }
+ return value->NumberValue();
+}
+
+inline optional<std::string> toString(v8::Local<v8::Value> value) {
+ Nan::HandleScope scope;
+ if (!value->IsString()) {
+ return {};
+ }
+ return std::string(*Nan::Utf8String(value));
+}
+
+inline optional<Value> toValue(v8::Local<v8::Value> value) {
+ if (value->IsFalse()) {
+ return { false };
+ } else if (value->IsTrue()) {
+ return { true };
+ } else if (value->IsString()) {
+ return { std::string(*Nan::Utf8String(value)) };
+ } else if (value->IsUint32()) {
+ return { std::uint64_t(value->Uint32Value()) };
+ } else if (value->IsInt32()) {
+ return { std::int64_t(value->Int32Value()) };
+ } else if (value->IsNumber()) {
+ return { value->NumberValue() };
+ } else {
+ return {};
+ }
+}
+
+} // namespace conversion
+} // namespace style
+} // namespace mbgl
diff --git a/platform/node/src/node_feature.cpp b/platform/node/src/node_feature.cpp
index 1a5e31fe97..6620cf1852 100644
--- a/platform/node/src/node_feature.cpp
+++ b/platform/node/src/node_feature.cpp
@@ -6,9 +6,10 @@ using namespace mapbox::geometry;
using Value = mbgl::Value;
using Feature = mbgl::Feature;
+using FeatureIdentifier = mbgl::FeatureIdentifier;
using Geometry = mbgl::Feature::geometry_type;
using GeometryCollection = mapbox::geometry::geometry_collection<double>;
-using Properties = mbgl::Feature::property_map;
+using Properties = mbgl::PropertyMap;
template <class T>
struct ToType {
@@ -76,7 +77,7 @@ public:
};
struct ToValue {
- v8::Local<v8::Value> operator()(std::nullptr_t) {
+ v8::Local<v8::Value> operator()(mbgl::NullValue) {
Nan::EscapableHandleScope scope;
return scope.Escape(Nan::Null());
}
@@ -159,7 +160,7 @@ v8::Local<v8::Object> toJS(const Feature& feature) {
Nan::Set(result, Nan::New("properties").ToLocalChecked(), toJS(feature.properties));
if (feature.id) {
- Nan::Set(result, Nan::New("id").ToLocalChecked(), Nan::New(double(*feature.id)));
+ Nan::Set(result, Nan::New("id").ToLocalChecked(), FeatureIdentifier::visit(*feature.id, ToValue()));
}
return scope.Escape(result);
diff --git a/platform/node/src/node_feature.hpp b/platform/node/src/node_feature.hpp
index 7973ee19d4..8d1eceba38 100644
--- a/platform/node/src/node_feature.hpp
+++ b/platform/node/src/node_feature.hpp
@@ -13,6 +13,6 @@ namespace node_mbgl {
v8::Local<v8::Value> toJS(const mbgl::Value&);
v8::Local<v8::Object> toJS(const mbgl::Feature&);
v8::Local<v8::Object> toJS(const mbgl::Feature::geometry_type&);
-v8::Local<v8::Object> toJS(const mbgl::Feature::property_map&);
+v8::Local<v8::Object> toJS(const mbgl::PropertyMap&);
}
diff --git a/platform/node/src/node_geojson.hpp b/platform/node/src/node_geojson.hpp
new file mode 100644
index 0000000000..ace4c91426
--- /dev/null
+++ b/platform/node/src/node_geojson.hpp
@@ -0,0 +1,14 @@
+#include <mbgl/style/conversion/geojson.hpp>
+
+namespace mbgl {
+namespace style {
+namespace conversion {
+
+template <>
+Result<GeoJSON> convertGeoJSON(const v8::Local<v8::Value>&) {
+ return Error { "not implemented" };
+}
+
+} // namespace conversion
+} // namespace style
+} // namespace mbgl
diff --git a/platform/node/src/node_log.cpp b/platform/node/src/node_log.cpp
index a741109b27..9872376904 100644
--- a/platform/node/src/node_log.cpp
+++ b/platform/node/src/node_log.cpp
@@ -1,6 +1,8 @@
#include "node_log.hpp"
#include "util/async_queue.hpp"
+#include <mbgl/util/enum.hpp>
+
namespace node_mbgl {
struct NodeLogObserver::LogMessage {
@@ -23,10 +25,10 @@ NodeLogObserver::NodeLogObserver(v8::Local<v8::Object> target)
auto msg = Nan::New<v8::Object>();
Nan::Set(msg, Nan::New("class").ToLocalChecked(),
- Nan::New(mbgl::EventClass(message.event).c_str()).ToLocalChecked());
+ Nan::New(mbgl::Enum<mbgl::Event>::toString(message.event)).ToLocalChecked());
Nan::Set(msg, Nan::New("severity").ToLocalChecked(),
- Nan::New(mbgl::EventSeverityClass(message.severity).c_str()).ToLocalChecked());
+ Nan::New(mbgl::Enum<mbgl::EventSeverity>::toString(message.severity)).ToLocalChecked());
if (message.code != -1) {
Nan::Set(msg, Nan::New("code").ToLocalChecked(),
@@ -40,7 +42,7 @@ NodeLogObserver::NodeLogObserver(v8::Local<v8::Object> target)
v8::Local<v8::Value> argv[] = { Nan::New("message").ToLocalChecked(), msg };
auto handle = Nan::New<v8::Object>(module);
- auto emit = Nan::Get(handle, Nan::New("emit").ToLocalChecked()).ToLocalChecked()->ToObject();
+ auto emit = Nan::To<v8::Object>(Nan::Get(handle, Nan::New("emit").ToLocalChecked()).ToLocalChecked()).ToLocalChecked();
Nan::CallAsFunction(emit, handle, 2, argv);
})) {
Nan::HandleScope scope;
diff --git a/platform/node/src/node_map.cpp b/platform/node/src/node_map.cpp
index 165e27b669..e89089ecbb 100644
--- a/platform/node/src/node_map.cpp
+++ b/platform/node/src/node_map.cpp
@@ -1,9 +1,14 @@
#include "node_map.hpp"
#include "node_request.hpp"
#include "node_feature.hpp"
+#include "node_conversion.hpp"
+#include "node_geojson.hpp"
#include <mbgl/platform/default/headless_display.hpp>
#include <mbgl/util/exception.hpp>
+#include <mbgl/style/conversion/source.hpp>
+#include <mbgl/style/conversion/layer.hpp>
+#include <mbgl/style/conversion/filter.hpp>
#include <unistd.h>
@@ -27,9 +32,6 @@ struct NodeMap::RenderOptions {
mbgl::MapDebugOptions debugOptions = mbgl::MapDebugOptions::NoDebug;
};
-////////////////////////////////////////////////////////////////////////////////////////////////
-// Static Node Methods
-
Nan::Persistent<v8::Function> NodeMap::constructor;
static std::shared_ptr<mbgl::HeadlessDisplay> sharedDisplay() {
@@ -48,8 +50,18 @@ NAN_MODULE_INIT(NodeMap::Init) {
tpl->SetClassName(Nan::New("Map").ToLocalChecked());
Nan::SetPrototypeMethod(tpl, "load", Load);
+ Nan::SetPrototypeMethod(tpl, "loaded", Loaded);
Nan::SetPrototypeMethod(tpl, "render", Render);
Nan::SetPrototypeMethod(tpl, "release", Release);
+
+ Nan::SetPrototypeMethod(tpl, "addClass", AddClass);
+ Nan::SetPrototypeMethod(tpl, "addSource", AddSource);
+ Nan::SetPrototypeMethod(tpl, "addLayer", AddLayer);
+ Nan::SetPrototypeMethod(tpl, "removeLayer", RemoveLayer);
+ Nan::SetPrototypeMethod(tpl, "setLayoutProperty", SetLayoutProperty);
+ Nan::SetPrototypeMethod(tpl, "setPaintProperty", SetPaintProperty);
+ Nan::SetPrototypeMethod(tpl, "setFilter", SetFilter);
+
Nan::SetPrototypeMethod(tpl, "dumpDebugLogs", DumpDebugLogs);
Nan::SetPrototypeMethod(tpl, "queryRenderedFeatures", QueryRenderedFeatures);
@@ -99,7 +111,7 @@ NAN_MODULE_INIT(NodeMap::Init) {
* fs.writeFileSync('image.png', image);
* });
*/
-NAN_METHOD(NodeMap::New) {
+void NodeMap::New(const Nan::FunctionCallbackInfo<v8::Value>& info) {
if (!info.IsConstructCall()) {
return Nan::ThrowTypeError("Use the new operator to create new Map objects");
}
@@ -108,7 +120,7 @@ NAN_METHOD(NodeMap::New) {
return Nan::ThrowTypeError("Requires an options object as first argument");
}
- auto options = info[0]->ToObject();
+ auto options = Nan::To<v8::Object>(info[0]).ToLocalChecked();
// Check that 'request' is set. If 'cancel' is set it must be a
// function and if 'ratio' is set it must be a number.
@@ -142,9 +154,12 @@ NAN_METHOD(NodeMap::New) {
std::string StringifyStyle(v8::Local<v8::Value> styleHandle) {
Nan::HandleScope scope;
- v8::Local<v8::Object> JSON = Nan::Get(
- Nan::GetCurrentContext()->Global(),
- Nan::New("JSON").ToLocalChecked()).ToLocalChecked()->ToObject();
+ v8::Local<v8::Object> JSON = Nan::To<v8::Object>(
+ Nan::Get(
+ Nan::GetCurrentContext()->Global(),
+ Nan::New("JSON").ToLocalChecked()
+ ).ToLocalChecked()
+ ).ToLocalChecked();
return *Nan::Utf8String(Nan::MakeCallback(JSON, "stringify", 1, &styleHandle));
}
@@ -164,10 +179,9 @@ std::string StringifyStyle(v8::Local<v8::Value> styleHandle) {
* // providing a string
* map.load(fs.readFileSync('./test/fixtures/style.json', 'utf8'));
*/
-NAN_METHOD(NodeMap::Load) {
+void NodeMap::Load(const Nan::FunctionCallbackInfo<v8::Value>& info) {
auto nodeMap = Nan::ObjectWrap::Unwrap<NodeMap>(info.Holder());
-
- if (!nodeMap->isValid()) return Nan::ThrowError(releasedMessage());
+ if (!nodeMap->map) return Nan::ThrowError(releasedMessage());
// Reset the flag as this could be the second time
// we are calling this (being the previous successful).
@@ -198,6 +212,21 @@ NAN_METHOD(NodeMap::Load) {
info.GetReturnValue().SetUndefined();
}
+void NodeMap::Loaded(const Nan::FunctionCallbackInfo<v8::Value>& info) {
+ auto nodeMap = Nan::ObjectWrap::Unwrap<NodeMap>(info.Holder());
+ if (!nodeMap->map) return Nan::ThrowError(releasedMessage());
+
+ bool loaded = false;
+
+ try {
+ loaded = nodeMap->map->isFullyLoaded();
+ } catch (const std::exception &ex) {
+ return Nan::ThrowError(ex.what());
+ }
+
+ info.GetReturnValue().Set(Nan::New(loaded));
+}
+
NodeMap::RenderOptions NodeMap::ParseOptions(v8::Local<v8::Object> obj) {
Nan::HandleScope scope;
@@ -233,16 +262,16 @@ NodeMap::RenderOptions NodeMap::ParseOptions(v8::Local<v8::Object> obj) {
}
if (Nan::Has(obj, Nan::New("classes").ToLocalChecked()).FromJust()) {
- auto classes = Nan::Get(obj, Nan::New("classes").ToLocalChecked()).ToLocalChecked()->ToObject().As<v8::Array>();
+ auto classes = Nan::To<v8::Object>(Nan::Get(obj, Nan::New("classes").ToLocalChecked()).ToLocalChecked()).ToLocalChecked().As<v8::Array>();
const int length = classes->Length();
options.classes.reserve(length);
for (int i = 0; i < length; i++) {
- options.classes.push_back(std::string { *Nan::Utf8String(Nan::Get(classes, i).ToLocalChecked()->ToString()) });
+ options.classes.push_back(std::string { *Nan::Utf8String(Nan::To<v8::String>(Nan::Get(classes, i).ToLocalChecked()).ToLocalChecked()) });
}
}
if (Nan::Has(obj, Nan::New("debug").ToLocalChecked()).FromJust()) {
- auto debug = Nan::Get(obj, Nan::New("debug").ToLocalChecked()).ToLocalChecked()->ToObject().As<v8::Object>();
+ auto debug = Nan::To<v8::Object>(Nan::Get(obj, Nan::New("debug").ToLocalChecked()).ToLocalChecked()).ToLocalChecked();
if (Nan::Has(debug, Nan::New("tileBorders").ToLocalChecked()).FromJust()) {
if (Nan::Get(debug, Nan::New("tileBorders").ToLocalChecked()).ToLocalChecked()->BooleanValue()) {
options.debugOptions = options.debugOptions | mbgl::MapDebugOptions::TileBorders;
@@ -263,6 +292,11 @@ NodeMap::RenderOptions NodeMap::ParseOptions(v8::Local<v8::Object> obj) {
options.debugOptions = options.debugOptions | mbgl::MapDebugOptions::Collision;
}
}
+ if (Nan::Has(debug, Nan::New("overdraw").ToLocalChecked()).FromJust()) {
+ if (Nan::Get(debug, Nan::New("overdraw").ToLocalChecked()).ToLocalChecked()->BooleanValue()) {
+ options.debugOptions = mbgl::MapDebugOptions::Overdraw;
+ }
+ }
}
return options;
@@ -279,15 +313,14 @@ NodeMap::RenderOptions NodeMap::ParseOptions(v8::Local<v8::Object> obj) {
* @param {Array<number>} [options.center=[0,0]] longitude, latitude center
* of the map
* @param {number} [options.bearing=0] rotation
- * @param {Array<string>} [options.classes=[]] GL Style Classes
+ * @param {Array<string>} [options.classes=[]] style classes
* @param {Function} callback
* @returns {undefined} calls callback
* @throws {Error} if stylesheet is not loaded or if map is already rendering
*/
-NAN_METHOD(NodeMap::Render) {
+void NodeMap::Render(const Nan::FunctionCallbackInfo<v8::Value>& info) {
auto nodeMap = Nan::ObjectWrap::Unwrap<NodeMap>(info.Holder());
-
- if (!nodeMap->isValid()) return Nan::ThrowError(releasedMessage());
+ if (!nodeMap->map) return Nan::ThrowError(releasedMessage());
if (info.Length() <= 0 || !info[0]->IsObject()) {
return Nan::ThrowTypeError("First argument must be an options object");
@@ -297,7 +330,7 @@ NAN_METHOD(NodeMap::Render) {
return Nan::ThrowTypeError("Second argument must be a callback function");
}
- if (!nodeMap->isLoaded()) {
+ if (!nodeMap->loaded) {
return Nan::ThrowTypeError("Style is not loaded");
}
@@ -305,7 +338,7 @@ NAN_METHOD(NodeMap::Render) {
return Nan::ThrowError("Map is currently rendering an image");
}
- auto options = ParseOptions(info[0]->ToObject());
+ auto options = ParseOptions(Nan::To<v8::Object>(info[0]).ToLocalChecked());
assert(!nodeMap->callback);
assert(!nodeMap->image.data);
@@ -415,10 +448,9 @@ void NodeMap::renderFinished() {
* @name release
* @returns {undefined}
*/
-NAN_METHOD(NodeMap::Release) {
+void NodeMap::Release(const Nan::FunctionCallbackInfo<v8::Value>& info) {
auto nodeMap = Nan::ObjectWrap::Unwrap<NodeMap>(info.Holder());
-
- if (!nodeMap->isValid()) return Nan::ThrowError(releasedMessage());
+ if (!nodeMap->map) return Nan::ThrowError(releasedMessage());
try {
nodeMap->release();
@@ -430,31 +462,231 @@ NAN_METHOD(NodeMap::Release) {
}
void NodeMap::release() {
- if (!isValid()) throw mbgl::util::Exception(releasedMessage());
-
- valid = false;
+ if (!map) throw mbgl::util::Exception(releasedMessage());
uv_close(reinterpret_cast<uv_handle_t *>(async), [] (uv_handle_t *h) {
delete reinterpret_cast<uv_async_t *>(h);
});
- map.reset(nullptr);
+ map.reset();
}
-NAN_METHOD(NodeMap::DumpDebugLogs) {
+void NodeMap::AddClass(const Nan::FunctionCallbackInfo<v8::Value>& info) {
auto nodeMap = Nan::ObjectWrap::Unwrap<NodeMap>(info.Holder());
+ if (!nodeMap->map) return Nan::ThrowError(releasedMessage());
- if (!nodeMap->isValid()) return Nan::ThrowError(releasedMessage());
+ if (info.Length() <= 0 || !info[0]->IsString()) {
+ return Nan::ThrowTypeError("First argument must be a string");
+ }
+
+ try {
+ nodeMap->map->addClass(*Nan::Utf8String(info[0]));
+ } catch (const std::exception &ex) {
+ return Nan::ThrowError(ex.what());
+ }
- nodeMap->map->dumpDebugLogs();
info.GetReturnValue().SetUndefined();
}
-NAN_METHOD(NodeMap::QueryRenderedFeatures) {
+void NodeMap::AddSource(const Nan::FunctionCallbackInfo<v8::Value>& info) {
+ using namespace mbgl::style;
+ using namespace mbgl::style::conversion;
+
auto nodeMap = Nan::ObjectWrap::Unwrap<NodeMap>(info.Holder());
- Nan::HandleScope scope;
+ if (!nodeMap->map) return Nan::ThrowError(releasedMessage());
- if (!nodeMap->isValid()) return Nan::ThrowError(releasedMessage());
+ if (info.Length() != 2) {
+ return Nan::ThrowTypeError("Two argument required");
+ }
+
+ if (!info[0]->IsString()) {
+ return Nan::ThrowTypeError("First argument must be a string");
+ }
+
+ Result<std::unique_ptr<Source>> source = convert<std::unique_ptr<Source>>(info[1], *Nan::Utf8String(info[0]));
+ if (!source) {
+ Nan::ThrowTypeError(source.error().message.c_str());
+ return;
+ }
+
+ nodeMap->map->addSource(std::move(*source));
+}
+
+void NodeMap::AddLayer(const Nan::FunctionCallbackInfo<v8::Value>& info) {
+ using namespace mbgl::style;
+ using namespace mbgl::style::conversion;
+
+ auto nodeMap = Nan::ObjectWrap::Unwrap<NodeMap>(info.Holder());
+ if (!nodeMap->map) return Nan::ThrowError(releasedMessage());
+
+ if (info.Length() != 1) {
+ return Nan::ThrowTypeError("One argument required");
+ }
+
+ Result<std::unique_ptr<Layer>> layer = convert<std::unique_ptr<Layer>>(info[0]);
+ if (!layer) {
+ Nan::ThrowTypeError(layer.error().message.c_str());
+ return;
+ }
+
+ nodeMap->map->addLayer(std::move(*layer));
+}
+
+void NodeMap::RemoveLayer(const Nan::FunctionCallbackInfo<v8::Value>& info) {
+ using namespace mbgl::style;
+ using namespace mbgl::style::conversion;
+
+ auto nodeMap = Nan::ObjectWrap::Unwrap<NodeMap>(info.Holder());
+ if (!nodeMap->map) return Nan::ThrowError(releasedMessage());
+
+ if (info.Length() != 1) {
+ return Nan::ThrowTypeError("One argument required");
+ }
+
+ if (!info[0]->IsString()) {
+ return Nan::ThrowTypeError("First argument must be a string");
+ }
+
+ nodeMap->map->removeLayer(*Nan::Utf8String(info[0]));
+}
+
+void NodeMap::SetLayoutProperty(const Nan::FunctionCallbackInfo<v8::Value>& info) {
+ using namespace mbgl::style;
+ using namespace mbgl::style::conversion;
+
+ auto nodeMap = Nan::ObjectWrap::Unwrap<NodeMap>(info.Holder());
+ if (!nodeMap->map) return Nan::ThrowError(releasedMessage());
+
+ if (info.Length() < 3) {
+ return Nan::ThrowTypeError("Three arguments required");
+ }
+
+ if (!info[0]->IsString()) {
+ return Nan::ThrowTypeError("First argument must be a string");
+ }
+
+ mbgl::style::Layer* layer = nodeMap->map->getLayer(*Nan::Utf8String(info[0]));
+ if (!layer) {
+ return Nan::ThrowTypeError("layer not found");
+ }
+
+ if (!info[1]->IsString()) {
+ return Nan::ThrowTypeError("Second argument must be a string");
+ }
+
+ mbgl::optional<Error> error = setLayoutProperty(*layer, *Nan::Utf8String(info[1]), info[2]);
+ if (error) {
+ return Nan::ThrowTypeError(error->message.c_str());
+ }
+
+ nodeMap->map->update(mbgl::Update::RecalculateStyle);
+ info.GetReturnValue().SetUndefined();
+}
+
+void NodeMap::SetPaintProperty(const Nan::FunctionCallbackInfo<v8::Value>& info) {
+ using namespace mbgl::style;
+ using namespace mbgl::style::conversion;
+
+ auto nodeMap = Nan::ObjectWrap::Unwrap<NodeMap>(info.Holder());
+ if (!nodeMap->map) return Nan::ThrowError(releasedMessage());
+
+ if (info.Length() < 3) {
+ return Nan::ThrowTypeError("Three arguments required");
+ }
+
+ if (!info[0]->IsString()) {
+ return Nan::ThrowTypeError("First argument must be a string");
+ }
+
+ mbgl::style::Layer* layer = nodeMap->map->getLayer(*Nan::Utf8String(info[0]));
+ if (!layer) {
+ return Nan::ThrowTypeError("layer not found");
+ }
+
+ if (!info[1]->IsString()) {
+ return Nan::ThrowTypeError("Second argument must be a string");
+ }
+
+ mbgl::optional<std::string> klass;
+ if (info.Length() == 4 && info[3]->IsString()) {
+ klass = std::string(*Nan::Utf8String(info[3]));
+ }
+
+ mbgl::optional<Error> error = setPaintProperty(*layer, *Nan::Utf8String(info[1]), info[2], klass);
+ if (error) {
+ return Nan::ThrowTypeError(error->message.c_str());
+ }
+
+ nodeMap->map->update(mbgl::Update::RecalculateStyle | mbgl::Update::Classes);
+ info.GetReturnValue().SetUndefined();
+}
+
+void NodeMap::SetFilter(const Nan::FunctionCallbackInfo<v8::Value>& info) {
+ using namespace mbgl::style;
+ using namespace mbgl::style::conversion;
+
+ auto nodeMap = Nan::ObjectWrap::Unwrap<NodeMap>(info.Holder());
+ if (!nodeMap->map) return Nan::ThrowError(releasedMessage());
+
+ if (info.Length() < 2) {
+ return Nan::ThrowTypeError("Two arguments required");
+ }
+
+ if (!info[0]->IsString()) {
+ return Nan::ThrowTypeError("First argument must be a string");
+ }
+
+ mbgl::style::Layer* layer = nodeMap->map->getLayer(*Nan::Utf8String(info[0]));
+ if (!layer) {
+ return Nan::ThrowTypeError("layer not found");
+ }
+
+ Filter filter;
+
+ if (!info[1]->IsNull() && !info[1]->IsUndefined()) {
+ Result<Filter> converted = convert<Filter>(info[1]);
+ if (!converted) {
+ Nan::ThrowTypeError(converted.error().message.c_str());
+ return;
+ }
+ filter = std::move(*converted);
+ }
+
+ if (layer->is<FillLayer>()) {
+ layer->as<FillLayer>()->setFilter(filter);
+ info.GetReturnValue().SetUndefined();
+ return;
+ }
+ if (layer->is<LineLayer>()) {
+ layer->as<LineLayer>()->setFilter(filter);
+ info.GetReturnValue().SetUndefined();
+ return;
+ }
+ if (layer->is<SymbolLayer>()) {
+ layer->as<SymbolLayer>()->setFilter(filter);
+ info.GetReturnValue().SetUndefined();
+ return;
+ }
+ if (layer->is<CircleLayer>()) {
+ layer->as<CircleLayer>()->setFilter(filter);
+ info.GetReturnValue().SetUndefined();
+ return;
+ }
+
+ Nan::ThrowTypeError("layer doesn't support filters");
+}
+
+void NodeMap::DumpDebugLogs(const Nan::FunctionCallbackInfo<v8::Value>& info) {
+ auto nodeMap = Nan::ObjectWrap::Unwrap<NodeMap>(info.Holder());
+ if (!nodeMap->map) return Nan::ThrowError(releasedMessage());
+
+ nodeMap->map->dumpDebugLogs();
+ info.GetReturnValue().SetUndefined();
+}
+
+void NodeMap::QueryRenderedFeatures(const Nan::FunctionCallbackInfo<v8::Value>& info) {
+ auto nodeMap = Nan::ObjectWrap::Unwrap<NodeMap>(info.Holder());
+ if (!nodeMap->map) return Nan::ThrowError(releasedMessage());
if (info.Length() <= 0 || !info[0]->IsArray()) {
return Nan::ThrowTypeError("First argument must be an array");
@@ -500,9 +732,6 @@ NAN_METHOD(NodeMap::QueryRenderedFeatures) {
}
}
-////////////////////////////////////////////////////////////////////////////////////////////////
-// Instance
-
NodeMap::NodeMap(v8::Local<v8::Object> options) :
view(sharedDisplay(), [&] {
Nan::HandleScope scope;
@@ -521,20 +750,26 @@ NodeMap::NodeMap(v8::Local<v8::Object> options) :
}
NodeMap::~NodeMap() {
- if (valid) release();
+ if (map) release();
}
-std::unique_ptr<mbgl::AsyncRequest> NodeMap::request(const mbgl::Resource& resource, Callback callback_) {
+std::unique_ptr<mbgl::AsyncRequest> NodeMap::request(const mbgl::Resource& resource, mbgl::FileSource::Callback callback_) {
Nan::HandleScope scope;
- auto requestHandle = NodeRequest::Create(resource, callback_)->ToObject();
- auto request = Nan::ObjectWrap::Unwrap<NodeRequest>(requestHandle);
- auto callbackHandle = Nan::New<v8::Function>(NodeRequest::Respond, requestHandle);
+ v8::Local<v8::Value> argv[] = {
+ Nan::New<v8::External>(this),
+ Nan::New<v8::External>(&callback_)
+ };
- v8::Local<v8::Value> argv[] = { requestHandle, callbackHandle };
- Nan::MakeCallback(handle()->GetInternalField(1)->ToObject(), "request", 2, argv);
+ auto instance = Nan::New(NodeRequest::constructor)->NewInstance(2, argv);
+
+ Nan::Set(instance, Nan::New("url").ToLocalChecked(), Nan::New(resource.url).ToLocalChecked());
+ Nan::Set(instance, Nan::New("kind").ToLocalChecked(), Nan::New<v8::Integer>(resource.kind));
+
+ auto request = Nan::ObjectWrap::Unwrap<NodeRequest>(instance);
+ request->Execute();
return std::make_unique<NodeRequest::NodeAsyncRequest>(request);
}
-} // namespace node_mbgl
+}
diff --git a/platform/node/src/node_map.hpp b/platform/node/src/node_map.hpp
index 6e28eb541e..3673b5f2ba 100644
--- a/platform/node/src/node_map.hpp
+++ b/platform/node/src/node_map.hpp
@@ -10,8 +10,6 @@
#include <nan.h>
#pragma GCC diagnostic pop
-#include <queue>
-
namespace node_mbgl {
class NodeMap : public Nan::ObjectWrap,
@@ -20,30 +18,36 @@ public:
struct RenderOptions;
class RenderWorker;
+ NodeMap(v8::Local<v8::Object>);
+ ~NodeMap();
+
+ static Nan::Persistent<v8::Function> constructor;
+
static NAN_MODULE_INIT(Init);
- static NAN_METHOD(New);
- static NAN_METHOD(Load);
- static NAN_METHOD(Render);
- static NAN_METHOD(Release);
- static NAN_METHOD(DumpDebugLogs);
- static NAN_METHOD(QueryRenderedFeatures);
+ static void New(const Nan::FunctionCallbackInfo<v8::Value>&);
+ static void Load(const Nan::FunctionCallbackInfo<v8::Value>&);
+ static void Loaded(const Nan::FunctionCallbackInfo<v8::Value>&);
+ static void Render(const Nan::FunctionCallbackInfo<v8::Value>&);
+ static void Release(const Nan::FunctionCallbackInfo<v8::Value>&);
+ static void AddClass(const Nan::FunctionCallbackInfo<v8::Value>&);
+ static void AddSource(const Nan::FunctionCallbackInfo<v8::Value>&);
+ static void AddLayer(const Nan::FunctionCallbackInfo<v8::Value>&);
+ static void RemoveLayer(const Nan::FunctionCallbackInfo<v8::Value>&);
+ static void SetLayoutProperty(const Nan::FunctionCallbackInfo<v8::Value>&);
+ static void SetPaintProperty(const Nan::FunctionCallbackInfo<v8::Value>&);
+ static void SetFilter(const Nan::FunctionCallbackInfo<v8::Value>&);
+ static void DumpDebugLogs(const Nan::FunctionCallbackInfo<v8::Value>&);
+ static void QueryRenderedFeatures(const Nan::FunctionCallbackInfo<v8::Value>&);
void startRender(RenderOptions options);
void renderFinished();
void release();
- inline bool isLoaded() { return loaded; }
- inline bool isValid() { return valid; }
-
static RenderOptions ParseOptions(v8::Local<v8::Object>);
- static Nan::Persistent<v8::Function> constructor;
-
- NodeMap(v8::Local<v8::Object>);
- ~NodeMap();
- std::unique_ptr<mbgl::AsyncRequest> request(const mbgl::Resource&, Callback);
+ std::unique_ptr<mbgl::AsyncRequest> request(const mbgl::Resource&, mbgl::FileSource::Callback);
mbgl::HeadlessView view;
std::unique_ptr<mbgl::Map> map;
@@ -56,7 +60,6 @@ public:
uv_async_t *async;
bool loaded = false;
- bool valid = true;
};
}
diff --git a/platform/node/src/node_mapbox_gl_native.cpp b/platform/node/src/node_mapbox_gl_native.cpp
index 26c49918be..7c5a959553 100644
--- a/platform/node/src/node_mapbox_gl_native.cpp
+++ b/platform/node/src/node_mapbox_gl_native.cpp
@@ -61,10 +61,14 @@ void RegisterModule(v8::Local<v8::Object> target, v8::Local<v8::Object> module)
Nan::New("require").ToLocalChecked()).ToLocalChecked().As<v8::Function>();
v8::Local<v8::Value> eventsString = Nan::New("events").ToLocalChecked();
- v8::Local<v8::Object> events = Nan::Call(require, module, 1, &eventsString).ToLocalChecked()->ToObject();
-
- v8::Local<v8::Object> EventEmitter = Nan::Get(events,
- Nan::New("EventEmitter").ToLocalChecked()).ToLocalChecked()->ToObject();
+ v8::Local<v8::Object> events = Nan::To<v8::Object>(Nan::Call(require, module, 1, &eventsString).ToLocalChecked()).ToLocalChecked();
+
+ v8::Local<v8::Object> EventEmitter = Nan::To<v8::Object>(
+ Nan::Get(
+ events,
+ Nan::New("EventEmitter").ToLocalChecked()
+ ).ToLocalChecked()
+ ).ToLocalChecked();
Nan::SetPrototype(target,
Nan::Get(EventEmitter, Nan::New("prototype").ToLocalChecked()).ToLocalChecked());
diff --git a/platform/node/src/node_request.cpp b/platform/node/src/node_request.cpp
index fa560ed4e7..56015726cb 100644
--- a/platform/node/src/node_request.cpp
+++ b/platform/node/src/node_request.cpp
@@ -1,14 +1,28 @@
#include "node_request.hpp"
+#include "node_map.hpp"
#include <mbgl/storage/response.hpp>
#include <mbgl/util/chrono.hpp>
#include <cmath>
-#include <iostream>
namespace node_mbgl {
-////////////////////////////////////////////////////////////////////////////////////////////////
-// Static Node Methods
+NodeRequest::NodeRequest(
+ NodeMap* target_,
+ mbgl::FileSource::Callback callback_)
+ : AsyncWorker(nullptr),
+ target(target_),
+ callback(callback_) {
+}
+
+NodeRequest::~NodeRequest() {
+ // When this object gets garbage collected, make sure that the
+ // AsyncRequest can no longer attempt to remove the callback function
+ // this object was holding (it can't be fired anymore).
+ if (asyncRequest) {
+ asyncRequest->request = nullptr;
+ }
+}
Nan::Persistent<v8::Function> NodeRequest::constructor;
@@ -19,73 +33,50 @@ NAN_MODULE_INIT(NodeRequest::Init) {
tpl->SetClassName(Nan::New("Request").ToLocalChecked());
constructor.Reset(tpl->GetFunction());
- Nan::Set(target, Nan::New("Request").ToLocalChecked(), tpl->GetFunction());
-}
-NAN_METHOD(NodeRequest::New) {
- auto req = new NodeRequest(*reinterpret_cast<mbgl::FileSource::Callback*>(info[0].As<v8::External>()->Value()));
- req->Wrap(info.This());
- info.GetReturnValue().Set(info.This());
+ // TODO: Remove this from the public JavaScript API
+ Nan::Set(target, Nan::New("Request").ToLocalChecked(), tpl->GetFunction());
}
-v8::Handle<v8::Object> NodeRequest::Create(const mbgl::Resource& resource, mbgl::FileSource::Callback callback) {
- Nan::EscapableHandleScope scope;
+void NodeRequest::New(const Nan::FunctionCallbackInfo<v8::Value>& info) {
+ auto target = reinterpret_cast<NodeMap*>(info[0].As<v8::External>()->Value());
+ auto callback = reinterpret_cast<mbgl::FileSource::Callback*>(info[1].As<v8::External>()->Value());
- v8::Local<v8::Value> argv[] = {
- Nan::New<v8::External>(const_cast<mbgl::FileSource::Callback*>(&callback))
- };
- auto instance = Nan::New(constructor)->NewInstance(1, argv);
+ auto request = new NodeRequest(target, *callback);
- Nan::Set(instance, Nan::New("url").ToLocalChecked(), Nan::New(resource.url).ToLocalChecked());
- Nan::Set(instance, Nan::New("kind").ToLocalChecked(), Nan::New<v8::Integer>(int(resource.kind)));
-
- return scope.Escape(instance);
+ request->Wrap(info.This());
+ info.GetReturnValue().Set(info.This());
}
-NAN_METHOD(NodeRequest::Respond) {
- using Error = mbgl::Response::Error;
-
+void NodeRequest::HandleCallback(const Nan::FunctionCallbackInfo<v8::Value>& info) {
// Move out of the object so callback() can only be fired once.
auto request = Nan::ObjectWrap::Unwrap<NodeRequest>(info.Data().As<v8::Object>());
auto callback = std::move(request->callback);
if (!callback) {
- info.GetReturnValue().SetUndefined();
- return;
+ return info.GetReturnValue().SetUndefined();
}
mbgl::Response response;
if (info.Length() < 1) {
response.noContent = true;
+ } else if (info[0]->IsObject()) {
+ auto err = Nan::To<v8::Object>(info[0]).ToLocalChecked();
+ auto msg = Nan::New("message").ToLocalChecked();
- } else if (info[0]->BooleanValue()) {
- std::unique_ptr<Nan::Utf8String> message;
-
- // Store the error string.
- if (info[0]->IsObject()) {
- auto err = info[0]->ToObject();
- if (Nan::Has(err, Nan::New("message").ToLocalChecked()).FromJust()) {
- message = std::make_unique<Nan::Utf8String>(
- Nan::Get(err, Nan::New("message").ToLocalChecked())
- .ToLocalChecked()
- ->ToString());
- }
- }
-
- if (!message) {
- message = std::make_unique<Nan::Utf8String>(info[0]->ToString());
+ if (Nan::Has(err, msg).FromJust()) {
+ request->SetErrorMessage(*Nan::Utf8String(
+ Nan::Get(err, msg).ToLocalChecked()));
}
- response.error = std::make_unique<Error>(
- Error::Reason::Other, std::string{ **message, size_t(message->length()) });
-
+ } else if (info[0]->IsString()) {
+ request->SetErrorMessage(*Nan::Utf8String(info[0]));
} else if (info.Length() < 2 || !info[1]->IsObject()) {
return Nan::ThrowTypeError("Second argument must be a response object");
-
} else {
- auto res = info[1]->ToObject();
+ auto res = Nan::To<v8::Object>(info[1]).ToLocalChecked();
if (Nan::Has(res, Nan::New("modified").ToLocalChecked()).FromJust()) {
- const double modified = Nan::Get(res, Nan::New("modified").ToLocalChecked()).ToLocalChecked()->ToNumber()->Value();
+ const double modified = Nan::To<double>(Nan::Get(res, Nan::New("modified").ToLocalChecked()).ToLocalChecked()).FromJust();
if (!std::isnan(modified)) {
response.modified = mbgl::Timestamp{ mbgl::Seconds(
static_cast<mbgl::Seconds::rep>(modified / 1000)) };
@@ -93,7 +84,7 @@ NAN_METHOD(NodeRequest::Respond) {
}
if (Nan::Has(res, Nan::New("expires").ToLocalChecked()).FromJust()) {
- const double expires = Nan::Get(res, Nan::New("expires").ToLocalChecked()).ToLocalChecked()->ToNumber()->Value();
+ const double expires = Nan::To<double>(Nan::Get(res, Nan::New("expires").ToLocalChecked()).ToLocalChecked()).FromJust();
if (!std::isnan(expires)) {
response.expires = mbgl::Timestamp{ mbgl::Seconds(
static_cast<mbgl::Seconds::rep>(expires / 1000)) };
@@ -101,19 +92,16 @@ NAN_METHOD(NodeRequest::Respond) {
}
if (Nan::Has(res, Nan::New("etag").ToLocalChecked()).FromJust()) {
- auto etagHandle = Nan::Get(res, Nan::New("etag").ToLocalChecked()).ToLocalChecked();
- if (etagHandle->BooleanValue()) {
- const Nan::Utf8String etag { etagHandle->ToString() };
- response.etag = std::string { *etag, size_t(etag.length()) };
- }
+ const Nan::Utf8String etag(Nan::Get(res, Nan::New("etag").ToLocalChecked()).ToLocalChecked());
+ response.etag = std::string { *etag, size_t(etag.length()) };
}
if (Nan::Has(res, Nan::New("data").ToLocalChecked()).FromJust()) {
- auto dataHandle = Nan::Get(res, Nan::New("data").ToLocalChecked()).ToLocalChecked();
- if (node::Buffer::HasInstance(dataHandle)) {
+ auto data = Nan::Get(res, Nan::New("data").ToLocalChecked()).ToLocalChecked();
+ if (node::Buffer::HasInstance(data)) {
response.data = std::make_shared<std::string>(
- node::Buffer::Data(dataHandle),
- node::Buffer::Length(dataHandle)
+ node::Buffer::Data(data),
+ node::Buffer::Length(data)
);
} else {
return Nan::ThrowTypeError("Response data must be a Buffer");
@@ -121,40 +109,44 @@ NAN_METHOD(NodeRequest::Respond) {
}
}
+ if (request->ErrorMessage()) {
+ response.error = std::make_unique<mbgl::Response::Error>(
+ mbgl::Response::Error::Reason::Other,
+ request->ErrorMessage()
+ );
+ }
+
// Send the response object to the NodeFileSource object
callback(response);
info.GetReturnValue().SetUndefined();
}
-////////////////////////////////////////////////////////////////////////////////////////////////
-// Instance
+void NodeRequest::Execute() {
+ // Enter a new v8::Context to avoid leaking v8::FunctionTemplate
+ // from Nan::New<v8::Function>
+ v8::Local<v8::Context> context = v8::Context::New(v8::Isolate::GetCurrent());
+ v8::Context::Scope scope(context);
+
+ v8::Local<v8::Value> argv[] = { handle(), Nan::New<v8::Function>(NodeRequest::HandleCallback, handle()) };
+
+ Nan::MakeCallback(Nan::To<v8::Object>(target->handle()->GetInternalField(1)).ToLocalChecked(), "request", 2, argv);
+}
NodeRequest::NodeAsyncRequest::NodeAsyncRequest(NodeRequest* request_) : request(request_) {
assert(request);
- // Make sure the JS object has a pointer to this so that it can remove its pointer in the
- // destructor
+
+ // Make sure the JS object has a pointer to this so that it can remove
+ // its pointer in the destructor
request->asyncRequest = this;
}
NodeRequest::NodeAsyncRequest::~NodeAsyncRequest() {
if (request) {
- // Remove the callback function because the AsyncRequest was canceled and we are no longer
- // interested in the result.
+ // Remove the callback function because the AsyncRequest was
+ // canceled and we are no longer interested in the result.
request->callback = {};
request->asyncRequest = nullptr;
}
}
-NodeRequest::NodeRequest(mbgl::FileSource::Callback callback_)
- : callback(callback_) {
-}
-
-NodeRequest::~NodeRequest() {
- // When this object gets garbage collected, make sure that the AsyncRequest can no longer
- // attempt to remove the callback function this object was holding (it can't be fired anymore).
- if (asyncRequest) {
- asyncRequest->request = nullptr;
- }
}
-
-} // namespace node_mbgl
diff --git a/platform/node/src/node_request.hpp b/platform/node/src/node_request.hpp
index 2d307a3f19..f7fce91726 100644
--- a/platform/node/src/node_request.hpp
+++ b/platform/node/src/node_request.hpp
@@ -11,29 +11,31 @@
namespace node_mbgl {
-class NodeFileSource;
-class NodeRequest;
+class NodeMap;
-class NodeRequest : public Nan::ObjectWrap {
+class NodeRequest : public Nan::ObjectWrap,
+ public Nan::AsyncWorker {
public:
- static NAN_MODULE_INIT(Init);
-
- static NAN_METHOD(New);
- static NAN_METHOD(Respond);
-
- static v8::Handle<v8::Object> Create(const mbgl::Resource&, mbgl::FileSource::Callback);
- static Nan::Persistent<v8::Function> constructor;
-
- NodeRequest(mbgl::FileSource::Callback);
- ~NodeRequest();
-
struct NodeAsyncRequest : public mbgl::AsyncRequest {
NodeAsyncRequest(NodeRequest*);
~NodeAsyncRequest() override;
NodeRequest* request;
};
+ NodeRequest(NodeMap*, mbgl::FileSource::Callback);
+ ~NodeRequest();
+
+ static Nan::Persistent<v8::Function> constructor;
+
+ static NAN_MODULE_INIT(Init);
+
+ static void New(const Nan::FunctionCallbackInfo<v8::Value>&);
+ static void HandleCallback(const Nan::FunctionCallbackInfo<v8::Value>&);
+
+ void Execute();
+
private:
+ NodeMap* target;
mbgl::FileSource::Callback callback;
NodeAsyncRequest* asyncRequest = nullptr;
};
diff --git a/platform/node/test/memory.test.js b/platform/node/test/memory.test.js
new file mode 100644
index 0000000000..e958f8a29b
--- /dev/null
+++ b/platform/node/test/memory.test.js
@@ -0,0 +1,108 @@
+'use strict';
+
+var fs = require('fs');
+var mbgl = require('../../../lib/mapbox-gl-native');
+var path = require('path');
+var test = require('tape');
+
+var testParams = {
+ mapPoolSize: 10,
+ numRenderings: 100,
+ heapGrowthThreshold: 0,
+ ratio: 2
+};
+
+function readFixture(file) {
+ return fs.readFileSync(path.join('test/fixtures/resources', file));
+}
+
+var style_raster = readFixture('style_raster.json').toString('utf8');
+var style_vector = readFixture('style_vector.json').toString('utf8');
+var sprite_json = readFixture('sprite.json');
+var sprite_png = readFixture('sprite.png');
+var glyph = readFixture('glyphs.pbf');
+var source_raster = readFixture('source_raster.json');
+var source_vector = readFixture('source_vector.json');
+var tile_raster = readFixture('raster.tile');
+var tile_vector = readFixture('vector.tile');
+
+test('Memory', function(t) {
+ // Trigger garbage collection before starting test, then initialize
+ // heap size
+ if (typeof gc === 'function') gc();
+ var lastHeapSize = process.memoryUsage()['heapUsed'];
+
+ var options = {
+ request: function(req, callback) {
+ if (req.url == null) {
+ t.fail('invalid file request');
+ } else if (req.url.indexOf('sprite') > -1 && req.url.endsWith('json')) {
+ callback(null, { data: sprite_json });
+ } else if (req.url.indexOf('sprite') > -1 && req.url.endsWith('png')) {
+ callback(null, { data: sprite_png });
+ } else if (req.url.indexOf('fonts') > -1 && req.url.endsWith('pbf')) {
+ callback(null, { data: glyph });
+ } else if (req.url.endsWith('mapbox.satellite')) {
+ callback(null, { data: source_raster });
+ } else if (req.url.indexOf('satellite') > -1 && (req.url.endsWith('png') || req.url.endsWith('webp'))) {
+ callback(null, { data: tile_raster });
+ } else if (req.url.endsWith('mapbox.mapbox-streets-v7')) {
+ callback(null, { data: source_vector });
+ } else if (req.url.indexOf('streets') > -1 && req.url.endsWith('pbf')) {
+ callback(null, { data: tile_vector });
+ } else {
+ t.fail('unhandled file request: ' + req.url);
+ }
+ },
+ ratio: testParams.ratio,
+ };
+
+ var mapPool = []
+
+ for (var i = 0; i < testParams.mapPoolSize; ++i) {
+ var map = new mbgl.Map(options);
+ mapPool.push(map);
+ }
+
+ var renderCount = 0;
+ var heapGrowth = 0;
+
+ var interval = setInterval(function () {
+ if (mapPool.length == 0) {
+ return;
+ }
+
+ var map = mapPool.shift();
+
+ if (Math.floor(Math.random() * 2)) {
+ map.load(style_raster);
+ } else {
+ map.load(style_vector);
+ }
+
+ map.render({ zoom: 16 }, function(err, pixels) {
+ mapPool.push(map);
+
+ if (renderCount % (testParams.numRenderings / 10) == 0) {
+ // Manually trigger garbage collection
+ if (typeof gc === 'function') gc();
+
+ var currentHeapSize = process.memoryUsage()['heapUsed'];
+
+ // Print some progress, so slow build bots don't timeout.
+ t.comment("Rendering (" + renderCount.toString() +
+ "/" + testParams.numRenderings.toString() + ")");
+
+ heapGrowth = heapGrowth + currentHeapSize - lastHeapSize;
+ lastHeapSize = currentHeapSize;
+ }
+
+ if (++renderCount == testParams.numRenderings) {
+ t.ok(heapGrowth < testParams.heapGrowthThreshold, heapGrowth);
+ t.end();
+
+ clearInterval(interval);
+ }
+ });
+ }, 1);
+});
diff --git a/platform/node/test/suite_implementation.js b/platform/node/test/suite_implementation.js
index da226a68f4..05c2da0a6d 100644
--- a/platform/node/test/suite_implementation.js
+++ b/platform/node/test/suite_implementation.js
@@ -36,21 +36,45 @@ module.exports = function (style, options, callback) {
options.pitch = style.pitch;
options.debug = {
tileBorders: options.debug,
- collision: options.collisionDebug
+ collision: options.collisionDebug,
+ overdraw: options.showOverdrawInspector,
};
map.load(style);
- map.render(options, function (err, pixels) {
- var results = options.queryGeometry ?
- map.queryRenderedFeatures(options.queryGeometry) :
- [];
- map.release();
- if (timedOut) return;
- clearTimeout(watchdog);
- callback(err, pixels, results.map(prepareFeatures));
+ applyOperations(options.operations, function() {
+ map.render(options, function (err, pixels) {
+ var results = options.queryGeometry ?
+ map.queryRenderedFeatures(options.queryGeometry) :
+ [];
+ map.release();
+ if (timedOut) return;
+ clearTimeout(watchdog);
+ callback(err, pixels, results.map(prepareFeatures));
+ });
});
+ function applyOperations(operations, callback) {
+ var operation = operations && operations[0];
+ if (!operations || operations.length === 0) {
+ callback();
+
+ } else if (operation[0] === 'wait') {
+ var wait = function() {
+ if (map.loaded()) {
+ applyOperations(operations.slice(1), callback);
+ } else {
+ map.render(options, wait);
+ }
+ };
+ wait();
+
+ } else {
+ map[operation[0]].apply(map, operation.slice(1));
+ applyOperations(operations.slice(1), callback);
+ }
+ }
+
function prepareFeatures(r) {
delete r.layer;
return r;
diff --git a/platform/qt/app/mapwindow.cpp b/platform/qt/app/mapwindow.cpp
index 35f56a0bef..bc83e2d972 100644
--- a/platform/qt/app/mapwindow.cpp
+++ b/platform/qt/app/mapwindow.cpp
@@ -1,7 +1,9 @@
#include "mapwindow.hpp"
#include <QApplication>
+#include <QColor>
#include <QDebug>
+#include <QFile>
#include <QIcon>
#include <QKeyEvent>
#include <QMouseEvent>
@@ -67,13 +69,49 @@ void MapWindow::changeStyle()
void MapWindow::keyPressEvent(QKeyEvent *ev)
{
+ static const QMapbox::TransitionOptions transition { 300, {} };
+
switch (ev->key()) {
case Qt::Key_S:
changeStyle();
break;
+ case Qt::Key_L: {
+ m_map.setPaintProperty("water", "fill-color", QColor(255, 0, 0));
+ m_map.setPaintProperty("building", "fill-color", "red");
+ m_map.setPaintProperty("road-secondary-tertiary", "line-color", "red");
+
+ m_map.setLayoutProperty("road-label-small", "symbol-placement", "point");
+ m_map.setLayoutProperty("road-label-medium", "symbol-placement", "point");
+ m_map.setLayoutProperty("road-label-large", "symbol-placement", "point");
+
+ QFile geojson(":source.geojson");
+ geojson.open(QIODevice::ReadOnly);
+
+ QVariantMap testSource;
+ testSource["type"] = "geojson";
+ testSource["data"] = geojson.readAll();
+
+ m_map.addSource("testSource", testSource);
+
+ QVariantMap testLayer;
+ testLayer["id"] = "testLayer";
+ testLayer["type"] = "fill";
+ testLayer["source"] = "testSource";
+
+ m_map.addLayer(testLayer);
+ m_map.setPaintProperty("testLayer", "fill-color", QColor("blue"));
+ }
+ break;
case Qt::Key_Tab:
m_map.cycleDebugOptions();
break;
+ case Qt::Key_R:
+ if (m_map.hasClass("night")) {
+ m_map.removeClass("night", transition);
+ } else {
+ m_map.addClass("night", transition);
+ }
+ break;
default:
break;
}
diff --git a/platform/qt/app/qmapboxgl.gypi b/platform/qt/app/qmapboxgl.gypi
index 62a2939ad2..22b4e1281e 100644
--- a/platform/qt/app/qmapboxgl.gypi
+++ b/platform/qt/app/qmapboxgl.gypi
@@ -17,6 +17,7 @@
'main.cpp',
'mapwindow.cpp',
'mapwindow.hpp',
+ 'source.qrc',
],
'include_dirs': [
@@ -30,6 +31,8 @@
'<@(qt_gui_cflags)',
'<@(qt_opengl_cflags)',
'-fPIC',
+ # Qt4 generates code with unused variables.
+ '-Wno-unused-variable',
],
'ldflags': [
'<@(opengl_ldflags)',
diff --git a/platform/qt/app/source.geojson b/platform/qt/app/source.geojson
new file mode 100644
index 0000000000..f639c1913e
--- /dev/null
+++ b/platform/qt/app/source.geojson
@@ -0,0 +1,253 @@
+{
+ "type": "FeatureCollection",
+ "features": [
+ {
+ "type": "Feature",
+ "properties": {},
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 69.2578125,
+ -40.17887331434695
+ ],
+ [
+ 69.2578125,
+ -10.141931686131018
+ ],
+ [
+ 110.74218749999999,
+ -10.141931686131018
+ ],
+ [
+ 110.74218749999999,
+ -40.17887331434695
+ ],
+ [
+ 69.2578125,
+ -40.17887331434695
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {},
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ -71.71875,
+ -33.43144133557529
+ ],
+ [
+ -71.71875,
+ 20.3034175184893
+ ],
+ [
+ -0.703125,
+ 20.3034175184893
+ ],
+ [
+ -0.703125,
+ -33.43144133557529
+ ],
+ [
+ -71.71875,
+ -33.43144133557529
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {},
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 97.3828125,
+ 38.548165423046584
+ ],
+ [
+ 97.3828125,
+ 65.2198939361321
+ ],
+ [
+ 155.0390625,
+ 65.2198939361321
+ ],
+ [
+ 155.0390625,
+ 38.548165423046584
+ ],
+ [
+ 97.3828125,
+ 38.548165423046584
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {},
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 24.93617534637451,
+ 60.17058143435276
+ ],
+ [
+ 24.93617534637451,
+ 60.17149933938796
+ ],
+ [
+ 24.93808507919311,
+ 60.17149933938796
+ ],
+ [
+ 24.93808507919311,
+ 60.17058143435276
+ ],
+ [
+ 24.93617534637451,
+ 60.17058143435276
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {},
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 24.94398593902588,
+ 60.170346617317186
+ ],
+ [
+ 24.94398593902588,
+ 60.171456646699184
+ ],
+ [
+ 24.947032928466797,
+ 60.171456646699184
+ ],
+ [
+ 24.947032928466797,
+ 60.170346617317186
+ ],
+ [
+ 24.94398593902588,
+ 60.170346617317186
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {},
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 24.938321113586426,
+ 60.16800902895082
+ ],
+ [
+ 24.938321113586426,
+ 60.169204528711674
+ ],
+ [
+ 24.941797256469727,
+ 60.169204528711674
+ ],
+ [
+ 24.941797256469727,
+ 60.16800902895082
+ ],
+ [
+ 24.938321113586426,
+ 60.16800902895082
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {},
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 24.939115047454834,
+ 60.17280143974311
+ ],
+ [
+ 24.939115047454834,
+ 60.17387936902026
+ ],
+ [
+ 24.94175434112549,
+ 60.17387936902026
+ ],
+ [
+ 24.94175434112549,
+ 60.17280143974311
+ ],
+ [
+ 24.939115047454834,
+ 60.17280143974311
+ ]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {},
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 24.944372177124023,
+ 60.16034398818875
+ ],
+ [
+ 24.944372177124023,
+ 60.16837195311943
+ ],
+ [
+ 24.963769912719727,
+ 60.16837195311943
+ ],
+ [
+ 24.963769912719727,
+ 60.16034398818875
+ ],
+ [
+ 24.944372177124023,
+ 60.16034398818875
+ ]
+ ]
+ ]
+ }
+ }
+ ]
+} \ No newline at end of file
diff --git a/platform/qt/app/source.qrc b/platform/qt/app/source.qrc
new file mode 100644
index 0000000000..60282b7178
--- /dev/null
+++ b/platform/qt/app/source.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/">
+ <file>source.geojson</file>
+ </qresource>
+</RCC>
diff --git a/platform/qt/bitrise-qt4.yml b/platform/qt/bitrise-qt4.yml
index 24e0f44932..aeff150ee7 100644
--- a/platform/qt/bitrise-qt4.yml
+++ b/platform/qt/bitrise-qt4.yml
@@ -34,7 +34,7 @@ workflows:
brew linkapps qt
export BUILDTYPE=Debug
make qt-app
- make test-qt
+ make test-qt-*
- is_debug: 'yes'
- slack:
title: Post to Slack
diff --git a/platform/qt/bitrise-qt5.yml b/platform/qt/bitrise-qt5.yml
index 18fa44dd2c..a612263e48 100644
--- a/platform/qt/bitrise-qt5.yml
+++ b/platform/qt/bitrise-qt5.yml
@@ -35,7 +35,7 @@ workflows:
export BUILDTYPE=Debug
make qt-app
make qt-qml-app
- make test-qt
+ make test-qt-*
- is_debug: 'yes'
- slack:
title: Post to Slack
diff --git a/platform/qt/include/QQuickMapboxGLStyleProperty b/platform/qt/include/QQuickMapboxGLStyleProperty
new file mode 100644
index 0000000000..8e61ec1d4a
--- /dev/null
+++ b/platform/qt/include/QQuickMapboxGLStyleProperty
@@ -0,0 +1 @@
+#include "qquickmapboxglstyleproperty.hpp"
diff --git a/platform/qt/include/qmapbox.hpp b/platform/qt/include/qmapbox.hpp
index 3200da2729..60ef0a306f 100644
--- a/platform/qt/include/qmapbox.hpp
+++ b/platform/qt/include/qmapbox.hpp
@@ -11,8 +11,7 @@
namespace QMapbox {
typedef QPair<double, double> Coordinate;
-typedef QList<Coordinate> Coordinates;
-typedef QList<Coordinates> CoordinateSegments;
+typedef QList<Coordinate> LineString;
typedef QPair<Coordinate, double> CoordinateZoom;
@@ -22,7 +21,7 @@ typedef QList<AnnotationID> AnnotationIDs;
typedef QPair<Coordinate, QString> PointAnnotation;
// FIXME: We need to add support for custom style properties
-typedef QPair<CoordinateSegments, QString> ShapeAnnotation;
+typedef QPair<LineString, QString> ShapeAnnotation;
enum NetworkMode {
Online, // Default
@@ -54,6 +53,11 @@ struct Q_DECL_EXPORT CustomLayerRenderParameters {
double altitude;
};
+struct Q_DECL_EXPORT TransitionOptions {
+ QVariant duration; // qint64
+ QVariant delay; // qint64
+};
+
typedef void (*CustomLayerInitializeFunction)(void* context) ;
typedef void (*CustomLayerRenderFunction)(void* context, const CustomLayerRenderParameters&);
typedef void (*CustomLayerDeinitializeFunction)(void* context);
diff --git a/platform/qt/include/qmapboxgl.hpp b/platform/qt/include/qmapboxgl.hpp
index 8ce6b02f47..e95dc84550 100644
--- a/platform/qt/include/qmapboxgl.hpp
+++ b/platform/qt/include/qmapboxgl.hpp
@@ -159,9 +159,12 @@ public:
void setGestureInProgress(bool inProgress);
void addClass(const QString &);
+ void addClass(const QString &, const QMapbox::TransitionOptions &);
void removeClass(const QString &);
+ void removeClass(const QString &, const QMapbox::TransitionOptions &);
bool hasClass(const QString &) const;
void setClasses(const QStringList &);
+ void setClasses(const QStringList &, const QMapbox::TransitionOptions &);
QStringList getClasses() const;
QMapbox::AnnotationID addPointAnnotation(const QMapbox::PointAnnotation &);
@@ -171,6 +174,9 @@ public:
void removeAnnotation(QMapbox::AnnotationID);
+ void setLayoutProperty(const QString &layer, const QString &property, const QVariant &value);
+ void setPaintProperty(const QString &layer, const QString &property, const QVariant &value, const QString &klass = QString());
+
bool isRotating() const;
bool isScaling() const;
bool isPanning() const;
@@ -193,13 +199,19 @@ public:
void setMargins(const QMargins &margins);
QMargins margins() const;
+ void addSource(const QString& sourceID, const QVariant& value);
+ void removeSource(const QString& sourceID);
+
void addCustomLayer(const QString &id,
QMapbox::CustomLayerInitializeFunction,
QMapbox::CustomLayerRenderFunction,
QMapbox::CustomLayerDeinitializeFunction,
void* context,
char* before = NULL);
- void removeCustomLayer(const QString& id);
+ void addLayer(const QVariant &value);
+ void removeLayer(const QString &id);
+
+ void setFilter(const QString &layer, const QVariant &filter);
public slots:
void render();
diff --git a/platform/qt/include/qquickmapboxgl.hpp b/platform/qt/include/qquickmapboxgl.hpp
index 6c2847fe59..c651afef00 100644
--- a/platform/qt/include/qquickmapboxgl.hpp
+++ b/platform/qt/include/qquickmapboxgl.hpp
@@ -34,6 +34,19 @@ class Q_DECL_EXPORT QQuickMapboxGL : public QQuickFramebufferObject
Q_PROPERTY(qreal pitch READ pitch WRITE setPitch NOTIFY pitchChanged)
public:
+ struct LayoutPropertyChange {
+ QString layer;
+ QString property;
+ QVariant value;
+ };
+
+ struct PaintPropertyChange {
+ QString layer;
+ QString property;
+ QVariant value;
+ QString klass;
+ };
+
QQuickMapboxGL(QQuickItem *parent = 0);
virtual ~QQuickMapboxGL();
@@ -69,6 +82,9 @@ public:
Q_INVOKABLE void pan(int dx, int dy);
+ QList<LayoutPropertyChange>& layoutPropertyChanges() { return m_layoutChanges; }
+ QList<PaintPropertyChange>& paintPropertyChanges() { return m_paintChanges; }
+
// MapboxGL QML Type interface.
void setStyle(const QString &style);
QString style() const;
@@ -81,6 +97,9 @@ public:
QPointF swapPan();
+ void setLayoutProperty(const QString &layer, const QString &property, const QVariant &value);
+ void setPaintProperty(const QString &layer, const QString &property, const QVariant &value, const QString &klass = QString());
+
enum SyncState {
NothingNeedsSync = 0,
ZoomNeedsSync = 1 << 0,
@@ -122,6 +141,9 @@ private:
QGeoCoordinate m_center;
QGeoShape m_visibleRegion;
+ QColor m_color;
+ QList<LayoutPropertyChange> m_layoutChanges;
+ QList<PaintPropertyChange> m_paintChanges;
QString m_style;
qreal m_bearing = 0;
diff --git a/platform/qt/include/qquickmapboxglstyleproperty.hpp b/platform/qt/include/qquickmapboxglstyleproperty.hpp
new file mode 100644
index 0000000000..99832eed85
--- /dev/null
+++ b/platform/qt/include/qquickmapboxglstyleproperty.hpp
@@ -0,0 +1,75 @@
+#ifndef QQUICKMAPBOXGLSTYLEPROPERTY_H
+#define QQUICKMAPBOXGLSTYLEPROPERTY_H
+
+#include <QQuickItem>
+
+class Q_DECL_EXPORT QQuickMapboxGLStyleProperty : public QQuickItem
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QString layer READ layer WRITE setLayer NOTIFY layerChanged)
+ Q_PROPERTY(QString property READ property WRITE setProperty NOTIFY propertyChanged)
+ Q_PROPERTY(QVariant value READ value WRITE setValue NOTIFY valueChanged)
+
+public:
+ virtual ~QQuickMapboxGLStyleProperty() {}
+
+ // QQuickItem implementation
+ virtual void itemChange(QQuickItem::ItemChange, const QQuickItem::ItemChangeData &);
+
+ void setLayer(const QString &);
+ QString layer() const;
+
+ void setProperty(const QString &);
+ QString property() const;
+
+ void setValue(const QVariant &);
+ QVariant value() const;
+
+signals:
+ void layerChanged(const QString &);
+ void propertyChanged(const QString &);
+ void valueChanged(const QVariant &);
+
+protected:
+ QQuickMapboxGLStyleProperty(QQuickItem *parent);
+ virtual void updateParent() = 0;
+
+ QVariant m_layer;
+ QVariant m_property;
+ QVariant m_value;
+};
+
+class Q_DECL_EXPORT QQuickMapboxGLLayoutStyleProperty : public QQuickMapboxGLStyleProperty
+{
+public:
+ QQuickMapboxGLLayoutStyleProperty(QQuickItem *parent = 0);
+ virtual ~QQuickMapboxGLLayoutStyleProperty() {}
+
+protected:
+ virtual void updateParent();
+};
+
+class Q_DECL_EXPORT QQuickMapboxGLPaintStyleProperty : public QQuickMapboxGLStyleProperty
+{
+ Q_OBJECT
+ Q_PROPERTY(QString styleClass READ styleClass WRITE setStyleClass NOTIFY classChanged)
+
+public:
+ QQuickMapboxGLPaintStyleProperty(QQuickItem *parent = 0);
+ virtual ~QQuickMapboxGLPaintStyleProperty() {}
+
+ void setStyleClass(const QString &);
+ QString styleClass() const;
+
+signals:
+ void classChanged(const QString &);
+
+protected:
+ virtual void updateParent();
+
+private:
+ QVariant m_class;
+};
+
+#endif // QQUICKMAPBOXGLSTYLEPROPERTY_H
diff --git a/platform/qt/platform.gyp b/platform/qt/platform.gyp
index 2a0e1c57bc..cb46aab07e 100644
--- a/platform/qt/platform.gyp
+++ b/platform/qt/platform.gyp
@@ -46,11 +46,10 @@
'../default/mbgl/storage/offline_download.cpp',
'../default/online_file_source.cpp',
'../default/sqlite3.cpp',
- '../default/string_stdlib.cpp',
- '../default/thread.cpp',
'include/qmapbox.hpp',
'include/qmapboxgl.hpp',
'include/qquickmapboxgl.hpp',
+ 'include/qquickmapboxglstyleproperty.hpp',
'qmapbox.qrc',
'src/async_task.cpp',
'src/async_task_impl.hpp',
@@ -63,10 +62,12 @@
'src/qmapboxgl.cpp',
'src/qmapboxgl_p.hpp',
'src/qquickmapboxgl.cpp',
+ 'src/qquickmapboxglstyleproperty.cpp',
'src/qquickmapboxglrenderer.cpp',
'src/qquickmapboxglrenderer.hpp',
'src/run_loop.cpp',
'src/run_loop_impl.hpp',
+ 'src/string_stdlib.cpp',
'src/timer.cpp',
'src/timer_impl.hpp',
],
@@ -74,6 +75,8 @@
'variables': {
'cflags': [
'<@(boost_cflags)',
+ '<@(geojson_cflags)',
+ '<@(libjpeg-turbo_cflags)',
'<@(nunicode_cflags)',
'<@(opengl_cflags)',
'<@(qt_core_cflags)',
@@ -93,6 +96,8 @@
'<@(zlib_ldflags)',
],
'libraries': [
+ '<@(geojson_static_libs)',
+ '<@(libjpeg-turbo_static_libs)',
'<@(nunicode_static_libs)',
'<@(sqlite_static_libs)',
'<@(zlib_static_libs)',
@@ -126,6 +131,12 @@
'<@(webp_static_libs)',
],
},
+ }, {
+ 'variables': {
+ 'cflags': [
+ '-DQT_IMAGE_DECODERS',
+ ],
+ },
}],
['<(qt_version_major) == 4', {
'variables': {
@@ -158,16 +169,25 @@
['OS == "mac"', {
'xcode_settings': {
'OTHER_CPLUSPLUSFLAGS': [ '<@(cflags)' ],
- }
+ },
+ 'sources': [
+ '../darwin/src/nsthread.mm',
+ ],
}, {
'cflags_cc': [ '<@(cflags)' ],
+ 'sources': [
+ '../default/thread.cpp',
+ ],
}]
],
'link_settings': {
'conditions': [
['OS == "mac"', {
- 'libraries': [ '<@(libraries)' ],
+ 'libraries': [
+ '<@(libraries)',
+ '$(SDKROOT)/System/Library/Frameworks/Cocoa.framework',
+ ],
'xcode_settings': { 'OTHER_LDFLAGS': [ '<@(ldflags)' ] }
}, {
'libraries': [ '<@(libraries)', '<@(ldflags)' ],
diff --git a/platform/qt/qmlapp/main.cpp b/platform/qt/qmlapp/main.cpp
index 1b07c699cc..0a376c6bdd 100644
--- a/platform/qt/qmlapp/main.cpp
+++ b/platform/qt/qmlapp/main.cpp
@@ -4,6 +4,7 @@
#include <qqml.h>
#include <QQuickMapboxGL>
+#include <QQuickMapboxGLStyleProperty>
int main(int argc, char *argv[])
{
@@ -13,7 +14,9 @@ int main(int argc, char *argv[])
app.setWindowIcon(QIcon(":icon.png"));
#endif
- qmlRegisterType<QQuickMapboxGL>("QQuickMapboxGL", 1, 0, "QQuickMapboxGL");
+ qmlRegisterType<QQuickMapboxGL>("QQuickMapboxGL", 1, 0, "MapboxMap");
+ qmlRegisterType<QQuickMapboxGLLayoutStyleProperty>("QQuickMapboxGL", 1, 0, "MapboxLayoutStyleProperty");
+ qmlRegisterType<QQuickMapboxGLPaintStyleProperty>("QQuickMapboxGL", 1, 0, "MapboxPaintStyleProperty");
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
diff --git a/platform/qt/qmlapp/main.qml b/platform/qt/qmlapp/main.qml
index a8629e94f6..6edfd7490e 100644
--- a/platform/qt/qmlapp/main.qml
+++ b/platform/qt/qmlapp/main.qml
@@ -3,6 +3,7 @@ import QtPositioning 5.0
import QtQuick 2.0
import QtQuick.Controls 1.0
import QtQuick.Layouts 1.0
+import QtQuick.Dialogs 1.0
import QQuickMapboxGL 1.0
@@ -12,6 +13,39 @@ ApplicationWindow {
height: 768
visible: true
+ ColorDialog {
+ id: landColorDialog
+ title: "Land color"
+ onCurrentColorChanged: { mapStreets.color = currentColor }
+ }
+
+ ColorDialog {
+ id: waterColorDialog
+ title: "Water color"
+ onCurrentColorChanged: { waterColor.value = currentColor }
+ }
+
+ MapboxLayoutStyleProperty {
+ parent: mapStreets
+ layer: "road-label-large"
+ property: "visibility"
+ value: roadLabel.checked ? "visible" : "none"
+ }
+
+ MapboxLayoutStyleProperty {
+ parent: mapStreets
+ layer: "road-label-medium"
+ property: "visibility"
+ value: roadLabel.checked ? "visible" : "none"
+ }
+
+ MapboxLayoutStyleProperty {
+ parent: mapStreets
+ layer: "road-label-small"
+ property: "visibility"
+ value: roadLabel.checked ? "visible" : "none"
+ }
+
RowLayout {
anchors.fill: parent
anchors.margins: 50
@@ -35,7 +69,7 @@ ApplicationWindow {
front: Rectangle {
anchors.fill: parent
- QQuickMapboxGL {
+ MapboxMap {
id: mapStreets
anchors.fill: parent
@@ -51,9 +85,15 @@ ApplicationWindow {
bearing: bearingSlider.value
pitch: pitchSlider.value
- color: "red"
+ color: landColorDialog.color
copyrightsVisible: true
+ MapboxPaintStyleProperty {
+ id: waterColor
+ layer: "water"
+ property: "fill-color"
+ }
+
Image {
id: logo
@@ -113,7 +153,7 @@ ApplicationWindow {
back: Rectangle {
anchors.fill: parent
- QQuickMapboxGL {
+ MapboxMap {
id: mapSatellite
anchors.fill: parent
@@ -184,37 +224,66 @@ ApplicationWindow {
}
}
- Slider {
- id: bearingSlider
+ ColumnLayout {
+ RowLayout {
+ anchors.margins: 50
+ spacing: anchors.margins
- Layout.fillHeight: true
- orientation: Qt.Vertical
+ Slider {
+ id: bearingSlider
- value: 0
- minimumValue: 0
- maximumValue: 180
- }
+ Layout.fillHeight: true
+ orientation: Qt.Vertical
- Slider {
- id: pitchSlider
+ value: 0
+ minimumValue: 0
+ maximumValue: 180
+ }
- Layout.fillHeight: true
- orientation: Qt.Vertical
+ Slider {
+ id: pitchSlider
- value: 0
- minimumValue: 0
- maximumValue: 60
- }
+ Layout.fillHeight: true
+ orientation: Qt.Vertical
- Slider {
- id: flipSlider
+ value: 0
+ minimumValue: 0
+ maximumValue: 60
+ }
- Layout.fillHeight: true
- orientation: Qt.Vertical
+ Slider {
+ id: flipSlider
+
+ Layout.fillHeight: true
+ orientation: Qt.Vertical
+
+ value: 0
+ minimumValue: 0
+ maximumValue: 180
+ }
+ }
+
+ Button {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ text: "Select land color"
+ onClicked: landColorDialog.open()
+ }
- value: 0
- minimumValue: 0
- maximumValue: 180
+ Button {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ text: "Select water color"
+ onClicked: waterColorDialog.open()
+ }
+
+ CheckBox {
+ id: roadLabel
+ anchors.left: parent.left
+ anchors.right: parent.right
+ text: "Toggle road label"
+ checked: true
+ }
}
}
}
diff --git a/platform/qt/scripts/configure.sh b/platform/qt/scripts/configure.sh
index 4b855f7c58..23f4b0bf52 100644
--- a/platform/qt/scripts/configure.sh
+++ b/platform/qt/scripts/configure.sh
@@ -1,15 +1,17 @@
#!/usr/bin/env bash
-CXX11ABI=$(scripts/check-cxx11abi.sh)
+CXX11ABI=${CXX11ABI:-$(scripts/check-cxx11abi.sh)}
UNIQUE_RESOURCE_VERSION=dev
PROTOZERO_VERSION=1.3.0
BOOST_VERSION=1.60.0
-GEOMETRY_VERSION=0.5.0
-GEOJSONVT_VERSION=4.1.2${CXX11ABI:-}
+GEOMETRY_VERSION=0.8.0
+GEOJSON_VERSION=0.1.4${CXX11ABI:-}
+GEOJSONVT_VERSION=6.1.2
+SUPERCLUSTER_VERSION=0.2.0
+KDBUSH_VERSION=0.1.1
GTEST_VERSION=1.7.0${CXX11ABI:-}
LIBJPEG_TURBO_VERSION=1.4.2
-NUNICODE_VERSION=1.6
PIXELMATCH_VERSION=0.9.0
RAPIDJSON_VERSION=1.0.2
SQLITE_VERSION=3.9.1
@@ -19,12 +21,15 @@ WEBP_VERSION=0.5.0
EARCUT_VERSION=0.11
function print_default_flags {
- CONFIG+=" 'cflags': $(quote_flags -fvisibility=hidden),"$LN
+ CONFIG+=" 'cflags': $(quote_flags -fvisibility=hidden -D__QT__),"$LN
}
if [ "$MASON_PLATFORM" == "osx" ]; then
+ # XXX: Argh, adding the __QT__ flag here because GYP for OSX does
+ # not respect the `cflags` variable above and we need it to reach
+ # the utests somehow. Gonna be fixed properly when we move to CMake.
function print_opengl_flags {
- CONFIG+=" 'opengl_cflags%': [],"$LN
+ CONFIG+=" 'opengl_cflags%': ['-D__QT__'],"$LN
CONFIG+=" 'opengl_ldflags%': ['-framework OpenGL', '-framework CoreFoundation'],"$LN
}
else
@@ -37,7 +42,12 @@ fi
function print_qt_flags {
mason install Qt system
- QT_VERSION_MAJOR=$(qmake -query QT_VERSION | cut -d. -f1)
+ QMAKE="qmake"
+ if [ ! $(which ${QMAKE} 2>/dev/null) ]; then
+ QMAKE="qmake-qt5"
+ fi
+
+ QT_VERSION_MAJOR=$(${QMAKE} -query QT_VERSION | cut -d. -f1)
CONFIG+=" 'qt_version_major%': ['${QT_VERSION_MAJOR}'],"$LN
CONFIG+=" 'qt_image_decoders%': [0],"$LN
diff --git a/platform/qt/src/async_task_impl.hpp b/platform/qt/src/async_task_impl.hpp
index 171990b15c..ea86079a90 100644
--- a/platform/qt/src/async_task_impl.hpp
+++ b/platform/qt/src/async_task_impl.hpp
@@ -16,7 +16,7 @@ class AsyncTask::Impl : public QObject {
Q_OBJECT
public:
- Impl(std::function<void()>&& fn);
+ Impl(std::function<void()> &&);
void maySend();
@@ -34,5 +34,5 @@ private:
};
-}
-}
+} // namespace util
+} // namespace mbgl
diff --git a/platform/qt/src/http_file_source.hpp b/platform/qt/src/http_file_source.hpp
index 274b464026..777228d191 100644
--- a/platform/qt/src/http_file_source.hpp
+++ b/platform/qt/src/http_file_source.hpp
@@ -24,14 +24,14 @@ public:
Impl();
virtual ~Impl() = default;
- void request(HTTPRequest*);
- void cancel(HTTPRequest*);
+ void request(HTTPRequest *);
+ void cancel(HTTPRequest *);
public slots:
- void replyFinish(QNetworkReply* reply);
+ void replyFinish(QNetworkReply *);
private:
- QMap<QUrl, QPair<QNetworkReply*, QVector<HTTPRequest*>>> m_pending;
+ QMap<QUrl, QPair<QNetworkReply *, QVector<HTTPRequest *>>> m_pending;
QNetworkAccessManager *m_manager;
QSslConfiguration m_ssl;
};
diff --git a/platform/qt/src/http_request.cpp b/platform/qt/src/http_request.cpp
index 7290f5a974..ac7d969e36 100644
--- a/platform/qt/src/http_request.cpp
+++ b/platform/qt/src/http_request.cpp
@@ -39,7 +39,8 @@ QNetworkRequest HTTPRequest::networkRequest() const
req.setRawHeader("User-Agent", "MapboxGL/1.0 [Qt]");
if (m_resource.priorEtag) {
- req.setRawHeader("If-None-Match", QByteArray(m_resource.priorEtag->data(), m_resource.priorEtag->size()));
+ const auto etag = m_resource.priorEtag;
+ req.setRawHeader("If-None-Match", QByteArray(etag->data(), etag->size()));
} else if (m_resource.priorModified) {
req.setRawHeader("If-Modified-Since", util::rfc1123(*m_resource.priorModified).c_str());
}
@@ -89,7 +90,7 @@ void HTTPRequest::handleNetworkReply(QNetworkReply *reply)
if (bytes.isEmpty()) {
response.data = std::make_shared<std::string>();
} else {
- response.data = std::make_shared<std::string>(bytes.data(), bytes.size());
+ response.data = std::make_shared<std::string>(bytes.constData(), bytes.size());
}
break;
}
diff --git a/platform/qt/src/http_request.hpp b/platform/qt/src/http_request.hpp
index 9af219f3c9..29a10467b3 100644
--- a/platform/qt/src/http_request.hpp
+++ b/platform/qt/src/http_request.hpp
@@ -15,13 +15,13 @@ class Response;
class HTTPRequest : public AsyncRequest
{
public:
- HTTPRequest(HTTPFileSource::Impl*, const Resource&, FileSource::Callback);
+ HTTPRequest(HTTPFileSource::Impl *, const Resource&, FileSource::Callback);
virtual ~HTTPRequest();
QUrl requestUrl() const;
QNetworkRequest networkRequest() const;
- void handleNetworkReply(QNetworkReply *reply);
+ void handleNetworkReply(QNetworkReply *);
private:
HTTPFileSource::Impl* m_context;
diff --git a/platform/qt/src/qmapboxgl.cpp b/platform/qt/src/qmapboxgl.cpp
index 144d545d3c..d9eb43cf05 100644
--- a/platform/qt/src/qmapboxgl.cpp
+++ b/platform/qt/src/qmapboxgl.cpp
@@ -1,10 +1,17 @@
#include "qmapboxgl_p.hpp"
+#include "qt_conversion.hpp"
+#include "qt_geojson.hpp"
+
#include <mbgl/annotation/annotation.hpp>
#include <mbgl/gl/gl.hpp>
#include <mbgl/map/camera.hpp>
#include <mbgl/map/map.hpp>
+#include <mbgl/style/conversion.hpp>
+#include <mbgl/style/conversion/layer.hpp>
+#include <mbgl/style/conversion/source.hpp>
#include <mbgl/style/layers/custom_layer.hpp>
+#include <mbgl/style/transition_options.hpp>
#include <mbgl/sprite/sprite_image.hpp>
#include <mbgl/storage/network_status.hpp>
#include <mbgl/util/constants.hpp>
@@ -19,6 +26,7 @@
#include <QCoreApplication>
#endif
+#include <QDebug>
#include <QImage>
#include <QMapboxGL>
#include <QMargins>
@@ -73,6 +81,41 @@ namespace {
QThreadStorage<std::shared_ptr<mbgl::util::RunLoop>> loop;
+// Convertion helper functions.
+
+auto fromQMapboxGLShapeAnnotation(const ShapeAnnotation &shapeAnnotation) {
+ const LineString &lineString = shapeAnnotation.first;
+ const QString &styleLayer = shapeAnnotation.second;
+
+ mbgl::LineString<double> mbglLineString;
+ mbglLineString.reserve(lineString.size());
+
+ for (const Coordinate &coordinate : lineString) {
+ mbglLineString.emplace_back(mbgl::Point<double> { coordinate.first, coordinate.second });
+ }
+
+ return mbgl::StyleSourcedAnnotation { std::move(mbglLineString), styleLayer.toStdString() };
+}
+
+auto fromQMapboxTransitionOptions(const QMapbox::TransitionOptions &options) {
+ auto convert = [](auto& value) -> mbgl::optional<mbgl::Duration> {
+ if (value.isValid()) {
+ return std::chrono::duration_cast<mbgl::Duration>(mbgl::Milliseconds(value.template value<qint64>()));
+ };
+ return {};
+ };
+ return mbgl::style::TransitionOptions { convert(options.duration), convert(options.delay) };
+}
+
+auto fromQStringList(const QStringList &list)
+{
+ std::vector<std::string> strings(list.size());
+ for (const QString &string : list) {
+ strings.emplace_back(string.toStdString());
+ }
+ return strings;
+}
+
}
QMapboxGLSettings::QMapboxGLSettings()
@@ -345,11 +388,21 @@ void QMapboxGL::addClass(const QString &className)
d_ptr->mapObj->addClass(className.toStdString());
}
+void QMapboxGL::addClass(const QString &className, const QMapbox::TransitionOptions &options)
+{
+ d_ptr->mapObj->addClass(className.toStdString(), fromQMapboxTransitionOptions(options));
+}
+
void QMapboxGL::removeClass(const QString &className)
{
d_ptr->mapObj->removeClass(className.toStdString());
}
+void QMapboxGL::removeClass(const QString &className, const QMapbox::TransitionOptions &options)
+{
+ d_ptr->mapObj->removeClass(className.toStdString(), fromQMapboxTransitionOptions(options));
+}
+
bool QMapboxGL::hasClass(const QString &className) const
{
return d_ptr->mapObj->hasClass(className.toStdString());
@@ -357,14 +410,12 @@ bool QMapboxGL::hasClass(const QString &className) const
void QMapboxGL::setClasses(const QStringList &classNames)
{
- std::vector<std::string> mbglClassNames;
- mbglClassNames.reserve(classNames.size());
-
- for (const QString &className : classNames) {
- mbglClassNames.emplace_back(className.toStdString());
- }
+ d_ptr->mapObj->setClasses(fromQStringList(classNames));
+}
- d_ptr->mapObj->setClasses(mbglClassNames);
+void QMapboxGL::setClasses(const QStringList &classNames, const QMapbox::TransitionOptions &options)
+{
+ d_ptr->mapObj->setClasses(fromQStringList(classNames), fromQMapboxTransitionOptions(options));
}
QStringList QMapboxGL::getClasses() const
@@ -392,35 +443,55 @@ void QMapboxGL::updatePointAnnotation(AnnotationID id, const PointAnnotation &po
d_ptr->mapObj->updateAnnotation(id, fromPointAnnotation(pointAnnotation));
}
-mbgl::Annotation fromQMapboxGLShapeAnnotation(const ShapeAnnotation &shapeAnnotation) {
- const CoordinateSegments &segments = shapeAnnotation.first;
- const QString &styleLayer = shapeAnnotation.second;
+AnnotationID QMapboxGL::addShapeAnnotation(const ShapeAnnotation &shapeAnnotation)
+{
+ return d_ptr->mapObj->addAnnotation(fromQMapboxGLShapeAnnotation(shapeAnnotation));
+}
- mbgl::Polygon<double> polygon;
- polygon.reserve(segments.size());
+void QMapboxGL::removeAnnotation(AnnotationID annotationID)
+{
+ d_ptr->mapObj->removeAnnotation(annotationID);
+}
- for (const Coordinates &coordinates : segments) {
- mbgl::LinearRing<double> linearRing;
- linearRing.reserve(coordinates.size());
+void QMapboxGL::setLayoutProperty(const QString& layer_, const QString& property, const QVariant& value)
+{
+ using namespace mbgl::style;
- for (const Coordinate &coordinate : coordinates) {
- linearRing.emplace_back(mbgl::Point<double>(coordinate.first, coordinate.second));
- }
+ Layer* layer = d_ptr->mapObj->getLayer(layer_.toStdString());
+ if (!layer) {
+ qWarning() << "Layer not found:" << layer_;
+ return;
+ }
- polygon.emplace_back(linearRing);
+ if (conversion::setLayoutProperty(*layer, property.toStdString(), value)) {
+ qWarning() << "Error setting layout property:" << layer_ << "-" << property;
+ return;
}
- return mbgl::StyleSourcedAnnotation { polygon, styleLayer.toStdString() };
+ d_ptr->mapObj->update(mbgl::Update::RecalculateStyle);
}
-AnnotationID QMapboxGL::addShapeAnnotation(const ShapeAnnotation &shapeAnnotation)
+void QMapboxGL::setPaintProperty(const QString& layer_, const QString& property, const QVariant& value, const QString& klass_)
{
- return d_ptr->mapObj->addAnnotation(fromQMapboxGLShapeAnnotation(shapeAnnotation));
-}
+ using namespace mbgl::style;
-void QMapboxGL::removeAnnotation(AnnotationID annotationID)
-{
- d_ptr->mapObj->removeAnnotation(annotationID);
+ Layer* layer = d_ptr->mapObj->getLayer(layer_.toStdString());
+ if (!layer) {
+ qWarning() << "Layer not found:" << layer_;
+ return;
+ }
+
+ mbgl::optional<std::string> klass;
+ if (!klass_.isEmpty()) {
+ klass = klass_.toStdString();
+ }
+
+ if (conversion::setPaintProperty(*layer, property.toStdString(), value, klass)) {
+ qWarning() << "Error setting paint property:" << layer_ << "-" << property;
+ return;
+ }
+
+ d_ptr->mapObj->update(mbgl::Update::RecalculateStyle | mbgl::Update::Classes);
}
bool QMapboxGL::isRotating() const
@@ -550,6 +621,25 @@ QMargins QMapboxGL::margins() const
);
}
+void QMapboxGL::addSource(const QString& sourceID, const QVariant& value)
+{
+ using namespace mbgl::style;
+ using namespace mbgl::style::conversion;
+
+ Result<std::unique_ptr<Source>> source = convert<std::unique_ptr<Source>>(value, sourceID.toStdString());
+ if (!source) {
+ qWarning() << "Unable to add source:" << source.error().message.c_str();
+ return;
+ }
+
+ d_ptr->mapObj->addSource(std::move(*source));
+}
+
+void QMapboxGL::removeSource(const QString& sourceID)
+{
+ d_ptr->mapObj->removeSource(sourceID.toStdString());
+}
+
void QMapboxGL::addCustomLayer(const QString &id,
QMapbox::CustomLayerInitializeFunction initFn,
QMapbox::CustomLayerRenderFunction renderFn,
@@ -568,11 +658,65 @@ void QMapboxGL::addCustomLayer(const QString &id,
before ? mbgl::optional<std::string>(before) : mbgl::optional<std::string>());
}
-void QMapboxGL::removeCustomLayer(const QString& id)
+void QMapboxGL::addLayer(const QVariant& value)
+{
+ using namespace mbgl::style;
+ using namespace mbgl::style::conversion;
+
+ Result<std::unique_ptr<Layer>> layer = convert<std::unique_ptr<Layer>>(value);
+ if (!layer) {
+ qWarning() << "Unable to add layer:" << layer.error().message.c_str();
+ return;
+ }
+
+ d_ptr->mapObj->addLayer(std::move(*layer));
+}
+
+void QMapboxGL::removeLayer(const QString& id)
{
d_ptr->mapObj->removeLayer(id.toStdString());
}
+void QMapboxGL::setFilter(const QString& layer_, const QVariant& filter_)
+{
+ using namespace mbgl::style;
+ using namespace mbgl::style::conversion;
+
+ Layer* layer = d_ptr->mapObj->getLayer(layer_.toStdString());
+ if (!layer) {
+ qWarning() << "Layer not found:" << layer_;
+ return;
+ }
+
+ Filter filter;
+
+ Result<Filter> converted = convert<Filter>(filter_);
+ if (!converted) {
+ qWarning() << "Error parsing filter:" << converted.error().message.c_str();
+ return;
+ }
+ filter = std::move(*converted);
+
+ if (layer->is<FillLayer>()) {
+ layer->as<FillLayer>()->setFilter(filter);
+ return;
+ }
+ if (layer->is<LineLayer>()) {
+ layer->as<LineLayer>()->setFilter(filter);
+ return;
+ }
+ if (layer->is<SymbolLayer>()) {
+ layer->as<SymbolLayer>()->setFilter(filter);
+ return;
+ }
+ if (layer->is<CircleLayer>()) {
+ layer->as<CircleLayer>()->setFilter(filter);
+ return;
+ }
+
+ qWarning() << "Layer doesn't support filters";
+}
+
void QMapboxGL::render()
{
d_ptr->dirty = false;
@@ -586,7 +730,6 @@ void QMapboxGL::connectionEstablished()
QMapboxGLPrivate::QMapboxGLPrivate(QMapboxGL *q, const QMapboxGLSettings &settings)
: QObject(q)
- , size(0, 0)
, q_ptr(q)
, fileSourceObj(std::make_unique<mbgl::DefaultFileSource>(
settings.cacheDatabasePath().toStdString(),
diff --git a/platform/qt/src/qmapboxgl_p.hpp b/platform/qt/src/qmapboxgl_p.hpp
index fdbfb7f2c1..fb8a5df4e7 100644
--- a/platform/qt/src/qmapboxgl_p.hpp
+++ b/platform/qt/src/qmapboxgl_p.hpp
@@ -1,5 +1,4 @@
-#ifndef QMAPBOXGL_P_H
-#define QMAPBOXGL_P_H
+#pragma once
#include <mbgl/map/map.hpp>
#include <mbgl/map/view.hpp>
@@ -15,7 +14,7 @@ class QMapboxGLPrivate : public QObject, public mbgl::View
Q_OBJECT
public:
- explicit QMapboxGLPrivate(QMapboxGL *q, const QMapboxGLSettings &);
+ explicit QMapboxGLPrivate(QMapboxGL *, const QMapboxGLSettings &);
virtual ~QMapboxGLPrivate();
// mbgl::View implementation.
@@ -26,17 +25,17 @@ public:
void activate() final {}
void deactivate() final {}
void invalidate() final;
- void notifyMapChange(mbgl::MapChange change) final;
+ void notifyMapChange(mbgl::MapChange) final;
mbgl::EdgeInsets margins;
- QSize size;
+ QSize size { 0, 0 };
- QMapboxGL *q_ptr = nullptr;
+ QMapboxGL *q_ptr { nullptr };
std::unique_ptr<mbgl::DefaultFileSource> fileSourceObj;
std::unique_ptr<mbgl::Map> mapObj;
- bool dirty = false;
+ bool dirty { false };
public slots:
void connectionEstablished();
@@ -45,5 +44,3 @@ signals:
void needsRendering();
void mapChanged(QMapboxGL::MapChange);
};
-
-#endif // QMAPBOXGL_P_H
diff --git a/platform/qt/src/qquickmapboxgl.cpp b/platform/qt/src/qquickmapboxgl.cpp
index 2961925c8b..d8492c5218 100644
--- a/platform/qt/src/qquickmapboxgl.cpp
+++ b/platform/qt/src/qquickmapboxgl.cpp
@@ -148,16 +148,22 @@ bool QQuickMapboxGL::copyrightsVisible() const
return false;
}
-void QQuickMapboxGL::setColor(const QColor &)
+void QQuickMapboxGL::setColor(const QColor &color)
{
- // TODO: can be made functional after landing #837
- qWarning() << __PRETTY_FUNCTION__
- << "Use Mapbox Studio to change the map background color.";
+ if (m_color == color) {
+ return;
+ }
+
+ m_color = color;
+
+ setPaintProperty("background", "background-color", color);
+
+ emit colorChanged(m_color);
}
QColor QQuickMapboxGL::color() const
{
- return QColor();
+ return m_color;
}
void QQuickMapboxGL::pan(int dx, int dy)
@@ -168,6 +174,18 @@ void QQuickMapboxGL::pan(int dx, int dy)
update();
}
+void QQuickMapboxGL::setLayoutProperty(const QString &layer, const QString &property, const QVariant &value)
+{
+ m_layoutChanges.append(LayoutPropertyChange { layer, property, value });
+ update();
+}
+
+void QQuickMapboxGL::setPaintProperty(const QString &layer, const QString &property, const QVariant &value, const QString &klass)
+{
+ m_paintChanges.append(PaintPropertyChange { layer, property, value, klass });
+ update();
+}
+
void QQuickMapboxGL::setStyle(const QString &styleUrl)
{
if (m_style == styleUrl) {
diff --git a/platform/qt/src/qquickmapboxglrenderer.cpp b/platform/qt/src/qquickmapboxglrenderer.cpp
index 6212c4f128..326eafa928 100644
--- a/platform/qt/src/qquickmapboxglrenderer.cpp
+++ b/platform/qt/src/qquickmapboxglrenderer.cpp
@@ -19,12 +19,21 @@ QQuickMapboxGLRenderer::QQuickMapboxGLRenderer()
settings.setViewportMode(QMapboxGLSettings::FlippedYViewport);
m_map.reset(new QMapboxGL(nullptr, settings));
+ connect(m_map.data(), SIGNAL(mapChanged(QMapboxGL::MapChange)), this, SLOT(onMapChanged(QMapboxGL::MapChange)));
}
QQuickMapboxGLRenderer::~QQuickMapboxGLRenderer()
{
}
+void QQuickMapboxGLRenderer::onMapChanged(QMapboxGL::MapChange change)
+{
+ if (change == QMapboxGL::MapChangeDidFinishLoadingMap) {
+ m_styleLoaded = true;
+ update();
+ }
+}
+
QOpenGLFramebufferObject* QQuickMapboxGLRenderer::createFramebufferObject(const QSize &size)
{
m_map->resize(size);
@@ -61,6 +70,7 @@ void QQuickMapboxGLRenderer::synchronize(QQuickFramebufferObject *item)
if (syncStatus & QQuickMapboxGL::StyleNeedsSync) {
m_map->setStyleURL(quickMap->style());
+ m_styleLoaded = false;
}
if (syncStatus & QQuickMapboxGL::PanNeedsSync) {
@@ -75,4 +85,20 @@ void QQuickMapboxGLRenderer::synchronize(QQuickFramebufferObject *item)
if (syncStatus & QQuickMapboxGL::PitchNeedsSync) {
m_map->setPitch(quickMap->pitch());
}
+
+ if (m_styleLoaded) {
+ if (!quickMap->layoutPropertyChanges().empty()) {
+ for (const auto& change: quickMap->layoutPropertyChanges()) {
+ m_map->setLayoutProperty(change.layer, change.property, change.value);
+ }
+ quickMap->layoutPropertyChanges().clear();
+ }
+
+ if (!quickMap->paintPropertyChanges().empty()) {
+ for (const auto& change: quickMap->paintPropertyChanges()) {
+ m_map->setPaintProperty(change.layer, change.property, change.value, change.klass);
+ }
+ quickMap->paintPropertyChanges().clear();
+ }
+ }
}
diff --git a/platform/qt/src/qquickmapboxglrenderer.hpp b/platform/qt/src/qquickmapboxglrenderer.hpp
index 80a5cb3278..d7ca7430ab 100644
--- a/platform/qt/src/qquickmapboxglrenderer.hpp
+++ b/platform/qt/src/qquickmapboxglrenderer.hpp
@@ -1,12 +1,12 @@
-#ifndef QQUICKMAPBOXGLRENDERER_H
-#define QQUICKMAPBOXGLRENDERER_H
+#pragma once
#include <QObject>
#include <QQuickFramebufferObject>
#include <QScopedPointer>
+#include <QMapboxGL>
+
class QGeoCoordinate;
-class QMapboxGL;
class QOpenGLFramebufferObject;
class QSize;
@@ -18,18 +18,20 @@ public:
QQuickMapboxGLRenderer();
virtual ~QQuickMapboxGLRenderer();
- virtual QOpenGLFramebufferObject* createFramebufferObject(const QSize& size);
+ virtual QOpenGLFramebufferObject * createFramebufferObject(const QSize &);
virtual void render();
- virtual void synchronize(QQuickFramebufferObject *item);
+ virtual void synchronize(QQuickFramebufferObject *);
signals:
- void centerChanged(const QGeoCoordinate &coordinate);
+ void centerChanged(const QGeoCoordinate &);
+
+public slots:
+ void onMapChanged(QMapboxGL::MapChange);
private:
bool m_initialized = false;
+ bool m_styleLoaded = false;
QScopedPointer<QMapboxGL> m_map;
};
-
-#endif // QQUICKMAPBOXGLRENDERER_H
diff --git a/platform/qt/src/qquickmapboxglstyleproperty.cpp b/platform/qt/src/qquickmapboxglstyleproperty.cpp
new file mode 100644
index 0000000000..77e6a00583
--- /dev/null
+++ b/platform/qt/src/qquickmapboxglstyleproperty.cpp
@@ -0,0 +1,118 @@
+#include <QQuickMapboxGLStyleProperty>
+#include <QQuickMapboxGL>
+
+QQuickMapboxGLStyleProperty::QQuickMapboxGLStyleProperty(QQuickItem *parent_)
+ : QQuickItem(parent_)
+{
+}
+
+QQuickMapboxGLLayoutStyleProperty::QQuickMapboxGLLayoutStyleProperty(QQuickItem *parent_)
+ : QQuickMapboxGLStyleProperty(parent_)
+{
+}
+
+QQuickMapboxGLPaintStyleProperty::QQuickMapboxGLPaintStyleProperty(QQuickItem *parent_)
+ : QQuickMapboxGLStyleProperty(parent_)
+{
+}
+
+void QQuickMapboxGLLayoutStyleProperty::updateParent()
+{
+ if (m_layer.isNull() || m_property.isNull() || m_value.isNull()) {
+ return;
+ }
+
+ QQuickMapboxGL *map = qobject_cast<QQuickMapboxGL *>(parentItem());
+ if (map) {
+ map->setLayoutProperty(layer(), property(), m_value);
+ } else {
+ qWarning() << "Style property requires QQuickMapboxGL as parent item.";
+ }
+}
+
+void QQuickMapboxGLPaintStyleProperty::updateParent()
+{
+ if (m_layer.isNull() || m_property.isNull() || m_value.isNull()) {
+ return;
+ }
+
+ QQuickMapboxGL *map = qobject_cast<QQuickMapboxGL *>(parentItem());
+ if (map) {
+ map->setPaintProperty(layer(), property(), m_value, styleClass());
+ } else {
+ qWarning() << "Style property requires QQuickMapboxGL as parent item.";
+ }
+}
+
+void QQuickMapboxGLStyleProperty::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data)
+{
+ QQuickItem::itemChange(change, data);
+
+ if (change == QQuickItem::ItemParentHasChanged) {
+ updateParent();
+ }
+}
+
+void QQuickMapboxGLStyleProperty::setLayer(const QString &layer)
+{
+ if (layer == m_layer.toString()) {
+ return;
+ }
+
+ m_layer = layer;
+ emit layerChanged(layer);
+ updateParent();
+}
+
+QString QQuickMapboxGLStyleProperty::layer() const
+{
+ return m_layer.toString();
+}
+
+void QQuickMapboxGLStyleProperty::setProperty(const QString &property)
+{
+ if (property == m_property.toString()) {
+ return;
+ }
+
+ m_property = property;
+ emit propertyChanged(property);
+ updateParent();
+}
+
+QString QQuickMapboxGLStyleProperty::property() const
+{
+ return m_property.toString();
+}
+
+void QQuickMapboxGLStyleProperty::setValue(const QVariant &value)
+{
+ if (value == m_value) {
+ return;
+ }
+
+ m_value = value;
+ emit valueChanged(value);
+ updateParent();
+}
+
+QVariant QQuickMapboxGLStyleProperty::value() const
+{
+ return m_value;
+}
+
+void QQuickMapboxGLPaintStyleProperty::setStyleClass(const QString &styleClass)
+{
+ if (styleClass == m_class.toString()) {
+ return;
+ }
+
+ m_class = styleClass;
+ emit classChanged(styleClass);
+ updateParent();
+}
+
+QString QQuickMapboxGLPaintStyleProperty::styleClass() const
+{
+ return m_class.toString();
+}
diff --git a/platform/qt/src/qt_conversion.hpp b/platform/qt/src/qt_conversion.hpp
new file mode 100644
index 0000000000..dc20aa4753
--- /dev/null
+++ b/platform/qt/src/qt_conversion.hpp
@@ -0,0 +1,106 @@
+#pragma once
+
+#include <mbgl/style/conversion.hpp>
+#include <mbgl/util/feature.hpp>
+#include <mbgl/util/optional.hpp>
+
+#include <QColor>
+#include <QVariant>
+
+namespace mbgl {
+namespace style {
+namespace conversion {
+
+inline bool isUndefined(const QVariant& value) {
+ return value.isNull() || !value.isValid();
+}
+
+inline bool isArray(const QVariant& value) {
+ return value.canConvert(QVariant::List);
+}
+
+inline std::size_t arrayLength(const QVariant& value) {
+ return value.toList().size();
+}
+
+inline QVariant arrayMember(const QVariant& value, std::size_t i) {
+ return value.toList()[i];
+}
+
+inline bool isObject(const QVariant& value) {
+ return value.canConvert(QVariant::Map) || value.type() == QVariant::ByteArray;
+}
+
+inline optional<QVariant> objectMember(const QVariant& value, const char* key) {
+ auto map = value.toMap();
+ auto iter = map.constFind(key);
+
+ if (iter != map.constEnd()) {
+ return iter.value();
+ } else {
+ return {};
+ }
+}
+
+template <class Fn>
+optional<Error> eachMember(const QVariant& value, Fn&& fn) {
+ auto map = value.toMap();
+ auto iter = map.constBegin();
+
+ while (iter != map.constEnd()) {
+ optional<Error> result = fn(iter.key().toStdString(), iter.value());
+ if (result) {
+ return result;
+ }
+
+ ++iter;
+ }
+
+ return {};
+}
+
+inline optional<bool> toBool(const QVariant& value) {
+ if (value.type() == QVariant::Bool) {
+ return value.toBool();
+ } else {
+ return {};
+ }
+}
+
+inline optional<float> toNumber(const QVariant& value) {
+ if (value.type() == QVariant::Double) {
+ return value.toFloat();
+ } else {
+ return {};
+ }
+}
+
+inline optional<std::string> toString(const QVariant& value) {
+ if (value.type() == QVariant::String) {
+ return value.toString().toStdString();
+ } else if (value.type() == QVariant::Color) {
+ return value.value<QColor>().name().toStdString();
+ } else {
+ return {};
+ }
+}
+
+inline optional<Value> toValue(const QVariant& value) {
+ if (value.type() == QVariant::Bool) {
+ return { value.toBool() };
+ } else if (value.type() == QVariant::String) {
+ return { value.toString().toStdString() };
+ } else if (value.type() == QVariant::Color) {
+ return { value.value<QColor>().name().toStdString() };
+ } else if (value.type() == QVariant::Int) {
+ return { value.toInt() };
+ } else if (value.canConvert(QVariant::Double)) {
+ return { value.toFloat() };
+ } else {
+ return {};
+ }
+}
+
+} // namespace conversion
+} // namespace style
+} // namespace mbgl
diff --git a/platform/qt/src/qt_geojson.hpp b/platform/qt/src/qt_geojson.hpp
new file mode 100644
index 0000000000..fd2b689fed
--- /dev/null
+++ b/platform/qt/src/qt_geojson.hpp
@@ -0,0 +1,49 @@
+#pragma once
+
+#include <mapbox/geojson.hpp>
+#include <mbgl/style/conversion/geojson.hpp>
+#include <mbgl/util/rapidjson.hpp>
+
+#include <sstream>
+#include <string>
+
+#include <QByteArray>
+#include <QVariant>
+
+namespace mbgl {
+namespace style {
+namespace conversion {
+
+template <>
+Result<GeoJSON> convertGeoJSON(const QVariant& value) {
+ if (value.type() != QVariant::ByteArray) {
+ return Error { "JSON data must be in QByteArray" };
+ }
+
+ auto data = value.toByteArray();
+
+ rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::CrtAllocator> d;
+ if (data.endsWith(char(0))) {
+ d.Parse<0>(value.toByteArray().data());
+ } else {
+ d.Parse<0>(value.toByteArray().constData());
+ }
+
+ if (d.HasParseError()) {
+ std::stringstream message;
+ message << d.GetErrorOffset() << " - " << rapidjson::GetParseError_En(d.GetParseError());
+
+ return Error { message.str() };
+ }
+
+ conversion::Result<GeoJSON> geoJSON = conversion::convertGeoJSON<JSValue>(d);
+ if (!geoJSON) {
+ return Error { geoJSON.error().message };
+ }
+
+ return geoJSON;
+}
+
+} // namespace conversion
+} // namespace style
+} // namespace mbgl
diff --git a/platform/qt/src/run_loop_impl.hpp b/platform/qt/src/run_loop_impl.hpp
index 6cabbbb425..ea64e4b977 100644
--- a/platform/qt/src/run_loop_impl.hpp
+++ b/platform/qt/src/run_loop_impl.hpp
@@ -35,5 +35,5 @@ public slots:
void onWriteEvent(int fd);
};
-}
-}
+} // namespace util
+} // namespace mbgl
diff --git a/platform/qt/src/string_stdlib.cpp b/platform/qt/src/string_stdlib.cpp
new file mode 100644
index 0000000000..c4adecea06
--- /dev/null
+++ b/platform/qt/src/string_stdlib.cpp
@@ -0,0 +1,24 @@
+#include <mbgl/platform/platform.hpp>
+
+#include <QByteArray>
+#include <QString>
+
+#include <string>
+
+namespace mbgl {
+namespace platform {
+
+std::string uppercase(const std::string& str) {
+ auto upper = QString::fromUtf8(str.c_str()).toUpper().toUtf8();
+
+ return std::string(upper.constData(), upper.size());
+}
+
+std::string lowercase(const std::string& str) {
+ auto lower = QString::fromUtf8(str.c_str()).toLower().toUtf8();
+
+ return std::string(lower.constData(), lower.size());
+}
+
+} // namespace platform
+} // namespace mbgl
diff --git a/platform/qt/src/timer_impl.hpp b/platform/qt/src/timer_impl.hpp
index a54abfd8b5..ea22b20974 100644
--- a/platform/qt/src/timer_impl.hpp
+++ b/platform/qt/src/timer_impl.hpp
@@ -14,7 +14,7 @@ class Timer::Impl : public QObject {
public:
Impl();
- void start(uint64_t timeout, uint64_t repeat, std::function<void ()>&& cb);
+ void start(uint64_t timeout, uint64_t repeat, std::function<void ()> &&);
void stop();
public slots:
@@ -27,5 +27,5 @@ private:
QTimer timer;
};
-}
-}
+} // namespace util
+} // namespace mbgl