summaryrefslogtreecommitdiff
path: root/platform/android
diff options
context:
space:
mode:
Diffstat (limited to 'platform/android')
-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
262 files changed, 18444 insertions, 1862 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: