summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
Diffstat (limited to 'platform')
-rw-r--r--platform/android/.gitignore5
-rw-r--r--platform/android/CHANGELOG.md37
-rw-r--r--platform/android/CONTRIBUTING_LINUX.md49
-rw-r--r--platform/android/CONTRIBUTING_MACOS.md69
-rw-r--r--platform/android/DISTRIBUTE.md43
-rw-r--r--platform/android/MapboxGLAndroidSDK/build.gradle77
-rw-r--r--platform/android/MapboxGLAndroidSDK/gradle-tests-staticblockremover.gradle59
-rw-r--r--platform/android/MapboxGLAndroidSDK/gradle.properties4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/LibraryLoader.java15
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java22
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Polygon.java38
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/PolygonOptions.java68
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java1
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/Style.java26
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/MapboxConfigurationException.java (renamed from platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidAccessTokenException.java)17
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java28
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java116
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationSource.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationContainer.java86
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java474
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Annotations.java25
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java177
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java40
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java136
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxEventWrapper.java48
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java41
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java76
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MarkerContainer.java267
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Markers.java39
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java77
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolygonContainer.java104
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Polygons.java22
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolylineContainer.java105
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Polylines.java22
-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.java12
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java16
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java60
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java22
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java82
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/NativeConnectivityListener.java4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java32
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java5
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionDefinition.java5
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java10
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/BackgroundLayer.java66
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java184
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillExtrusionLayer.java339
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillLayer.java118
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Layer.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LineLayer.java207
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java21
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java198
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/RasterLayer.java155
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/SymbolLayer.java272
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/TransitionOptions.java56
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/layer.java.ejs41
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java100
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterSource.java13
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java26
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/VectorSource.java14
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml18
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/mapbox_logo_icon.pngbin3408 -> 4778 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/mapbox_logo_icon.pngbin1958 -> 2622 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/mapbox_logo_icon.pngbin4492 -> 6579 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/mapbox_logo_icon.pngbin7059 -> 10802 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/mapbox_logo_icon.pngbin9402 -> 14441 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/drawable/mapbox_info_icon_default.xml8
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/drawable/mapbox_info_icon_selected.xml10
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_infowindow_content.xml3
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_internal.xml3
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_preview.xml35
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values-ca/strings.xml14
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values-es/strings.xml15
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values-lt/strings.xml15
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values-nl/strings.xml14
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values-sv/strings.xml15
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values-vi/strings.xml15
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values/arrays.xml16
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml1
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml9
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values/strings.xml21
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/MapboxTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/MapboxTest.java)4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/AnnotationTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/AnnotationTest.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/IconTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/IconTest.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/InfoWindowTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/InfoWindowTest.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerTest.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerViewTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerViewTest.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/PolygonTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/PolygonTest.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/PolylineTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/PolylineTest.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/constants/AppConstant.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/constants/AppConstant.java)2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java)115
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngSpanTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngSpanTest.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngTest.java)75
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/ProjectedMetersTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/ProjectedMetersTest.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/VisibleRegionTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/VisibleRegionTest.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/AnnotationManagerTest.java81
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/TrackingSettingsTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/TrackingSettingsTest.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettingsTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettingsTest.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/layers/FilterTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/style/layers/FilterTest.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/layers/FunctionTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/style/layers/FunctionTest.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/telemetry/HttpTransportTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/telemetry/HttpTransportTest.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/utils/MockParcel.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/utils/MockParcel.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker)0
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/README.md78
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/build.gradle7
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/gradle-config.gradle11
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java214
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseActivityTest.java65
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/activity.junit.ejs2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/MarkerTest.java33
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/MarkerViewTest.java32
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/PolygonTest.java31
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/PolylineTest.java29
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraAnimateTest.java55
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraEaseTest.java54
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraInternalApiTest.java32
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraMoveTest.java54
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/feature/QueryRenderedFeaturesBoxCountTest.java28
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/feature/QueryRenderedFeaturesHighlightTest.java49
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/feature/QueryRenderedFeaturesPropertiesTest.java29
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/feature/QueryRenderedSymbolBoxCountTest.java29
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/AttributionTest.java130
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/CompassViewTest.java38
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/LogoTest.java32
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/MyLocationViewTest.java33
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BackgroundLayerTest.java91
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BaseStyleTest.java41
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerTest.java295
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillExtrusionLayerTest.java760
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerTest.java190
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/GeoJsonSourceTests.java188
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java308
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RasterLayerTest.java164
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleTests.java87
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleTimingTests.java30
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java1071
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs91
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/ScreenshotUtil.java137
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml64
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapboxApplication.java17
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/FeatureOverviewActivity.java11
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PolygonActivity.java31
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/LatLngBoundsActivity.java8
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/LatLngBoundsForCameraActivity.java109
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/storage/UrlTransformActivity.java104
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/BuildingFillExtrusionActivity.java95
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/CircleLayerActivity.java203
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/FillExtrusionActivity.java135
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleActivity.java35
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/BaseLocationActivity.java49
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/CustomLocationEngineActivity.java100
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MockLocationEngine.java93
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationDrawableActivity.java38
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationTintActivity.java39
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationToggleActivity.java38
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/TokenUtils.java37
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_building_layer.xml18
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_circle_layer.xml39
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_custom_location_engine.xml27
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_fill_extrusion_layer.xml17
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_multi_map.xml4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_restricted_bounds.xml18
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/fragment_dialog_map.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_polygon.xml4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/test_feature_collection.geojson26
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/test_feature_properties.geojson21
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/test_line_string_feature.geojson17
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/test_multi_line_string_feature.geojson29
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/test_multi_point_feature.geojson17
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/test_multi_polygon_feature.geojson49
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/test_point_feature.geojson11
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/test_polygon_feature.geojson27
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/test_polygon_with_hole_feature.geojson45
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml12
-rw-r--r--platform/android/MapboxGLAndroidSDKWearTestApp/build.gradle4
-rw-r--r--platform/android/MapboxGLAndroidSDKWearTestApp/src/main/res/layout/activity_simple_mapview.xml2
-rw-r--r--platform/android/README.md87
-rw-r--r--platform/android/TESTS.md117
-rw-r--r--platform/android/art/tests/FirebaseTestsAS_1.pngbin0 -> 53000 bytes
-rw-r--r--platform/android/art/tests/FirebaseTestsAS_2.pngbin0 -> 93449 bytes
-rw-r--r--platform/android/art/tests/FirebaseTestsAS_3-5.pngbin0 -> 219290 bytes
-rw-r--r--platform/android/art/tests/FirebaseTestsAS_6.pngbin0 -> 154418 bytes
-rw-r--r--platform/android/art/tests/FirebaseTestsAS_7.pngbin0 -> 221809 bytes
-rw-r--r--platform/android/bitrise.yml99
-rw-r--r--platform/android/build.gradle3
-rw-r--r--platform/android/config.cmake406
-rw-r--r--platform/android/dependencies.gradle10
-rwxr-xr-xplatform/android/scripts/debug.sh42
-rw-r--r--platform/android/scripts/generate-style-code.js3
-rw-r--r--platform/android/scripts/generate-test-code.js2
-rwxr-xr-xplatform/android/scripts/metrics.sh14
-rwxr-xr-xplatform/android/scripts/ndk.sh111
-rw-r--r--platform/android/src/annotation/polygon.cpp20
-rw-r--r--platform/android/src/annotation/polygon.hpp2
-rw-r--r--platform/android/src/asset_file_source.cpp113
-rw-r--r--platform/android/src/asset_manager.hpp14
-rw-r--r--platform/android/src/asset_manager_file_source.cpp53
-rw-r--r--platform/android/src/asset_manager_file_source.hpp28
-rw-r--r--platform/android/src/file_source.cpp13
-rw-r--r--platform/android/src/file_source.hpp4
-rw-r--r--platform/android/src/geojson/conversion/feature.hpp (renamed from platform/android/src/geometry/conversion/feature.hpp)18
-rw-r--r--platform/android/src/geojson/conversion/geometry.hpp (renamed from platform/android/src/geometry/conversion/geometry.hpp)0
-rw-r--r--platform/android/src/geojson/feature.cpp63
-rw-r--r--platform/android/src/geojson/feature.hpp (renamed from platform/android/src/geometry/feature.hpp)16
-rw-r--r--platform/android/src/geojson/feature_collection.cpp40
-rw-r--r--platform/android/src/geojson/feature_collection.hpp29
-rw-r--r--platform/android/src/geojson/geometry.cpp52
-rw-r--r--platform/android/src/geojson/geometry.hpp27
-rw-r--r--platform/android/src/geojson/line_string.cpp54
-rw-r--r--platform/android/src/geojson/line_string.hpp34
-rw-r--r--platform/android/src/geojson/multi_line_string.cpp56
-rw-r--r--platform/android/src/geojson/multi_line_string.hpp33
-rw-r--r--platform/android/src/geojson/multi_point.cpp37
-rw-r--r--platform/android/src/geojson/multi_point.hpp31
-rw-r--r--platform/android/src/geojson/multi_polygon.cpp46
-rw-r--r--platform/android/src/geojson/multi_polygon.hpp31
-rw-r--r--platform/android/src/geojson/point.cpp28
-rw-r--r--platform/android/src/geojson/point.hpp31
-rw-r--r--platform/android/src/geojson/polygon.cpp52
-rw-r--r--platform/android/src/geojson/polygon.hpp33
-rw-r--r--platform/android/src/geojson/position.cpp27
-rw-r--r--platform/android/src/geojson/position.hpp27
-rw-r--r--platform/android/src/geojson/util.hpp22
-rw-r--r--platform/android/src/geometry/feature.cpp20
-rw-r--r--platform/android/src/geometry/geometry.hpp16
-rw-r--r--platform/android/src/geometry/lat_lng.cpp4
-rw-r--r--platform/android/src/geometry/lat_lng.hpp2
-rw-r--r--platform/android/src/gson/json_array.cpp40
-rw-r--r--platform/android/src/gson/json_array.hpp25
-rw-r--r--platform/android/src/gson/json_element.cpp62
-rw-r--r--platform/android/src/gson/json_element.hpp33
-rw-r--r--platform/android/src/gson/json_object.cpp64
-rw-r--r--platform/android/src/gson/json_object.hpp11
-rw-r--r--platform/android/src/gson/json_primitive.cpp66
-rw-r--r--platform/android/src/gson/json_primitive.hpp39
-rw-r--r--platform/android/src/java/util.cpp6
-rw-r--r--platform/android/src/java/util.hpp42
-rw-r--r--platform/android/src/java_types.cpp4
-rw-r--r--platform/android/src/java_types.hpp2
-rwxr-xr-xplatform/android/src/jni.cpp36
-rw-r--r--platform/android/src/jni.hpp1
-rw-r--r--platform/android/src/map/camera_position.cpp5
-rwxr-xr-xplatform/android/src/native_map_view.cpp197
-rwxr-xr-xplatform/android/src/native_map_view.hpp48
-rw-r--r--platform/android/src/run_loop.cpp1
-rw-r--r--platform/android/src/run_loop_impl.hpp2
-rw-r--r--platform/android/src/style/android_conversion.hpp7
-rw-r--r--platform/android/src/style/conversion/filter.hpp5
-rw-r--r--platform/android/src/style/conversion/geojson.hpp43
-rw-r--r--platform/android/src/style/conversion/transition_options.hpp29
-rw-r--r--platform/android/src/style/conversion/url_or_tileset.hpp36
-rw-r--r--platform/android/src/style/layers/background_layer.cpp47
-rw-r--r--platform/android/src/style/layers/background_layer.hpp11
-rw-r--r--platform/android/src/style/layers/circle_layer.cpp122
-rw-r--r--platform/android/src/style/layers/circle_layer.hpp21
-rw-r--r--platform/android/src/style/layers/fill_extrusion_layer.cpp200
-rw-r--r--platform/android/src/style/layers/fill_extrusion_layer.hpp62
-rw-r--r--platform/android/src/style/layers/fill_layer.cpp77
-rw-r--r--platform/android/src/style/layers/fill_layer.hpp15
-rw-r--r--platform/android/src/style/layers/layer.cpp34
-rw-r--r--platform/android/src/style/layers/layer.cpp.ejs24
-rw-r--r--platform/android/src/style/layers/layer.hpp6
-rw-r--r--platform/android/src/style/layers/layer.hpp.ejs9
-rw-r--r--platform/android/src/style/layers/layers.cpp8
-rw-r--r--platform/android/src/style/layers/line_layer.cpp137
-rw-r--r--platform/android/src/style/layers/line_layer.hpp23
-rw-r--r--platform/android/src/style/layers/raster_layer.cpp107
-rw-r--r--platform/android/src/style/layers/raster_layer.hpp19
-rw-r--r--platform/android/src/style/layers/symbol_layer.cpp182
-rw-r--r--platform/android/src/style/layers/symbol_layer.hpp29
-rw-r--r--platform/android/src/style/layers/unknown_layer.cpp2
-rw-r--r--platform/android/src/style/sources/geojson_source.cpp79
-rw-r--r--platform/android/src/style/sources/geojson_source.hpp17
-rw-r--r--platform/android/src/style/sources/raster_source.cpp10
-rw-r--r--platform/android/src/style/sources/raster_source.hpp2
-rw-r--r--platform/android/src/style/sources/source.cpp8
-rw-r--r--platform/android/src/style/sources/source.hpp2
-rw-r--r--platform/android/src/style/sources/unknown_source.cpp2
-rw-r--r--platform/android/src/style/sources/vector_source.cpp23
-rw-r--r--platform/android/src/style/sources/vector_source.hpp8
-rw-r--r--platform/android/src/style/transition_options.cpp20
-rw-r--r--platform/android/src/style/transition_options.hpp25
-rw-r--r--platform/android/src/style/value.cpp38
-rw-r--r--platform/android/src/style/value.hpp8
-rw-r--r--platform/android/tests/docs/UI_TESTS.md4
-rw-r--r--platform/android/tests/docs/UNIT_TESTS.md4
-rw-r--r--platform/darwin/docs/guides/For Style Authors.md.ejs3
-rw-r--r--platform/darwin/docs/guides/Using Style Functions at Runtime.md.ejs76
-rw-r--r--platform/darwin/docs/theme/assets/img/mapbox.svg63
-rw-r--r--platform/darwin/resources/es.lproj/Foundation.strings291
-rw-r--r--platform/darwin/scripts/generate-style-code.js40
-rw-r--r--platform/darwin/scripts/style-spec-cocoa-conventions-v8.json4
-rw-r--r--platform/darwin/scripts/style-spec-overrides-v8.json14
-rw-r--r--platform/darwin/scripts/update-examples.js2
-rw-r--r--platform/darwin/src/MGLAttributionInfo.mm7
-rw-r--r--platform/darwin/src/MGLBackgroundStyleLayer.h12
-rw-r--r--platform/darwin/src/MGLBackgroundStyleLayer.mm61
-rw-r--r--platform/darwin/src/MGLCircleStyleLayer.h15
-rw-r--r--platform/darwin/src/MGLCircleStyleLayer.mm61
-rw-r--r--platform/darwin/src/MGLDistanceFormatter.m2
-rw-r--r--platform/darwin/src/MGLFillExtrusionStyleLayer.h364
-rw-r--r--platform/darwin/src/MGLFillExtrusionStyleLayer.mm335
-rw-r--r--platform/darwin/src/MGLFillStyleLayer.h15
-rw-r--r--platform/darwin/src/MGLFillStyleLayer.mm61
-rw-r--r--platform/darwin/src/MGLForegroundStyleLayer.h18
-rw-r--r--platform/darwin/src/MGLForegroundStyleLayer.mm (renamed from platform/darwin/src/MGLForegroundStyleLayer.m)10
-rw-r--r--platform/darwin/src/MGLGeometry.mm9
-rw-r--r--platform/darwin/src/MGLGeometry_Private.h6
-rw-r--r--platform/darwin/src/MGLLineStyleLayer.h15
-rw-r--r--platform/darwin/src/MGLLineStyleLayer.mm61
-rw-r--r--platform/darwin/src/MGLMapCamera.mm27
-rw-r--r--platform/darwin/src/MGLMultiPoint.h40
-rw-r--r--platform/darwin/src/MGLMultiPoint.mm6
-rw-r--r--platform/darwin/src/MGLOpenGLStyleLayer.h2
-rw-r--r--platform/darwin/src/MGLOpenGLStyleLayer.mm40
-rw-r--r--platform/darwin/src/MGLPointCollection.mm11
-rw-r--r--platform/darwin/src/MGLRasterSource.h103
-rw-r--r--platform/darwin/src/MGLRasterSource.mm80
-rw-r--r--platform/darwin/src/MGLRasterSource_Private.h9
-rw-r--r--platform/darwin/src/MGLRasterStyleLayer.h15
-rw-r--r--platform/darwin/src/MGLRasterStyleLayer.mm61
-rw-r--r--platform/darwin/src/MGLShapeSource.mm69
-rw-r--r--platform/darwin/src/MGLShapeSource_Private.h4
-rw-r--r--platform/darwin/src/MGLSource.mm39
-rw-r--r--platform/darwin/src/MGLSource_Private.h29
-rw-r--r--platform/darwin/src/MGLStyle.h206
-rw-r--r--platform/darwin/src/MGLStyle.mm128
-rw-r--r--platform/darwin/src/MGLStyleLayer.h20
-rw-r--r--platform/darwin/src/MGLStyleLayer.h.ejs30
-rw-r--r--platform/darwin/src/MGLStyleLayer.mm44
-rw-r--r--platform/darwin/src/MGLStyleLayer.mm.ejs69
-rw-r--r--platform/darwin/src/MGLStyleLayer_Private.h22
-rw-r--r--platform/darwin/src/MGLStyleValue_Private.h5
-rw-r--r--platform/darwin/src/MGLSymbolStyleLayer.h74
-rw-r--r--platform/darwin/src/MGLSymbolStyleLayer.mm91
-rw-r--r--platform/darwin/src/MGLTileSource.h129
-rw-r--r--platform/darwin/src/MGLTileSource.mm8
-rw-r--r--platform/darwin/src/MGLTypes.h4
-rw-r--r--platform/darwin/src/MGLVectorSource.h120
-rw-r--r--platform/darwin/src/MGLVectorSource.mm72
-rw-r--r--platform/darwin/src/MGLVectorSource_Private.h9
-rw-r--r--platform/darwin/src/headless_backend_cgl.cpp4
-rw-r--r--platform/darwin/src/headless_backend_eagl.mm6
-rw-r--r--platform/darwin/test/MGLAttributionInfoTests.m2
-rw-r--r--platform/darwin/test/MGLDocumentationExampleTests.swift16
-rw-r--r--platform/darwin/test/MGLDocumentationGuideTests.swift214
-rw-r--r--platform/darwin/test/MGLFillExtrusionStyleLayerTests.mm445
-rw-r--r--platform/darwin/test/MGLSDKTestHelpers.swift47
-rw-r--r--platform/darwin/test/MGLShapeSourceTests.mm104
-rw-r--r--platform/darwin/test/MGLSourceQueryTests.m60
-rw-r--r--platform/darwin/test/MGLStyleLayerTests.mm.ejs2
-rw-r--r--platform/darwin/test/MGLStyleTests.mm77
-rw-r--r--platform/darwin/test/MGLSymbolStyleLayerTests.mm127
-rw-r--r--platform/darwin/test/query-style.json98
-rw-r--r--platform/default/async_task.cpp10
-rw-r--r--platform/default/bidi.cpp8
-rw-r--r--platform/default/default_file_source.cpp24
-rw-r--r--platform/default/headless_backend_osmesa.cpp2
-rw-r--r--platform/default/image.cpp2
-rw-r--r--platform/default/jpeg_reader.cpp8
-rw-r--r--platform/default/mbgl/gl/headless_backend.cpp18
-rw-r--r--platform/default/mbgl/gl/headless_backend.hpp16
-rw-r--r--platform/default/mbgl/gl/offscreen_view.cpp2
-rw-r--r--platform/default/mbgl/gl/offscreen_view.hpp2
-rw-r--r--platform/default/mbgl/storage/offline_download.cpp91
-rw-r--r--platform/default/mbgl/util/default_styles.cpp14
-rw-r--r--platform/default/mbgl/util/default_styles.hpp6
-rw-r--r--platform/default/png_reader.cpp4
-rw-r--r--platform/default/resources/attribution-logo.svg92
-rw-r--r--platform/default/resources/mapbox-icon-large.svg84
-rw-r--r--platform/default/run_loop.cpp15
-rw-r--r--platform/default/sqlite3.cpp18
-rw-r--r--platform/default/sqlite3.hpp4
-rw-r--r--platform/default/timer.cpp10
-rw-r--r--platform/glfw/glfw_view.cpp130
-rw-r--r--platform/glfw/glfw_view.hpp23
-rw-r--r--platform/glfw/main.cpp34
-rw-r--r--platform/ios/CHANGELOG.md40
-rw-r--r--platform/ios/DEVELOPING.md2
-rw-r--r--platform/ios/INSTALL.md16
-rw-r--r--platform/ios/Mapbox-iOS-SDK-nightly-dynamic.podspec30
-rw-r--r--platform/ios/Mapbox-iOS-SDK-symbols.podspec2
-rw-r--r--platform/ios/Mapbox-iOS-SDK.podspec2
-rw-r--r--platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-29@2x-1.pngbin1103 -> 1745 bytes
-rw-r--r--platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-29@2x.pngbin1103 -> 1745 bytes
-rw-r--r--platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-29@3x.pngbin1234 -> 2580 bytes
-rw-r--r--platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-40.pngbin951 -> 1270 bytes
-rw-r--r--platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-40@2x-1.pngbin1276 -> 2351 bytes
-rw-r--r--platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.pngbin1528 -> 2351 bytes
-rw-r--r--platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.pngbin2091 -> 3497 bytes
-rw-r--r--platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.pngbin1300 -> 5275 bytes
-rw-r--r--platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-76.pngbin1447 -> 2250 bytes
-rw-r--r--platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.pngbin2520 -> 4425 bytes
-rw-r--r--platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.pngbin2536 -> 4895 bytes
-rw-r--r--platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-Small.pngbin684 -> 907 bytes
-rw-r--r--platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-Spotlight-40@3x.pngbin961 -> 3497 bytes
-rw-r--r--platform/ios/app/Info.plist13
-rw-r--r--platform/ios/app/MBXAnnotationView.m13
-rw-r--r--platform/ios/app/MBXEmbeddedMapViewController.h5
-rw-r--r--platform/ios/app/MBXEmbeddedMapViewController.m89
-rw-r--r--platform/ios/app/MBXViewController.m53
-rw-r--r--platform/ios/app/Main.storyboard174
-rw-r--r--platform/ios/bitrise.yml35
-rw-r--r--platform/ios/config.cmake11
-rw-r--r--platform/ios/docs/guides/For Style Authors.md9
-rw-r--r--platform/ios/docs/guides/Using Style Functions at Runtime.md73
-rw-r--r--platform/ios/docs/pod-README.md2
-rw-r--r--platform/ios/ios.xcodeproj/project.pbxproj106
-rw-r--r--platform/ios/ios.xcodeproj/xcshareddata/xcschemes/iosapp.xcscheme7
-rw-r--r--platform/ios/jazzy.yml1
-rw-r--r--platform/ios/resources/Base.lproj/Localizable.strings15
-rw-r--r--platform/ios/resources/ca.lproj/Localizable.strings18
-rw-r--r--platform/ios/resources/ca.lproj/Localizable.stringsdict19
-rw-r--r--platform/ios/resources/de.lproj/Localizable.stringsdict19
-rw-r--r--platform/ios/resources/en.lproj/Localizable.stringsdict19
-rw-r--r--platform/ios/resources/es.lproj/Localizable.strings2
-rw-r--r--platform/ios/resources/es.lproj/Localizable.stringsdict34
-rw-r--r--platform/ios/resources/fr.lproj/Localizable.stringsdict13
-rw-r--r--platform/ios/resources/lt.lproj/Localizable.strings20
-rw-r--r--platform/ios/resources/lt.lproj/Localizable.stringsdict38
-rw-r--r--platform/ios/resources/mapbox.pngbin1085 -> 2347 bytes
-rw-r--r--platform/ios/resources/mapbox@2x.pngbin2180 -> 5290 bytes
-rw-r--r--platform/ios/resources/mapbox@3x.pngbin3293 -> 8245 bytes
-rw-r--r--platform/ios/resources/pt-BR.lproj/Localizable.stringsdict13
-rw-r--r--platform/ios/resources/ru.lproj/Localizable.stringsdict27
-rw-r--r--platform/ios/resources/sv.lproj/Localizable.strings22
-rw-r--r--platform/ios/resources/sv.lproj/Localizable.stringsdict34
-rw-r--r--platform/ios/resources/vi.lproj/Localizable.strings18
-rw-r--r--platform/ios/resources/vi.lproj/Localizable.stringsdict30
-rw-r--r--platform/ios/resources/zh-Hans.lproj/Localizable.strings27
-rwxr-xr-xplatform/ios/scripts/deploy-nightly.sh20
-rwxr-xr-xplatform/ios/scripts/publish.sh15
-rw-r--r--platform/ios/src/MGLMapView.h26
-rw-r--r--platform/ios/src/MGLMapView.mm575
-rw-r--r--platform/ios/src/MGLScaleBar.h9
-rw-r--r--platform/ios/src/MGLScaleBar.mm366
-rw-r--r--platform/ios/src/Mapbox.h1
-rw-r--r--platform/ios/src/UIImage+MGLAdditions.h6
-rw-r--r--platform/ios/src/UIImage+MGLAdditions.mm15
-rw-r--r--platform/ios/test/MGLAnnotationViewTests.m2
-rw-r--r--platform/ios/test/MGLMapViewDelegateIntegrationTests.swift82
-rw-r--r--platform/ios/test/MGLSourceTests.m24
m---------platform/ios/vendor/SMCalloutView0
-rw-r--r--platform/linux/config.cmake17
-rw-r--r--platform/linux/src/headless_backend_egl.cpp21
-rw-r--r--platform/linux/src/headless_backend_glx.cpp10
-rw-r--r--platform/linux/src/headless_display_egl.cpp4
-rw-r--r--platform/linux/src/headless_display_glx.cpp5
-rw-r--r--platform/macos/CHANGELOG.md28
-rw-r--r--platform/macos/DEVELOPING.md2
-rw-r--r--platform/macos/INSTALL.md2
-rw-r--r--platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon128x128.pngbin3668 -> 8183 bytes
-rw-r--r--platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon128x128@2x.pngbin0 -> 17649 bytes
-rw-r--r--platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon16x16.pngbin713 -> 917 bytes
-rw-r--r--platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon16x16@2x.pngbin0 -> 2009 bytes
-rw-r--r--platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon256x256-1.pngbin8495 -> 0 bytes
-rw-r--r--platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon256x256.pngbin8495 -> 17649 bytes
-rw-r--r--platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon256x256@2x.pngbin0 -> 38577 bytes
-rw-r--r--platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon32x32-1.pngbin1213 -> 0 bytes
-rw-r--r--platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon32x32.pngbin1213 -> 1730 bytes
-rw-r--r--platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon32x32@2x.pngbin0 -> 3905 bytes
-rw-r--r--platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon512x512-1.pngbin20280 -> 0 bytes
-rw-r--r--platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon512x512.pngbin20280 -> 38577 bytes
-rw-r--r--platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon512x512@2x.pngbin0 -> 85668 bytes
-rw-r--r--platform/macos/app/Assets.xcassets/AppIcon.appiconset/Contents.json10
-rw-r--r--platform/macos/app/Assets.xcassets/AppIcon.appiconset/icon-1.pngbin2205 -> 0 bytes
-rw-r--r--platform/macos/app/Assets.xcassets/AppIcon.appiconset/icon.pngbin9293 -> 0 bytes
-rw-r--r--platform/macos/app/Base.lproj/MainMenu.xib22
-rw-r--r--platform/macos/app/Base.lproj/MapDocument.xib25
-rw-r--r--platform/macos/app/MapDocument.m54
-rw-r--r--platform/macos/bitrise.yml58
-rw-r--r--platform/macos/config.cmake49
-rw-r--r--platform/macos/docs/guides/For Style Authors.md9
-rw-r--r--platform/macos/docs/guides/Using Style Functions at Runtime.md73
-rw-r--r--platform/macos/jazzy.yml1
-rw-r--r--platform/macos/macos.xcodeproj/project.pbxproj100
-rw-r--r--platform/macos/sdk/Base.lproj/Localizable.strings12
-rw-r--r--platform/macos/sdk/lt.lproj/Localizable.strings14
-rw-r--r--platform/macos/sdk/mapbox.pdfbin3762 -> 26280 bytes
-rw-r--r--platform/macos/sdk/sv.lproj/Localizable.strings14
-rw-r--r--platform/macos/src/MGLMapView.mm451
-rw-r--r--platform/macos/src/Mapbox.h1
-rw-r--r--platform/macos/src/NSImage+MGLAdditions.h6
-rw-r--r--platform/macos/src/NSImage+MGLAdditions.mm19
-rw-r--r--platform/macos/test/MGLMapViewDelegateIntegrationTests.swift56
-rw-r--r--platform/node/CHANGELOG.md23
-rw-r--r--platform/node/README.md6
-rw-r--r--platform/node/bitrise.yml105
-rwxr-xr-xplatform/node/scripts/after_success.sh7
-rw-r--r--platform/node/src/node_geojson.hpp5
-rw-r--r--platform/node/src/node_map.cpp123
-rw-r--r--platform/node/src/node_map.hpp13
-rw-r--r--platform/node/src/node_request.cpp10
-rw-r--r--platform/node/src/node_request.hpp6
-rw-r--r--platform/node/src/util/async_queue.hpp8
-rw-r--r--platform/node/test/benchmark.js104
-rw-r--r--platform/node/test/js/cancel.test.js116
-rw-r--r--platform/node/test/js/map.test.js8
-rw-r--r--platform/node/test/js/request_fail.test.js59
-rw-r--r--platform/node/test/js/request_notfound.test.js74
-rw-r--r--platform/node/test/memory.test.js41
-rw-r--r--platform/node/test/mockfs.js53
-rw-r--r--platform/node/test/suite_implementation.js4
-rw-r--r--platform/qt/app/mapwindow.cpp72
-rw-r--r--platform/qt/app/mapwindow.hpp1
-rw-r--r--platform/qt/bitrise-qt4.yml17
-rw-r--r--platform/qt/bitrise-qt5.yml22
-rw-r--r--platform/qt/include/qmapbox.hpp8
-rw-r--r--platform/qt/include/qmapboxgl.hpp14
-rw-r--r--platform/qt/qt4.cmake4
-rw-r--r--platform/qt/resources/common.qrc2
-rw-r--r--platform/qt/src/qmapbox.cpp34
-rw-r--r--platform/qt/src/qmapboxgl.cpp353
-rw-r--r--platform/qt/src/qmapboxgl_p.hpp28
-rw-r--r--platform/qt/src/qt_geojson.hpp38
-rw-r--r--platform/qt/src/sqlite3.cpp9
-rw-r--r--platform/qt/test/headless_backend_qt.cpp4
-rw-r--r--platform/qt/test/qmapboxgl.cpp22
522 files changed, 18334 insertions, 6482 deletions
diff --git a/platform/android/.gitignore b/platform/android/.gitignore
index 81eeaad167..7a3db0aafd 100644
--- a/platform/android/.gitignore
+++ b/platform/android/.gitignore
@@ -7,17 +7,16 @@
# Build files
build/
+.externalNativeBuild
*.so
*.apk
-# JNI
-MapboxGLAndroidSDK/src/main/jniLibs/
-
# Lib assets
MapboxGLAndroidSDK/src/main/assets/
# Local settings
local.properties
+/configuration.gradle
# Token file
MapboxGLAndroidSDKTestApp/src/main/res/values/developer-config.xml
diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md
index 2b0e40f21e..7807334c14 100644
--- a/platform/android/CHANGELOG.md
+++ b/platform/android/CHANGELOG.md
@@ -2,6 +2,43 @@
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.
+## 5.1.0 - TBA
+* Update attribution with new Mapbox wordmark [#8774](https://github.com/mapbox/mapbox-gl-native/pull/8774)
+
+## 5.1.0-beta.1 - May 2, 2017
+
+5.1.0 builds further on 5.0.2 and adds:
+
+* Support for FillExtrusionLayer [#8431](https://github.com/mapbox/mapbox-gl-native/pull/8431)
+* Limit Viewport [#8622](https://github.com/mapbox/mapbox-gl-native/pull/8622)
+* Transition Properties for Layer attributes [#8509](https://github.com/mapbox/mapbox-gl-native/pull/8509)
+* Style wide transition duration and transition offset in milliseconds [#8576](https://github.com/mapbox/mapbox-gl-native/pull/8576)
+* Transifex integration, Catalan & Dutch translations [#8556](https://github.com/mapbox/mapbox-gl-native/pull/8556)
+* LatLngBounds includes with another bounds [#8517](https://github.com/mapbox/mapbox-gl-native/pull/8517)
+* LatLngBounds includes takes in account LatLng on the edges (cfr. core) [#8517](https://github.com/mapbox/mapbox-gl-native/pull/8517)
+* LatLngBounds facility getters/setters for LatLnbg on the edges of the bounds [#8517](https://github.com/mapbox/mapbox-gl-native/pull/8517)
+* Expose world bounds in LatLngBounds [#8517](https://github.com/mapbox/mapbox-gl-native/pull/8517)
+* OfflineRegion are validated if the bounds is found in the world bounds, else onError will be invoked [#8517](https://github.com/mapbox/mapbox-gl-native/pull/8517)
+* Polygon holes [#8557](https://github.com/mapbox/mapbox-gl-native/pull/8557) and [#8722](https://github.com/mapbox/mapbox-gl-native/pull/8722)
+* Custom location source [#8710](https://github.com/mapbox/mapbox-gl-native/pull/8710)
+* Expose source layer identifier [#8709](https://github.com/mapbox/mapbox-gl-native/pull/8709)
+* Ensure surface is created after display and context [#8759](https://github.com/mapbox/mapbox-gl-native/pull/8759)
+* Harden telemetry event dispatch [#8767](https://github.com/mapbox/mapbox-gl-native/pull/8767)
+* Move LatLngBounds calculation for CameraUpdateFactory to core [#8765](https://github.com/mapbox/mapbox-gl-native/pull/8765)
+* Spanish, Lithuanian, and Vietnamese localizations [#8852](https://github.com/mapbox/mapbox-gl-native/pull/8852)
+* Warning when updating a non-added annotation [#8832](https://github.com/mapbox/mapbox-gl-native/pull/8832)
+* Share location source between components [#8825](https://github.com/mapbox/mapbox-gl-native/pull/8825)
+* Test application runtime permissions for pre lollipop devices [#8823](https://github.com/mapbox/mapbox-gl-native/pull/8823)
+* Do not call OnMarkerClick listener twice [#8804](https://github.com/mapbox/mapbox-gl-native/pull/8804)
+* Rework instrumentation tests [#8793](https://github.com/mapbox/mapbox-gl-native/pull/8793)
+* Set first render flag to false when destroying the surface [#8739](https://github.com/mapbox/mapbox-gl-native/pull/8739)
+* Post resetting tracking settings to avoid race condition reset [#8738](https://github.com/mapbox/mapbox-gl-native/pull/8738)
+* Expose Source Layer identifier [#8709](https://github.com/mapbox/mapbox-gl-native/pull/8709)
+* Derived source attribution [#8630](https://github.com/mapbox/mapbox-gl-native/pull/8630)
+* Consistent use of duration unit [#8578](https://github.com/mapbox/mapbox-gl-native/pull/8578)
+* Swedish localization [#8883](https://github.com/mapbox/mapbox-gl-native/pull/8883)
+* Streets v10, Outdoors v10, Satellite Streets v10, Traffic Day v2, Traffic Night v2 [#6301](https://github.com/mapbox/mapbox-gl-native/pull/6301)
+
## 5.0.2 - April 3, 2017
5.0.2 is a patch release that contains the following changes:
diff --git a/platform/android/CONTRIBUTING_LINUX.md b/platform/android/CONTRIBUTING_LINUX.md
deleted file mode 100644
index 875f7a800a..0000000000
--- a/platform/android/CONTRIBUTING_LINUX.md
+++ /dev/null
@@ -1,49 +0,0 @@
-# Contributing to the Android SDK on Linux
-
-_These instructions were tested on Ubuntu 16.04 LTS (aka Xenial Xerus)._
-
-Install the build dependencies:
-
-```
-$ sudo apt-get install -y android-tools-adb build-essential curl git \
- lib32stdc++6 lib32z1 openjdk-8-jdk pkg-config python
-```
-
-Install the Android SDK. We recommend doing this by way of [Android command line tools for Linux](http://developer.android.com/sdk/index.html) but you can also achieve same results with the Android Studio package.
-
-Unpack the SDK and make sure you have the proper environment variables set.
-
-```
-$ export PATH=/path/to/android-sdk-linux/tools:$PATH
-$ export ANDROID_HOME=/path/to/android-sdk-linux
-```
-
-Update the Android SDK to the latest version:
-
-```
-$ android update sdk -u
-```
-
-## Setting Mapbox Access Token
-
-_The demo applications use Mapbox vector tiles, which require a Mapbox account and API access token. Obtain an access token on the [Mapbox account page](https://www.mapbox.com/studio/account/tokens/)._
-
-gradle will take the value of the `MAPBOX_ACCESS_TOKEN` environ variable and save it to `platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/developer-config.xml` where the app will read it from. Otherwise, you can edit `developer-config.xml` and add the value manually as `mapbox_access_token`.
-
-## Building
-
-Checking out the code:
-
-```
-$ git clone https://github.com/mapbox/mapbox-gl-native.git
-$ cd mapbox-gl-native
-```
-
-Building a debug version will generated a self-signed test application that can be installed on the phone or emulator:
-
-```
-$ BUILDTYPE=Debug make android
-$ adb install -r platform/android/MapboxGLAndroidSDKTestApp/build/outputs/apk/MapboxGLAndroidSDKTestApp-debug.apk
-```
-
-The debug version will emit considerable more log information (and run slower). Use simply `make android` to build a release version.
diff --git a/platform/android/CONTRIBUTING_MACOS.md b/platform/android/CONTRIBUTING_MACOS.md
deleted file mode 100644
index 6ab55921e3..0000000000
--- a/platform/android/CONTRIBUTING_MACOS.md
+++ /dev/null
@@ -1,69 +0,0 @@
-# Contributing to the Android SDK on macOS
-
-## Install JDK 7+ and Android Studio:
-
- Android Studio requires the Java Development Kit (JDK) which you can [download here](http://www.oracle.com/technetwork/java/javase/downloads/index.html). Once the JDK is installed, you can grab the [latest version of Android Studio here](https://developer.android.com/sdk/index.html) and install it following the on screen instructions.
-
-Once Android Studio is installed, the [first time it's run it'll ask to install the Android SDK](http://developer.android.com/sdk/installing/index.html?pkg=studio) which you should do. While doing so in the Android SDK Manager make sure to also select and install the latest versions of "Android Support Repository" and "Android Support Library" from "Extras":
-
-![image](https://cloud.githubusercontent.com/assets/98601/9915837/289f398e-5c6e-11e5-9a84-ed4d08d52d1f.png)
-
-By default, the Android SDK will be installed to `/Users/<user>/Library/Android/sdk/`. For more information on how to [configure Android Studio](http://tools.android.com/tech-docs/configuration) and how to [set Project JDK vs IDE JDK](http://tools.android.com/tech-docs/configuration/osx-jdk) please see [Google's documentation](http://tools.android.com/overview).
-
-## Setting Mapbox Access Token
-
-_The test application (used for development purposes) uses Mapbox vector tiles, which require a Mapbox account and API access token. Obtain a free access token on the [Mapbox account page](https://www.mapbox.com/studio/account/tokens/)._
-
-If you start Android Studio from your terminal, gradle will take the value of the `MAPBOX_ACCESS_TOKEN` environment variable and save it to `MapboxGLAndroidSDKTestApp/src/main/res/values/developer-config.xml` where the app will read it from. Otherwise,
-you can edit `developer-config.xml` and add the value manually as `mapbox_access_token`.
-
-## Developing In Android Studio
-
-To work with the Mapbox Android SDK, you'll first need to get it set up as a Project in Android Studio. To do so Open Android Studio and select "Import project (Eclipse ADT, Gradle, etc.)" from the Welcome to Android Studio dialog. From there select the `platform/android` directory from the local file system where `mapbox-gl-native` was cloned. For example:
-
-```sh
-/Users/<user>/development/mapbox-gl-native/platform/android
-```
-
-The Mapbox Android SDK is a multi-module Gradle based project. Specifically, the SDK itself is an [Android Library](http://developer.android.com/tools/projects/index.html#LibraryModules) module and it utilizes a companion [test module](http://developer.android.com/tools/projects/index.html#testing) (aka "the TestApp") for daily development. When Android Studio finishes importing the project both `MapboxGLAndroidSDK` and `MapboxGLAndroidSDKTestApp` modules should be visible.
-
-## Setting `ANDROID_HOME`
-
-For `build android` to work, you'll need to set the `ANDROID_HOME` environment
-to point to your Android SDK installation:
-
-```
-export ANDROID_HOME=/<installation location>/android-sdk-macosx
-```
-
-This environment variable configuration should go into a file that's read on
-your shell's startup, like `~/.profile`.
-
-## Speeding up gradle builds
-
-To optimise you development machine for faster gradle builds create the following `/Users/name/.gradle/gradle.properties` file:
-
-```
-org.gradle.daemon=true
-org.gradle.jvmargs=-Xmx3072M
-```
-
-## Running The TestApp
-
-In order to run the TestApp on an emulator or device the Core GL portion needs to built first. Core GL is the common C++ based OpenGL engine that powers the maps for iOS, Android, and Qt in the project. To build it, open Terminal and run the following commands from the root of the `mapbox-gl-native` source code
-
-Run:
-
- // From /Users/<user>/development/mapbox-gl-native
-
- // Makes arm7 ABI version of Core GL
- // Can be run on most Android phones and arm emulator
- make android
-
- // Make x86 version of Core GL
- // Useful for running faster Anroid x86 emulator on Macs
- make android-lib-x86
-
-Once Core GL has been built, the TestApp can be run by selecting `MapboxGLAndroidSDKTestApp` from the Run menu or toolbar in Android Studio.
-
-**Next: get your app [running on a hardware Android Device](platform/android/README.md#running-mapbox-gl-native-on-a-hardware-android-device) or [simulator](platform/android/README.md#setting-up-the-android-emulator)**
diff --git a/platform/android/DISTRIBUTE.md b/platform/android/DISTRIBUTE.md
index e7df5650f1..648f26ce25 100644
--- a/platform/android/DISTRIBUTE.md
+++ b/platform/android/DISTRIBUTE.md
@@ -1,21 +1,30 @@
# Distributing Mapbox GL Native for Android
-Depending on your use case, you may want to support all or just a subset of [Android ABIs](http://developer.android.com/ndk/guides/abis.html).
-This can be achieved using the different `Makefile` targets that are available.
+Depending on your use case, you may want to support all or just a subset of [Android ABIs](http://developer.android.com/ndk/guides/abis.html). This document covers building an `.aar` file from the Mapbox Android SDK and building `.so` files for specific ABIs. In normal circumstances an application developer will use [APK splits](https://developer.android.com/studio/build/configure-apk-splits.html) to optimize this at application level.
-##### Build native libraries for all supported ABIs
+##### Build types
+
+With a `BUILDTYPE` var you can specify the build type for the `.so` and `.aar` files:
+
+```bash
+BUILDTYPE=Debug or BUILDTYPE=Release
+```
+
+##### Creating an Android Archive file that supports all ABIs
```sh
-make apackage
+BUILDTYPE=RELEASE make apackage
```
This will build native libraries to support following ABIs:
- - armeabi
- - armeabi-v7a
- - arm64-v8a
- - x86
- - x86_64
- - mips
+- armeabi
+- armeabi-v7a
+- arm64-v8a
+- x86
+- x86_64
+- mips
+
+After succesfully finish building the native libraries, gradle will build the MapboxAndroidSDK module and generate an Android Archive file in `MapboxAndroidSDK/build/outputs/aar `. The packaged native libraries can be found in `MapboxAndroidSDK/src/main/jniLibs/<abi>`.
##### Build native libraries for a specific ABI
@@ -26,13 +35,13 @@ make android-lib-%%
In the command above you'll need to replace `%%` with an ABI key listed below:
| ABI Key | Android ABI |
-|---------|-------------|
-| arm-v5 | armeabi |
-| arm-v7 | armeabi-v7a |
-| arm-v8 | arm64-v8a |
-| x86 | x86 |
-| x86-64 | x86_64 |
-| mips | mips |
+| ------- | ----------- |
+| arm-v5 | armeabi |
+| arm-v7 | armeabi-v7a |
+| arm-v8 | arm64-v8a |
+| x86 | x86 |
+| x86-64 | x86_64 |
+| mips | mips |
For example, to build the arm64-v8a ABI the Makefile target would be:
diff --git a/platform/android/MapboxGLAndroidSDK/build.gradle b/platform/android/MapboxGLAndroidSDK/build.gradle
index 2ce3780421..40712da065 100644
--- a/platform/android/MapboxGLAndroidSDK/build.gradle
+++ b/platform/android/MapboxGLAndroidSDK/build.gradle
@@ -1,12 +1,14 @@
apply plugin: 'com.android.library'
dependencies {
- compile "com.android.support:support-annotations:${supportLibVersion}"
- compile "com.android.support:support-v4:${supportLibVersion}"
- compile "com.android.support:design:${supportLibVersion}"
+ compile rootProject.ext.dep.supportAnnotations
+ compile rootProject.ext.dep.supportV4
+ compile rootProject.ext.dep.supportDesign
compile rootProject.ext.dep.timber
compile rootProject.ext.dep.okhttp3
compile rootProject.ext.dep.lost
+ testCompile rootProject.ext.dep.junit
+ testCompile rootProject.ext.dep.mockito
// Mapbox Android Services (GeoJSON support)
compile(rootProject.ext.dep.mapboxJavaGeoJSON) {
@@ -31,6 +33,70 @@ android {
buildConfigField "String", "MAPBOX_EVENTS_USER_AGENT", String.format("\"MapboxEventsAndroid/%s\"", project.VERSION_NAME)
}
+ defaultPublishConfig project.hasProperty("mapbox.buildtype") ? project.getProperty("mapbox.buildtype") : "debug"
+
+ // We sometimes want to invoke Gradle without building a native dependency, e.g. when we just want
+ // to invoke the Java tests. When we explicitly specify an ABI of 'none', no native dependencies are
+ // added. When another ABI is specified explicitly, we're just going to build that ABI. In all other
+ // cases, all ABIs are built.
+ // When invoking from the command line, set `-Pmapbox.abis=...` to only build the desired architectures.
+ // When building from Android Studio, gradle.properties sets `android.buildOnlyTargetAbi=true` so that
+ // only the architecture for the device you're running on gets built.
+ def abi = 'all'
+ if (!project.hasProperty('android.injected.invoked.from.ide')) {
+ // Errors when the user invokes Gradle from the command line and didn't set mapbox.abis
+ abi = project.getProperty("mapbox.abis")
+ }
+
+ if (abi != 'none') {
+ externalNativeBuild {
+ cmake {
+ path "../../../CMakeLists.txt"
+ }
+ }
+ }
+
+ defaultConfig {
+ if (abi != 'none') {
+ externalNativeBuild {
+ cmake {
+ arguments "-DANDROID_TOOLCHAIN=clang"
+ arguments "-DANDROID_STL=c++_static"
+ arguments "-DANDROID_CPP_FEATURES=rtti;exceptions"
+ arguments "-DMBGL_PLATFORM=android"
+ arguments "-DMASON_PLATFORM=android"
+ arguments "-DNodeJS_EXECUTABLE=" + rootProject.ext.node
+ arguments "-Dnpm_EXECUTABLE=" + rootProject.ext.npm
+
+ // Enable ccache if the user has installed it.
+ if (rootProject.ext.ccache?.trim()) {
+ arguments "-DANDROID_CCACHE=" + rootProject.ext.ccache
+ // ccache splits up the compile command until multiple invocations and uses -E
+ // with one of them, and clang doesn't like unused arguments in that case.
+ cFlags "-Qunused-arguments"
+ cppFlags "-Qunused-arguments"
+ }
+
+ targets "mapbox-gl"
+
+ if (defaultPublishConfig.equalsIgnoreCase("debug")) {
+ targets "example-custom-layer"
+ }
+
+ if (project.hasProperty("mapbox.with_test")) {
+ targets "mbgl-test"
+ }
+
+ if (abi != 'all') {
+ abiFilters abi.split(' ')
+ } else {
+ abiFilters "armeabi", "armeabi-v7a", "mips", "x86", "arm64-v8a", "x86_64"
+ }
+ }
+ }
+ }
+ }
+
// avoid naming conflicts, force usage of prefix
resourcePrefix 'mapbox_'
@@ -49,6 +115,10 @@ android {
warningsAsErrors true
}
+ testOptions {
+ unitTests.returnDefaultValues = true
+ }
+
buildTypes {
debug {
jniDebuggable true
@@ -77,3 +147,4 @@ configurations {
apply from: 'gradle-javadoc.gradle'
apply from: 'gradle-publish.gradle'
apply from: 'gradle-checkstyle.gradle'
+apply from: 'gradle-tests-staticblockremover.gradle'
diff --git a/platform/android/MapboxGLAndroidSDK/gradle-tests-staticblockremover.gradle b/platform/android/MapboxGLAndroidSDK/gradle-tests-staticblockremover.gradle
new file mode 100644
index 0000000000..523dc99dd1
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/gradle-tests-staticblockremover.gradle
@@ -0,0 +1,59 @@
+buildscript {
+ repositories {
+ mavenCentral()
+ mavenLocal()
+ }
+
+ dependencies {
+ classpath 'com.darylteo.gradle:javassist-plugin:0.4.1'
+ }
+}
+
+import com.darylteo.gradle.javassist.tasks.TransformationTask
+import com.darylteo.gradle.javassist.transformers.ClassTransformer
+import javassist.CtClass
+import javassist.CtConstructor
+
+class StaticBlockRemover extends ClassTransformer {
+
+ private static final NATIVE_MAP_VIEW = "com.mapbox.mapboxsdk.maps.NativeMapView";
+ private static
+ final NATIVE_CONNECTIVITY_LISTENER = "com.mapbox.mapboxsdk.net.NativeConnectivityListener";
+ private static final OFFLINE_MANAGER = "com.mapbox.mapboxsdk.offline.OfflineManager";
+ private static final OFFLINE_REGION = "com.mapbox.mapboxsdk.offline.OfflineRegion";
+
+ public void applyTransformations(CtClass clazz) throws Exception {
+ if (shouldFilter(clazz)) {
+ CtConstructor constructor = clazz.getClassInitializer()
+ if (constructor != null) {
+ clazz.removeConstructor(constructor)
+ }
+ }
+ }
+
+ public boolean shouldFilter(CtClass clazz) {
+ return hasAStaticBlock(clazz);
+ }
+
+ private boolean hasAStaticBlock(CtClass clazz) {
+ String name = clazz.getName();
+ boolean isNativeMapView = name.equals(NATIVE_MAP_VIEW);
+ boolean isNativeConnectivityListener = name.equals(NATIVE_CONNECTIVITY_LISTENER);
+ boolean isOfflineManager = name.equals(OFFLINE_MANAGER);
+ boolean isOfflineRegion = name.equals(OFFLINE_REGION);
+
+ return isNativeMapView || isNativeConnectivityListener || isOfflineManager || isOfflineRegion;
+ }
+}
+
+task removeStatic(type: TransformationTask) {
+ // TODO Find a better way to get output classes path
+ String fromToDirPath = buildDir.getAbsolutePath() + "/intermediates/classes/debug"
+ from fromToDirPath
+ transformation = new StaticBlockRemover()
+ into fromToDirPath
+}
+
+afterEvaluate {
+ compileDebugUnitTestSources.dependsOn(removeStatic)
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/gradle.properties b/platform/android/MapboxGLAndroidSDK/gradle.properties
index 7a6f777a3b..9f555da5f8 100644
--- a/platform/android/MapboxGLAndroidSDK/gradle.properties
+++ b/platform/android/MapboxGLAndroidSDK/gradle.properties
@@ -14,3 +14,7 @@ POM_DEVELOPER_NAME=Mapbox
POM_NAME=Mapbox Android SDK
POM_ARTIFACT_ID=mapbox-android-sdk
POM_PACKAGING=aar
+
+# Only build native dependencies for the current ABI
+# See https://code.google.com/p/android/issues/detail?id=221098#c20
+android.buildOnlyTargetAbi=true
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/LibraryLoader.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/LibraryLoader.java
new file mode 100644
index 0000000000..8a75176ccd
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/LibraryLoader.java
@@ -0,0 +1,15 @@
+package com.mapbox.mapboxsdk;
+
+/**
+ * Centralises the knowledge about "mapbox-gl" library loading.
+ */
+public class LibraryLoader {
+
+ /**
+ * Loads "libmapbox-gl.so" native shared library.
+ */
+ public static void load() {
+ System.loadLibrary("mapbox-gl");
+ }
+
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java
index 83d04e7023..8098ee4d86 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java
@@ -4,10 +4,11 @@ import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.support.annotation.NonNull;
+import android.support.annotation.UiThread;
import android.text.TextUtils;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
-import com.mapbox.mapboxsdk.exceptions.InvalidAccessTokenException;
+import com.mapbox.mapboxsdk.exceptions.MapboxConfigurationException;
import com.mapbox.mapboxsdk.location.LocationSource;
import com.mapbox.mapboxsdk.net.ConnectivityReceiver;
import com.mapbox.services.android.telemetry.MapboxTelemetry;
@@ -31,11 +32,12 @@ public final class Mapbox {
* @param accessToken Mapbox access token
* @return the single instance of Mapbox
*/
+ @UiThread
public static synchronized Mapbox getInstance(@NonNull Context context, @NonNull String accessToken) {
if (INSTANCE == null) {
Context appContext = context.getApplicationContext();
INSTANCE = new Mapbox(appContext, accessToken);
- LocationEngine locationEngine = new LocationSource(appContext);
+ LocationEngine locationEngine = LocationSource.getLocationEngine(appContext);
locationEngine.setPriority(LocationEnginePriority.NO_POWER);
MapboxTelemetry.getInstance().initialize(
appContext, accessToken, BuildConfig.MAPBOX_EVENTS_USER_AGENT, locationEngine);
@@ -55,20 +57,30 @@ public final class Mapbox {
* @return Mapbox Access Token
*/
public static String getAccessToken() {
+ validateMapbox();
validateAccessToken();
return INSTANCE.accessToken;
}
/**
+ * Runtime validation of Mapbox creation.
+ */
+ private static void validateMapbox() throws MapboxConfigurationException {
+ if (INSTANCE == null) {
+ throw new MapboxConfigurationException();
+ }
+ }
+
+ /**
* Runtime validation of Access Token.
*
- * @throws InvalidAccessTokenException exception thrown when not using a valid accessToken
+ * @throws MapboxConfigurationException exception thrown when not using a valid accessToken
*/
- private static void validateAccessToken() throws InvalidAccessTokenException {
+ private static void validateAccessToken() throws MapboxConfigurationException {
String accessToken = INSTANCE.accessToken;
if (TextUtils.isEmpty(accessToken) || (!accessToken.toLowerCase(MapboxConstants.MAPBOX_LOCALE).startsWith("pk.")
&& !accessToken.toLowerCase(MapboxConstants.MAPBOX_LOCALE).startsWith("sk."))) {
- throw new InvalidAccessTokenException();
+ throw new MapboxConfigurationException();
}
}
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 4a72cb7d89..dd2c37762a 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,8 +2,12 @@ package com.mapbox.mapboxsdk.annotations;
import android.graphics.Color;
+import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapboxMap;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* Polygon is a geometry annotation that's a closed loop of coordinates.
*/
@@ -11,9 +15,11 @@ public final class Polygon extends BasePointCollection {
private int fillColor = Color.BLACK; // default fillColor is black
private int strokeColor = Color.BLACK; // default strokeColor is black
+ private List<List<LatLng>> holes;
Polygon() {
super();
+ holes = new ArrayList<>();
}
/**
@@ -26,7 +32,7 @@ public final class Polygon extends BasePointCollection {
}
/**
- * Get the color fo the stroke of the polygon.
+ * Get the color of the stroke of the polygon.
*
* @return The color of the stroke.
*/
@@ -35,6 +41,15 @@ public final class Polygon extends BasePointCollection {
}
/**
+ * Returns a copy of the holes.
+ *
+ * @return A {@link List} of {@link List} of {@link LatLng} points making up the holes.
+ */
+ public List<List<LatLng>> getHoles() {
+ return new ArrayList<>(holes);
+ }
+
+ /**
* Sets the color of the fill region of the polygon.
*
* @param color The color in ARGB format.
@@ -54,6 +69,27 @@ public final class Polygon extends BasePointCollection {
update();
}
+ /**
+ * Sets the holes of this polygon. This method will take a copy of the holes, so further
+ * mutations to holes will have no effect on this polygon.
+ *
+ * @param holes A {@link List} of {@link List} of {@link LatLng} points making up the holes.
+ */
+ public void setHoles(List<? extends List<LatLng>> holes) {
+ this.holes = new ArrayList<>(holes);
+ update();
+ }
+
+ /**
+ * Add a hole to the polygon.
+ *
+ * @param hole A {@link List} of {@link List} of {@link LatLng} points making up the hole to be added.
+ */
+ void addHole(List<LatLng> hole) {
+ holes.add(hole);
+ update();
+ }
+
@Override
void update() {
MapboxMap mapboxMap = getMapboxMap();
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/PolygonOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/PolygonOptions.java
index 22f1258fc7..eaad25133e 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/PolygonOptions.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/PolygonOptions.java
@@ -27,9 +27,12 @@ public final class PolygonOptions implements Parcelable {
private PolygonOptions(Parcel in) {
polygon = new Polygon();
- ArrayList<LatLng> pointsList = new ArrayList<>();
+ List<LatLng> pointsList = new ArrayList<>();
in.readList(pointsList, LatLng.class.getClassLoader());
addAll(pointsList);
+ List<List<LatLng>> holes = new ArrayList<>();
+ in.readList(holes, LatLng.class.getClassLoader());
+ addAllHoles(holes);
alpha(in.readFloat());
fillColor(in.readInt());
strokeColor(in.readInt());
@@ -56,6 +59,7 @@ public final class PolygonOptions implements Parcelable {
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeList(getPoints());
+ out.writeList(getHoles());
out.writeFloat(getAlpha());
out.writeInt(getFillColor());
out.writeInt(getStrokeColor());
@@ -109,6 +113,43 @@ public final class PolygonOptions implements Parcelable {
}
/**
+ * Adds a hole to the outline of the polygon being built.
+ *
+ * @param hole {@link List} list made up of {@link LatLng} points defining the hole
+ * @return This {@link PolygonOptions} object with the given hole added to the outline.
+ */
+ public PolygonOptions addHole(List<LatLng> hole) {
+ polygon.addHole(hole);
+ return this;
+ }
+
+ /**
+ * Adds holes to the outline of the polygon being built.
+ *
+ * @param holes {@link List} list made up of {@link LatLng} holes to be added to polygon geometry
+ * @return This {@link PolygonOptions} object with the given holes added to the outline.
+ */
+ public PolygonOptions addHole(List<LatLng>... holes) {
+ for (List<LatLng> hole : holes) {
+ addHole(hole);
+ }
+ return this;
+ }
+
+ /**
+ * Adds holes to the outline of the polygon being built.
+ *
+ * @param holes {@link Iterable} list made up of {@link List} list of {@link LatLng} holes defining the hole geometry
+ * @return This {@link PolygonOptions} object with the given holes added to the outline.
+ */
+ public PolygonOptions addAllHoles(Iterable<List<LatLng>> holes) {
+ for (List<LatLng> hole : holes) {
+ addHole(hole);
+ }
+ return this;
+ }
+
+ /**
* Set the alpha value of the polyline.
*
* @param alpha float value between 0 (not visible) and 1.
@@ -177,18 +218,33 @@ public final class PolygonOptions implements Parcelable {
return polygon.getStrokeColor();
}
+ /**
+ * Gets the points set for this {@link PolygonOptions} object.
+ *
+ * @return The list made up of {@link LatLng} points defining the polygon.
+ */
public List<LatLng> getPoints() {
// the getter gives us a copy, which is the safe thing to do...
return polygon.getPoints();
}
/**
+ * Gets the holes set for this {@link PolygonOptions} object.
+ *
+ * @return The list made up of {@link List} of {@link List} of {@link LatLng} points defining the holes.
+ */
+ public List<List<LatLng>> getHoles() {
+ return polygon.getHoles();
+ }
+
+
+ /**
* Compares this {@link PolygonOptions} object with another {@link PolygonOptions} and
* determines if their color, alpha, stroke color, and vertices match.
*
* @param o Another {@link PolygonOptions} to compare with this object.
- * @return True if color, alpha, stroke color, and vertices match this {@link PolygonOptions}
- * object. Else, false.
+ * @return True if color, alpha, stroke color, vertices and holes match this {@link PolygonOptions}
+ * {@link PolygonOptions} object. Else, false.
*/
@Override
public boolean equals(Object o) {
@@ -210,7 +266,10 @@ public final class PolygonOptions implements Parcelable {
if (getStrokeColor() != polygon.getStrokeColor()) {
return false;
}
- return !(getPoints() != null ? !getPoints().equals(polygon.getPoints()) : polygon.getPoints() != null);
+ if (getPoints() != null ? !getPoints().equals(polygon.getPoints()) : polygon.getPoints() != null) {
+ return false;
+ }
+ return !(getHoles() != null ? !getHoles().equals(polygon.getHoles()) : polygon.getHoles() != null);
}
/**
@@ -228,6 +287,7 @@ public final class PolygonOptions implements Parcelable {
result = 31 * result + getFillColor();
result = 31 * result + getStrokeColor();
result = 31 * result + (getPoints() != null ? getPoints().hashCode() : 0);
+ result = 31 * result + (getHoles() != null ? getHoles().hashCode() : 0);
return result;
}
}
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 0bd9523f4f..9adefa3221 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
@@ -121,6 +121,7 @@ public class MapboxConstants {
public static final String STATE_COMPASS_MARGIN_RIGHT = "mapbox_compassMarginRight";
public static final String STATE_COMPASS_MARGIN_BOTTOM = "mapbox_compassMarginBottom";
public static final String STATE_COMPASS_FADE_WHEN_FACING_NORTH = "mapbox_compassFade";
+ public static final String STATE_COMPASS_IMAGE_BITMAP = "mapbox_compassImage";
public static final String STATE_LOGO_GRAVITY = "mapbox_logoGravity";
public static final String STATE_LOGO_MARGIN_LEFT = "mapbox_logoMarginLeft";
public static final String STATE_LOGO_MARGIN_TOP = "mapbox_logoMarginTop";
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 d55fd4c023..77d0929df3 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
@@ -23,7 +23,7 @@ public class Style {
* constants means your map style will always use the latest version and may change as we
* improve the style
*/
- @StringDef( {MAPBOX_STREETS, OUTDOORS, LIGHT, DARK, SATELLITE, SATELLITE_STREETS})
+ @StringDef( {MAPBOX_STREETS, OUTDOORS, LIGHT, DARK, SATELLITE, SATELLITE_STREETS, TRAFFIC_DAY, TRAFFIC_NIGHT})
@Retention(RetentionPolicy.SOURCE)
public @interface StyleUrl {
}
@@ -35,13 +35,13 @@ public class Style {
* constant means your map style will always use the latest version and may change as we
* improve the style.
*/
- public static final String MAPBOX_STREETS = "mapbox://styles/mapbox/streets-v9";
+ public static final String MAPBOX_STREETS = "mapbox://styles/mapbox/streets-v10";
/**
* 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";
+ public static final String OUTDOORS = "mapbox://styles/mapbox/outdoors-v10";
/**
* Light: Subtle light backdrop for data visualizations. Using this constant means your map
@@ -66,5 +66,23 @@ public class Style {
* constant means your map style will always use the latest version and may change as we
* improve the style.
*/
- public static final String SATELLITE_STREETS = "mapbox://styles/mapbox/satellite-streets-v9";
+ public static final String SATELLITE_STREETS = "mapbox://styles/mapbox/satellite-streets-v10";
+
+ /**
+ * Traffic Day: Color-coded roads based on live traffic congestion data. Traffic data is currently
+ * available in
+ * <a href="https://www.mapbox.com/api-documentation/pages/traffic-countries.html">these select
+ * countries</a>. 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 TRAFFIC_DAY = "mapbox://styles/mapbox/traffic-day-v2";
+
+ /**
+ * Traffic Night: Color-coded roads based on live traffic congestion data, designed to maximize
+ * legibility in low-light situations. Traffic data is currently available in
+ * <a href="https://www.mapbox.com/api-documentation/pages/traffic-countries.html">these select
+ * countries</a>. 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 TRAFFIC_NIGHT = "mapbox://styles/mapbox/traffic-night-v2";
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidAccessTokenException.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/MapboxConfigurationException.java
index 95851fc1d2..74bceb196c 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidAccessTokenException.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/MapboxConfigurationException.java
@@ -1,21 +1,18 @@
package com.mapbox.mapboxsdk.exceptions;
import android.content.Context;
-import android.os.Bundle;
-
-import com.mapbox.mapboxsdk.maps.MapView;
/**
- * A {@code InvalidAccessTokenException} is thrown by {@link com.mapbox.mapboxsdk.maps.MapboxMap}
- * when there is either no access token set before {@link MapView#onCreate(Bundle)} or an invalid access token
- * is set in {@link com.mapbox.mapboxsdk.Mapbox#getInstance(Context, String)}
- *
- * @see MapView#onCreate(Bundle)
+ * A MapboxConfigurationException is thrown by MapboxMap when the SDK hasn't been properly initialised.
+ * <p>
+ * This occurs either when {@link com.mapbox.mapboxsdk.Mapbox} is not correctly initialised or the provided access token
+ * through {@link com.mapbox.mapboxsdk.Mapbox#getInstance(Context, String)} isn't valid.
+ * </p>
* @see com.mapbox.mapboxsdk.Mapbox#getInstance(Context, String)
*/
-public class InvalidAccessTokenException extends RuntimeException {
+public class MapboxConfigurationException extends RuntimeException {
- public InvalidAccessTokenException() {
+ public MapboxConfigurationException() {
super("\nUsing MapView requires setting a valid access token. Use Mapbox.getInstance(Context context, "
+ "String accessToken) to provide one. "
+ "\nPlease see https://www.mapbox.com/help/create-api-access-token/ to learn how to create one."
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java
index 5e3064f75f..ca2d3673b2 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java
@@ -50,8 +50,8 @@ public class LatLng implements ILatLng, Parcelable {
* @param longitude Longitude in degrees
*/
public LatLng(double latitude, double longitude) {
- this.latitude = latitude;
- this.longitude = longitude;
+ setLatitude(latitude);
+ setLongitude(longitude);
}
/**
@@ -62,9 +62,9 @@ public class LatLng implements ILatLng, Parcelable {
* @param altitude Altitude in meters
*/
public LatLng(double latitude, double longitude, double altitude) {
- this.latitude = latitude;
- this.longitude = longitude;
- this.altitude = altitude;
+ setLatitude(latitude);
+ setLongitude(longitude);
+ setAltitude(altitude);
}
/**
@@ -88,12 +88,18 @@ public class LatLng implements ILatLng, Parcelable {
}
protected LatLng(Parcel in) {
- latitude = in.readDouble();
- longitude = in.readDouble();
- altitude = in.readDouble();
+ setLatitude(in.readDouble());
+ setLongitude(in.readDouble());
+ setAltitude(in.readDouble());
}
public void setLatitude(double latitude) {
+ if (Double.isNaN(latitude)) {
+ throw new IllegalArgumentException("latitude must not be NaN");
+ }
+ if (Math.abs(latitude) > 90.0) {
+ throw new IllegalArgumentException("latitude must be between -90 and 90");
+ }
this.latitude = latitude;
}
@@ -103,6 +109,12 @@ public class LatLng implements ILatLng, Parcelable {
}
public void setLongitude(double longitude) {
+ if (Double.isNaN(longitude)) {
+ throw new IllegalArgumentException("longitude must not be NaN");
+ }
+ if (Double.isInfinite(longitude)) {
+ throw new IllegalArgumentException("longitude must not be infinite");
+ }
this.longitude = longitude;
}
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 3b92f0f0f5..4a4e2a30aa 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
@@ -5,12 +5,16 @@ import android.os.Parcelable;
import android.support.annotation.NonNull;
import com.mapbox.mapboxsdk.exceptions.InvalidLatLngBoundsException;
+import com.mapbox.services.android.telemetry.constants.GeoConstants;
import java.util.ArrayList;
import java.util.List;
/**
* A geographical area representing a latitude/longitude aligned rectangle.
+ * <p>
+ * This class does not wrap values to the world bounds.
+ * </p>
*/
public class LatLngBounds implements Parcelable {
@@ -37,6 +41,18 @@ public class LatLngBounds implements Parcelable {
}
/**
+ * Returns the world bounds.
+ *
+ * @return the bounds representing the world
+ */
+ public static LatLngBounds world() {
+ return new LatLngBounds.Builder()
+ .include(new LatLng(GeoConstants.MAX_LATITUDE, GeoConstants.MAX_LONGITUDE))
+ .include(new LatLng(GeoConstants.MIN_LATITUDE, GeoConstants.MIN_LONGITUDE))
+ .build();
+ }
+
+ /**
* Calculates the centerpoint of this LatLngBounds by simple interpolation and returns
* it as a point. This is a non-geodesic calculation which is not the geographic center.
*
@@ -47,23 +63,79 @@ public class LatLngBounds implements Parcelable {
(this.mLonEast + this.mLonWest) / 2);
}
+ /**
+ * Get the north latitude value of this bounds.
+ *
+ * @return double latitude value for north
+ */
public double getLatNorth() {
return this.mLatNorth;
}
+ /**
+ * Get the south latitude value of this bounds.
+ *
+ * @return double latitude value for south
+ */
public double getLatSouth() {
return this.mLatSouth;
}
+ /**
+ * Get the east longitude value of this bounds.
+ *
+ * @return double longitude value for east
+ */
public double getLonEast() {
return this.mLonEast;
}
+ /**
+ * Get the west longitude value of this bounds.
+ *
+ * @return double longitude value for west
+ */
public double getLonWest() {
return this.mLonWest;
}
/**
+ * Get the latitude-longitude pair of the south west corner of this bounds.
+ *
+ * @return LatLng of the south west corner
+ */
+ public LatLng getSouthWest() {
+ return new LatLng(mLatSouth, mLonWest);
+ }
+
+ /**
+ * Get the latitude-longitude paur if the north east corner of this bounds.
+ *
+ * @return LatLng of the north east corner
+ */
+ public LatLng getNorthEast() {
+ return new LatLng(mLatNorth, mLonEast);
+ }
+
+ /**
+ * Get the latitude-longitude pair of the south east corner of this bounds.
+ *
+ * @return LatLng of the south east corner
+ */
+ public LatLng getSouthEast() {
+ return new LatLng(mLatSouth, mLonEast);
+ }
+
+ /**
+ * Get the latitude-longitude pair of the north west corner of this bounds.
+ *
+ * @return LatLng of the north west corner
+ */
+ public LatLng getNorthWest() {
+ return new LatLng(mLatNorth, mLonWest);
+ }
+
+ /**
* Get the area spanned by this LatLngBounds
*
* @return LatLngSpan area
@@ -133,8 +205,27 @@ public class LatLngBounds implements Parcelable {
return new LatLngBounds(maxLat, maxLon, minLat, minLon);
}
+ /**
+ * Return an array of LatLng objects resembling this bounds.
+ *
+ * @return an array of 2 LatLng objects.
+ */
public LatLng[] toLatLngs() {
- return new LatLng[] {new LatLng(mLatNorth, mLonEast), new LatLng(mLatSouth, mLonWest)};
+ return new LatLng[] {getNorthEast(), getSouthWest()};
+ }
+
+ /**
+ * Constructs a LatLngBounds from current bounds with an additional latitude-longitude pair.
+ *
+ * @param latLng the latitude lognitude pair to include in the bounds.
+ * @return the newly constructed bounds
+ */
+ public LatLngBounds include(LatLng latLng) {
+ return new LatLngBounds.Builder()
+ .include(getNorthEast())
+ .include(getSouthWest())
+ .include(latLng)
+ .build();
}
/**
@@ -159,19 +250,28 @@ public class LatLngBounds implements Parcelable {
}
/**
- * Determines whether this LatLngBounds contains a point and the point
- * does not touch its boundary.
+ * Determines whether this LatLngBounds contains a point.
*
* @param latLng the point which may be contained
- * @return true, if the point is contained within the box.
+ * @return true, if the point is contained within the bounds
*/
public boolean contains(final ILatLng latLng) {
final double latitude = latLng.getLatitude();
final double longitude = latLng.getLongitude();
- return ((latitude < this.mLatNorth)
- && (latitude > this.mLatSouth))
- && ((longitude < this.mLonEast)
- && (longitude > this.mLonWest));
+ return ((latitude <= this.mLatNorth)
+ && (latitude >= this.mLatSouth))
+ && ((longitude <= this.mLonEast)
+ && (longitude >= this.mLonWest));
+ }
+
+ /**
+ * Determines whether this LatLngBounds contains another bounds.
+ *
+ * @param other the bounds which may be contained
+ * @return true, if the bounds is contained within the bounds
+ */
+ public boolean contains(final LatLngBounds other) {
+ return contains(other.getNorthEast()) && contains(other.getSouthWest());
}
/**
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationSource.java
index dd6e43d06a..b795cf1d5b 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationSource.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationSource.java
@@ -40,7 +40,7 @@ public class LocationSource extends LocationEngine implements
private WeakReference<Context> context;
private LostApiClient lostApiClient;
- public LocationSource(Context context) {
+ private LocationSource(Context context) {
super();
this.context = new WeakReference<>(context);
lostApiClient = new LostApiClient.Builder(this.context.get())
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationContainer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationContainer.java
new file mode 100644
index 0000000000..939fadc9c2
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationContainer.java
@@ -0,0 +1,86 @@
+package com.mapbox.mapboxsdk.maps;
+
+
+import android.support.annotation.NonNull;
+import android.support.v4.util.LongSparseArray;
+
+import com.mapbox.mapboxsdk.annotations.Annotation;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Encapsulates {@link Annotation}'s functionality..
+ */
+class AnnotationContainer implements Annotations {
+
+ private final NativeMapView nativeMapView;
+ private final LongSparseArray<Annotation> annotations;
+
+ AnnotationContainer(NativeMapView nativeMapView, LongSparseArray<Annotation> annotations) {
+ this.nativeMapView = nativeMapView;
+ this.annotations = annotations;
+ }
+
+ @Override
+ public Annotation obtainBy(long id) {
+ return annotations.get(id);
+ }
+
+ @Override
+ public List<Annotation> obtainAll() {
+ List<Annotation> annotations = new ArrayList<>();
+ for (int i = 0; i < this.annotations.size(); i++) {
+ annotations.add(this.annotations.get(this.annotations.keyAt(i)));
+ }
+ return annotations;
+ }
+
+ @Override
+ public void removeBy(long id) {
+ if (nativeMapView != null) {
+ nativeMapView.removeAnnotation(id);
+ }
+ annotations.remove(id);
+ }
+
+ @Override
+ public void removeBy(@NonNull Annotation annotation) {
+ long id = annotation.getId();
+ removeBy(id);
+ }
+
+ @Override
+ public void removeBy(@NonNull List<? extends Annotation> annotationList) {
+ int count = annotationList.size();
+ long[] ids = new long[count];
+ for (int i = 0; i < count; i++) {
+ ids[i] = annotationList.get(i).getId();
+ }
+
+ removeNativeAnnotations(ids);
+
+ for (long id : ids) {
+ annotations.remove(id);
+ }
+ }
+
+ @Override
+ public void removeAll() {
+ int count = annotations.size();
+ long[] ids = new long[count];
+ for (int i = 0; i < count; i++) {
+ ids[i] = annotations.keyAt(i);
+ }
+
+ removeNativeAnnotations(ids);
+
+ annotations.clear();
+ }
+
+ private void removeNativeAnnotations(long[] ids) {
+ if (nativeMapView != null) {
+ nativeMapView.removeAnnotations(ids);
+ }
+ }
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java
index 0c77723354..9b6706b90c 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java
@@ -9,7 +9,6 @@ import android.support.v4.util.LongSparseArray;
import com.mapbox.mapboxsdk.annotations.Annotation;
import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions;
import com.mapbox.mapboxsdk.annotations.BaseMarkerViewOptions;
-import com.mapbox.mapboxsdk.annotations.Icon;
import com.mapbox.mapboxsdk.annotations.Marker;
import com.mapbox.mapboxsdk.annotations.MarkerView;
import com.mapbox.mapboxsdk.annotations.MarkerViewManager;
@@ -40,17 +39,28 @@ class AnnotationManager {
private final IconManager iconManager;
private final InfoWindowManager infoWindowManager = new InfoWindowManager();
private final MarkerViewManager markerViewManager;
- private final LongSparseArray<Annotation> annotations = new LongSparseArray<>();
+ private final LongSparseArray<Annotation> annotationsArray;
private final List<Marker> selectedMarkers = new ArrayList<>();
private MapboxMap mapboxMap;
private MapboxMap.OnMarkerClickListener onMarkerClickListener;
-
- AnnotationManager(NativeMapView view, MapView mapView, MarkerViewManager markerViewManager) {
+ private Annotations annotations;
+ private Markers markers;
+ private Polygons polygons;
+ private Polylines polylines;
+
+ AnnotationManager(NativeMapView view, MapView mapView, LongSparseArray<Annotation> annotationsArray,
+ MarkerViewManager markerViewManager, IconManager iconManager, Annotations annotations,
+ Markers markers, Polygons polygons, Polylines polylines) {
this.nativeMapView = view;
this.mapView = mapView;
- this.iconManager = new IconManager(nativeMapView);
+ this.annotationsArray = annotationsArray;
this.markerViewManager = markerViewManager;
+ this.iconManager = iconManager;
+ this.annotations = annotations;
+ this.markers = markers;
+ this.polygons = polygons;
+ this.polylines = polylines;
if (view != null) {
// null checking needed for unit tests
nativeMapView.addOnMapChangedListener(markerViewManager);
@@ -75,15 +85,15 @@ class AnnotationManager {
//
Annotation getAnnotation(long id) {
- return annotations.get(id);
+ return annotations.obtainBy(id);
}
List<Annotation> getAnnotations() {
- List<Annotation> annotations = new ArrayList<>();
- for (int i = 0; i < this.annotations.size(); i++) {
- annotations.add(this.annotations.get(this.annotations.keyAt(i)));
- }
- return annotations;
+ return annotations.obtainAll();
+ }
+
+ void removeAnnotation(long id) {
+ annotations.removeBy(id);
}
void removeAnnotation(@NonNull Annotation annotation) {
@@ -94,25 +104,11 @@ class AnnotationManager {
markerViewManager.removeMarkerView((MarkerView) marker);
}
}
- long id = annotation.getId();
- if (nativeMapView != null) {
- nativeMapView.removeAnnotation(id);
- }
- annotations.remove(id);
- }
-
- void removeAnnotation(long id) {
- if (nativeMapView != null) {
- nativeMapView.removeAnnotation(id);
- }
- annotations.remove(id);
+ annotations.removeBy(annotation);
}
void removeAnnotations(@NonNull List<? extends Annotation> annotationList) {
- int count = annotationList.size();
- long[] ids = new long[count];
- for (int i = 0; i < count; i++) {
- Annotation annotation = annotationList.get(i);
+ for (Annotation annotation : annotationList) {
if (annotation instanceof Marker) {
Marker marker = (Marker) annotation;
marker.hideInfoWindow();
@@ -120,25 +116,17 @@ class AnnotationManager {
markerViewManager.removeMarkerView((MarkerView) marker);
}
}
- ids[i] = annotationList.get(i).getId();
- }
-
- if (nativeMapView != null) {
- nativeMapView.removeAnnotations(ids);
- }
-
- for (long id : ids) {
- annotations.remove(id);
}
+ annotations.removeBy(annotationList);
}
void removeAnnotations() {
Annotation annotation;
- int count = annotations.size();
+ int count = annotationsArray.size();
long[] ids = new long[count];
for (int i = 0; i < count; i++) {
- ids[i] = annotations.keyAt(i);
- annotation = annotations.get(ids[i]);
+ ids[i] = annotationsArray.keyAt(i);
+ annotation = annotationsArray.get(ids[i]);
if (annotation instanceof Marker) {
Marker marker = (Marker) annotation;
marker.hideInfoWindow();
@@ -147,12 +135,7 @@ class AnnotationManager {
}
}
}
-
- if (nativeMapView != null) {
- nativeMapView.removeAnnotations(ids);
- }
-
- annotations.clear();
+ annotations.removeAll();
}
//
@@ -160,139 +143,86 @@ class AnnotationManager {
//
Marker addMarker(@NonNull BaseMarkerOptions markerOptions, @NonNull MapboxMap mapboxMap) {
- Marker marker = prepareMarker(markerOptions);
- long id = nativeMapView != null ? nativeMapView.addMarker(marker) : 0;
- marker.setMapboxMap(mapboxMap);
- marker.setId(id);
- annotations.put(id, marker);
- return marker;
+ return markers.addBy(markerOptions, mapboxMap);
}
List<Marker> addMarkers(@NonNull List<? extends BaseMarkerOptions> markerOptionsList, @NonNull MapboxMap mapboxMap) {
- int count = markerOptionsList.size();
- List<Marker> markers = new ArrayList<>(count);
- if (count > 0) {
- BaseMarkerOptions markerOptions;
- Marker marker;
- for (int i = 0; i < count; i++) {
- markerOptions = markerOptionsList.get(i);
- marker = prepareMarker(markerOptions);
- markers.add(marker);
- }
-
- if (markers.size() > 0) {
- long[] ids = null;
- if (nativeMapView != null) {
- ids = nativeMapView.addMarkers(markers);
- }
+ return markers.addBy(markerOptionsList, mapboxMap);
+ }
- long id = 0;
- Marker m;
- for (int i = 0; i < markers.size(); i++) {
- m = markers.get(i);
- m.setMapboxMap(mapboxMap);
- if (ids != null) {
- id = ids[i];
- } else {
- // unit test
- id++;
- }
- m.setId(id);
- annotations.put(id, m);
- }
+ void updateMarker(@NonNull Marker updatedMarker, @NonNull MapboxMap mapboxMap) {
+ markers.update(updatedMarker, mapboxMap);
+ }
- }
- }
- return markers;
+ List<Marker> getMarkers() {
+ return markers.obtainAll();
}
- private Marker prepareMarker(BaseMarkerOptions markerOptions) {
- Marker marker = markerOptions.getMarker();
- Icon icon = iconManager.loadIconForMarker(marker);
- marker.setTopOffsetPixels(iconManager.getTopOffsetPixelsForIcon(icon));
- return marker;
+ @NonNull
+ List<Marker> getMarkersInRect(@NonNull RectF rectangle) {
+ return markers.obtainAllIn(rectangle);
}
MarkerView addMarker(@NonNull BaseMarkerViewOptions markerOptions, @NonNull MapboxMap mapboxMap,
@Nullable MarkerViewManager.OnMarkerViewAddedListener onMarkerViewAddedListener) {
- final MarkerView marker = prepareViewMarker(markerOptions);
+ return markers.addViewBy(markerOptions, mapboxMap, onMarkerViewAddedListener);
+ }
- // add marker to map
- marker.setMapboxMap(mapboxMap);
- long id = nativeMapView.addMarker(marker);
- marker.setId(id);
- annotations.put(id, marker);
+ List<MarkerView> addMarkerViews(@NonNull List<? extends BaseMarkerViewOptions> markerViewOptions,
+ @NonNull MapboxMap mapboxMap) {
+ return markers.addViewsBy(markerViewOptions, mapboxMap);
+ }
- if (onMarkerViewAddedListener != null) {
- markerViewManager.addOnMarkerViewAddedListener(marker, onMarkerViewAddedListener);
- }
- markerViewManager.setEnabled(true);
- markerViewManager.setWaitingForRenderInvoke(true);
- return marker;
+ List<MarkerView> getMarkerViewsInRect(@NonNull RectF rectangle) {
+ return markers.obtainViewsIn(rectangle);
}
+ void reloadMarkers() {
+ markers.reload();
+ }
- List<MarkerView> addMarkerViews(@NonNull List<? extends BaseMarkerViewOptions> markerViewOptions,
- @NonNull MapboxMap mapboxMap) {
- List<MarkerView> markers = new ArrayList<>();
- for (BaseMarkerViewOptions markerViewOption : markerViewOptions) {
- // if last marker
- if (markerViewOptions.indexOf(markerViewOption) == markerViewOptions.size() - 1) {
- // get notified when render occurs to invalidate and draw MarkerViews
- markerViewManager.setWaitingForRenderInvoke(true);
- }
- // add marker to map
- MarkerView marker = prepareViewMarker(markerViewOption);
- marker.setMapboxMap(mapboxMap);
- long id = nativeMapView.addMarker(marker);
- marker.setId(id);
- annotations.put(id, marker);
- markers.add(marker);
- }
- markerViewManager.setEnabled(true);
- markerViewManager.update();
- return markers;
+ //
+ // Polygons
+ //
+
+ Polygon addPolygon(@NonNull PolygonOptions polygonOptions, @NonNull MapboxMap mapboxMap) {
+ return polygons.addBy(polygonOptions, mapboxMap);
}
- private MarkerView prepareViewMarker(BaseMarkerViewOptions markerViewOptions) {
- MarkerView marker = markerViewOptions.getMarker();
- iconManager.loadIconForMarkerView(marker);
- return marker;
+ List<Polygon> addPolygons(@NonNull List<PolygonOptions> polygonOptionsList, @NonNull MapboxMap mapboxMap) {
+ return polygons.addBy(polygonOptionsList, mapboxMap);
}
- void updateMarker(@NonNull Marker updatedMarker, @NonNull MapboxMap mapboxMap) {
- if (updatedMarker == null) {
- return;
- }
+ void updatePolygon(Polygon polygon) {
+ polygons.update(polygon);
+ }
- if (updatedMarker.getId() == -1) {
- return;
- }
+ List<Polygon> getPolygons() {
+ return polygons.obtainAll();
+ }
- if (!(updatedMarker instanceof MarkerView)) {
- iconManager.ensureIconLoaded(updatedMarker, mapboxMap);
- }
+ //
+ // Polylines
+ //
- nativeMapView.updateMarker(updatedMarker);
+ Polyline addPolyline(@NonNull PolylineOptions polylineOptions, @NonNull MapboxMap mapboxMap) {
+ return polylines.addBy(polylineOptions, mapboxMap);
+ }
- int index = annotations.indexOfKey(updatedMarker.getId());
- if (index > -1) {
- annotations.setValueAt(index, updatedMarker);
- }
+ List<Polyline> addPolylines(@NonNull List<PolylineOptions> polylineOptionsList, @NonNull MapboxMap mapboxMap) {
+ return polylines.addBy(polylineOptionsList, mapboxMap);
}
- List<Marker> getMarkers() {
- List<Marker> markers = new ArrayList<>();
- Annotation annotation;
- for (int i = 0; i < annotations.size(); i++) {
- annotation = annotations.get(annotations.keyAt(i));
- if (annotation instanceof Marker) {
- markers.add((Marker) annotation);
- }
- }
- return markers;
+ void updatePolyline(Polyline polyline) {
+ polylines.update(polyline);
}
+ List<Polyline> getPolylines() {
+ return polylines.obtainAll();
+ }
+
+ // TODO Refactor from here still in progress
+
void setOnMarkerClickListener(@Nullable MapboxMap.OnMarkerClickListener listener) {
onMarkerClickListener = listener;
}
@@ -359,222 +289,6 @@ class AnnotationManager {
return selectedMarkers;
}
- @NonNull
- List<Marker> getMarkersInRect(@NonNull RectF rectangle) {
- // convert Rectangle to be density depedent
- float pixelRatio = nativeMapView.getPixelRatio();
- RectF rect = new RectF(rectangle.left / pixelRatio,
- rectangle.top / pixelRatio,
- rectangle.right / pixelRatio,
- rectangle.bottom / pixelRatio);
-
- long[] ids = nativeMapView.queryPointAnnotations(rect);
-
- List<Long> idsList = new ArrayList<>(ids.length);
- for (long id : ids) {
- idsList.add(id);
- }
-
- List<Marker> annotations = new ArrayList<>(ids.length);
- List<Annotation> annotationList = getAnnotations();
- int count = annotationList.size();
- for (int i = 0; i < count; i++) {
- Annotation annotation = annotationList.get(i);
- if (annotation instanceof com.mapbox.mapboxsdk.annotations.Marker && idsList.contains(annotation.getId())) {
- annotations.add((com.mapbox.mapboxsdk.annotations.Marker) annotation);
- }
- }
-
- return new ArrayList<>(annotations);
- }
-
- List<MarkerView> getMarkerViewsInRect(@NonNull RectF rectangle) {
- float pixelRatio = nativeMapView.getPixelRatio();
- RectF rect = new RectF(rectangle.left / pixelRatio,
- rectangle.top / pixelRatio,
- rectangle.right / pixelRatio,
- rectangle.bottom / pixelRatio);
-
- long[] ids = nativeMapView.queryPointAnnotations(rect);
-
- List<Long> idsList = new ArrayList<>(ids.length);
- for (long id : ids) {
- idsList.add(id);
- }
-
- List<MarkerView> annotations = new ArrayList<>(ids.length);
- List<Annotation> annotationList = getAnnotations();
- int count = annotationList.size();
- for (int i = 0; i < count; i++) {
- Annotation annotation = annotationList.get(i);
- if (annotation instanceof MarkerView && idsList.contains(annotation.getId())) {
- annotations.add((MarkerView) annotation);
- }
- }
-
- return new ArrayList<>(annotations);
- }
-
- //
- // Polygons
- //
-
- Polygon addPolygon(@NonNull PolygonOptions polygonOptions, @NonNull MapboxMap mapboxMap) {
- Polygon polygon = polygonOptions.getPolygon();
- if (!polygon.getPoints().isEmpty()) {
- long id = nativeMapView != null ? nativeMapView.addPolygon(polygon) : 0;
- polygon.setId(id);
- polygon.setMapboxMap(mapboxMap);
- annotations.put(id, polygon);
- }
- return polygon;
- }
-
- List<Polygon> addPolygons(@NonNull List<PolygonOptions> polygonOptionsList, @NonNull MapboxMap mapboxMap) {
- int count = polygonOptionsList.size();
-
- Polygon polygon;
- List<Polygon> polygons = new ArrayList<>(count);
- if (count > 0) {
- for (PolygonOptions polygonOptions : polygonOptionsList) {
- polygon = polygonOptions.getPolygon();
- if (!polygon.getPoints().isEmpty()) {
- polygons.add(polygon);
- }
- }
-
- long[] ids = null;
- if (nativeMapView != null) {
- ids = nativeMapView.addPolygons(polygons);
- }
-
- long id = 0;
- for (int i = 0; i < polygons.size(); i++) {
- polygon = polygons.get(i);
- polygon.setMapboxMap(mapboxMap);
- if (ids != null) {
- id = ids[i];
- } else {
- // unit test
- id++;
- }
- polygon.setId(id);
- annotations.put(id, polygon);
- }
- }
- return polygons;
- }
-
- void updatePolygon(Polygon polygon) {
- if (polygon == null) {
- return;
- }
-
- if (polygon.getId() == -1) {
- return;
- }
-
- nativeMapView.updatePolygon(polygon);
-
- int index = annotations.indexOfKey(polygon.getId());
- if (index > -1) {
- annotations.setValueAt(index, polygon);
- }
- }
-
- List<Polygon> getPolygons() {
- List<Polygon> polygons = new ArrayList<>();
- Annotation annotation;
- for (int i = 0; i < annotations.size(); i++) {
- annotation = annotations.get(annotations.keyAt(i));
- if (annotation instanceof Polygon) {
- polygons.add((Polygon) annotation);
- }
- }
- return polygons;
- }
-
- //
- // Polylines
- //
-
- Polyline addPolyline(@NonNull PolylineOptions polylineOptions, @NonNull MapboxMap mapboxMap) {
- Polyline polyline = polylineOptions.getPolyline();
- if (!polyline.getPoints().isEmpty()) {
- long id = nativeMapView != null ? nativeMapView.addPolyline(polyline) : 0;
- polyline.setMapboxMap(mapboxMap);
- polyline.setId(id);
- annotations.put(id, polyline);
- }
- return polyline;
- }
-
- List<Polyline> addPolylines(@NonNull List<PolylineOptions> polylineOptionsList, @NonNull MapboxMap mapboxMap) {
- int count = polylineOptionsList.size();
- Polyline polyline;
- List<Polyline> polylines = new ArrayList<>(count);
-
- if (count > 0) {
- for (PolylineOptions options : polylineOptionsList) {
- polyline = options.getPolyline();
- if (!polyline.getPoints().isEmpty()) {
- polylines.add(polyline);
- }
- }
-
- long[] ids = null;
- if (nativeMapView != null) {
- ids = nativeMapView.addPolylines(polylines);
- }
-
- long id = 0;
- Polyline p;
-
- for (int i = 0; i < polylines.size(); i++) {
- p = polylines.get(i);
- p.setMapboxMap(mapboxMap);
- if (ids != null) {
- id = ids[i];
- } else {
- // unit test
- id++;
- }
- p.setId(id);
- annotations.put(id, p);
- }
- }
- return polylines;
- }
-
- void updatePolyline(Polyline polyline) {
- if (polyline == null) {
- return;
- }
-
- if (polyline.getId() == -1) {
- return;
- }
-
- nativeMapView.updatePolyline(polyline);
-
- int index = annotations.indexOfKey(polyline.getId());
- if (index > -1) {
- annotations.setValueAt(index, polyline);
- }
- }
-
- List<Polyline> getPolylines() {
- List<Polyline> polylines = new ArrayList<>();
- Annotation annotation;
- for (int i = 0; i < annotations.size(); i++) {
- annotation = annotations.get(annotations.keyAt(i));
- if (annotation instanceof Polyline) {
- polylines.add((Polyline) annotation);
- }
- }
- return polylines;
- }
-
InfoWindowManager getInfoWindowManager() {
return infoWindowManager;
}
@@ -584,9 +298,9 @@ class AnnotationManager {
}
void adjustTopOffsetPixels(MapboxMap mapboxMap) {
- int count = annotations.size();
+ int count = annotationsArray.size();
for (int i = 0; i < count; i++) {
- Annotation annotation = annotations.get(i);
+ Annotation annotation = annotationsArray.get(i);
if (annotation instanceof Marker) {
Marker marker = (Marker) annotation;
marker.setTopOffsetPixels(
@@ -602,20 +316,6 @@ class AnnotationManager {
}
}
- void reloadMarkers() {
- iconManager.reloadIcons();
- int count = annotations.size();
- for (int i = 0; i < count; i++) {
- Annotation annotation = annotations.get(i);
- if (annotation instanceof Marker) {
- Marker marker = (Marker) annotation;
- nativeMapView.removeAnnotation(annotation.getId());
- long newId = nativeMapView.addMarker(marker);
- marker.setId(newId);
- }
- }
- }
-
//
// Click event
//
@@ -669,13 +369,9 @@ class AnnotationManager {
}
}
- if (annotation instanceof MarkerView) {
- markerViewManager.onClickMarkerView((MarkerView) annotation);
- } else {
- if (!handledDefaultClick) {
- // only select marker if user didn't handle the click event themselves
- selectMarker(marker);
- }
+ if (!handledDefaultClick) {
+ // only select marker if user didn't handle the click event themselves
+ selectMarker(marker);
}
return true;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Annotations.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Annotations.java
new file mode 100644
index 0000000000..ae41cbb0cb
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Annotations.java
@@ -0,0 +1,25 @@
+package com.mapbox.mapboxsdk.maps;
+
+
+import android.support.annotation.NonNull;
+
+import com.mapbox.mapboxsdk.annotations.Annotation;
+
+import java.util.List;
+
+/**
+ * Interface that defines convenient methods for working with a {@link Annotation}'s collection.
+ */
+interface Annotations {
+ Annotation obtainBy(long id);
+
+ List<Annotation> obtainAll();
+
+ void removeBy(long id);
+
+ void removeBy(@NonNull Annotation annotation);
+
+ void removeBy(@NonNull List<? extends Annotation> annotationList);
+
+ void removeAll();
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java
new file mode 100644
index 0000000000..5113a0cc73
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java
@@ -0,0 +1,177 @@
+package com.mapbox.mapboxsdk.maps;
+
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.support.v7.app.AlertDialog;
+import android.text.Html;
+import android.text.SpannableStringBuilder;
+import android.text.TextUtils;
+import android.text.style.URLSpan;
+import android.view.View;
+import android.widget.ArrayAdapter;
+import android.widget.Toast;
+
+import com.mapbox.mapboxsdk.R;
+import com.mapbox.mapboxsdk.camera.CameraPosition;
+import com.mapbox.mapboxsdk.style.sources.Source;
+import com.mapbox.services.android.telemetry.MapboxTelemetry;
+
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Locale;
+
+/**
+ * Responsible for managing attribution interactions on the map.
+ * <p>
+ * When the user clicks the attribution icon, {@link AttributionDialogManager#onClick(View)} will be invoked.
+ * An attribution dialog will be shown to the user with contents based on the attributions found in the map style.
+ * Additionally an telemetry option item is shown to configure telemetry settings.
+ * </p>
+ */
+class AttributionDialogManager implements View.OnClickListener, DialogInterface.OnClickListener {
+
+ private static final String MAP_FEEDBACK_URL = "https://www.mapbox.com/map-feedback";
+ private static final String MAP_FEEDBACK_LOCATION_FORMAT = MAP_FEEDBACK_URL + "/#/%f/%f/%d";
+
+ private final Context context;
+ private final MapboxMap mapboxMap;
+ private String[] attributionKeys;
+ private HashMap<String, String> attributionMap;
+
+ AttributionDialogManager(@NonNull Context context, @NonNull MapboxMap mapboxMap) {
+ this.context = context;
+ this.mapboxMap = mapboxMap;
+ }
+
+ // Called when someone presses the attribution icon on the map
+ @Override
+ public void onClick(View view) {
+ attributionMap = new AttributionBuilder(context, mapboxMap).build();
+ showAttributionDialog();
+ }
+
+ private void showAttributionDialog() {
+ attributionKeys = attributionMap.keySet().toArray(new String[attributionMap.size()]);
+ AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.mapbox_AlertDialogStyle);
+ builder.setTitle(R.string.mapbox_attributionsDialogTitle);
+ builder.setAdapter(new ArrayAdapter<>(context, R.layout.mapbox_attribution_list_item, attributionKeys), this);
+ builder.show();
+ }
+
+ // Called when someone selects an attribution or telemetry settings from the dialog
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ if (isLatestEntry(which)) {
+ showTelemetryDialog();
+ } else {
+ showMapFeedbackWebPage(which);
+ }
+ }
+
+ private boolean isLatestEntry(int attributionKeyIndex) {
+ return attributionKeyIndex == attributionKeys.length - 1;
+ }
+
+ private void showTelemetryDialog() {
+ AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.mapbox_AlertDialogStyle);
+ builder.setTitle(R.string.mapbox_attributionTelemetryTitle);
+ builder.setMessage(R.string.mapbox_attributionTelemetryMessage);
+ builder.setPositiveButton(R.string.mapbox_attributionTelemetryPositive, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ MapboxTelemetry.getInstance().setTelemetryEnabled(true);
+ dialog.cancel();
+ }
+ });
+ builder.setNeutralButton(R.string.mapbox_attributionTelemetryNeutral, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ showWebPage(context.getResources().getString(R.string.mapbox_telemetryLink));
+ dialog.cancel();
+ }
+ });
+ builder.setNegativeButton(R.string.mapbox_attributionTelemetryNegative, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ MapboxTelemetry.getInstance().setTelemetryEnabled(false);
+ dialog.cancel();
+ }
+ });
+ builder.show();
+ }
+
+ private void showMapFeedbackWebPage(int which) {
+ String url = attributionMap.get(attributionKeys[which]);
+ if (url.contains(MAP_FEEDBACK_URL)) {
+ url = buildMapFeedbackMapUrl(mapboxMap.getCameraPosition());
+ }
+ showWebPage(url);
+ }
+
+ private String buildMapFeedbackMapUrl(CameraPosition cameraPosition) {
+ // appends current location to the map feedback url if available
+ return cameraPosition != null ? String.format(Locale.getDefault(),
+ MAP_FEEDBACK_LOCATION_FORMAT, cameraPosition.target.getLongitude(), cameraPosition.target.getLatitude(),
+ (int) cameraPosition.zoom) : MAP_FEEDBACK_URL;
+ }
+
+ private void showWebPage(@NonNull String url) {
+ try {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setData(Uri.parse(url));
+ context.startActivity(intent);
+ } catch (ActivityNotFoundException exception) {
+ // explicitly handling if the device hasn't have a web browser installed. #8899
+ Toast.makeText(context, R.string.mapbox_attributionErrorNoBrowser, Toast.LENGTH_LONG).show();
+ }
+ }
+
+ private static class AttributionBuilder {
+
+ private final HashMap<String, String> map = new LinkedHashMap<>();
+ private final Context context;
+ private final MapboxMap mapboxMap;
+
+ AttributionBuilder(Context context, MapboxMap mapboxMap) {
+ this.context = context.getApplicationContext();
+ this.mapboxMap = mapboxMap;
+ }
+
+ private HashMap<String, String> build() {
+ for (Source source : mapboxMap.getSources()) {
+ parseAttribution(source.getAttribution());
+ }
+ addTelemetryEntryToAttributionMap();
+ return map;
+ }
+
+ private void parseAttribution(String attributionSource) {
+ if (!TextUtils.isEmpty(attributionSource)) {
+ SpannableStringBuilder htmlBuilder = (SpannableStringBuilder) Html.fromHtml(attributionSource);
+ URLSpan[] urlSpans = htmlBuilder.getSpans(0, htmlBuilder.length(), URLSpan.class);
+ for (URLSpan urlSpan : urlSpans) {
+ map.put(resolveAnchorValue(htmlBuilder, urlSpan), urlSpan.getURL());
+ }
+ }
+ }
+
+ private String resolveAnchorValue(SpannableStringBuilder htmlBuilder, URLSpan urlSpan) {
+ int start = htmlBuilder.getSpanStart(urlSpan);
+ int end = htmlBuilder.getSpanEnd(urlSpan);
+ int length = end - start;
+ char[] charKey = new char[length];
+ htmlBuilder.getChars(start, end, charKey, 0);
+ return String.valueOf(charKey);
+ }
+
+ private void addTelemetryEntryToAttributionMap() {
+ String telemetryKey = context.getString(R.string.mapbox_telemetrySettings);
+ String telemetryLink = context.getString(R.string.mapbox_telemetryLink);
+ map.put(telemetryKey, telemetryLink);
+ }
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java
index 67e55352f4..dca833bbf4 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java
@@ -153,9 +153,9 @@ final class MapGestureDetector {
&& uiSettings.isZoomGesturesEnabled();
if (twoTap) {
// Confirmed 2nd Finger Down
- MapboxTelemetry.getInstance().pushEvent(MapboxEvent.buildMapClickEvent(
+ MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapClickEvent(
getLocationFromGesture(event.getX(), event.getY()),
- MapboxEvent.GESTURE_TWO_FINGER_SINGLETAP, transform.getZoom()));
+ MapboxEvent.GESTURE_TWO_FINGER_SINGLETAP, transform));
}
break;
@@ -184,8 +184,8 @@ final class MapGestureDetector {
// Scroll / Pan Has Stopped
if (scrollInProgress) {
- MapboxTelemetry.getInstance().pushEvent(MapboxEvent.buildMapDragEndEvent(
- getLocationFromGesture(event.getX(), event.getY()), transform.getZoom()));
+ MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapDragEndEvent(
+ getLocationFromGesture(event.getX(), event.getY()), transform));
scrollInProgress = false;
}
@@ -230,7 +230,7 @@ final class MapGestureDetector {
float scrollDist = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
// Scale the map by the appropriate power of two factor
- transform.zoomBy(Math.pow(2.0, scrollDist), event.getX(), event.getY());
+ transform.zoomBy(scrollDist, event.getX(), event.getY());
return true;
@@ -284,9 +284,9 @@ final class MapGestureDetector {
break;
}
- MapboxTelemetry.getInstance().pushEvent(MapboxEvent.buildMapClickEvent(
+ MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapClickEvent(
getLocationFromGesture(e.getX(), e.getY()),
- MapboxEvent.GESTURE_DOUBLETAP, transform.getZoom()));
+ MapboxEvent.GESTURE_DOUBLETAP, transform));
return true;
}
@@ -315,9 +315,9 @@ final class MapGestureDetector {
}
}
- MapboxTelemetry.getInstance().pushEvent(MapboxEvent.buildMapClickEvent(
+ MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapClickEvent(
getLocationFromGesture(motionEvent.getX(), motionEvent.getY()),
- MapboxEvent.GESTURE_SINGLETAP, transform.getZoom()));
+ MapboxEvent.GESTURE_SINGLETAP, transform));
return true;
}
@@ -377,9 +377,9 @@ final class MapGestureDetector {
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
if (!scrollInProgress) {
scrollInProgress = true;
- MapboxTelemetry.getInstance().pushEvent(MapboxEvent.buildMapClickEvent(
+ MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapClickEvent(
getLocationFromGesture(e1.getX(), e1.getY()),
- MapboxEvent.GESTURE_PAN_START, transform.getZoom()));
+ MapboxEvent.GESTURE_PAN_START, transform));
}
if (!trackingSettings.isScrollGestureCurrentlyEnabled()) {
return false;
@@ -421,9 +421,9 @@ final class MapGestureDetector {
scaleGestureOccurred = true;
beginTime = detector.getEventTime();
- MapboxTelemetry.getInstance().pushEvent(MapboxEvent.buildMapClickEvent(
+ MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapClickEvent(
getLocationFromGesture(detector.getFocusX(), detector.getFocusY()),
- MapboxEvent.GESTURE_PINCH_START, transform.getZoom()));
+ MapboxEvent.GESTURE_PINCH_START, transform));
return true;
}
@@ -479,17 +479,17 @@ final class MapGestureDetector {
// Scale the map
if (focalPoint != null) {
// arround user provided focal point
- transform.zoomBy(detector.getScaleFactor(), focalPoint.x, focalPoint.y);
+ transform.zoomBy(Math.log(detector.getScaleFactor()) / Math.log(2), focalPoint.x, focalPoint.y);
} else if (quickZoom) {
// clamp scale factors we feed to core #7514
float scaleFactor = MathUtils.clamp(detector.getScaleFactor(),
MapboxConstants.MINIMUM_SCALE_FACTOR_CLAMP,
MapboxConstants.MAXIMUM_SCALE_FACTOR_CLAMP);
// around center map
- transform.zoomBy(scaleFactor, uiSettings.getWidth() / 2, uiSettings.getHeight() / 2);
+ transform.zoomBy(Math.log(scaleFactor) / Math.log(2), uiSettings.getWidth() / 2, uiSettings.getHeight() / 2);
} else {
// around gesture
- transform.zoomBy(detector.getScaleFactor(), detector.getFocusX(), detector.getFocusY());
+ transform.zoomBy(Math.log(detector.getScaleFactor()) / Math.log(2), detector.getFocusX(), detector.getFocusY());
}
return true;
@@ -513,9 +513,9 @@ final class MapGestureDetector {
}
beginTime = detector.getEventTime();
- MapboxTelemetry.getInstance().pushEvent(MapboxEvent.buildMapClickEvent(
+ MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapClickEvent(
getLocationFromGesture(detector.getFocusX(), detector.getFocusY()),
- MapboxEvent.GESTURE_ROTATION_START, transform.getZoom()));
+ MapboxEvent.GESTURE_ROTATION_START, transform));
return true;
}
@@ -594,9 +594,9 @@ final class MapGestureDetector {
}
beginTime = detector.getEventTime();
- MapboxTelemetry.getInstance().pushEvent(MapboxEvent.buildMapClickEvent(
+ MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapClickEvent(
getLocationFromGesture(detector.getFocusX(), detector.getFocusY()),
- MapboxEvent.GESTURE_PITCH_START, transform.getZoom()));
+ MapboxEvent.GESTURE_PITCH_START, transform));
return true;
}
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 8c8b70d788..4f90b0a8fe 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
@@ -1,15 +1,11 @@
package com.mapbox.mapboxsdk.maps;
import android.app.Activity;
-import android.app.Dialog;
import android.app.Fragment;
import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
import android.graphics.Canvas;
import android.graphics.PointF;
import android.graphics.SurfaceTexture;
-import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.CallSuper;
@@ -17,7 +13,7 @@ import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
-import android.support.v7.app.AlertDialog;
+import android.support.v4.util.LongSparseArray;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -28,22 +24,20 @@ import android.view.SurfaceView;
import android.view.TextureView;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ZoomButtonsController;
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.R;
+import com.mapbox.mapboxsdk.annotations.Annotation;
import com.mapbox.mapboxsdk.annotations.MarkerViewManager;
-import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
import com.mapbox.mapboxsdk.constants.Style;
import com.mapbox.mapboxsdk.maps.widgets.CompassView;
import com.mapbox.mapboxsdk.maps.widgets.MyLocationView;
import com.mapbox.mapboxsdk.maps.widgets.MyLocationViewSettings;
import com.mapbox.mapboxsdk.net.ConnectivityReceiver;
-import com.mapbox.services.android.telemetry.MapboxEvent;
import com.mapbox.services.android.telemetry.MapboxTelemetry;
import java.lang.annotation.Retention;
@@ -69,6 +63,7 @@ import java.util.List;
public class MapView extends FrameLayout {
private NativeMapView nativeMapView;
+ private boolean textureMode;
private boolean destroyed;
private boolean hasSurface;
@@ -112,12 +107,14 @@ public class MapView extends FrameLayout {
return;
}
+ // determine render surface
+ textureMode = options.getTextureMode();
+
// inflate view
View view = LayoutInflater.from(context).inflate(R.layout.mapbox_mapview_internal, this);
CompassView compassView = (CompassView) view.findViewById(R.id.compassView);
MyLocationView myLocationView = (MyLocationView) view.findViewById(R.id.userLocationView);
ImageView attrView = (ImageView) view.findViewById(R.id.attributionView);
- initalizeDrawingSurface(context, options);
// add accessibility support
setContentDescription(context.getString(R.string.mapbox_mapActionDescription));
@@ -139,14 +136,22 @@ public class MapView extends FrameLayout {
UiSettings uiSettings = new UiSettings(proj, focalPoint, compassView, attrView, view.findViewById(R.id.logoView));
TrackingSettings trackingSettings = new TrackingSettings(myLocationView, uiSettings, focalPoint, zoomInvalidator);
MyLocationViewSettings myLocationViewSettings = new MyLocationViewSettings(myLocationView, proj, focalPoint);
+ LongSparseArray<Annotation> annotationsArray = new LongSparseArray<>();
MarkerViewManager markerViewManager = new MarkerViewManager((ViewGroup) findViewById(R.id.markerViewContainer));
- AnnotationManager annotations = new AnnotationManager(nativeMapView, this, markerViewManager);
- Transform transform = new Transform(nativeMapView, annotations.getMarkerViewManager(), trackingSettings);
+ IconManager iconManager = new IconManager(nativeMapView);
+ Annotations annotations = new AnnotationContainer(nativeMapView, annotationsArray);
+ Markers markers = new MarkerContainer(nativeMapView, this, annotationsArray, iconManager, markerViewManager);
+ Polygons polygons = new PolygonContainer(nativeMapView, annotationsArray);
+ Polylines polylines = new PolylineContainer(nativeMapView, annotationsArray);
+ AnnotationManager annotationManager = new AnnotationManager(nativeMapView, this, annotationsArray,
+ markerViewManager, iconManager, annotations, markers, polygons, polylines);
+ Transform transform = new Transform(nativeMapView, annotationManager.getMarkerViewManager(), trackingSettings);
mapboxMap = new MapboxMap(nativeMapView, transform, uiSettings, trackingSettings, myLocationViewSettings, proj,
- registerTouchListener, annotations);
+ registerTouchListener, annotationManager);
// user input
- mapGestureDetector = new MapGestureDetector(context, transform, proj, uiSettings, trackingSettings, annotations);
+ mapGestureDetector = new MapGestureDetector(context, transform, proj, uiSettings, trackingSettings,
+ annotationManager);
mapKeyListener = new MapKeyListener(transform, trackingSettings, uiSettings);
MapZoomControllerListener zoomListener = new MapZoomControllerListener(mapGestureDetector, uiSettings, transform);
@@ -155,7 +160,7 @@ public class MapView extends FrameLayout {
// inject widgets with MapboxMap
compassView.setMapboxMap(mapboxMap);
myLocationView.setMapboxMap(mapboxMap);
- attrView.setOnClickListener(new AttributionOnClickListener(context, transform));
+ attrView.setOnClickListener(new AttributionDialogManager(context, mapboxMap));
// Ensure this view is interactable
setClickable(true);
@@ -174,18 +179,6 @@ public class MapView extends FrameLayout {
mapboxMap.initialise(context, options);
}
- private void initalizeDrawingSurface(Context context, MapboxMapOptions options) {
- if (options.getTextureMode()) {
- TextureView textureView = new TextureView(context);
- textureView.setSurfaceTextureListener(new SurfaceTextureListener());
- addView(textureView, 0);
- } else {
- SurfaceView surfaceView = (SurfaceView) findViewById(R.id.surfaceView);
- surfaceView.getHolder().addCallback(new SurfaceCallback());
- surfaceView.setVisibility(View.VISIBLE);
- }
- }
-
//
// Lifecycle events
//
@@ -204,16 +197,27 @@ public class MapView extends FrameLayout {
@UiThread
public void onCreate(@Nullable Bundle savedInstanceState) {
if (savedInstanceState == null) {
- MapboxTelemetry.getInstance().pushEvent(MapboxEvent.buildMapLoadEvent());
+ MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapLoadEvent());
} else if (savedInstanceState.getBoolean(MapboxConstants.STATE_HAS_SAVED_STATE)) {
mapboxMap.onRestoreInstanceState(savedInstanceState);
}
- // Initialize EGL
+ initialiseDrawingSurface(textureMode);
+ addOnMapChangedListener(mapCallback = new MapCallback(mapboxMap));
+ }
+
+ private void initialiseDrawingSurface(boolean textureMode) {
nativeMapView.initializeDisplay();
nativeMapView.initializeContext();
-
- addOnMapChangedListener(mapCallback = new MapCallback(mapboxMap));
+ if (textureMode) {
+ TextureView textureView = new TextureView(getContext());
+ textureView.setSurfaceTextureListener(new SurfaceTextureListener());
+ addView(textureView, 0);
+ } else {
+ SurfaceView surfaceView = (SurfaceView) findViewById(R.id.surfaceView);
+ surfaceView.getHolder().addCallback(new SurfaceCallback());
+ surfaceView.setVisibility(View.VISIBLE);
+ }
}
/**
@@ -593,78 +597,6 @@ public class MapView extends FrameLayout {
this.mapboxMap = mapboxMap;
}
- private static class AttributionOnClickListener implements View.OnClickListener, DialogInterface.OnClickListener {
-
- private static final int ATTRIBUTION_INDEX_IMPROVE_THIS_MAP = 2;
- private static final int ATTRIBUTION_INDEX_TELEMETRY_SETTINGS = 3;
- private Context context;
- private Transform transform;
-
- public AttributionOnClickListener(Context context, Transform transform) {
- this.context = context;
- this.transform = transform;
- }
-
- // Called when someone presses the attribution icon
- @Override
- public void onClick(View view) {
- AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.mapbox_AlertDialogStyle);
- builder.setTitle(R.string.mapbox_attributionsDialogTitle);
- String[] items = context.getResources().getStringArray(R.array.mapbox_attribution_names);
- builder.setAdapter(new ArrayAdapter<>(context, R.layout.mapbox_attribution_list_item, items), this);
- builder.show();
- }
-
- // Called when someone selects an attribution, 'Improve this map' adds location data to the url
- @Override
- public void onClick(DialogInterface dialog, int which) {
- final Context context = ((Dialog) dialog).getContext();
- if (which == ATTRIBUTION_INDEX_TELEMETRY_SETTINGS) {
- AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.mapbox_AlertDialogStyle);
- builder.setTitle(R.string.mapbox_attributionTelemetryTitle);
- builder.setMessage(R.string.mapbox_attributionTelemetryMessage);
- builder.setPositiveButton(R.string.mapbox_attributionTelemetryPositive, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- MapboxTelemetry.getInstance().setTelemetryEnabled(true);
- dialog.cancel();
- }
- });
- builder.setNeutralButton(R.string.mapbox_attributionTelemetryNeutral, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- String url = context.getResources().getStringArray(R.array.mapbox_attribution_links)[3];
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setData(Uri.parse(url));
- context.startActivity(intent);
- dialog.cancel();
- }
- });
- builder.setNegativeButton(R.string.mapbox_attributionTelemetryNegative, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- MapboxTelemetry.getInstance().setTelemetryEnabled(false);
- dialog.cancel();
- }
- });
-
- builder.show();
- return;
- }
- String url = context.getResources().getStringArray(R.array.mapbox_attribution_links)[which];
- if (which == ATTRIBUTION_INDEX_IMPROVE_THIS_MAP) {
- CameraPosition cameraPosition = transform.getCameraPosition();
- if (cameraPosition != null) {
- url = String.format(url, cameraPosition.target.getLongitude(),
- cameraPosition.target.getLatitude(), (int) cameraPosition.zoom);
- }
- }
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setData(Uri.parse(url));
- context.startActivity(intent);
- }
- }
-
/**
* Definition of a map change event.
*
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxEventWrapper.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxEventWrapper.java
new file mode 100644
index 0000000000..97734de493
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxEventWrapper.java
@@ -0,0 +1,48 @@
+package com.mapbox.mapboxsdk.maps;
+
+import android.location.Location;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import com.mapbox.services.android.telemetry.MapboxEvent;
+
+import java.util.Hashtable;
+
+/**
+ * Wrapper class for MapboxEvent
+ * <p>
+ * Provides facility methods to use Transform and handle the case that the zoom, required for a telemetry event,
+ * isn't available yet.
+ * </p>
+ */
+class MapboxEventWrapper {
+
+ @Nullable
+ static Hashtable<String, Object> buildMapClickEvent(
+ @NonNull Location location, @NonNull String gestureId, Transform transform) {
+ try {
+ return MapboxEvent.buildMapClickEvent(location, gestureId, transform.getZoom());
+ } catch (NullPointerException exception) {
+ // Map/Transform is not ready yet #8650
+ // returning null is valid, event is ignored.
+ return null;
+ }
+ }
+
+ @Nullable
+ static Hashtable<String, Object> buildMapDragEndEvent(
+ @NonNull Location location, Transform transform) {
+ try {
+ return MapboxEvent.buildMapDragEndEvent(location, transform.getZoom());
+ } catch (NullPointerException exception) {
+ // Map/Transform is not ready yet #8650
+ // returning null is valid, event is ignored.
+ return null;
+ }
+ }
+
+ @Nullable
+ static Hashtable<String, Object> buildMapLoadEvent() {
+ return MapboxEvent.buildMapLoadEvent();
+ }
+}
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 e7679a4066..79d36667ff 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
@@ -37,10 +37,12 @@ import com.mapbox.mapboxsdk.constants.MyLocationTracking;
import com.mapbox.mapboxsdk.constants.Style;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
+import com.mapbox.mapboxsdk.location.LocationSource;
import com.mapbox.mapboxsdk.maps.widgets.MyLocationViewSettings;
import com.mapbox.mapboxsdk.style.layers.Filter;
import com.mapbox.mapboxsdk.style.layers.Layer;
import com.mapbox.mapboxsdk.style.sources.Source;
+import com.mapbox.services.android.telemetry.location.LocationEngine;
import com.mapbox.services.commons.geojson.Feature;
import java.lang.reflect.ParameterizedType;
@@ -195,7 +197,7 @@ public final class MapboxMap {
* </p>
* The default value is zero, so any changes take effect without animation.
*
- * @return Duration in seconds
+ * @return Duration in milliseconds
*/
@UiThread
public long getTransitionDuration() {
@@ -205,11 +207,11 @@ public final class MapboxMap {
/**
* Set the animation duration for style changes.
*
- * @param duration Duration in seconds
+ * @param durationMs Duration in milliseconds
*/
@UiThread
- public void setTransitionDuration(long duration) {
- nativeMapView.setTransitionDuration(duration);
+ public void setTransitionDuration(long durationMs) {
+ nativeMapView.setTransitionDuration(durationMs);
}
/**
@@ -218,7 +220,7 @@ public final class MapboxMap {
* </p>
* The default value is zero, so any changes begin to animate immediately.
*
- * @return Delay in seconds
+ * @return Delay in milliseconds
*/
@UiThread
public long getTransitionDelay() {
@@ -228,11 +230,11 @@ public final class MapboxMap {
/**
* Set the animation delay for style changes.
*
- * @param delay Delay in seconds
+ * @param delayMs Delay in milliseconds
*/
@UiThread
- public void setTransitionDelay(long delay) {
- nativeMapView.setTransitionDelay(delay);
+ public void setTransitionDelay(long delayMs) {
+ nativeMapView.setTransitionDelay(delayMs);
}
/**
@@ -1509,6 +1511,17 @@ public final class MapboxMap {
// LatLngBounds
//
+ /**
+ * Sets a LatLngBounds that constraints map transformations to this bounds.
+ * <p>
+ * Set to null to clear current bounds, newly set bounds will override previously set bounds.
+ * </p>
+ *
+ * @param latLngBounds the bounds to constrain the map with
+ */
+ public void setLatLngBoundsForCameraTarget(@Nullable LatLngBounds latLngBounds) {
+ nativeMapView.setLatLngBounds(latLngBounds);
+ }
/**
* Gets a camera position that would fit a bounds.
@@ -1762,6 +1775,18 @@ public final class MapboxMap {
}
/**
+ * Replaces the location source of the my-location layer.
+ *
+ * @param locationSource A {@link LocationEngine} location source to use in the my-location layer.
+ * Set to null to use the default {@link LocationSource}
+ * location source.
+ */
+ @UiThread
+ public void setLocationSource(@Nullable LocationEngine locationSource) {
+ trackingSettings.setLocationSource(locationSource);
+ }
+
+ /**
* Sets a callback that's invoked when the location tracking mode changes.
*
* @param listener The callback that's invoked when the location tracking mode changes.
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 6467033ead..68603ab1a3 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
@@ -14,6 +14,7 @@ import android.support.annotation.IntRange;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
+import android.support.v4.content.res.ResourcesCompat;
import android.util.AttributeSet;
import android.view.Gravity;
@@ -34,10 +35,8 @@ import java.util.Arrays;
*/
public class MapboxMapOptions implements Parcelable {
- private static final float DIMENSION_SEVEN_DP = 7f;
- private static final float DIMENSION_TEN_DP = 10f;
- private static final float DIMENSION_SIXTEEN_DP = 16f;
- private static final float DIMENSION_SEVENTY_SIX_DP = 76f;
+ private static final float FOUR_DP = 4f;
+ private static final float EIGHTY_NINE_DP = 92f;
private CameraPosition cameraPosition;
@@ -47,6 +46,7 @@ public class MapboxMapOptions implements Parcelable {
private boolean fadeCompassFacingNorth = true;
private int compassGravity = Gravity.TOP | Gravity.END;
private int[] compassMargins;
+ private Drawable compassImage;
private boolean logoEnabled = true;
private int logoGravity = Gravity.BOTTOM | Gravity.START;
@@ -100,6 +100,11 @@ public class MapboxMapOptions implements Parcelable {
compassMargins = in.createIntArray();
fadeCompassFacingNorth = in.readByte() != 0;
+ Bitmap compassBitmap = in.readParcelable(getClass().getClassLoader());
+ if (compassBitmap != null) {
+ compassImage = new BitmapDrawable(compassBitmap);
+ }
+
logoEnabled = in.readByte() != 0;
logoGravity = in.readInt();
logoMargins = in.createIntArray();
@@ -147,7 +152,7 @@ public class MapboxMapOptions implements Parcelable {
textureMode = in.readByte() != 0;
}
- public static Bitmap getBitmapFromDrawable(Drawable drawable) {
+ static Bitmap getBitmapFromDrawable(Drawable drawable) {
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
} else {
@@ -199,28 +204,34 @@ public class MapboxMapOptions implements Parcelable {
Gravity.TOP | Gravity.END));
mapboxMapOptions.compassMargins(new int[] {
(int) (typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_uiCompassMarginLeft,
- DIMENSION_TEN_DP * pxlRatio)),
+ FOUR_DP * pxlRatio)),
((int) typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_uiCompassMarginTop,
- DIMENSION_TEN_DP * pxlRatio)),
+ FOUR_DP * pxlRatio)),
((int) typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_uiCompassMarginRight,
- DIMENSION_TEN_DP * pxlRatio)),
+ FOUR_DP * pxlRatio)),
((int) typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_uiCompassMarginBottom,
- DIMENSION_TEN_DP * pxlRatio))});
+ FOUR_DP * pxlRatio))});
mapboxMapOptions.compassFadesWhenFacingNorth(typedArray.getBoolean(
R.styleable.mapbox_MapView_mapbox_uiCompassFadeFacingNorth, true));
+ Drawable compassDrawable = typedArray.getDrawable(
+ R.styleable.mapbox_MapView_mapbox_uiCompassDrawable);
+ if (compassDrawable == null) {
+ compassDrawable = ResourcesCompat.getDrawable(context.getResources(), R.drawable.mapbox_compass_icon, null);
+ }
+ mapboxMapOptions.compassImage(compassDrawable);
mapboxMapOptions.logoEnabled(typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_uiLogo, true));
mapboxMapOptions.logoGravity(typedArray.getInt(R.styleable.mapbox_MapView_mapbox_uiLogoGravity,
Gravity.BOTTOM | Gravity.START));
mapboxMapOptions.logoMargins(new int[] {
(int) (typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_uiLogoMarginLeft,
- DIMENSION_SIXTEEN_DP * pxlRatio)),
+ FOUR_DP * pxlRatio)),
(int) (typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_uiLogoMarginTop,
- DIMENSION_SIXTEEN_DP * pxlRatio)),
+ FOUR_DP * pxlRatio)),
(int) (typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_uiLogoMarginRight,
- DIMENSION_SIXTEEN_DP * pxlRatio)),
+ FOUR_DP * pxlRatio)),
(int) (typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_uiLogoMarginBottom,
- DIMENSION_SIXTEEN_DP * pxlRatio))});
+ FOUR_DP * pxlRatio))});
mapboxMapOptions.attributionTintColor(typedArray.getColor(
R.styleable.mapbox_MapView_mapbox_uiAttributionTintColor, -1));
@@ -230,13 +241,13 @@ public class MapboxMapOptions implements Parcelable {
R.styleable.mapbox_MapView_mapbox_uiAttributionGravity, Gravity.BOTTOM));
mapboxMapOptions.attributionMargins(new int[] {
(int) (typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_uiAttributionMarginLeft,
- DIMENSION_SEVENTY_SIX_DP) * pxlRatio),
+ EIGHTY_NINE_DP * pxlRatio)),
(int) (typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_uiAttributionMarginTop,
- DIMENSION_SEVEN_DP * pxlRatio)),
+ FOUR_DP * pxlRatio)),
(int) (typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_uiAttributionMarginRight,
- DIMENSION_SEVEN_DP * pxlRatio)),
+ FOUR_DP * pxlRatio)),
(int) (typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_uiAttributionMarginBottom,
- DIMENSION_SEVEN_DP * pxlRatio))});
+ FOUR_DP * pxlRatio))});
mapboxMapOptions.locationEnabled(typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_myLocation, false));
mapboxMapOptions.myLocationForegroundTintColor(
@@ -401,6 +412,20 @@ public class MapboxMapOptions implements Parcelable {
}
/**
+ * Specifies the image of the CompassView.
+ * <p>
+ * By default this value is R.drawable.mapbox_compass_icon.
+ * </p>
+ *
+ * @param compass the drawable to show as image compass
+ * @return This
+ */
+ public MapboxMapOptions compassImage(Drawable compass) {
+ this.compassImage = compass;
+ return this;
+ }
+
+ /**
* Specifies the visibility state of a logo for a map view.
*
* @param enabled True and logo is shown
@@ -743,6 +768,15 @@ public class MapboxMapOptions implements Parcelable {
}
/**
+ * Get the current configured CompassView image.
+ *
+ * @return the drawable used as compass image
+ */
+ public Drawable getCompassImage() {
+ return compassImage;
+ }
+
+ /**
* Get the current configured visibility state for mapbox_compass_icon for a map view.
*
* @return Visibility state of the mapbox_compass_icon
@@ -993,6 +1027,8 @@ public class MapboxMapOptions implements Parcelable {
dest.writeInt(compassGravity);
dest.writeIntArray(compassMargins);
dest.writeByte((byte) (fadeCompassFacingNorth ? 1 : 0));
+ dest.writeParcelable(compassImage != null
+ ? getBitmapFromDrawable(compassImage) : null, flags);
dest.writeByte((byte) (logoEnabled ? 1 : 0));
dest.writeInt(logoGravity);
@@ -1052,6 +1088,11 @@ public class MapboxMapOptions implements Parcelable {
if (fadeCompassFacingNorth != options.fadeCompassFacingNorth) {
return false;
}
+ if (compassImage != null
+ ? !compassImage.equals(options.compassImage)
+ : options.compassImage != null) {
+ return false;
+ }
if (compassGravity != options.compassGravity) {
return false;
}
@@ -1157,6 +1198,7 @@ public class MapboxMapOptions implements Parcelable {
result = 31 * result + (compassEnabled ? 1 : 0);
result = 31 * result + (fadeCompassFacingNorth ? 1 : 0);
result = 31 * result + compassGravity;
+ result = 31 * result + (compassImage != null ? compassImage.hashCode() : 0);
result = 31 * result + Arrays.hashCode(compassMargins);
result = 31 * result + (logoEnabled ? 1 : 0);
result = 31 * result + logoGravity;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MarkerContainer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MarkerContainer.java
new file mode 100644
index 0000000000..306ad59b8d
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MarkerContainer.java
@@ -0,0 +1,267 @@
+package com.mapbox.mapboxsdk.maps;
+
+
+import android.graphics.RectF;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.util.LongSparseArray;
+
+import com.mapbox.mapboxsdk.annotations.Annotation;
+import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions;
+import com.mapbox.mapboxsdk.annotations.BaseMarkerViewOptions;
+import com.mapbox.mapboxsdk.annotations.Icon;
+import com.mapbox.mapboxsdk.annotations.IconFactory;
+import com.mapbox.mapboxsdk.annotations.Marker;
+import com.mapbox.mapboxsdk.annotations.MarkerView;
+import com.mapbox.mapboxsdk.annotations.MarkerViewManager;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import timber.log.Timber;
+
+/**
+ * Encapsulates {@link Marker}'s functionality.
+ */
+class MarkerContainer implements Markers {
+
+ private final NativeMapView nativeMapView;
+ private final MapView mapView;
+ private final LongSparseArray<Annotation> annotations;
+ private final IconManager iconManager;
+ private final MarkerViewManager markerViewManager;
+
+ MarkerContainer(NativeMapView nativeMapView, MapView mapView, LongSparseArray<Annotation> annotations, IconManager
+ iconManager, MarkerViewManager markerViewManager) {
+ this.nativeMapView = nativeMapView;
+ this.mapView = mapView;
+ this.annotations = annotations;
+ this.iconManager = iconManager;
+ this.markerViewManager = markerViewManager;
+ }
+
+ @Override
+ public Marker addBy(@NonNull BaseMarkerOptions markerOptions, @NonNull MapboxMap mapboxMap) {
+ Marker marker = prepareMarker(markerOptions);
+ long id = nativeMapView != null ? nativeMapView.addMarker(marker) : 0;
+ marker.setMapboxMap(mapboxMap);
+ marker.setId(id);
+ annotations.put(id, marker);
+ return marker;
+ }
+
+ @Override
+ public List<Marker> addBy(@NonNull List<? extends BaseMarkerOptions> markerOptionsList, @NonNull MapboxMap
+ mapboxMap) {
+ int count = markerOptionsList.size();
+ List<Marker> markers = new ArrayList<>(count);
+ if (count > 0) {
+ BaseMarkerOptions markerOptions;
+ Marker marker;
+ for (int i = 0; i < count; i++) {
+ markerOptions = markerOptionsList.get(i);
+ marker = prepareMarker(markerOptions);
+ markers.add(marker);
+ }
+
+ if (markers.size() > 0) {
+ long[] ids = null;
+ if (nativeMapView != null) {
+ ids = nativeMapView.addMarkers(markers);
+ }
+
+ long id = 0;
+ Marker m;
+ for (int i = 0; i < markers.size(); i++) {
+ m = markers.get(i);
+ m.setMapboxMap(mapboxMap);
+ if (ids != null) {
+ id = ids[i];
+ } else {
+ // unit test
+ id++;
+ }
+ m.setId(id);
+ annotations.put(id, m);
+ }
+
+ }
+ }
+ return markers;
+ }
+
+ @Override
+ public void update(@NonNull Marker updatedMarker, @NonNull MapboxMap mapboxMap) {
+ if (!isAddedToMap(updatedMarker)) {
+ Timber.w("Attempting to update non-added Marker with value %s", updatedMarker);
+ return;
+ }
+
+ ensureIconLoaded(updatedMarker, mapboxMap);
+ nativeMapView.updateMarker(updatedMarker);
+ annotations.setValueAt(annotations.indexOfKey(updatedMarker.getId()), updatedMarker);
+ }
+
+ @Override
+ public List<Marker> obtainAll() {
+ List<Marker> markers = new ArrayList<>();
+ Annotation annotation;
+ for (int i = 0; i < annotations.size(); i++) {
+ annotation = annotations.get(annotations.keyAt(i));
+ if (annotation instanceof Marker) {
+ markers.add((Marker) annotation);
+ }
+ }
+ return markers;
+ }
+
+ @NonNull
+ @Override
+ public List<Marker> obtainAllIn(@NonNull RectF rectangle) {
+ // convert Rectangle to be density depedent
+ float pixelRatio = nativeMapView.getPixelRatio();
+ RectF rect = new RectF(rectangle.left / pixelRatio,
+ rectangle.top / pixelRatio,
+ rectangle.right / pixelRatio,
+ rectangle.bottom / pixelRatio);
+
+ long[] ids = nativeMapView.queryPointAnnotations(rect);
+
+ List<Long> idsList = new ArrayList<>(ids.length);
+ for (long id : ids) {
+ idsList.add(id);
+ }
+
+ List<Marker> annotations = new ArrayList<>(ids.length);
+ List<Annotation> annotationList = obtainAnnotations();
+ int count = annotationList.size();
+ for (int i = 0; i < count; i++) {
+ Annotation annotation = annotationList.get(i);
+ if (annotation instanceof com.mapbox.mapboxsdk.annotations.Marker && idsList.contains(annotation.getId())) {
+ annotations.add((com.mapbox.mapboxsdk.annotations.Marker) annotation);
+ }
+ }
+
+ return new ArrayList<>(annotations);
+ }
+
+ @Override
+ public MarkerView addViewBy(@NonNull BaseMarkerViewOptions markerOptions, @NonNull MapboxMap mapboxMap, @Nullable
+ MarkerViewManager.OnMarkerViewAddedListener onMarkerViewAddedListener) {
+ final MarkerView marker = prepareViewMarker(markerOptions);
+
+ // add marker to map
+ marker.setMapboxMap(mapboxMap);
+ long id = nativeMapView.addMarker(marker);
+ marker.setId(id);
+ annotations.put(id, marker);
+
+ if (onMarkerViewAddedListener != null) {
+ markerViewManager.addOnMarkerViewAddedListener(marker, onMarkerViewAddedListener);
+ }
+ markerViewManager.setEnabled(true);
+ markerViewManager.setWaitingForRenderInvoke(true);
+ return marker;
+ }
+
+ @Override
+ public List<MarkerView> addViewsBy(@NonNull List<? extends BaseMarkerViewOptions> markerViewOptions, @NonNull
+ MapboxMap mapboxMap) {
+ List<MarkerView> markers = new ArrayList<>();
+ for (BaseMarkerViewOptions markerViewOption : markerViewOptions) {
+ // if last marker
+ if (markerViewOptions.indexOf(markerViewOption) == markerViewOptions.size() - 1) {
+ // get notified when render occurs to invalidate and draw MarkerViews
+ markerViewManager.setWaitingForRenderInvoke(true);
+ }
+ // add marker to map
+ MarkerView marker = prepareViewMarker(markerViewOption);
+ marker.setMapboxMap(mapboxMap);
+ long id = nativeMapView.addMarker(marker);
+ marker.setId(id);
+ annotations.put(id, marker);
+ markers.add(marker);
+ }
+ markerViewManager.setEnabled(true);
+ markerViewManager.update();
+ return markers;
+ }
+
+ @Override
+ public List<MarkerView> obtainViewsIn(@NonNull RectF rectangle) {
+ float pixelRatio = nativeMapView.getPixelRatio();
+ RectF rect = new RectF(rectangle.left / pixelRatio,
+ rectangle.top / pixelRatio,
+ rectangle.right / pixelRatio,
+ rectangle.bottom / pixelRatio);
+
+ long[] ids = nativeMapView.queryPointAnnotations(rect);
+
+ List<Long> idsList = new ArrayList<>(ids.length);
+ for (long id : ids) {
+ idsList.add(id);
+ }
+
+ List<MarkerView> annotations = new ArrayList<>(ids.length);
+ List<Annotation> annotationList = obtainAnnotations();
+ int count = annotationList.size();
+ for (int i = 0; i < count; i++) {
+ Annotation annotation = annotationList.get(i);
+ if (annotation instanceof MarkerView && idsList.contains(annotation.getId())) {
+ annotations.add((MarkerView) annotation);
+ }
+ }
+
+ return new ArrayList<>(annotations);
+ }
+
+ @Override
+ public void reload() {
+ iconManager.reloadIcons();
+ int count = annotations.size();
+ for (int i = 0; i < count; i++) {
+ Annotation annotation = annotations.get(i);
+ if (annotation instanceof Marker) {
+ Marker marker = (Marker) annotation;
+ nativeMapView.removeAnnotation(annotation.getId());
+ long newId = nativeMapView.addMarker(marker);
+ marker.setId(newId);
+ }
+ }
+ }
+
+ private Marker prepareMarker(BaseMarkerOptions markerOptions) {
+ Marker marker = markerOptions.getMarker();
+ Icon icon = iconManager.loadIconForMarker(marker);
+ marker.setTopOffsetPixels(iconManager.getTopOffsetPixelsForIcon(icon));
+ return marker;
+ }
+
+ private boolean isAddedToMap(Annotation annotation) {
+ return annotation != null && annotation.getId() != -1 && annotations.indexOfKey(annotation.getId()) != -1;
+ }
+
+ private void ensureIconLoaded(Marker marker, MapboxMap mapboxMap) {
+ if (!(marker instanceof MarkerView)) {
+ iconManager.ensureIconLoaded(marker, mapboxMap);
+ }
+ }
+
+ private List<Annotation> obtainAnnotations() {
+ List<Annotation> annotations = new ArrayList<>();
+ for (int i = 0; i < this.annotations.size(); i++) {
+ annotations.add(this.annotations.get(this.annotations.keyAt(i)));
+ }
+ return annotations;
+ }
+
+ private MarkerView prepareViewMarker(BaseMarkerViewOptions markerViewOptions) {
+ MarkerView marker = markerViewOptions.getMarker();
+ Icon icon = markerViewOptions.getIcon();
+ if (icon == null) {
+ icon = IconFactory.getInstance(mapView.getContext()).defaultMarkerView();
+ }
+ marker.setIcon(icon);
+ return marker;
+ }
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Markers.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Markers.java
new file mode 100644
index 0000000000..d646e0ac49
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Markers.java
@@ -0,0 +1,39 @@
+package com.mapbox.mapboxsdk.maps;
+
+
+import android.graphics.RectF;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions;
+import com.mapbox.mapboxsdk.annotations.BaseMarkerViewOptions;
+import com.mapbox.mapboxsdk.annotations.Marker;
+import com.mapbox.mapboxsdk.annotations.MarkerView;
+import com.mapbox.mapboxsdk.annotations.MarkerViewManager;
+
+import java.util.List;
+
+/**
+ * Interface that defines convenient methods for working with a {@link Marker}'s collection.
+ */
+interface Markers {
+ Marker addBy(@NonNull BaseMarkerOptions markerOptions, @NonNull MapboxMap mapboxMap);
+
+ List<Marker> addBy(@NonNull List<? extends BaseMarkerOptions> markerOptionsList, @NonNull MapboxMap mapboxMap);
+
+ void update(@NonNull Marker updatedMarker, @NonNull MapboxMap mapboxMap);
+
+ List<Marker> obtainAll();
+
+ List<Marker> obtainAllIn(@NonNull RectF rectangle);
+
+ MarkerView addViewBy(@NonNull BaseMarkerViewOptions markerOptions, @NonNull MapboxMap mapboxMap,
+ @Nullable MarkerViewManager.OnMarkerViewAddedListener onMarkerViewAddedListener);
+
+ List<MarkerView> addViewsBy(@NonNull List<? extends BaseMarkerViewOptions> markerViewOptions,
+ @NonNull MapboxMap mapboxMap);
+
+ List<MarkerView> obtainViewsIn(@NonNull RectF rectangle);
+
+ void reload();
+}
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 fae6311a03..ae4a8ee8d2 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
@@ -13,6 +13,7 @@ import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.view.Surface;
+import com.mapbox.mapboxsdk.LibraryLoader;
import com.mapbox.mapboxsdk.annotations.Icon;
import com.mapbox.mapboxsdk.annotations.Marker;
import com.mapbox.mapboxsdk.annotations.Polygon;
@@ -63,12 +64,8 @@ final class NativeMapView {
// Listener invoked to return a bitmap of the map
private MapboxMap.SnapshotReadyCallback snapshotReadyCallback;
- //
- // Static methods
- //
-
static {
- System.loadLibrary("mapbox-gl");
+ LibraryLoader.load();
}
//
@@ -261,6 +258,13 @@ final class NativeMapView {
return nativeGetStyleJson();
}
+ public void setLatLngBounds(LatLngBounds latLngBounds) {
+ if (isDestroyedOn("setLatLngBounds")) {
+ return;
+ }
+ nativeSetLatLngBounds(latLngBounds);
+ }
+
public void cancelTransitions() {
if (isDestroyedOn("cancelTransitions")) {
return;
@@ -339,55 +343,6 @@ final class NativeMapView {
nativeSetPitch(pitch, duration);
}
- public void scaleBy(double ds) {
- if (isDestroyedOn("scaleBy")) {
- return;
- }
- scaleBy(ds, Double.NaN, Double.NaN);
- }
-
- public void scaleBy(double ds, double cx, double cy) {
- if (isDestroyedOn("scaleBy")) {
- return;
- }
- scaleBy(ds, cx, cy, 0);
- }
-
- public void scaleBy(double ds, double cx, double cy, long duration) {
- if (isDestroyedOn("scaleBy")) {
- return;
- }
- nativeScaleBy(ds, cx / pixelRatio, cy / pixelRatio, duration);
- }
-
- public void setScale(double scale) {
- if (isDestroyedOn("setScale")) {
- return;
- }
- setScale(scale, Double.NaN, Double.NaN);
- }
-
- public void setScale(double scale, double cx, double cy) {
- if (isDestroyedOn("setScale")) {
- return;
- }
- setScale(scale, cx, cy, 0);
- }
-
- public void setScale(double scale, double cx, double cy, long duration) {
- if (isDestroyedOn("setScale")) {
- return;
- }
- nativeSetScale(scale, cx / pixelRatio, cy / pixelRatio, duration);
- }
-
- public double getScale() {
- if (isDestroyedOn("getScale")) {
- return 0;
- }
- return nativeGetScale();
- }
-
public void setZoom(double zoom, PointF focalPoint, long duration) {
if (isDestroyedOn("setZoom")) {
return;
@@ -948,7 +903,11 @@ final class NativeMapView {
protected void onMapChanged(int rawChange) {
if (onMapChangedListeners != null) {
for (MapView.OnMapChangedListener onMapChangedListener : onMapChangedListeners) {
- onMapChangedListener.onMapChanged(rawChange);
+ try {
+ onMapChangedListener.onMapChanged(rawChange);
+ } catch (RuntimeException err) {
+ Timber.e("Exception (%s) in MapView.OnMapChangedListener: %s", err.getClass(), err.getMessage());
+ }
}
}
}
@@ -1004,6 +963,8 @@ final class NativeMapView {
private native String nativeGetStyleJson();
+ private native void nativeSetLatLngBounds(LatLngBounds latLngBounds);
+
private native void nativeCancelTransitions();
private native void nativeSetGestureInProgress(boolean inProgress);
@@ -1022,12 +983,6 @@ final class NativeMapView {
private native void nativeSetPitch(double pitch, long duration);
- private native void nativeScaleBy(double ds, double cx, double cy, long duration);
-
- private native void nativeSetScale(double scale, double cx, double cy, long duration);
-
- private native double nativeGetScale();
-
private native void nativeSetZoom(double zoom, double cx, double cy, long duration);
private native double nativeGetZoom();
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolygonContainer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolygonContainer.java
new file mode 100644
index 0000000000..bcb94a975c
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolygonContainer.java
@@ -0,0 +1,104 @@
+package com.mapbox.mapboxsdk.maps;
+
+
+import android.support.annotation.NonNull;
+import android.support.v4.util.LongSparseArray;
+
+import com.mapbox.mapboxsdk.annotations.Annotation;
+import com.mapbox.mapboxsdk.annotations.Polygon;
+import com.mapbox.mapboxsdk.annotations.PolygonOptions;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import timber.log.Timber;
+
+/**
+ * Encapsulates {@link Polygon}'s functionality.
+ */
+class PolygonContainer implements Polygons {
+
+ private final NativeMapView nativeMapView;
+ private final LongSparseArray<Annotation> annotations;
+
+ PolygonContainer(NativeMapView nativeMapView, LongSparseArray<Annotation> annotations) {
+ this.nativeMapView = nativeMapView;
+ this.annotations = annotations;
+ }
+
+ @Override
+ public Polygon addBy(@NonNull PolygonOptions polygonOptions, @NonNull MapboxMap mapboxMap) {
+ Polygon polygon = polygonOptions.getPolygon();
+ if (!polygon.getPoints().isEmpty()) {
+ long id = nativeMapView != null ? nativeMapView.addPolygon(polygon) : 0;
+ polygon.setId(id);
+ polygon.setMapboxMap(mapboxMap);
+ annotations.put(id, polygon);
+ }
+ return polygon;
+ }
+
+ @Override
+ public List<Polygon> addBy(@NonNull List<PolygonOptions> polygonOptionsList, @NonNull MapboxMap mapboxMap) {
+ int count = polygonOptionsList.size();
+
+ Polygon polygon;
+ List<Polygon> polygons = new ArrayList<>(count);
+ if (count > 0) {
+ for (PolygonOptions polygonOptions : polygonOptionsList) {
+ polygon = polygonOptions.getPolygon();
+ if (!polygon.getPoints().isEmpty()) {
+ polygons.add(polygon);
+ }
+ }
+
+ long[] ids = null;
+ if (nativeMapView != null) {
+ ids = nativeMapView.addPolygons(polygons);
+ }
+
+ long id = 0;
+ for (int i = 0; i < polygons.size(); i++) {
+ polygon = polygons.get(i);
+ polygon.setMapboxMap(mapboxMap);
+ if (ids != null) {
+ id = ids[i];
+ } else {
+ // unit test
+ id++;
+ }
+ polygon.setId(id);
+ annotations.put(id, polygon);
+ }
+ }
+ return polygons;
+ }
+
+ @Override
+ public void update(Polygon polygon) {
+ if (!isAddedToMap(polygon)) {
+ Timber.w("Attempting to update non-added Polygon with value %s", polygon);
+ return;
+ }
+
+ nativeMapView.updatePolygon(polygon);
+ annotations.setValueAt(annotations.indexOfKey(polygon.getId()), polygon);
+ }
+
+ @Override
+ public List<Polygon> obtainAll() {
+ List<Polygon> polygons = new ArrayList<>();
+ Annotation annotation;
+ for (int i = 0; i < annotations.size(); i++) {
+ annotation = annotations.get(annotations.keyAt(i));
+ if (annotation instanceof Polygon) {
+ polygons.add((Polygon) annotation);
+ }
+ }
+ return polygons;
+ }
+
+ private boolean isAddedToMap(Annotation annotation) {
+ return annotation != null && annotation.getId() != -1 && annotations.indexOfKey(annotation.getId()) != -1;
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Polygons.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Polygons.java
new file mode 100644
index 0000000000..2a0190b5ba
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Polygons.java
@@ -0,0 +1,22 @@
+package com.mapbox.mapboxsdk.maps;
+
+
+import android.support.annotation.NonNull;
+
+import com.mapbox.mapboxsdk.annotations.Polygon;
+import com.mapbox.mapboxsdk.annotations.PolygonOptions;
+
+import java.util.List;
+
+/**
+ * Interface that defines convenient methods for working with a {@link Polygon}'s collection.
+ */
+interface Polygons {
+ Polygon addBy(@NonNull PolygonOptions polygonOptions, @NonNull MapboxMap mapboxMap);
+
+ List<Polygon> addBy(@NonNull List<PolygonOptions> polygonOptionsList, @NonNull MapboxMap mapboxMap);
+
+ void update(Polygon polygon);
+
+ List<Polygon> obtainAll();
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolylineContainer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolylineContainer.java
new file mode 100644
index 0000000000..7483f1082b
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolylineContainer.java
@@ -0,0 +1,105 @@
+package com.mapbox.mapboxsdk.maps;
+
+
+import android.support.annotation.NonNull;
+import android.support.v4.util.LongSparseArray;
+
+import com.mapbox.mapboxsdk.annotations.Annotation;
+import com.mapbox.mapboxsdk.annotations.Polyline;
+import com.mapbox.mapboxsdk.annotations.PolylineOptions;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import timber.log.Timber;
+
+/**
+ * Encapsulates {@link Polyline}'s functionality.
+ */
+class PolylineContainer implements Polylines {
+
+ private final NativeMapView nativeMapView;
+ private final LongSparseArray<Annotation> annotations;
+
+ PolylineContainer(NativeMapView nativeMapView, LongSparseArray<Annotation> annotations) {
+ this.nativeMapView = nativeMapView;
+ this.annotations = annotations;
+ }
+
+ @Override
+ public Polyline addBy(@NonNull PolylineOptions polylineOptions, @NonNull MapboxMap mapboxMap) {
+ Polyline polyline = polylineOptions.getPolyline();
+ if (!polyline.getPoints().isEmpty()) {
+ long id = nativeMapView != null ? nativeMapView.addPolyline(polyline) : 0;
+ polyline.setMapboxMap(mapboxMap);
+ polyline.setId(id);
+ annotations.put(id, polyline);
+ }
+ return polyline;
+ }
+
+ @Override
+ public List<Polyline> addBy(@NonNull List<PolylineOptions> polylineOptionsList, @NonNull MapboxMap mapboxMap) {
+ int count = polylineOptionsList.size();
+ Polyline polyline;
+ List<Polyline> polylines = new ArrayList<>(count);
+
+ if (count > 0) {
+ for (PolylineOptions options : polylineOptionsList) {
+ polyline = options.getPolyline();
+ if (!polyline.getPoints().isEmpty()) {
+ polylines.add(polyline);
+ }
+ }
+
+ long[] ids = null;
+ if (nativeMapView != null) {
+ ids = nativeMapView.addPolylines(polylines);
+ }
+
+ long id = 0;
+ Polyline p;
+
+ for (int i = 0; i < polylines.size(); i++) {
+ p = polylines.get(i);
+ p.setMapboxMap(mapboxMap);
+ if (ids != null) {
+ id = ids[i];
+ } else {
+ // unit test
+ id++;
+ }
+ p.setId(id);
+ annotations.put(id, p);
+ }
+ }
+ return polylines;
+ }
+
+ @Override
+ public void update(Polyline polyline) {
+ if (!isAddedToMap(polyline)) {
+ Timber.w("Attempting to update non-added Polyline with value %s", polyline);
+ }
+
+ nativeMapView.updatePolyline(polyline);
+ annotations.setValueAt(annotations.indexOfKey(polyline.getId()), polyline);
+ }
+
+ @Override
+ public List<Polyline> obtainAll() {
+ List<Polyline> polylines = new ArrayList<>();
+ Annotation annotation;
+ for (int i = 0; i < annotations.size(); i++) {
+ annotation = annotations.get(annotations.keyAt(i));
+ if (annotation instanceof Polyline) {
+ polylines.add((Polyline) annotation);
+ }
+ }
+ return polylines;
+ }
+
+ private boolean isAddedToMap(Annotation annotation) {
+ return annotation != null && annotation.getId() != -1 && annotations.indexOfKey(annotation.getId()) != -1;
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Polylines.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Polylines.java
new file mode 100644
index 0000000000..c9a865cdd0
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Polylines.java
@@ -0,0 +1,22 @@
+package com.mapbox.mapboxsdk.maps;
+
+
+import android.support.annotation.NonNull;
+
+import com.mapbox.mapboxsdk.annotations.Polyline;
+import com.mapbox.mapboxsdk.annotations.PolylineOptions;
+
+import java.util.List;
+
+/**
+ * Interface that defines convenient methods for working with a {@link Polyline}'s collection.
+ */
+interface Polylines {
+ Polyline addBy(@NonNull PolylineOptions polylineOptions, @NonNull MapboxMap mapboxMap);
+
+ List<Polyline> addBy(@NonNull List<PolylineOptions> polylineOptionsList, @NonNull MapboxMap mapboxMap);
+
+ void update(Polyline polyline);
+
+ List<Polyline> obtainAll();
+}
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 82d5dec6a0..ff466c436c 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
@@ -125,6 +125,6 @@ public class Projection {
* @return zoom level that fits the MapView.
*/
public double calculateZoom(float minScale) {
- return Math.log(nativeMapView.getScale() * minScale) / Math.log(2);
+ return nativeMapView.getZoom() + Math.log(minScale) / Math.log(2);
}
}
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 476f4554c1..25b60aa72d 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
@@ -12,6 +12,7 @@ import com.mapbox.mapboxsdk.constants.MyBearingTracking;
import com.mapbox.mapboxsdk.constants.MyLocationTracking;
import com.mapbox.mapboxsdk.location.LocationSource;
import com.mapbox.mapboxsdk.maps.widgets.MyLocationView;
+import com.mapbox.services.android.telemetry.location.LocationEngine;
import com.mapbox.services.android.telemetry.location.LocationEngineListener;
import com.mapbox.services.android.telemetry.permissions.PermissionsManager;
@@ -26,6 +27,7 @@ public final class TrackingSettings {
private final UiSettings uiSettings;
private final FocalPointChangeListener focalPointChangedListener;
private final CameraZoomInvalidator zoomInvalidator;
+ private LocationEngine locationSource;
private LocationEngineListener myLocationListener;
private boolean myLocationEnabled;
@@ -45,6 +47,7 @@ public final class TrackingSettings {
}
void initialise(MapboxMapOptions options) {
+ locationSource = LocationSource.getLocationEngine(myLocationView.getContext());
setMyLocationEnabled(options.getLocationEnabled());
}
@@ -328,9 +331,9 @@ public final class TrackingSettings {
}
}
};
- LocationSource.getLocationEngine(myLocationView.getContext()).addLocationEngineListener(myLocationListener);
+ locationSource.addLocationEngineListener(myLocationListener);
} else {
- LocationSource.getLocationEngine(myLocationView.getContext()).removeLocationEngineListener(myLocationListener);
+ locationSource.removeLocationEngineListener(myLocationListener);
myLocationListener = null;
}
}
@@ -362,6 +365,11 @@ public final class TrackingSettings {
myLocationView.setEnabled(locationEnabled);
}
+ void setLocationSource(LocationEngine locationSource) {
+ this.locationSource = locationSource;
+ myLocationView.setLocationSource(locationSource);
+ }
+
void update() {
if (!myLocationView.isEnabled()) {
return;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java
index 15e0fb8925..e101340111 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java
@@ -13,8 +13,6 @@ import com.mapbox.mapboxsdk.constants.MapboxConstants;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.widgets.MyLocationView;
-import java.util.concurrent.TimeUnit;
-
import timber.log.Timber;
import static com.mapbox.mapboxsdk.maps.MapView.REGION_DID_CHANGE_ANIMATED;
@@ -49,6 +47,8 @@ final class Transform implements MapView.OnMapChangedListener {
if (position != null && !position.equals(CameraPosition.DEFAULT)) {
moveCamera(mapboxMap, CameraUpdateFactory.newCameraPosition(position), null);
}
+ setMinZoom(options.getMinZoomPreference());
+ setMaxZoom(options.getMaxZoomPreference());
}
//
@@ -108,7 +108,7 @@ final class Transform implements MapView.OnMapChangedListener {
mapView.addOnMapChangedListener(this);
}
- mapView.easeTo(cameraPosition.bearing, cameraPosition.target, getDurationNano(durationMs), cameraPosition.tilt,
+ mapView.easeTo(cameraPosition.bearing, cameraPosition.target, durationMs, cameraPosition.tilt,
cameraPosition.zoom, easingInterpolator);
}
}
@@ -126,7 +126,7 @@ final class Transform implements MapView.OnMapChangedListener {
mapView.addOnMapChangedListener(this);
}
- mapView.flyTo(cameraPosition.bearing, cameraPosition.target, getDurationNano(durationMs), cameraPosition.tilt,
+ mapView.flyTo(cameraPosition.bearing, cameraPosition.target, durationMs, cameraPosition.tilt,
cameraPosition.zoom);
}
}
@@ -161,10 +161,6 @@ final class Transform implements MapView.OnMapChangedListener {
this.onCameraChangeListener = listener;
}
- private long getDurationNano(long durationMs) {
- return durationMs > 0 ? TimeUnit.NANOSECONDS.convert(durationMs, TimeUnit.MILLISECONDS) : 0;
- }
-
//
// non Camera API
//
@@ -277,8 +273,8 @@ final class Transform implements MapView.OnMapChangedListener {
}
}
- void zoomBy(double pow, float x, float y) {
- mapView.scaleBy(pow, x, y);
+ void zoomBy(double z, float x, float y) {
+ mapView.setZoom(mapView.getZoom() + z, new PointF(x, y), 0);
}
void moveBy(double offsetX, double offsetY, long duration) {
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 8a3ae1e4f3..1bcf8a70b9 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
@@ -3,14 +3,19 @@ package com.mapbox.mapboxsdk.maps;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.PointF;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
import android.support.v4.content.ContextCompat;
+import android.support.v4.content.res.ResourcesCompat;
import android.view.Gravity;
import android.view.View;
import android.widget.FrameLayout;
@@ -22,6 +27,8 @@ import com.mapbox.mapboxsdk.constants.MapboxConstants;
import com.mapbox.mapboxsdk.maps.widgets.CompassView;
import com.mapbox.mapboxsdk.utils.ColorUtils;
+import java.io.ByteArrayOutputStream;
+
/**
* Settings for the user interface of a MapboxMap. To obtain this interface, call getUiSettings().
*/
@@ -139,10 +146,14 @@ public final class UiSettings {
if (compassMargins != null) {
setCompassMargins(compassMargins[0], compassMargins[1], compassMargins[2], compassMargins[3]);
} else {
- int tenDp = (int) resources.getDimension(R.dimen.mapbox_ten_dp);
+ int tenDp = (int) resources.getDimension(R.dimen.mapbox_four_dp);
setCompassMargins(tenDp, tenDp, tenDp, tenDp);
}
setCompassFadeFacingNorth(options.getCompassFadeFacingNorth());
+ if (options.getCompassImage() == null) {
+ options.compassImage(ResourcesCompat.getDrawable(resources, R.drawable.mapbox_compass_icon, null));
+ }
+ setCompassImage(options.getCompassImage());
}
private void saveCompass(Bundle outState) {
@@ -153,6 +164,14 @@ public final class UiSettings {
outState.putInt(MapboxConstants.STATE_COMPASS_MARGIN_BOTTOM, getCompassMarginBottom());
outState.putInt(MapboxConstants.STATE_COMPASS_MARGIN_RIGHT, getCompassMarginRight());
outState.putBoolean(MapboxConstants.STATE_COMPASS_FADE_WHEN_FACING_NORTH, isCompassFadeWhenFacingNorth());
+ outState.putByteArray(MapboxConstants.STATE_COMPASS_IMAGE_BITMAP,
+ convert(MapboxMapOptions.getBitmapFromDrawable(getCompassImage())));
+ }
+
+ private byte[] convert(Bitmap resource) {
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ resource.compress(Bitmap.CompressFormat.PNG, 100, stream);
+ return stream.toByteArray();
}
private void restoreCompass(Bundle savedInstanceState) {
@@ -163,6 +182,12 @@ public final class UiSettings {
savedInstanceState.getInt(MapboxConstants.STATE_COMPASS_MARGIN_RIGHT),
savedInstanceState.getInt(MapboxConstants.STATE_COMPASS_MARGIN_BOTTOM));
setCompassFadeFacingNorth(savedInstanceState.getBoolean(MapboxConstants.STATE_COMPASS_FADE_WHEN_FACING_NORTH));
+ setCompassImage(decode(savedInstanceState.getByteArray(MapboxConstants.STATE_COMPASS_IMAGE_BITMAP)));
+ }
+
+ private Drawable decode(byte[] bitmap) {
+ Bitmap compass = BitmapFactory.decodeByteArray(bitmap, 0, bitmap.length);
+ return new BitmapDrawable(compassView.getResources(), compass);
}
private void initialiseLogo(MapboxMapOptions options, Resources resources) {
@@ -172,8 +197,8 @@ public final class UiSettings {
if (logoMargins != null) {
setLogoMargins(logoMargins[0], logoMargins[1], logoMargins[2], logoMargins[3]);
} else {
- int sixteenDp = (int) resources.getDimension(R.dimen.mapbox_sixteen_dp);
- setLogoMargins(sixteenDp, sixteenDp, sixteenDp, sixteenDp);
+ int twoDp = (int) resources.getDimension(R.dimen.mapbox_two_dp);
+ setLogoMargins(twoDp, twoDp, twoDp, twoDp);
}
}
@@ -196,16 +221,12 @@ public final class UiSettings {
}
private void initialiseAttribution(Context context, MapboxMapOptions options) {
- Resources resources = context.getResources();
setAttributionEnabled(options.getAttributionEnabled());
setAttributionGravity(options.getAttributionGravity());
int[] attributionMargins = options.getAttributionMargins();
if (attributionMargins != null) {
- setAttributionMargins(attributionMargins[0], attributionMargins[1], attributionMargins[2], attributionMargins[3]);
- } else {
- int sevenDp = (int) resources.getDimension(R.dimen.mapbox_seven_dp);
- int seventySixDp = (int) resources.getDimension(R.dimen.mapbox_seventy_six_dp);
- setAttributionMargins(seventySixDp, sevenDp, sevenDp, sevenDp);
+ setAttributionMargins(attributionMargins[0], attributionMargins[1],
+ attributionMargins[2], attributionMargins[3]);
}
int attributionTintColor = options.getAttributionTintColor();
@@ -297,6 +318,18 @@ public final class UiSettings {
}
/**
+ * Specifies the CompassView image.
+ * <p>
+ * By default this value is R.drawable.mapbox_compass_icon.
+ * </p>
+ *
+ * @param compass the drawable to show as image compass
+ */
+ public void setCompassImage(Drawable compass) {
+ compassView.setCompassImage(compass);
+ }
+
+ /**
* Returns whether the compass performs a fading animation out when facing north.
*
* @return True if the compass will fade, false if it remains visible
@@ -364,6 +397,15 @@ public final class UiSettings {
return ((FrameLayout.LayoutParams) compassView.getLayoutParams()).bottomMargin;
}
+ /**
+ * Get the current configured CompassView image.
+ *
+ * @return the drawable used as compass image
+ */
+ public Drawable getCompassImage() {
+ return compassView.getCompassImage();
+ }
+
void update(@NonNull CameraPosition cameraPosition) {
if (!isCompassEnabled()) {
return;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java
index a0d9646915..2b327409ae 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java
@@ -2,9 +2,9 @@ package com.mapbox.mapboxsdk.maps.widgets;
import android.content.Context;
import android.graphics.PointF;
+import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
-import android.support.v4.content.ContextCompat;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.ViewPropertyAnimatorCompat;
import android.support.v4.view.ViewPropertyAnimatorListenerAdapter;
@@ -13,7 +13,6 @@ import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
-import com.mapbox.mapboxsdk.R;
import com.mapbox.mapboxsdk.maps.FocalPointChangeListener;
import com.mapbox.mapboxsdk.maps.MapboxMap;
@@ -55,7 +54,6 @@ public final class CompassView extends AppCompatImageView implements Runnable, F
}
private void initialize(Context context) {
- setImageDrawable(ContextCompat.getDrawable(getContext(), R.drawable.mapbox_compass_icon));
setEnabled(false);
// Layout params
@@ -139,6 +137,24 @@ public final class CompassView extends AppCompatImageView implements Runnable, F
return fadeCompassViewFacingNorth;
}
+ /**
+ * Set the CompassView image.
+ *
+ * @param compass the drawable to use as compass image
+ */
+ public void setCompassImage(Drawable compass) {
+ setImageDrawable(compass);
+ }
+
+ /**
+ * Get the current configured CompassView image.
+ *
+ * @return the drawable used as compass image
+ */
+ public Drawable getCompassImage() {
+ return getDrawable();
+ }
+
@Override
public void run() {
if (isFacingNorth() && fadeCompassViewFacingNorth) {
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 663202eacc..aecf3cc655 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
@@ -58,6 +58,7 @@ public class MyLocationView extends View {
private LatLng latLng;
private Location location;
+ private LocationEngine locationSource;
private long locationUpdateTimestamp;
private float previousDirection;
@@ -320,8 +321,7 @@ public class MyLocationView extends View {
if (location != null) {
setCompass(location.getBearing() - bearing);
}
- } else if (myBearingTrackingMode == MyBearingTracking.COMPASS
- && compassListener.isSensorAvailable()) {
+ } else if (myBearingTrackingMode == MyBearingTracking.COMPASS && compassListener.isSensorAvailable()) {
setCompass(magneticHeading - bearing);
}
}
@@ -335,8 +335,7 @@ public class MyLocationView extends View {
}
public void onStart() {
- if (myBearingTrackingMode == MyBearingTracking.COMPASS
- && compassListener.isSensorAvailable()) {
+ if (myBearingTrackingMode == MyBearingTracking.COMPASS && compassListener.isSensorAvailable()) {
compassListener.onResume();
}
if (isEnabled()) {
@@ -369,7 +368,8 @@ public class MyLocationView extends View {
}
if (userLocationListener != null) {
- LocationSource.getLocationEngine(getContext()).removeLocationEngineListener(userLocationListener);
+ locationSource.removeLocationEngineListener(userLocationListener);
+ locationSource = null;
userLocationListener = null;
}
}
@@ -419,29 +419,32 @@ public class MyLocationView extends View {
* @param enableGps true if GPS is to be enabled, false if GPS is to be disabled
*/
private void toggleGps(boolean enableGps) {
- LocationEngine locationEngine = LocationSource.getLocationEngine(getContext());
+ if (locationSource == null) {
+ locationSource = LocationSource.getLocationEngine(this.getContext());
+ }
+
if (enableGps) {
// Set an initial location if one available
- Location lastLocation = locationEngine.getLastLocation();
+ Location lastLocation = locationSource.getLastLocation();
if (lastLocation != null) {
setLocation(lastLocation);
}
if (userLocationListener == null) {
- userLocationListener = new GpsLocationListener(this);
+ userLocationListener = new GpsLocationListener(this, locationSource);
}
- locationEngine.addLocationEngineListener(userLocationListener);
- locationEngine.activate();
+ locationSource.addLocationEngineListener(userLocationListener);
+ locationSource.activate();
} else {
// Disable location and user dot
location = null;
- locationEngine.removeLocationEngineListener(userLocationListener);
- locationEngine.deactivate();
+ locationSource.removeLocationEngineListener(userLocationListener);
+ locationSource.deactivate();
}
- locationEngine.setPriority(LocationEnginePriority.HIGH_ACCURACY);
+ locationSource.setPriority(LocationEnginePriority.HIGH_ACCURACY);
}
public Location getLocation() {
@@ -460,8 +463,7 @@ public class MyLocationView extends View {
public void setMyBearingTrackingMode(@MyBearingTracking.Mode int myBearingTrackingMode) {
this.myBearingTrackingMode = myBearingTrackingMode;
- if (myBearingTrackingMode == MyBearingTracking.COMPASS
- && compassListener.isSensorAvailable()) {
+ if (myBearingTrackingMode == MyBearingTracking.COMPASS && compassListener.isSensorAvailable()) {
compassListener.onResume();
} else {
compassListener.onPause();
@@ -561,22 +563,28 @@ public class MyLocationView extends View {
contentPaddingY = (padding[1] - padding[3]) / 2;
}
+ public void setLocationSource(LocationEngine locationSource) {
+ this.locationSource = locationSource;
+ }
+
private static class GpsLocationListener implements LocationEngineListener {
private WeakReference<MyLocationView> userLocationView;
+ private WeakReference<LocationEngine> locationSource;
- GpsLocationListener(MyLocationView myLocationView) {
+ GpsLocationListener(MyLocationView myLocationView, LocationEngine locationEngine) {
userLocationView = new WeakReference<>(myLocationView);
+ locationSource = new WeakReference<>(locationEngine);
}
@Override
public void onConnected() {
MyLocationView locationView = userLocationView.get();
if (locationView != null) {
- LocationEngine locationSource = LocationSource.getLocationEngine(locationView.getContext());
- Location location = locationSource.getLastLocation();
+ LocationEngine locationEngine = locationSource.get();
+ Location location = locationEngine.getLastLocation();
locationView.setLocation(location);
- locationSource.requestLocationUpdates();
+ locationEngine.requestLocationUpdates();
}
}
@@ -741,7 +749,7 @@ public class MyLocationView extends View {
abstract void invalidate();
}
- private class MyLocationTrackingBehavior extends MyLocationBehavior {
+ private class MyLocationTrackingBehavior extends MyLocationBehavior implements MapboxMap.CancelableCallback {
@Override
void updateLatLng(@NonNull Location location) {
@@ -757,11 +765,11 @@ public class MyLocationView extends View {
locationUpdateTimestamp = SystemClock.elapsedRealtime();
// calculate animation duration
- float animationDuration;
+ int animationDuration;
if (previousUpdateTimeStamp == 0) {
animationDuration = 0;
} else {
- animationDuration = (locationUpdateTimestamp - previousUpdateTimeStamp) * 1.1f
+ animationDuration = (int) ((locationUpdateTimestamp - previousUpdateTimeStamp) * 1.1f)
/*make animation slightly longer*/;
}
@@ -780,20 +788,10 @@ public class MyLocationView extends View {
// accuracy
updateAccuracy(location);
+ // disable dismiss of tracking settings, enabled in #onFinish
mapboxMap.getTrackingSettings().setDismissTrackingModeForCameraPositionChange(false);
// ease to new camera position with a linear interpolator
- mapboxMap.easeCamera(CameraUpdateFactory.newCameraPosition(builder.build()), (int) animationDuration,
- false /*linear interpolator*/, new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
-
- }
-
- @Override
- public void onFinish() {
- mapboxMap.getTrackingSettings().setDismissTrackingModeForCameraPositionChange(true);
- }
- });
+ mapboxMap.easeCamera(CameraUpdateFactory.newCameraPosition(builder.build()), animationDuration, false, this);
}
@Override
@@ -804,6 +802,22 @@ public class MyLocationView extends View {
screenLocation = new PointF(x, y);
MyLocationView.this.invalidate();
}
+
+ @Override
+ public void onCancel() {
+ //no op
+ }
+
+ @Override
+ public void onFinish() {
+ // Posting to end message queue to avoid race condition #8560
+ post(new Runnable() {
+ @Override
+ public void run() {
+ mapboxMap.getTrackingSettings().setDismissTrackingModeForCameraPositionChange(true);
+ }
+ });
+ }
}
private class MyLocationShowBehavior extends MyLocationBehavior {
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/NativeConnectivityListener.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/NativeConnectivityListener.java
index 76ce1de9d7..ae74859228 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/NativeConnectivityListener.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/NativeConnectivityListener.java
@@ -1,12 +1,14 @@
package com.mapbox.mapboxsdk.net;
+import com.mapbox.mapboxsdk.LibraryLoader;
+
/**
* Updates the native library's connectivity state
*/
class NativeConnectivityListener implements ConnectivityListener {
static {
- System.loadLibrary("mapbox-gl");
+ LibraryLoader.load();
}
private long nativePtr;
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 8bf19c4065..50ae6716e6 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
@@ -5,6 +5,9 @@ import android.os.Handler;
import android.os.Looper;
import android.support.annotation.NonNull;
+import com.mapbox.mapboxsdk.LibraryLoader;
+import com.mapbox.mapboxsdk.R;
+import com.mapbox.mapboxsdk.geometry.LatLngBounds;
import com.mapbox.mapboxsdk.net.ConnectivityReceiver;
import com.mapbox.mapboxsdk.storage.FileSource;
@@ -23,10 +26,9 @@ public class OfflineManager {
//
static {
- System.loadLibrary("mapbox-gl");
+ LibraryLoader.load();
}
-
// Native peer pointer
private long nativePtr;
@@ -139,7 +141,8 @@ public class OfflineManager {
*
* @param callback the callback to be invoked
*/
- public void listOfflineRegions(@NonNull final ListOfflineRegionsCallback callback) {
+ public void listOfflineRegions(@NonNull
+ final ListOfflineRegionsCallback callback) {
listOfflineRegions(fileSource, new ListOfflineRegionsCallback() {
@Override
@@ -180,10 +183,15 @@ public class OfflineManager {
* @param metadata the metadata in bytes
* @param callback the callback to be invoked
*/
- public void createOfflineRegion(
- @NonNull OfflineRegionDefinition definition,
- @NonNull byte[] metadata,
- @NonNull final CreateOfflineRegionCallback callback) {
+ public void createOfflineRegion(@NonNull OfflineRegionDefinition definition, @NonNull byte[] metadata,
+ final CreateOfflineRegionCallback callback) {
+ if (!isValidOfflineRegionDefinition(definition)) {
+ callback.onError(
+ String.format(context.getString(R.string.mapbox_offline_error_region_definition_invalid),
+ definition.getBounds())
+ );
+ return;
+ }
ConnectivityReceiver.instance(context).activate();
createOfflineRegion(fileSource, definition, metadata, new CreateOfflineRegionCallback() {
@@ -212,6 +220,16 @@ public class OfflineManager {
});
}
+ /**
+ * Validates if the offline region definition bounds is valid for an offline region download.
+ *
+ * @param definition the offline region definition
+ * @return true if the region fits the world bounds.
+ */
+ private boolean isValidOfflineRegionDefinition(OfflineRegionDefinition definition) {
+ return LatLngBounds.world().contains(definition.getBounds());
+ }
+
/*
* Changing or bypassing this limit without permission from Mapbox is prohibited
* by the Mapbox Terms of Service.
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 a55e8dd848..5ed6579e1c 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
@@ -5,6 +5,7 @@ import android.os.Looper;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
+import com.mapbox.mapboxsdk.LibraryLoader;
import com.mapbox.mapboxsdk.storage.FileSource;
import java.lang.annotation.Retention;
@@ -22,7 +23,7 @@ public class OfflineRegion {
//
static {
- System.loadLibrary("mapbox-gl");
+ LibraryLoader.load();
}
// Members
@@ -205,7 +206,7 @@ public class OfflineRegion {
/**
* Constructor
- *
+ * <p>
* For JNI use only, to create a new offline region, use
* {@link OfflineManager#createOfflineRegion} instead.
*/
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionDefinition.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionDefinition.java
index a21ff0a443..18d662a286 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionDefinition.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionDefinition.java
@@ -1,9 +1,14 @@
package com.mapbox.mapboxsdk.offline;
+import com.mapbox.mapboxsdk.geometry.LatLngBounds;
+
/**
* This is the interface that all Offline Region definitions have to implement.
* <p>
* For the present, a tile pyramid is the only type of offline region.
*/
public interface OfflineRegionDefinition {
+
+ LatLngBounds getBounds();
+
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java
index a12d8f9954..06676d76a1 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java
@@ -5,6 +5,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Environment;
import android.support.annotation.NonNull;
+import android.content.res.AssetManager;
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
@@ -40,8 +41,7 @@ public class FileSource {
public static synchronized FileSource getInstance(Context context) {
if (INSTANCE == null) {
String cachePath = getCachePath(context);
- String apkPath = context.getPackageCodePath();
- INSTANCE = new FileSource(cachePath, apkPath);
+ INSTANCE = new FileSource(cachePath, context.getResources().getAssets());
}
return INSTANCE;
@@ -107,8 +107,8 @@ public class FileSource {
private long nativePtr;
- private FileSource(String cachePath, String apkPath) {
- initialize(Mapbox.getAccessToken(), cachePath, apkPath);
+ private FileSource(String cachePath, AssetManager assetManager) {
+ initialize(Mapbox.getAccessToken(), cachePath, assetManager);
}
public native void setAccessToken(@NonNull String accessToken);
@@ -127,7 +127,7 @@ public class FileSource {
*/
public native void setResourceTransform(final ResourceTransformCallback callback);
- private native void initialize(String accessToken, String cachePath, String apkPath);
+ private native void initialize(String accessToken, String cachePath, AssetManager assetManager);
@Override
protected native void finalize() throws Throwable;
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
index 0f1265f1a1..978fa29ef8 100644
--- 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
@@ -8,6 +8,8 @@ import android.support.annotation.UiThread;
import static com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor;
+import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
+
/**
* The background color or pattern of the map.
*
@@ -75,6 +77,23 @@ public class BackgroundLayer extends Layer {
}
}
+ /**
+ * Get the BackgroundColor property transition options
+ *
+ * @return transition options for String
+ */
+ public TransitionOptions getBackgroundColorTransition() {
+ return nativeGetBackgroundColorTransition();
+ }
+
+ /**
+ * Set the BackgroundColor property transition options
+ *
+ * @param options transition options for String
+ */
+ public void setBackgroundColorTransition(TransitionOptions options) {
+ nativeSetBackgroundColorTransition(options.getDuration(), options.getDelay());
+ }
/**
* Get the BackgroundPattern property
@@ -87,6 +106,24 @@ public class BackgroundLayer extends Layer {
}
/**
+ * Get the BackgroundPattern property transition options
+ *
+ * @return transition options for String
+ */
+ public TransitionOptions getBackgroundPatternTransition() {
+ return nativeGetBackgroundPatternTransition();
+ }
+
+ /**
+ * Set the BackgroundPattern property transition options
+ *
+ * @param options transition options for String
+ */
+ public void setBackgroundPatternTransition(TransitionOptions options) {
+ nativeSetBackgroundPatternTransition(options.getDuration(), options.getDelay());
+ }
+
+ /**
* Get the BackgroundOpacity property
*
* @return property wrapper value around Float
@@ -96,12 +133,41 @@ public class BackgroundLayer extends Layer {
return (PropertyValue<Float>) new PropertyValue("background-opacity", nativeGetBackgroundOpacity());
}
+ /**
+ * Get the BackgroundOpacity property transition options
+ *
+ * @return transition options for Float
+ */
+ public TransitionOptions getBackgroundOpacityTransition() {
+ return nativeGetBackgroundOpacityTransition();
+ }
+
+ /**
+ * Set the BackgroundOpacity property transition options
+ *
+ * @param options transition options for Float
+ */
+ public void setBackgroundOpacityTransition(TransitionOptions options) {
+ nativeSetBackgroundOpacityTransition(options.getDuration(), options.getDelay());
+ }
+
private native Object nativeGetBackgroundColor();
+ private native TransitionOptions nativeGetBackgroundColorTransition();
+
+ private native void nativeSetBackgroundColorTransition(long duration, long delay);
+
private native Object nativeGetBackgroundPattern();
+ private native TransitionOptions nativeGetBackgroundPatternTransition();
+
+ private native void nativeSetBackgroundPatternTransition(long duration, long delay);
+
private native Object nativeGetBackgroundOpacity();
+ private native TransitionOptions nativeGetBackgroundOpacityTransition();
+
+ private native void nativeSetBackgroundOpacityTransition(long duration, long delay);
@Override
protected native void finalize() throws Throwable;
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
index 43ec255e81..1a7df06031 100644
--- 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
@@ -8,6 +8,8 @@ import android.support.annotation.UiThread;
import static com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor;
+import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
+
/**
* A filled circle.
*
@@ -58,6 +60,15 @@ public class CircleLayer extends Layer {
}
/**
+ * Get the source layer.
+ *
+ * @return sourceLayer the source layer to get
+ */
+ public String getSourceLayer() {
+ return nativeGetSourceLayer();
+ }
+
+ /**
* Set a single filter.
*
* @param filter the filter to set
@@ -101,6 +112,24 @@ public class CircleLayer extends Layer {
}
/**
+ * Get the CircleRadius property transition options
+ *
+ * @return transition options for Float
+ */
+ public TransitionOptions getCircleRadiusTransition() {
+ return nativeGetCircleRadiusTransition();
+ }
+
+ /**
+ * Set the CircleRadius property transition options
+ *
+ * @param options transition options for Float
+ */
+ public void setCircleRadiusTransition(TransitionOptions options) {
+ nativeSetCircleRadiusTransition(options.getDuration(), options.getDelay());
+ }
+
+ /**
* Get the CircleColor property
*
* @return property wrapper value around String
@@ -126,6 +155,23 @@ public class CircleLayer extends Layer {
}
}
+ /**
+ * Get the CircleColor property transition options
+ *
+ * @return transition options for String
+ */
+ public TransitionOptions getCircleColorTransition() {
+ return nativeGetCircleColorTransition();
+ }
+
+ /**
+ * Set the CircleColor property transition options
+ *
+ * @param options transition options for String
+ */
+ public void setCircleColorTransition(TransitionOptions options) {
+ nativeSetCircleColorTransition(options.getDuration(), options.getDelay());
+ }
/**
* Get the CircleBlur property
@@ -138,6 +184,24 @@ public class CircleLayer extends Layer {
}
/**
+ * Get the CircleBlur property transition options
+ *
+ * @return transition options for Float
+ */
+ public TransitionOptions getCircleBlurTransition() {
+ return nativeGetCircleBlurTransition();
+ }
+
+ /**
+ * Set the CircleBlur property transition options
+ *
+ * @param options transition options for Float
+ */
+ public void setCircleBlurTransition(TransitionOptions options) {
+ nativeSetCircleBlurTransition(options.getDuration(), options.getDelay());
+ }
+
+ /**
* Get the CircleOpacity property
*
* @return property wrapper value around Float
@@ -148,6 +212,24 @@ public class CircleLayer extends Layer {
}
/**
+ * Get the CircleOpacity property transition options
+ *
+ * @return transition options for Float
+ */
+ public TransitionOptions getCircleOpacityTransition() {
+ return nativeGetCircleOpacityTransition();
+ }
+
+ /**
+ * Set the CircleOpacity property transition options
+ *
+ * @param options transition options for Float
+ */
+ public void setCircleOpacityTransition(TransitionOptions options) {
+ nativeSetCircleOpacityTransition(options.getDuration(), options.getDelay());
+ }
+
+ /**
* Get the CircleTranslate property
*
* @return property wrapper value around Float[]
@@ -158,6 +240,24 @@ public class CircleLayer extends Layer {
}
/**
+ * Get the CircleTranslate property transition options
+ *
+ * @return transition options for Float[]
+ */
+ public TransitionOptions getCircleTranslateTransition() {
+ return nativeGetCircleTranslateTransition();
+ }
+
+ /**
+ * Set the CircleTranslate property transition options
+ *
+ * @param options transition options for Float[]
+ */
+ public void setCircleTranslateTransition(TransitionOptions options) {
+ nativeSetCircleTranslateTransition(options.getDuration(), options.getDelay());
+ }
+
+ /**
* Get the CircleTranslateAnchor property
*
* @return property wrapper value around String
@@ -188,6 +288,24 @@ public class CircleLayer extends Layer {
}
/**
+ * Get the CircleStrokeWidth property transition options
+ *
+ * @return transition options for Float
+ */
+ public TransitionOptions getCircleStrokeWidthTransition() {
+ return nativeGetCircleStrokeWidthTransition();
+ }
+
+ /**
+ * Set the CircleStrokeWidth property transition options
+ *
+ * @param options transition options for Float
+ */
+ public void setCircleStrokeWidthTransition(TransitionOptions options) {
+ nativeSetCircleStrokeWidthTransition(options.getDuration(), options.getDelay());
+ }
+
+ /**
* Get the CircleStrokeColor property
*
* @return property wrapper value around String
@@ -213,6 +331,23 @@ public class CircleLayer extends Layer {
}
}
+ /**
+ * Get the CircleStrokeColor property transition options
+ *
+ * @return transition options for String
+ */
+ public TransitionOptions getCircleStrokeColorTransition() {
+ return nativeGetCircleStrokeColorTransition();
+ }
+
+ /**
+ * Set the CircleStrokeColor property transition options
+ *
+ * @param options transition options for String
+ */
+ public void setCircleStrokeColorTransition(TransitionOptions options) {
+ nativeSetCircleStrokeColorTransition(options.getDuration(), options.getDelay());
+ }
/**
* Get the CircleStrokeOpacity property
@@ -224,26 +359,75 @@ public class CircleLayer extends Layer {
return (PropertyValue<Float>) new PropertyValue("circle-stroke-opacity", nativeGetCircleStrokeOpacity());
}
+ /**
+ * Get the CircleStrokeOpacity property transition options
+ *
+ * @return transition options for Float
+ */
+ public TransitionOptions getCircleStrokeOpacityTransition() {
+ return nativeGetCircleStrokeOpacityTransition();
+ }
+
+ /**
+ * Set the CircleStrokeOpacity property transition options
+ *
+ * @param options transition options for Float
+ */
+ public void setCircleStrokeOpacityTransition(TransitionOptions options) {
+ nativeSetCircleStrokeOpacityTransition(options.getDuration(), options.getDelay());
+ }
+
private native Object nativeGetCircleRadius();
+ private native TransitionOptions nativeGetCircleRadiusTransition();
+
+ private native void nativeSetCircleRadiusTransition(long duration, long delay);
+
private native Object nativeGetCircleColor();
+ private native TransitionOptions nativeGetCircleColorTransition();
+
+ private native void nativeSetCircleColorTransition(long duration, long delay);
+
private native Object nativeGetCircleBlur();
+ private native TransitionOptions nativeGetCircleBlurTransition();
+
+ private native void nativeSetCircleBlurTransition(long duration, long delay);
+
private native Object nativeGetCircleOpacity();
+ private native TransitionOptions nativeGetCircleOpacityTransition();
+
+ private native void nativeSetCircleOpacityTransition(long duration, long delay);
+
private native Object nativeGetCircleTranslate();
+ private native TransitionOptions nativeGetCircleTranslateTransition();
+
+ private native void nativeSetCircleTranslateTransition(long duration, long delay);
+
private native Object nativeGetCircleTranslateAnchor();
private native Object nativeGetCirclePitchScale();
private native Object nativeGetCircleStrokeWidth();
+ private native TransitionOptions nativeGetCircleStrokeWidthTransition();
+
+ private native void nativeSetCircleStrokeWidthTransition(long duration, long delay);
+
private native Object nativeGetCircleStrokeColor();
+ private native TransitionOptions nativeGetCircleStrokeColorTransition();
+
+ private native void nativeSetCircleStrokeColorTransition(long duration, long delay);
+
private native Object nativeGetCircleStrokeOpacity();
+ private native TransitionOptions nativeGetCircleStrokeOpacityTransition();
+
+ private native void nativeSetCircleStrokeOpacityTransition(long duration, long delay);
@Override
protected native void finalize() throws Throwable;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillExtrusionLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillExtrusionLayer.java
new file mode 100644
index 0000000000..6772da73b1
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillExtrusionLayer.java
@@ -0,0 +1,339 @@
+// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
+
+package com.mapbox.mapboxsdk.style.layers;
+
+import android.support.annotation.ColorInt;
+import android.support.annotation.NonNull;
+import android.support.annotation.UiThread;
+
+import static com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor;
+
+import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
+
+/**
+ * An extruded (3D) polygon.
+ *
+ * @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#layers-fill-extrusion">The online documentation</a>
+ */
+@UiThread
+public class FillExtrusionLayer extends Layer {
+
+ /**
+ * Creates a FillExtrusionLayer.
+ *
+ * @param nativePtr pointer used by core
+ */
+ public FillExtrusionLayer(long nativePtr) {
+ super(nativePtr);
+ }
+
+ /**
+ * Creates a FillExtrusionLayer.
+ *
+ * @param layerId the id of the layer
+ * @param sourceId the id of the source
+ */
+ public FillExtrusionLayer(String layerId, String sourceId) {
+ initialize(layerId, sourceId);
+ }
+
+ protected native void initialize(String layerId, String sourceId);
+
+ /**
+ * Set the source layer.
+ *
+ * @param sourceLayer the source layer to set
+ */
+ public void setSourceLayer(String sourceLayer) {
+ nativeSetSourceLayer(sourceLayer);
+ }
+
+ /**
+ * Set the source Layer.
+ *
+ * @param sourceLayer the source layer to set
+ * @return This
+ */
+ public FillExtrusionLayer withSourceLayer(String sourceLayer) {
+ setSourceLayer(sourceLayer);
+ return this;
+ }
+
+ /**
+ * Get the source layer.
+ *
+ * @return sourceLayer the source layer to get
+ */
+ public String getSourceLayer() {
+ return nativeGetSourceLayer();
+ }
+
+ /**
+ * Set a single filter.
+ *
+ * @param filter the filter to set
+ */
+ public void setFilter(Filter.Statement filter) {
+ nativeSetFilter(filter.toArray());
+ }
+
+ /**
+ * Set a single filter.
+ *
+ * @param filter the filter to set
+ * @return This
+ */
+ public FillExtrusionLayer withFilter(Filter.Statement filter) {
+ setFilter(filter);
+ return this;
+ }
+
+ /**
+ * Set a property or properties.
+ *
+ * @param properties the var-args properties
+ * @return This
+ */
+ public FillExtrusionLayer withProperties(@NonNull PropertyValue<?>... properties) {
+ setProperties(properties);
+ return this;
+ }
+
+ // Property getters
+
+ /**
+ * Get the FillExtrusionOpacity property
+ *
+ * @return property wrapper value around Float
+ */
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getFillExtrusionOpacity() {
+ return (PropertyValue<Float>) new PropertyValue("fill-extrusion-opacity", nativeGetFillExtrusionOpacity());
+ }
+
+ /**
+ * Get the FillExtrusionOpacity property transition options
+ *
+ * @return transition options for Float
+ */
+ public TransitionOptions getFillExtrusionOpacityTransition() {
+ return nativeGetFillExtrusionOpacityTransition();
+ }
+
+ /**
+ * Set the FillExtrusionOpacity property transition options
+ *
+ * @param options transition options for Float
+ */
+ public void setFillExtrusionOpacityTransition(TransitionOptions options) {
+ nativeSetFillExtrusionOpacityTransition(options.getDuration(), options.getDelay());
+ }
+
+ /**
+ * Get the FillExtrusionColor property
+ *
+ * @return property wrapper value around String
+ */
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getFillExtrusionColor() {
+ return (PropertyValue<String>) new PropertyValue("fill-extrusion-color", nativeGetFillExtrusionColor());
+ }
+
+ /**
+ * The base color of the extruded fill. The extrusion's surfaces will be shaded differently based on this color in combination with the root `light` settings. If this color is specified as `rgba` with an alpha component, the alpha component will be ignored; use `fill-extrusion-opacity` to set layer opacity.
+ *
+ * @return int representation of a rgba string color
+ * @throws RuntimeException thrown if property isn't a value
+ */
+ @ColorInt
+ public int getFillExtrusionColorAsInt() {
+ PropertyValue<String> value = getFillExtrusionColor();
+ if (value.isValue()) {
+ return rgbaToColor(value.getValue());
+ } else {
+ throw new RuntimeException("fill-extrusion-color was set as a Function");
+ }
+ }
+
+ /**
+ * Get the FillExtrusionColor property transition options
+ *
+ * @return transition options for String
+ */
+ public TransitionOptions getFillExtrusionColorTransition() {
+ return nativeGetFillExtrusionColorTransition();
+ }
+
+ /**
+ * Set the FillExtrusionColor property transition options
+ *
+ * @param options transition options for String
+ */
+ public void setFillExtrusionColorTransition(TransitionOptions options) {
+ nativeSetFillExtrusionColorTransition(options.getDuration(), options.getDelay());
+ }
+
+ /**
+ * Get the FillExtrusionTranslate property
+ *
+ * @return property wrapper value around Float[]
+ */
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float[]> getFillExtrusionTranslate() {
+ return (PropertyValue<Float[]>) new PropertyValue("fill-extrusion-translate", nativeGetFillExtrusionTranslate());
+ }
+
+ /**
+ * Get the FillExtrusionTranslate property transition options
+ *
+ * @return transition options for Float[]
+ */
+ public TransitionOptions getFillExtrusionTranslateTransition() {
+ return nativeGetFillExtrusionTranslateTransition();
+ }
+
+ /**
+ * Set the FillExtrusionTranslate property transition options
+ *
+ * @param options transition options for Float[]
+ */
+ public void setFillExtrusionTranslateTransition(TransitionOptions options) {
+ nativeSetFillExtrusionTranslateTransition(options.getDuration(), options.getDelay());
+ }
+
+ /**
+ * Get the FillExtrusionTranslateAnchor property
+ *
+ * @return property wrapper value around String
+ */
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getFillExtrusionTranslateAnchor() {
+ return (PropertyValue<String>) new PropertyValue("fill-extrusion-translate-anchor", nativeGetFillExtrusionTranslateAnchor());
+ }
+
+ /**
+ * Get the FillExtrusionPattern property
+ *
+ * @return property wrapper value around String
+ */
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getFillExtrusionPattern() {
+ return (PropertyValue<String>) new PropertyValue("fill-extrusion-pattern", nativeGetFillExtrusionPattern());
+ }
+
+ /**
+ * Get the FillExtrusionPattern property transition options
+ *
+ * @return transition options for String
+ */
+ public TransitionOptions getFillExtrusionPatternTransition() {
+ return nativeGetFillExtrusionPatternTransition();
+ }
+
+ /**
+ * Set the FillExtrusionPattern property transition options
+ *
+ * @param options transition options for String
+ */
+ public void setFillExtrusionPatternTransition(TransitionOptions options) {
+ nativeSetFillExtrusionPatternTransition(options.getDuration(), options.getDelay());
+ }
+
+ /**
+ * Get the FillExtrusionHeight property
+ *
+ * @return property wrapper value around Float
+ */
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getFillExtrusionHeight() {
+ return (PropertyValue<Float>) new PropertyValue("fill-extrusion-height", nativeGetFillExtrusionHeight());
+ }
+
+ /**
+ * Get the FillExtrusionHeight property transition options
+ *
+ * @return transition options for Float
+ */
+ public TransitionOptions getFillExtrusionHeightTransition() {
+ return nativeGetFillExtrusionHeightTransition();
+ }
+
+ /**
+ * Set the FillExtrusionHeight property transition options
+ *
+ * @param options transition options for Float
+ */
+ public void setFillExtrusionHeightTransition(TransitionOptions options) {
+ nativeSetFillExtrusionHeightTransition(options.getDuration(), options.getDelay());
+ }
+
+ /**
+ * Get the FillExtrusionBase property
+ *
+ * @return property wrapper value around Float
+ */
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getFillExtrusionBase() {
+ return (PropertyValue<Float>) new PropertyValue("fill-extrusion-base", nativeGetFillExtrusionBase());
+ }
+
+ /**
+ * Get the FillExtrusionBase property transition options
+ *
+ * @return transition options for Float
+ */
+ public TransitionOptions getFillExtrusionBaseTransition() {
+ return nativeGetFillExtrusionBaseTransition();
+ }
+
+ /**
+ * Set the FillExtrusionBase property transition options
+ *
+ * @param options transition options for Float
+ */
+ public void setFillExtrusionBaseTransition(TransitionOptions options) {
+ nativeSetFillExtrusionBaseTransition(options.getDuration(), options.getDelay());
+ }
+
+ private native Object nativeGetFillExtrusionOpacity();
+
+ private native TransitionOptions nativeGetFillExtrusionOpacityTransition();
+
+ private native void nativeSetFillExtrusionOpacityTransition(long duration, long delay);
+
+ private native Object nativeGetFillExtrusionColor();
+
+ private native TransitionOptions nativeGetFillExtrusionColorTransition();
+
+ private native void nativeSetFillExtrusionColorTransition(long duration, long delay);
+
+ private native Object nativeGetFillExtrusionTranslate();
+
+ private native TransitionOptions nativeGetFillExtrusionTranslateTransition();
+
+ private native void nativeSetFillExtrusionTranslateTransition(long duration, long delay);
+
+ private native Object nativeGetFillExtrusionTranslateAnchor();
+
+ private native Object nativeGetFillExtrusionPattern();
+
+ private native TransitionOptions nativeGetFillExtrusionPatternTransition();
+
+ private native void nativeSetFillExtrusionPatternTransition(long duration, long delay);
+
+ private native Object nativeGetFillExtrusionHeight();
+
+ private native TransitionOptions nativeGetFillExtrusionHeightTransition();
+
+ private native void nativeSetFillExtrusionHeightTransition(long duration, long delay);
+
+ private native Object nativeGetFillExtrusionBase();
+
+ private native TransitionOptions nativeGetFillExtrusionBaseTransition();
+
+ private native void nativeSetFillExtrusionBaseTransition(long duration, long delay);
+
+ @Override
+ protected native void finalize() throws Throwable;
+
+}
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
index 8989f3a2ec..3719ae9e1b 100644
--- 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
@@ -8,6 +8,8 @@ import android.support.annotation.UiThread;
import static com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor;
+import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
+
/**
* A filled polygon with an optional stroked border.
*
@@ -58,6 +60,15 @@ public class FillLayer extends Layer {
}
/**
+ * Get the source layer.
+ *
+ * @return sourceLayer the source layer to get
+ */
+ public String getSourceLayer() {
+ return nativeGetSourceLayer();
+ }
+
+ /**
* Set a single filter.
*
* @param filter the filter to set
@@ -111,6 +122,24 @@ public class FillLayer extends Layer {
}
/**
+ * Get the FillOpacity property transition options
+ *
+ * @return transition options for Float
+ */
+ public TransitionOptions getFillOpacityTransition() {
+ return nativeGetFillOpacityTransition();
+ }
+
+ /**
+ * Set the FillOpacity property transition options
+ *
+ * @param options transition options for Float
+ */
+ public void setFillOpacityTransition(TransitionOptions options) {
+ nativeSetFillOpacityTransition(options.getDuration(), options.getDelay());
+ }
+
+ /**
* Get the FillColor property
*
* @return property wrapper value around String
@@ -136,6 +165,23 @@ public class FillLayer extends Layer {
}
}
+ /**
+ * Get the FillColor property transition options
+ *
+ * @return transition options for String
+ */
+ public TransitionOptions getFillColorTransition() {
+ return nativeGetFillColorTransition();
+ }
+
+ /**
+ * Set the FillColor property transition options
+ *
+ * @param options transition options for String
+ */
+ public void setFillColorTransition(TransitionOptions options) {
+ nativeSetFillColorTransition(options.getDuration(), options.getDelay());
+ }
/**
* Get the FillOutlineColor property
@@ -163,6 +209,23 @@ public class FillLayer extends Layer {
}
}
+ /**
+ * Get the FillOutlineColor property transition options
+ *
+ * @return transition options for String
+ */
+ public TransitionOptions getFillOutlineColorTransition() {
+ return nativeGetFillOutlineColorTransition();
+ }
+
+ /**
+ * Set the FillOutlineColor property transition options
+ *
+ * @param options transition options for String
+ */
+ public void setFillOutlineColorTransition(TransitionOptions options) {
+ nativeSetFillOutlineColorTransition(options.getDuration(), options.getDelay());
+ }
/**
* Get the FillTranslate property
@@ -175,6 +238,24 @@ public class FillLayer extends Layer {
}
/**
+ * Get the FillTranslate property transition options
+ *
+ * @return transition options for Float[]
+ */
+ public TransitionOptions getFillTranslateTransition() {
+ return nativeGetFillTranslateTransition();
+ }
+
+ /**
+ * Set the FillTranslate property transition options
+ *
+ * @param options transition options for Float[]
+ */
+ public void setFillTranslateTransition(TransitionOptions options) {
+ nativeSetFillTranslateTransition(options.getDuration(), options.getDelay());
+ }
+
+ /**
* Get the FillTranslateAnchor property
*
* @return property wrapper value around String
@@ -194,20 +275,57 @@ public class FillLayer extends Layer {
return (PropertyValue<String>) new PropertyValue("fill-pattern", nativeGetFillPattern());
}
+ /**
+ * Get the FillPattern property transition options
+ *
+ * @return transition options for String
+ */
+ public TransitionOptions getFillPatternTransition() {
+ return nativeGetFillPatternTransition();
+ }
+
+ /**
+ * Set the FillPattern property transition options
+ *
+ * @param options transition options for String
+ */
+ public void setFillPatternTransition(TransitionOptions options) {
+ nativeSetFillPatternTransition(options.getDuration(), options.getDelay());
+ }
+
private native Object nativeGetFillAntialias();
private native Object nativeGetFillOpacity();
+ private native TransitionOptions nativeGetFillOpacityTransition();
+
+ private native void nativeSetFillOpacityTransition(long duration, long delay);
+
private native Object nativeGetFillColor();
+ private native TransitionOptions nativeGetFillColorTransition();
+
+ private native void nativeSetFillColorTransition(long duration, long delay);
+
private native Object nativeGetFillOutlineColor();
+ private native TransitionOptions nativeGetFillOutlineColorTransition();
+
+ private native void nativeSetFillOutlineColorTransition(long duration, long delay);
+
private native Object nativeGetFillTranslate();
+ private native TransitionOptions nativeGetFillTranslateTransition();
+
+ private native void nativeSetFillTranslateTransition(long duration, long delay);
+
private native Object nativeGetFillTranslateAnchor();
private native Object nativeGetFillPattern();
+ private native TransitionOptions nativeGetFillPatternTransition();
+
+ private native void nativeSetFillPatternTransition(long duration, long delay);
@Override
protected native void finalize() throws Throwable;
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
index b4120f4f9a..5015dd009d 100644
--- 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
@@ -73,6 +73,8 @@ public abstract class Layer {
protected native void nativeSetSourceLayer(String sourceLayer);
+ protected native String nativeGetSourceLayer();
+
protected native float nativeGetMinZoom();
protected native float nativeGetMaxZoom();
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
index 6992c22ace..ca106cc106 100644
--- 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
@@ -8,6 +8,8 @@ import android.support.annotation.UiThread;
import static com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor;
+import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
+
/**
* A stroked line.
*
@@ -58,6 +60,15 @@ public class LineLayer extends Layer {
}
/**
+ * Get the source layer.
+ *
+ * @return sourceLayer the source layer to get
+ */
+ public String getSourceLayer() {
+ return nativeGetSourceLayer();
+ }
+
+ /**
* Set a single filter.
*
* @param filter the filter to set
@@ -141,6 +152,24 @@ public class LineLayer extends Layer {
}
/**
+ * Get the LineOpacity property transition options
+ *
+ * @return transition options for Float
+ */
+ public TransitionOptions getLineOpacityTransition() {
+ return nativeGetLineOpacityTransition();
+ }
+
+ /**
+ * Set the LineOpacity property transition options
+ *
+ * @param options transition options for Float
+ */
+ public void setLineOpacityTransition(TransitionOptions options) {
+ nativeSetLineOpacityTransition(options.getDuration(), options.getDelay());
+ }
+
+ /**
* Get the LineColor property
*
* @return property wrapper value around String
@@ -166,6 +195,23 @@ public class LineLayer extends Layer {
}
}
+ /**
+ * Get the LineColor property transition options
+ *
+ * @return transition options for String
+ */
+ public TransitionOptions getLineColorTransition() {
+ return nativeGetLineColorTransition();
+ }
+
+ /**
+ * Set the LineColor property transition options
+ *
+ * @param options transition options for String
+ */
+ public void setLineColorTransition(TransitionOptions options) {
+ nativeSetLineColorTransition(options.getDuration(), options.getDelay());
+ }
/**
* Get the LineTranslate property
@@ -178,6 +224,24 @@ public class LineLayer extends Layer {
}
/**
+ * Get the LineTranslate property transition options
+ *
+ * @return transition options for Float[]
+ */
+ public TransitionOptions getLineTranslateTransition() {
+ return nativeGetLineTranslateTransition();
+ }
+
+ /**
+ * Set the LineTranslate property transition options
+ *
+ * @param options transition options for Float[]
+ */
+ public void setLineTranslateTransition(TransitionOptions options) {
+ nativeSetLineTranslateTransition(options.getDuration(), options.getDelay());
+ }
+
+ /**
* Get the LineTranslateAnchor property
*
* @return property wrapper value around String
@@ -198,6 +262,24 @@ public class LineLayer extends Layer {
}
/**
+ * Get the LineWidth property transition options
+ *
+ * @return transition options for Float
+ */
+ public TransitionOptions getLineWidthTransition() {
+ return nativeGetLineWidthTransition();
+ }
+
+ /**
+ * Set the LineWidth property transition options
+ *
+ * @param options transition options for Float
+ */
+ public void setLineWidthTransition(TransitionOptions options) {
+ nativeSetLineWidthTransition(options.getDuration(), options.getDelay());
+ }
+
+ /**
* Get the LineGapWidth property
*
* @return property wrapper value around Float
@@ -208,6 +290,24 @@ public class LineLayer extends Layer {
}
/**
+ * Get the LineGapWidth property transition options
+ *
+ * @return transition options for Float
+ */
+ public TransitionOptions getLineGapWidthTransition() {
+ return nativeGetLineGapWidthTransition();
+ }
+
+ /**
+ * Set the LineGapWidth property transition options
+ *
+ * @param options transition options for Float
+ */
+ public void setLineGapWidthTransition(TransitionOptions options) {
+ nativeSetLineGapWidthTransition(options.getDuration(), options.getDelay());
+ }
+
+ /**
* Get the LineOffset property
*
* @return property wrapper value around Float
@@ -218,6 +318,24 @@ public class LineLayer extends Layer {
}
/**
+ * Get the LineOffset property transition options
+ *
+ * @return transition options for Float
+ */
+ public TransitionOptions getLineOffsetTransition() {
+ return nativeGetLineOffsetTransition();
+ }
+
+ /**
+ * Set the LineOffset property transition options
+ *
+ * @param options transition options for Float
+ */
+ public void setLineOffsetTransition(TransitionOptions options) {
+ nativeSetLineOffsetTransition(options.getDuration(), options.getDelay());
+ }
+
+ /**
* Get the LineBlur property
*
* @return property wrapper value around Float
@@ -228,6 +346,24 @@ public class LineLayer extends Layer {
}
/**
+ * Get the LineBlur property transition options
+ *
+ * @return transition options for Float
+ */
+ public TransitionOptions getLineBlurTransition() {
+ return nativeGetLineBlurTransition();
+ }
+
+ /**
+ * Set the LineBlur property transition options
+ *
+ * @param options transition options for Float
+ */
+ public void setLineBlurTransition(TransitionOptions options) {
+ nativeSetLineBlurTransition(options.getDuration(), options.getDelay());
+ }
+
+ /**
* Get the LineDasharray property
*
* @return property wrapper value around Float[]
@@ -238,6 +374,24 @@ public class LineLayer extends Layer {
}
/**
+ * Get the LineDasharray property transition options
+ *
+ * @return transition options for Float[]
+ */
+ public TransitionOptions getLineDasharrayTransition() {
+ return nativeGetLineDasharrayTransition();
+ }
+
+ /**
+ * Set the LineDasharray property transition options
+ *
+ * @param options transition options for Float[]
+ */
+ public void setLineDasharrayTransition(TransitionOptions options) {
+ nativeSetLineDasharrayTransition(options.getDuration(), options.getDelay());
+ }
+
+ /**
* Get the LinePattern property
*
* @return property wrapper value around String
@@ -247,6 +401,24 @@ public class LineLayer extends Layer {
return (PropertyValue<String>) new PropertyValue("line-pattern", nativeGetLinePattern());
}
+ /**
+ * Get the LinePattern property transition options
+ *
+ * @return transition options for String
+ */
+ public TransitionOptions getLinePatternTransition() {
+ return nativeGetLinePatternTransition();
+ }
+
+ /**
+ * Set the LinePattern property transition options
+ *
+ * @param options transition options for String
+ */
+ public void setLinePatternTransition(TransitionOptions options) {
+ nativeSetLinePatternTransition(options.getDuration(), options.getDelay());
+ }
+
private native Object nativeGetLineCap();
private native Object nativeGetLineJoin();
@@ -257,24 +429,59 @@ public class LineLayer extends Layer {
private native Object nativeGetLineOpacity();
+ private native TransitionOptions nativeGetLineOpacityTransition();
+
+ private native void nativeSetLineOpacityTransition(long duration, long delay);
+
private native Object nativeGetLineColor();
+ private native TransitionOptions nativeGetLineColorTransition();
+
+ private native void nativeSetLineColorTransition(long duration, long delay);
+
private native Object nativeGetLineTranslate();
+ private native TransitionOptions nativeGetLineTranslateTransition();
+
+ private native void nativeSetLineTranslateTransition(long duration, long delay);
+
private native Object nativeGetLineTranslateAnchor();
private native Object nativeGetLineWidth();
+ private native TransitionOptions nativeGetLineWidthTransition();
+
+ private native void nativeSetLineWidthTransition(long duration, long delay);
+
private native Object nativeGetLineGapWidth();
+ private native TransitionOptions nativeGetLineGapWidthTransition();
+
+ private native void nativeSetLineGapWidthTransition(long duration, long delay);
+
private native Object nativeGetLineOffset();
+ private native TransitionOptions nativeGetLineOffsetTransition();
+
+ private native void nativeSetLineOffsetTransition(long duration, long delay);
+
private native Object nativeGetLineBlur();
+ private native TransitionOptions nativeGetLineBlurTransition();
+
+ private native void nativeSetLineBlurTransition(long duration, long delay);
+
private native Object nativeGetLineDasharray();
+ private native TransitionOptions nativeGetLineDasharrayTransition();
+
+ private native void nativeSetLineDasharrayTransition(long duration, long delay);
+
private native Object nativeGetLinePattern();
+ private native TransitionOptions nativeGetLinePatternTransition();
+
+ private native void nativeSetLinePatternTransition(long duration, long delay);
@Override
protected native void finalize() throws Throwable;
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
index 641ee551a2..48e0ec5de3 100644
--- 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
@@ -446,6 +446,27 @@ public final class Property {
@Retention(RetentionPolicy.SOURCE)
public @interface CIRCLE_PITCH_SCALE {}
+ // FILL_EXTRUSION_TRANSLATE_ANCHOR: Controls the translation reference point.
+
+ /**
+ * The fill extrusion is translated relative to the map.
+ */
+ public static final String FILL_EXTRUSION_TRANSLATE_ANCHOR_MAP = "map";
+ /**
+ * The fill extrusion is translated relative to the viewport.
+ */
+ public static final String FILL_EXTRUSION_TRANSLATE_ANCHOR_VIEWPORT = "viewport";
+
+ /**
+ * Controls the translation reference point.
+ */
+ @StringDef({
+ FILL_EXTRUSION_TRANSLATE_ANCHOR_MAP,
+ FILL_EXTRUSION_TRANSLATE_ANCHOR_VIEWPORT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface FILL_EXTRUSION_TRANSLATE_ANCHOR {}
+
private Property() {
}
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
index 5cd0d99270..e4ea9676fa 100644
--- 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
@@ -1029,6 +1029,170 @@ public class PropertyFactory {
}
/**
+ * The opacity of the entire fill extrusion layer. This is rendered on a per-layer, not per-feature, basis, and data-driven styling is not available.
+ *
+ * @param value a Float value
+ * @return property wrapper around Float
+ */
+ public static PropertyValue<Float> fillExtrusionOpacity(Float value) {
+ return new PaintPropertyValue<>("fill-extrusion-opacity", value);
+ }
+
+
+ /**
+ * The opacity of the entire fill extrusion layer. This is rendered on a per-layer, not per-feature, basis, and data-driven styling is not available.
+ *
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Float
+ * @return property wrapper around a Float function
+ */
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> fillExtrusionOpacity(CameraFunction<Z, Float> function) {
+ return new PaintPropertyValue<>("fill-extrusion-opacity", function);
+ }
+
+ /**
+ * The base color of the extruded fill. The extrusion's surfaces will be shaded differently based on this color in combination with the root `light` settings. If this color is specified as `rgba` with an alpha component, the alpha component will be ignored; use {@link PropertyFactory#fillExtrusionOpacity} to set layer opacity.
+ *
+ * @param value a int color value
+ * @return property wrapper around String color
+ */
+ public static PropertyValue<String> fillExtrusionColor(@ColorInt int value) {
+ return new PaintPropertyValue<>("fill-extrusion-color", colorToRgbaString(value));
+ }
+
+ /**
+ * The base color of the extruded fill. The extrusion's surfaces will be shaded differently based on this color in combination with the root `light` settings. If this color is specified as `rgba` with an alpha component, the alpha component will be ignored; use {@link PropertyFactory#fillExtrusionOpacity} to set layer opacity.
+ *
+ * @param value a String value
+ * @return property wrapper around String
+ */
+ public static PropertyValue<String> fillExtrusionColor(String value) {
+ return new PaintPropertyValue<>("fill-extrusion-color", value);
+ }
+
+
+ /**
+ * The base color of the extruded fill. The extrusion's surfaces will be shaded differently based on this color in combination with the root `light` settings. If this color is specified as `rgba` with an alpha component, the alpha component will be ignored; use {@link PropertyFactory#fillExtrusionOpacity} to set layer opacity.
+ *
+ * @param <T> the function input type
+ * @param function a wrapper function for String
+ * @return property wrapper around a String function
+ */
+ public static <T> PropertyValue<Function<T, String>> fillExtrusionColor(Function<T, String> function) {
+ return new PaintPropertyValue<>("fill-extrusion-color", function);
+ }
+
+ /**
+ * The geometry's offset. Values are [x, y] where negatives indicate left and up (on the flat plane), respectively.
+ *
+ * @param value a Float[] value
+ * @return property wrapper around Float[]
+ */
+ public static PropertyValue<Float[]> fillExtrusionTranslate(Float[] value) {
+ return new PaintPropertyValue<>("fill-extrusion-translate", value);
+ }
+
+
+ /**
+ * The geometry's offset. Values are [x, y] where negatives indicate left and up (on the flat plane), respectively.
+ *
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Float[]
+ * @return property wrapper around a Float[] function
+ */
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Float[]>> fillExtrusionTranslate(CameraFunction<Z, Float[]> function) {
+ return new PaintPropertyValue<>("fill-extrusion-translate", function);
+ }
+
+ /**
+ * Controls the translation reference point.
+ *
+ * @param value a String value
+ * @return property wrapper around String
+ */
+ public static PropertyValue<String> fillExtrusionTranslateAnchor(@Property.FILL_EXTRUSION_TRANSLATE_ANCHOR String value) {
+ return new PaintPropertyValue<>("fill-extrusion-translate-anchor", value);
+ }
+
+
+ /**
+ * Controls the translation reference point.
+ *
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for String
+ * @return property wrapper around a String function
+ */
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> fillExtrusionTranslateAnchor(CameraFunction<Z, String> function) {
+ return new PaintPropertyValue<>("fill-extrusion-translate-anchor", function);
+ }
+
+ /**
+ * Name of image in sprite to use for drawing images on extruded fills. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512).
+ *
+ * @param value a String value
+ * @return property wrapper around String
+ */
+ public static PropertyValue<String> fillExtrusionPattern(String value) {
+ return new PaintPropertyValue<>("fill-extrusion-pattern", value);
+ }
+
+
+ /**
+ * Name of image in sprite to use for drawing images on extruded fills. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512).
+ *
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for String
+ * @return property wrapper around a String function
+ */
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> fillExtrusionPattern(CameraFunction<Z, String> function) {
+ return new PaintPropertyValue<>("fill-extrusion-pattern", function);
+ }
+
+ /**
+ * The height with which to extrude this layer.
+ *
+ * @param value a Float value
+ * @return property wrapper around Float
+ */
+ public static PropertyValue<Float> fillExtrusionHeight(Float value) {
+ return new PaintPropertyValue<>("fill-extrusion-height", value);
+ }
+
+
+ /**
+ * The height with which to extrude this layer.
+ *
+ * @param <T> the function input type
+ * @param function a wrapper function for Float
+ * @return property wrapper around a Float function
+ */
+ public static <T> PropertyValue<Function<T, Float>> fillExtrusionHeight(Function<T, Float> function) {
+ return new PaintPropertyValue<>("fill-extrusion-height", function);
+ }
+
+ /**
+ * The height with which to extrude the base of this layer. Must be less than or equal to {@link PropertyFactory#fillExtrusionHeight}.
+ *
+ * @param value a Float value
+ * @return property wrapper around Float
+ */
+ public static PropertyValue<Float> fillExtrusionBase(Float value) {
+ return new PaintPropertyValue<>("fill-extrusion-base", value);
+ }
+
+
+ /**
+ * The height with which to extrude the base of this layer. Must be less than or equal to {@link PropertyFactory#fillExtrusionHeight}.
+ *
+ * @param <T> the function input type
+ * @param function a wrapper function for Float
+ * @return property wrapper around a Float function
+ */
+ public static <T> PropertyValue<Function<T, Float>> fillExtrusionBase(Function<T, Float> function) {
+ return new PaintPropertyValue<>("fill-extrusion-base", function);
+ }
+
+ /**
* The opacity at which the image will be drawn.
*
* @param value a Float value
@@ -1526,11 +1690,11 @@ public class PropertyFactory {
/**
* Scale factor for icon. 1 is original size, 3 triples the size.
*
- * @param <Z> the zoom parameter type
- * @param function a wrapper {@link CameraFunction} for Float
+ * @param <T> the function input type
+ * @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
- public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> iconSize(CameraFunction<Z, Float> function) {
+ public static <T> PropertyValue<Function<T, Float>> iconSize(Function<T, Float> function) {
return new LayoutPropertyValue<>("icon-size", function);
}
@@ -1581,7 +1745,7 @@ public class PropertyFactory {
}
/**
- * A string with {tokens} replaced, referencing the data property to pull from.
+ * Name of image in sprite to use for drawing an image background. A string with {tokens} replaced, referencing the data property to pull from.
*
* @param value a String value
* @return property wrapper around String
@@ -1593,13 +1757,13 @@ public class PropertyFactory {
/**
- * A string with {tokens} replaced, referencing the data property to pull from.
+ * Name of image in sprite to use for drawing an image background. A string with {tokens} replaced, referencing the data property to pull from.
*
- * @param <Z> the zoom parameter type
- * @param function a wrapper {@link CameraFunction} for String
+ * @param <T> the function input type
+ * @param function a wrapper function for String
* @return property wrapper around a String function
*/
- public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> iconImage(CameraFunction<Z, String> function) {
+ public static <T> PropertyValue<Function<T, String>> iconImage(Function<T, String> function) {
return new LayoutPropertyValue<>("icon-image", function);
}
@@ -1802,11 +1966,11 @@ public class PropertyFactory {
/**
* Font size.
*
- * @param <Z> the zoom parameter type
- * @param function a wrapper {@link CameraFunction} for Float
+ * @param <T> the function input type
+ * @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
- public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> textSize(CameraFunction<Z, Float> function) {
+ public static <T> PropertyValue<Function<T, Float>> textSize(Function<T, Float> function) {
return new LayoutPropertyValue<>("text-size", function);
}
@@ -1963,11 +2127,11 @@ public class PropertyFactory {
/**
* Rotates the text clockwise.
*
- * @param <Z> the zoom parameter type
- * @param function a wrapper {@link CameraFunction} for Float
+ * @param <T> the function input type
+ * @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
- public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> textRotate(CameraFunction<Z, Float> function) {
+ public static <T> PropertyValue<Function<T, Float>> textRotate(Function<T, Float> function) {
return new LayoutPropertyValue<>("text-rotate", function);
}
@@ -2055,11 +2219,11 @@ public class PropertyFactory {
/**
* Offset distance of text from its anchor. Positive values indicate right and down, while negative values indicate left and up.
*
- * @param <Z> the zoom parameter type
- * @param function a wrapper {@link CameraFunction} for Float[]
+ * @param <T> the function input type
+ * @param function a wrapper function for Float[]
* @return property wrapper around a Float[] function
*/
- public static <Z extends Number> PropertyValue<CameraFunction<Z, Float[]>> textOffset(CameraFunction<Z, Float[]> function) {
+ public static <T> PropertyValue<Function<T, Float[]>> textOffset(Function<T, Float[]> function) {
return new LayoutPropertyValue<>("text-offset", function);
}
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
index 1871686429..e67e71b61d 100644
--- 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
@@ -8,6 +8,8 @@ import android.support.annotation.UiThread;
import static com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor;
+import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
+
/**
* Raster map textures such as satellite imagery.
*
@@ -81,6 +83,24 @@ public class RasterLayer extends Layer {
}
/**
+ * Get the RasterOpacity property transition options
+ *
+ * @return transition options for Float
+ */
+ public TransitionOptions getRasterOpacityTransition() {
+ return nativeGetRasterOpacityTransition();
+ }
+
+ /**
+ * Set the RasterOpacity property transition options
+ *
+ * @param options transition options for Float
+ */
+ public void setRasterOpacityTransition(TransitionOptions options) {
+ nativeSetRasterOpacityTransition(options.getDuration(), options.getDelay());
+ }
+
+ /**
* Get the RasterHueRotate property
*
* @return property wrapper value around Float
@@ -91,6 +111,24 @@ public class RasterLayer extends Layer {
}
/**
+ * Get the RasterHueRotate property transition options
+ *
+ * @return transition options for Float
+ */
+ public TransitionOptions getRasterHueRotateTransition() {
+ return nativeGetRasterHueRotateTransition();
+ }
+
+ /**
+ * Set the RasterHueRotate property transition options
+ *
+ * @param options transition options for Float
+ */
+ public void setRasterHueRotateTransition(TransitionOptions options) {
+ nativeSetRasterHueRotateTransition(options.getDuration(), options.getDelay());
+ }
+
+ /**
* Get the RasterBrightnessMin property
*
* @return property wrapper value around Float
@@ -101,6 +139,24 @@ public class RasterLayer extends Layer {
}
/**
+ * Get the RasterBrightnessMin property transition options
+ *
+ * @return transition options for Float
+ */
+ public TransitionOptions getRasterBrightnessMinTransition() {
+ return nativeGetRasterBrightnessMinTransition();
+ }
+
+ /**
+ * Set the RasterBrightnessMin property transition options
+ *
+ * @param options transition options for Float
+ */
+ public void setRasterBrightnessMinTransition(TransitionOptions options) {
+ nativeSetRasterBrightnessMinTransition(options.getDuration(), options.getDelay());
+ }
+
+ /**
* Get the RasterBrightnessMax property
*
* @return property wrapper value around Float
@@ -111,6 +167,24 @@ public class RasterLayer extends Layer {
}
/**
+ * Get the RasterBrightnessMax property transition options
+ *
+ * @return transition options for Float
+ */
+ public TransitionOptions getRasterBrightnessMaxTransition() {
+ return nativeGetRasterBrightnessMaxTransition();
+ }
+
+ /**
+ * Set the RasterBrightnessMax property transition options
+ *
+ * @param options transition options for Float
+ */
+ public void setRasterBrightnessMaxTransition(TransitionOptions options) {
+ nativeSetRasterBrightnessMaxTransition(options.getDuration(), options.getDelay());
+ }
+
+ /**
* Get the RasterSaturation property
*
* @return property wrapper value around Float
@@ -121,6 +195,24 @@ public class RasterLayer extends Layer {
}
/**
+ * Get the RasterSaturation property transition options
+ *
+ * @return transition options for Float
+ */
+ public TransitionOptions getRasterSaturationTransition() {
+ return nativeGetRasterSaturationTransition();
+ }
+
+ /**
+ * Set the RasterSaturation property transition options
+ *
+ * @param options transition options for Float
+ */
+ public void setRasterSaturationTransition(TransitionOptions options) {
+ nativeSetRasterSaturationTransition(options.getDuration(), options.getDelay());
+ }
+
+ /**
* Get the RasterContrast property
*
* @return property wrapper value around Float
@@ -131,6 +223,24 @@ public class RasterLayer extends Layer {
}
/**
+ * Get the RasterContrast property transition options
+ *
+ * @return transition options for Float
+ */
+ public TransitionOptions getRasterContrastTransition() {
+ return nativeGetRasterContrastTransition();
+ }
+
+ /**
+ * Set the RasterContrast property transition options
+ *
+ * @param options transition options for Float
+ */
+ public void setRasterContrastTransition(TransitionOptions options) {
+ nativeSetRasterContrastTransition(options.getDuration(), options.getDelay());
+ }
+
+ /**
* Get the RasterFadeDuration property
*
* @return property wrapper value around Float
@@ -140,20 +250,65 @@ public class RasterLayer extends Layer {
return (PropertyValue<Float>) new PropertyValue("raster-fade-duration", nativeGetRasterFadeDuration());
}
+ /**
+ * Get the RasterFadeDuration property transition options
+ *
+ * @return transition options for Float
+ */
+ public TransitionOptions getRasterFadeDurationTransition() {
+ return nativeGetRasterFadeDurationTransition();
+ }
+
+ /**
+ * Set the RasterFadeDuration property transition options
+ *
+ * @param options transition options for Float
+ */
+ public void setRasterFadeDurationTransition(TransitionOptions options) {
+ nativeSetRasterFadeDurationTransition(options.getDuration(), options.getDelay());
+ }
+
private native Object nativeGetRasterOpacity();
+ private native TransitionOptions nativeGetRasterOpacityTransition();
+
+ private native void nativeSetRasterOpacityTransition(long duration, long delay);
+
private native Object nativeGetRasterHueRotate();
+ private native TransitionOptions nativeGetRasterHueRotateTransition();
+
+ private native void nativeSetRasterHueRotateTransition(long duration, long delay);
+
private native Object nativeGetRasterBrightnessMin();
+ private native TransitionOptions nativeGetRasterBrightnessMinTransition();
+
+ private native void nativeSetRasterBrightnessMinTransition(long duration, long delay);
+
private native Object nativeGetRasterBrightnessMax();
+ private native TransitionOptions nativeGetRasterBrightnessMaxTransition();
+
+ private native void nativeSetRasterBrightnessMaxTransition(long duration, long delay);
+
private native Object nativeGetRasterSaturation();
+ private native TransitionOptions nativeGetRasterSaturationTransition();
+
+ private native void nativeSetRasterSaturationTransition(long duration, long delay);
+
private native Object nativeGetRasterContrast();
+ private native TransitionOptions nativeGetRasterContrastTransition();
+
+ private native void nativeSetRasterContrastTransition(long duration, long delay);
+
private native Object nativeGetRasterFadeDuration();
+ private native TransitionOptions nativeGetRasterFadeDurationTransition();
+
+ private native void nativeSetRasterFadeDurationTransition(long duration, long delay);
@Override
protected native void finalize() throws Throwable;
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
index c1efdc9636..290e162da8 100644
--- 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
@@ -8,6 +8,8 @@ import android.support.annotation.UiThread;
import static com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor;
+import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
+
/**
* An icon or a text label.
*
@@ -58,6 +60,15 @@ public class SymbolLayer extends Layer {
}
/**
+ * Get the source layer.
+ *
+ * @return sourceLayer the source layer to get
+ */
+ public String getSourceLayer() {
+ return nativeGetSourceLayer();
+ }
+
+ /**
* Set a single filter.
*
* @param filter the filter to set
@@ -441,6 +452,24 @@ public class SymbolLayer extends Layer {
}
/**
+ * Get the IconOpacity property transition options
+ *
+ * @return transition options for Float
+ */
+ public TransitionOptions getIconOpacityTransition() {
+ return nativeGetIconOpacityTransition();
+ }
+
+ /**
+ * Set the IconOpacity property transition options
+ *
+ * @param options transition options for Float
+ */
+ public void setIconOpacityTransition(TransitionOptions options) {
+ nativeSetIconOpacityTransition(options.getDuration(), options.getDelay());
+ }
+
+ /**
* Get the IconColor property
*
* @return property wrapper value around String
@@ -466,6 +495,23 @@ public class SymbolLayer extends Layer {
}
}
+ /**
+ * Get the IconColor property transition options
+ *
+ * @return transition options for String
+ */
+ public TransitionOptions getIconColorTransition() {
+ return nativeGetIconColorTransition();
+ }
+
+ /**
+ * Set the IconColor property transition options
+ *
+ * @param options transition options for String
+ */
+ public void setIconColorTransition(TransitionOptions options) {
+ nativeSetIconColorTransition(options.getDuration(), options.getDelay());
+ }
/**
* Get the IconHaloColor property
@@ -493,6 +539,23 @@ public class SymbolLayer extends Layer {
}
}
+ /**
+ * Get the IconHaloColor property transition options
+ *
+ * @return transition options for String
+ */
+ public TransitionOptions getIconHaloColorTransition() {
+ return nativeGetIconHaloColorTransition();
+ }
+
+ /**
+ * Set the IconHaloColor property transition options
+ *
+ * @param options transition options for String
+ */
+ public void setIconHaloColorTransition(TransitionOptions options) {
+ nativeSetIconHaloColorTransition(options.getDuration(), options.getDelay());
+ }
/**
* Get the IconHaloWidth property
@@ -505,6 +568,24 @@ public class SymbolLayer extends Layer {
}
/**
+ * Get the IconHaloWidth property transition options
+ *
+ * @return transition options for Float
+ */
+ public TransitionOptions getIconHaloWidthTransition() {
+ return nativeGetIconHaloWidthTransition();
+ }
+
+ /**
+ * Set the IconHaloWidth property transition options
+ *
+ * @param options transition options for Float
+ */
+ public void setIconHaloWidthTransition(TransitionOptions options) {
+ nativeSetIconHaloWidthTransition(options.getDuration(), options.getDelay());
+ }
+
+ /**
* Get the IconHaloBlur property
*
* @return property wrapper value around Float
@@ -515,6 +596,24 @@ public class SymbolLayer extends Layer {
}
/**
+ * Get the IconHaloBlur property transition options
+ *
+ * @return transition options for Float
+ */
+ public TransitionOptions getIconHaloBlurTransition() {
+ return nativeGetIconHaloBlurTransition();
+ }
+
+ /**
+ * Set the IconHaloBlur property transition options
+ *
+ * @param options transition options for Float
+ */
+ public void setIconHaloBlurTransition(TransitionOptions options) {
+ nativeSetIconHaloBlurTransition(options.getDuration(), options.getDelay());
+ }
+
+ /**
* Get the IconTranslate property
*
* @return property wrapper value around Float[]
@@ -525,6 +624,24 @@ public class SymbolLayer extends Layer {
}
/**
+ * Get the IconTranslate property transition options
+ *
+ * @return transition options for Float[]
+ */
+ public TransitionOptions getIconTranslateTransition() {
+ return nativeGetIconTranslateTransition();
+ }
+
+ /**
+ * Set the IconTranslate property transition options
+ *
+ * @param options transition options for Float[]
+ */
+ public void setIconTranslateTransition(TransitionOptions options) {
+ nativeSetIconTranslateTransition(options.getDuration(), options.getDelay());
+ }
+
+ /**
* Get the IconTranslateAnchor property
*
* @return property wrapper value around String
@@ -545,6 +662,24 @@ public class SymbolLayer extends Layer {
}
/**
+ * Get the TextOpacity property transition options
+ *
+ * @return transition options for Float
+ */
+ public TransitionOptions getTextOpacityTransition() {
+ return nativeGetTextOpacityTransition();
+ }
+
+ /**
+ * Set the TextOpacity property transition options
+ *
+ * @param options transition options for Float
+ */
+ public void setTextOpacityTransition(TransitionOptions options) {
+ nativeSetTextOpacityTransition(options.getDuration(), options.getDelay());
+ }
+
+ /**
* Get the TextColor property
*
* @return property wrapper value around String
@@ -570,6 +705,23 @@ public class SymbolLayer extends Layer {
}
}
+ /**
+ * Get the TextColor property transition options
+ *
+ * @return transition options for String
+ */
+ public TransitionOptions getTextColorTransition() {
+ return nativeGetTextColorTransition();
+ }
+
+ /**
+ * Set the TextColor property transition options
+ *
+ * @param options transition options for String
+ */
+ public void setTextColorTransition(TransitionOptions options) {
+ nativeSetTextColorTransition(options.getDuration(), options.getDelay());
+ }
/**
* Get the TextHaloColor property
@@ -597,6 +749,23 @@ public class SymbolLayer extends Layer {
}
}
+ /**
+ * Get the TextHaloColor property transition options
+ *
+ * @return transition options for String
+ */
+ public TransitionOptions getTextHaloColorTransition() {
+ return nativeGetTextHaloColorTransition();
+ }
+
+ /**
+ * Set the TextHaloColor property transition options
+ *
+ * @param options transition options for String
+ */
+ public void setTextHaloColorTransition(TransitionOptions options) {
+ nativeSetTextHaloColorTransition(options.getDuration(), options.getDelay());
+ }
/**
* Get the TextHaloWidth property
@@ -609,6 +778,24 @@ public class SymbolLayer extends Layer {
}
/**
+ * Get the TextHaloWidth property transition options
+ *
+ * @return transition options for Float
+ */
+ public TransitionOptions getTextHaloWidthTransition() {
+ return nativeGetTextHaloWidthTransition();
+ }
+
+ /**
+ * Set the TextHaloWidth property transition options
+ *
+ * @param options transition options for Float
+ */
+ public void setTextHaloWidthTransition(TransitionOptions options) {
+ nativeSetTextHaloWidthTransition(options.getDuration(), options.getDelay());
+ }
+
+ /**
* Get the TextHaloBlur property
*
* @return property wrapper value around Float
@@ -619,6 +806,24 @@ public class SymbolLayer extends Layer {
}
/**
+ * Get the TextHaloBlur property transition options
+ *
+ * @return transition options for Float
+ */
+ public TransitionOptions getTextHaloBlurTransition() {
+ return nativeGetTextHaloBlurTransition();
+ }
+
+ /**
+ * Set the TextHaloBlur property transition options
+ *
+ * @param options transition options for Float
+ */
+ public void setTextHaloBlurTransition(TransitionOptions options) {
+ nativeSetTextHaloBlurTransition(options.getDuration(), options.getDelay());
+ }
+
+ /**
* Get the TextTranslate property
*
* @return property wrapper value around Float[]
@@ -629,6 +834,24 @@ public class SymbolLayer extends Layer {
}
/**
+ * Get the TextTranslate property transition options
+ *
+ * @return transition options for Float[]
+ */
+ public TransitionOptions getTextTranslateTransition() {
+ return nativeGetTextTranslateTransition();
+ }
+
+ /**
+ * Set the TextTranslate property transition options
+ *
+ * @param options transition options for Float[]
+ */
+ public void setTextTranslateTransition(TransitionOptions options) {
+ nativeSetTextTranslateTransition(options.getDuration(), options.getDelay());
+ }
+
+ /**
* Get the TextTranslateAnchor property
*
* @return property wrapper value around String
@@ -708,32 +931,79 @@ public class SymbolLayer extends Layer {
private native Object nativeGetIconOpacity();
+ private native TransitionOptions nativeGetIconOpacityTransition();
+
+ private native void nativeSetIconOpacityTransition(long duration, long delay);
+
private native Object nativeGetIconColor();
+ private native TransitionOptions nativeGetIconColorTransition();
+
+ private native void nativeSetIconColorTransition(long duration, long delay);
+
private native Object nativeGetIconHaloColor();
+ private native TransitionOptions nativeGetIconHaloColorTransition();
+
+ private native void nativeSetIconHaloColorTransition(long duration, long delay);
+
private native Object nativeGetIconHaloWidth();
+ private native TransitionOptions nativeGetIconHaloWidthTransition();
+
+ private native void nativeSetIconHaloWidthTransition(long duration, long delay);
+
private native Object nativeGetIconHaloBlur();
+ private native TransitionOptions nativeGetIconHaloBlurTransition();
+
+ private native void nativeSetIconHaloBlurTransition(long duration, long delay);
+
private native Object nativeGetIconTranslate();
+ private native TransitionOptions nativeGetIconTranslateTransition();
+
+ private native void nativeSetIconTranslateTransition(long duration, long delay);
+
private native Object nativeGetIconTranslateAnchor();
private native Object nativeGetTextOpacity();
+ private native TransitionOptions nativeGetTextOpacityTransition();
+
+ private native void nativeSetTextOpacityTransition(long duration, long delay);
+
private native Object nativeGetTextColor();
+ private native TransitionOptions nativeGetTextColorTransition();
+
+ private native void nativeSetTextColorTransition(long duration, long delay);
+
private native Object nativeGetTextHaloColor();
+ private native TransitionOptions nativeGetTextHaloColorTransition();
+
+ private native void nativeSetTextHaloColorTransition(long duration, long delay);
+
private native Object nativeGetTextHaloWidth();
+ private native TransitionOptions nativeGetTextHaloWidthTransition();
+
+ private native void nativeSetTextHaloWidthTransition(long duration, long delay);
+
private native Object nativeGetTextHaloBlur();
+ private native TransitionOptions nativeGetTextHaloBlurTransition();
+
+ private native void nativeSetTextHaloBlurTransition(long duration, long delay);
+
private native Object nativeGetTextTranslate();
- private native Object nativeGetTextTranslateAnchor();
+ private native TransitionOptions nativeGetTextTranslateTransition();
+ private native void nativeSetTextTranslateTransition(long duration, long delay);
+
+ private native Object nativeGetTextTranslateAnchor();
@Override
protected native void finalize() throws Throwable;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/TransitionOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/TransitionOptions.java
new file mode 100644
index 0000000000..a46c11b35c
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/TransitionOptions.java
@@ -0,0 +1,56 @@
+package com.mapbox.mapboxsdk.style.layers;
+
+public class TransitionOptions {
+
+ private long duration;
+ private long delay;
+
+ public TransitionOptions(long duration, long delay) {
+ this.duration = duration;
+ this.delay = delay;
+ }
+
+ public static TransitionOptions fromTransitionOptions(long duration, long delay) {
+ return new TransitionOptions(duration, delay);
+ }
+
+ public long getDuration() {
+ return duration;
+ }
+
+ public long getDelay() {
+ return delay;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ TransitionOptions that = (TransitionOptions) o;
+
+ if (duration != that.duration) {
+ return false;
+ }
+ return delay == that.delay;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = (int) (duration ^ (duration >>> 32));
+ result = 31 * result + (int) (delay ^ (delay >>> 32));
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "TransitionOptions{"
+ + "duration=" + duration
+ + ", delay=" + delay
+ + '}';
+ }
+}
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
index 5eab4c355e..56e0af8b45 100644
--- 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
@@ -13,6 +13,8 @@ import android.support.annotation.UiThread;
import static com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor;
+import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
+
/**
* <%- doc %>
*
@@ -78,6 +80,15 @@ public class <%- camelize(type) %>Layer extends Layer {
<% } -%>
<% if (type !== 'background' && type !== 'raster') { -%>
/**
+ * Get the source layer.
+ *
+ * @return sourceLayer the source layer to get
+ */
+ public String getSourceLayer() {
+ return nativeGetSourceLayer();
+ }
+
+ /**
* Set a single filter.
*
* @param filter the filter to set
@@ -110,8 +121,8 @@ public class <%- camelize(type) %>Layer extends Layer {
}
// Property getters
-
<% for (const property of properties) { -%>
+
/**
* Get the <%- camelize(property.name) %> property
*
@@ -138,15 +149,39 @@ public class <%- camelize(type) %>Layer extends Layer {
throw new RuntimeException("<%- property.name %> was set as a Function");
}
}
-
<% } -%>
+<% if (property.transition) { -%>
+
+ /**
+ * Get the <%- camelize(property.name) %> property transition options
+ *
+ * @return transition options for <%- propertyType(property) %>
+ */
+ public TransitionOptions get<%- camelize(property.name) %>Transition() {
+ return nativeGet<%- camelize(property.name) %>Transition();
+ }
+ /**
+ * Set the <%- camelize(property.name) %> property transition options
+ *
+ * @param options transition options for <%- propertyType(property) %>
+ */
+ public void set<%- camelize(property.name) %>Transition(TransitionOptions options) {
+ nativeSet<%- camelize(property.name) %>Transition(options.getDuration(), options.getDelay());
+ }
<% } -%>
+<% } -%>
+
<% for (const property of properties) { -%>
private native Object nativeGet<%- camelize(property.name) %>();
-<% } -%>
+<% if (property.transition) { -%>
+ private native TransitionOptions nativeGet<%- camelize(property.name) %>Transition();
+ private native void nativeSet<%- camelize(property.name) %>Transition(long duration, long delay);
+
+<% } -%>
+<% } -%>
@Override
protected native void finalize() throws Throwable;
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
index 5e9ca7d0a8..10ecb945ad 100644
--- 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
@@ -7,11 +7,11 @@ import android.support.annotation.UiThread;
import com.mapbox.mapboxsdk.style.layers.Filter;
import com.mapbox.services.commons.geojson.Feature;
import com.mapbox.services.commons.geojson.FeatureCollection;
+import com.mapbox.services.commons.geojson.Geometry;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.HashMap;
import java.util.List;
/**
@@ -128,13 +128,76 @@ public class GeoJsonSource extends Source {
}
/**
+ * Create a GeoJsonSource from a {@link Feature}
+ *
+ * @param id the source id
+ * @param feature the feature
+ */
+ public GeoJsonSource(String id, Feature feature) {
+ initialize(id, null);
+ setGeoJson(feature);
+ }
+
+ /**
+ * Create a GeoJsonSource from a {@link Feature} and non-default {@link GeoJsonOptions}
+ *
+ * @param id the source id
+ * @param feature the feature
+ * @param options options
+ */
+ public GeoJsonSource(String id, Feature feature, GeoJsonOptions options) {
+ initialize(id, options);
+ setGeoJson(feature);
+ }
+
+ /**
+ * Create a GeoJsonSource from a {@link Geometry}
+ *
+ * @param id the source id
+ * @param geometry the geometry
+ */
+ public GeoJsonSource(String id, Geometry geometry) {
+ initialize(id, null);
+ setGeoJson(geometry);
+ }
+
+ /**
+ * Create a GeoJsonSource from a {@link Geometry} and non-default {@link GeoJsonOptions}
+ *
+ * @param id the source id
+ * @param geometry the geometry
+ * @param options options
+ */
+ public GeoJsonSource(String id, Geometry geometry, GeoJsonOptions options) {
+ initialize(id, options);
+ setGeoJson(geometry);
+ }
+
+ /**
+ * Updates the GeoJson with a single feature
+ *
+ * @param feature the GeoJSON {@link Feature} to set
+ */
+ public void setGeoJson(Feature feature) {
+ nativeSetFeature(feature);
+ }
+
+ /**
+ * Updates the GeoJson with a single geometry
+ *
+ * @param geometry the GeoJSON {@link Geometry} to set
+ */
+ public void setGeoJson(Geometry<?> geometry) {
+ nativeSetGeometry(geometry);
+ }
+
+ /**
* Updates the GeoJson
*
* @param features the GeoJSON FeatureCollection
*/
public void setGeoJson(FeatureCollection features) {
- checkValidity();
- setGeoJson(features.toJson());
+ nativeSetFeatureCollection(features);
}
/**
@@ -143,8 +206,7 @@ public class GeoJsonSource extends Source {
* @param json the raw GeoJson FeatureCollection string
*/
public void setGeoJson(String json) {
- checkValidity();
- setRawJson(json);
+ nativeSetGeoJsonString(json);
}
/**
@@ -153,7 +215,6 @@ public class GeoJsonSource extends Source {
* @param url the GeoJSON FeatureCollection url
*/
public void setUrl(URL url) {
- checkValidity();
setUrl(url.toExternalForm());
}
@@ -163,11 +224,18 @@ public class GeoJsonSource extends Source {
* @param url the GeoJSON FeatureCollection url
*/
public void setUrl(String url) {
- checkValidity();
nativeSetUrl(url);
}
/**
+ * @return The url or null
+ */
+ @Nullable
+ public String getUrl() {
+ return nativeGetUrl();
+ }
+
+ /**
* Queries the source for features.
*
* @param filter an optional filter statement to filter the returned Features
@@ -179,19 +247,19 @@ public class GeoJsonSource extends Source {
return features != null ? Arrays.asList(features) : new ArrayList<Feature>();
}
- protected void setRawJson(String geoJson) {
- // 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", geoJson);
- nativeSetGeoJson(wrapper);
- }
-
protected native void initialize(String layerId, Object options);
protected native void nativeSetUrl(String url);
- private native void nativeSetGeoJson(Object geoJson);
+ protected native String nativeGetUrl();
+
+ private native void nativeSetGeoJsonString(String geoJson);
+
+ private native void nativeSetFeatureCollection(FeatureCollection geoJson);
+
+ private native void nativeSetFeature(Feature feature);
+
+ private native void nativeSetGeometry(Geometry<?> geometry);
private native Feature[] querySourceFeatures(Object[] filter);
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
index 98b74afcff..38ed208618 100644
--- 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
@@ -1,5 +1,7 @@
package com.mapbox.mapboxsdk.style.sources;
+import android.support.annotation.Nullable;
+
import java.net.URL;
/**
@@ -72,8 +74,19 @@ public class RasterSource extends Source {
initialize(id, tileSet.toValueObject(), tileSize);
}
+ /**
+ * @return The url or null
+ */
+ @Nullable
+ public String getUrl() {
+ return nativeGetUrl();
+ }
+
protected native void initialize(String layerId, Object payload, int tileSize);
@Override
protected native void finalize() throws Throwable;
+
+ protected native String nativeGetUrl();
+
}
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
index 6826fed1b5..22b2244537 100644
--- 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
@@ -5,7 +5,6 @@ package com.mapbox.mapboxsdk.style.sources;
*/
public abstract class Source {
private long nativePtr;
- private boolean invalidated;
/**
* Internal use
@@ -25,11 +24,22 @@ public abstract class Source {
* @return the source id
*/
public String getId() {
- checkValidity();
return nativeGetId();
}
/**
+ * Retrieve the source attribution.
+ * <p>
+ * Will return an empty String if no attribution is available.
+ * </p>
+ *
+ * @return the string representation of the attribution in html format
+ */
+ public String getAttribution() {
+ return nativeGetAttribution();
+ }
+
+ /**
* Internal use
*
* @return the native peer pointer
@@ -40,16 +50,6 @@ public abstract class Source {
protected native String nativeGetId();
- protected void checkValidity() {
- if (invalidated) {
- throw new RuntimeException("Layer has been invalidated. Request a new reference after adding");
- }
- }
+ protected native String nativeGetAttribution();
- /**
- * Internal use - invalidates the source for further use (after adding it to the map)
- */
- public final void invalidate() {
- this.invalidated = true;
- }
}
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
index cff5ab6353..9b59cf8967 100644
--- 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
@@ -31,10 +31,10 @@ public class VectorSource extends Source {
}
/**
- * Create a vector source from a remote url
+ * Create a vector source from a remote url pointing to a TileJSON resource
*
* @param id the source id
- * @param url the url
+ * @param url the TileJSON resource url
*/
public VectorSource(String id, URL url) {
this(id, url.toExternalForm());
@@ -76,11 +76,21 @@ public class VectorSource extends Source {
return features != null ? Arrays.asList(features) : new ArrayList<Feature>();
}
+ /**
+ * @return The url or null
+ */
+ @Nullable
+ public String getUrl() {
+ return nativeGetUrl();
+ }
+
protected native void initialize(String layerId, Object payload);
@Override
protected native void finalize() throws Throwable;
+ protected native String nativeGetUrl();
+
private native Feature[] querySourceFeatures(String[] sourceLayerId,
Object[] filter);
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml b/platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml
index 641020906a..7294f43c02 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml
@@ -54,6 +54,7 @@
<public name="mapbox_uiCompassMarginRight" type="attr" />
<public name="mapbox_uiCompassMarginBottom" type="attr" />
<public name="mapbox_uiCompassFadeFacingNorth" type="attr" />
+ <public name="mapbox_uiCompassDrawable" type="attr" />
<!--Logo-->
<public name="mapbox_uiLogo" type="attr" />
@@ -75,9 +76,6 @@
<public name="mapbox_renderTextureMode" type="attr" />
<!-- Exposed content descriptions -->
- <public name="mapbox_compassContentDescription" type="string" />
- <public name="mapbox_attributionsIconContentDescription" type="string" />
- <public name="mapbox_myLocationViewContentDescription" type="string" />
<public name="mapbox_logoContentDescription" type="string" />
<!-- Exposed styles -->
@@ -88,6 +86,20 @@
<public name="mapbox_style_satellite" type="string" />
<public name="mapbox_style_satellite_streets" type="string" />
+ <!-- Exposed strings -->
+ <public name="mapbox_compassContentDescription" type="string" />
+ <public name="mapbox_attributionsIconContentDescription" type="string" />
+ <public name="mapbox_myLocationViewContentDescription" type="string" />
+ <public name="mapbox_mapActionDescription" type="string" />
+ <public name="mapbox_attributionsDialogTitle" type="string" />
+ <public name="mapbox_attributionTelemetryTitle" type="string" />
+ <public name="mapbox_attributionTelemetryMessage" type="string" />
+ <public name="mapbox_attributionTelemetryPositive" type="string" />
+ <public name="mapbox_attributionTelemetryNegative" type="string" />
+ <public name="mapbox_attributionTelemetryNeutral" type="string" />
+ <public name="mapbox_telemetrySettings" type="string"/>
+ <public name="mapbox_offline_error_region_definition_invalid" type="string" />
+
<!-- Exposed drawables -->
<public name="mapbox_logo_icon" type="drawable" />
<public name="mapbox_compass_icon" type="drawable" />
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/mapbox_logo_icon.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/mapbox_logo_icon.png
index c0f4ed2c4c..7568387a8d 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/mapbox_logo_icon.png
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/mapbox_logo_icon.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/mapbox_logo_icon.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/mapbox_logo_icon.png
index 5a9da3fe39..9cdec5151c 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/mapbox_logo_icon.png
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/mapbox_logo_icon.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/mapbox_logo_icon.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/mapbox_logo_icon.png
index 194aa64da2..7eec45f4b1 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/mapbox_logo_icon.png
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/mapbox_logo_icon.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/mapbox_logo_icon.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/mapbox_logo_icon.png
index d1260a16f3..5876056f1c 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/mapbox_logo_icon.png
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/mapbox_logo_icon.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/mapbox_logo_icon.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/mapbox_logo_icon.png
index 5f9647610a..e5780ccc07 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/mapbox_logo_icon.png
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/mapbox_logo_icon.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable/mapbox_info_icon_default.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable/mapbox_info_icon_default.xml
index fa82bb8d9b..65837d65d0 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable/mapbox_info_icon_default.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable/mapbox_info_icon_default.xml
@@ -1,8 +1,8 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
+ android:width="21dp"
+ android:height="21dp"
+ android:viewportHeight="24.0"
+ android:viewportWidth="24.0">
<path
android:fillColor="#FF1E8CAB"
android:pathData="M11,17h2v-6h-2v6zm1,-15C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zm0,18c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,9h2V7h-2v2z"/>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable/mapbox_info_icon_selected.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable/mapbox_info_icon_selected.xml
index 074928d05a..ccbd1d8d39 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable/mapbox_info_icon_selected.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable/mapbox_info_icon_selected.xml
@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportHeight="24.0"
- android:viewportWidth="24.0">
+ android:width="21dp"
+ android:height="21dp"
+ android:viewportHeight="24.0"
+ android:viewportWidth="24.0">
<path
android:fillColor="#551E8CAB"
- android:pathData="M11,17h2v-6h-2v6zm1,-15C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zm0,18c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,9h2V7h-2v2z" />
+ android:pathData="M11,17h2v-6h-2v6zm1,-15C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zm0,18c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,9h2V7h-2v2z"/>
</vector>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_infowindow_content.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_infowindow_content.xml
index e4f01cb40f..26c974dc0d 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_infowindow_content.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_infowindow_content.xml
@@ -24,7 +24,6 @@
android:layout_height="wrap_content"
android:layout_marginBottom="2dp"
android:maxEms="17"
- android:text="@string/mapbox_infoWindowTitle"
android:textColor="@android:color/black"
android:textSize="18sp"
android:textStyle="bold"/>
@@ -37,7 +36,6 @@
android:layout_marginTop="2dp"
android:lineSpacingExtra="1dp"
android:maxEms="17"
- android:text="@string/mapbox_infoWindowDescription"
android:textColor="@color/mapbox_gray"
android:textSize="14sp"/>
@@ -46,7 +44,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxEms="17"
- android:text="@string/mapbox_infoWindowAddress"
android:textColor="@android:color/black"
android:textSize="12sp"
android:visibility="gone"/>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_internal.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_internal.xml
index e6a2677785..6d07de7baa 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_internal.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_internal.xml
@@ -39,10 +39,9 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
- android:background="@drawable/mapbox_default_bg_selector"
android:clickable="true"
+ android:focusable="true"
android:contentDescription="@string/mapbox_attributionsIconContentDescription"
- android:padding="7dp"
android:src="@drawable/mapbox_info_bg_selector"/>
</merge>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_preview.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_preview.xml
index d015bc5785..1c1ab0e71b 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_preview.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_preview.xml
@@ -1,22 +1,29 @@
<?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"
+ android:orientation="vertical">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
- android:src="@drawable/mapbox_mapview_preview" />
+ android:contentDescription="@null"
+ android:src="@drawable/mapbox_mapview_preview"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"/>
<ImageView
+ android:id="@id/logoView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
- android:layout_marginBottom="@dimen/mapbox_eight_dp"
- android:layout_marginLeft="@dimen/mapbox_eight_dp"
+ android:layout_alignParentStart="true"
+ android:layout_marginBottom="@dimen/mapbox_four_dp"
+ android:layout_marginLeft="@dimen/mapbox_four_dp"
+ android:layout_marginStart="@dimen/mapbox_four_dp"
android:contentDescription="@null"
android:src="@drawable/mapbox_logo_icon"/>
@@ -24,18 +31,22 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
- android:layout_marginBottom="@dimen/mapbox_seven_dp"
- android:layout_marginLeft="@dimen/mapbox_seventy_six_dp"
+ android:layout_toEndOf="@+id/logoView"
+ android:contentDescription="@null"
+ android:layout_marginBottom="@dimen/mapbox_four_dp"
android:background="@drawable/mapbox_default_bg_selector"
- android:clickable="true"
- android:contentDescription="@string/mapbox_attributionsIconContentDescription"
- android:src="@drawable/mapbox_info_bg_selector" />
+ android:src="@drawable/mapbox_info_bg_selector"
+ android:layout_marginLeft="@dimen/mapbox_four_dp"
+ android:layout_marginStart="@dimen/mapbox_four_dp"
+ android:layout_toRightOf="@+id/logoView"/>
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
+ android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_margin="10dp"
- android:src="@drawable/mapbox_compass_icon" />
+ android:contentDescription="@null"
+ android:src="@drawable/mapbox_compass_icon"/>
</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values-ca/strings.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values-ca/strings.xml
new file mode 100644
index 0000000000..34e9914e46
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values-ca/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="mapbox_compassContentDescription">Brúixola del mapa. Activa per restablir la rotació del mapa al Nord.</string>
+ <string name="mapbox_attributionsIconContentDescription">Icona d\'atribució. Activa per mostrar el diàleg de l\'atribució.</string>
+ <string name="mapbox_myLocationViewContentDescription">Vista de posició. Mostra la teva posició al mapa.</string>
+ <string name="mapbox_mapActionDescription">Mostrant un mapa creat amb Mapbox. Desplaça\'t arrossegant amb dos dits. Fes zoom pessigant amb dos dits.</string>
+ <string name="mapbox_attributionsDialogTitle">Mapbox Android SDK</string>
+ <string name="mapbox_attributionTelemetryTitle">Millora els mapes de Mapbox</string>
+ <string name="mapbox_attributionTelemetryMessage">Estàs ajudant a millorar els mapes d\'OpenStreetMap i de Mapbox aportant dades d\'ús anònimes.</string>
+ <string name="mapbox_attributionTelemetryPositive">D\'acord</string>
+ <string name="mapbox_attributionTelemetryNegative">Disconforme</string>
+ <string name="mapbox_attributionTelemetryNeutral">Més informació</string>
+ <string name="mapbox_offline_error_region_definition_invalid">La OfflineRegionDefinition proporcionada no encaixa amb els límits del món: %s</string>
+</resources>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values-es/strings.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values-es/strings.xml
new file mode 100644
index 0000000000..92c055223f
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values-es/strings.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="mapbox_compassContentDescription">Brújula del mapa. Actívala para restablecer la rotación del mapa al norte.</string>
+ <string name="mapbox_attributionsIconContentDescription">Ícono de atribución. Actívalo para mostrar el diálogo de atribución.</string>
+ <string name="mapbox_myLocationViewContentDescription">Vista de ubicación. Muestra tu ubicación en el mapa.</string>
+ <string name="mapbox_mapActionDescription">Se está mostrando un mapa creado con Mapbox. Arrastra dos dedos para desplazarte o pellizca para acercar.</string>
+ <string name="mapbox_attributionsDialogTitle">Mapbox Android SDK</string>
+ <string name="mapbox_attributionTelemetryTitle">Ayúdanos a mejorar los mapas de Mapbox</string>
+ <string name="mapbox_attributionTelemetryMessage">Gracias a tu contribución de datos anónimos de uso, ayudas a mejorar OpenStreetMap y Mapbox.</string>
+ <string name="mapbox_attributionTelemetryPositive">Aceptar</string>
+ <string name="mapbox_attributionTelemetryNegative">Rechazar</string>
+ <string name="mapbox_attributionTelemetryNeutral">Más información</string>
+ <string name="mapbox_offline_error_region_definition_invalid">El parámetro OfflineRegionDefinition que se ingresó no coincide con los límites mundiales: %s</string>
+
+ </resources>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values-lt/strings.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values-lt/strings.xml
new file mode 100644
index 0000000000..e01be03352
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values-lt/strings.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="mapbox_compassContentDescription">Žemėlapio kompasas. Spustelk, kad atstatytum žemėlapio pasukimą į šiaurę.</string>
+ <string name="mapbox_attributionsIconContentDescription">Įnašo ikona. Paspausk norėdamas pamatyti dialogą su detalėmis</string>
+ <string name="mapbox_myLocationViewContentDescription">Vartotojo vietos vaizdas. Nurodo tavo poziciją žemėlapyje</string>
+ <string name="mapbox_mapActionDescription">Rodomas Mapbox kurtas žemėlapis. Naviguok tempdamas du pirštus. Valdyk žemėlapio pritraukimą suimdamas/atitolindamas du pirštus.</string>
+ <string name="mapbox_attributionsDialogTitle">Mapbox Android SDK</string>
+ <string name="mapbox_attributionTelemetryTitle">Prisidėk prie Mapbox žemėlapių tobulinimo</string>
+ <string name="mapbox_attributionTelemetryMessage">Jūs padedate padaryti OpenStreetMap ir Mapbox žemėlapius geresniais dalindamiesi anoniminiais naudojimosi duomenimis.</string>
+ <string name="mapbox_attributionTelemetryPositive">Sutikti</string>
+ <string name="mapbox_attributionTelemetryNegative">Nesutikti</string>
+ <string name="mapbox_attributionTelemetryNeutral">Daugiau informacijos</string>
+ <string name="mapbox_offline_error_region_definition_invalid">Pasirinktas OfflineRegionDefinition netalpa į rėžius: %s</string>
+
+ </resources>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values-nl/strings.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values-nl/strings.xml
new file mode 100644
index 0000000000..fef652c542
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values-nl/strings.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="mapbox_compassContentDescription">Kompas van de map. Activeer om de map rotatie te herzetten naar het noorden.</string>
+ <string name="mapbox_attributionsIconContentDescription">Attributie icoon. Activeer voor het tonen van het attributie dialoog. </string>
+ <string name="mapbox_myLocationViewContentDescription">Locatie Element. Dit toont jouw locatie op de map.</string>
+ <string name="mapbox_mapActionDescription">Toont een map gemaakt met Mapbox. Scroll door het slepen met twee vingers. Zoom door vingers te nijpen.</string>
+ <string name="mapbox_attributionsDialogTitle">Mapbox Android SDK</string>
+ <string name="mapbox_attributionTelemetryTitle">Maak Mapbox Maps beter</string>
+ <string name="mapbox_attributionTelemetryMessage">U helpt OpenStreetMap en Mapbox maps te verbeteren door het bijdragen van anonieme gebruikersgegevens. </string>
+ <string name="mapbox_attributionTelemetryPositive">Toestemmen</string>
+ <string name="mapbox_attributionTelemetryNegative">Intrekken</string>
+ <string name="mapbox_attributionTelemetryNeutral">Meer informatie</string>
+ <string name="mapbox_offline_error_region_definition_invalid">Aangeleverde OfflineRegionDefinition past niet in de wereld omtrek: %s</string>
+</resources>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values-sv/strings.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values-sv/strings.xml
new file mode 100644
index 0000000000..c9474fa473
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values-sv/strings.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="mapbox_compassContentDescription">Kompass. Aktivera för att nollställa kartans rotation mot norr.</string>
+ <string name="mapbox_attributionsIconContentDescription">Tillskrivningsikon. Aktivera för att visa tillskrivningsdialog.</string>
+ <string name="mapbox_myLocationViewContentDescription">Positionsvy. Denna visar din position på kartan.</string>
+ <string name="mapbox_mapActionDescription">Visar en karta skapad med Mapbox. Scrolla genom att dra med två fingrar. Zooma genom att nypa med två fingrar.</string>
+ <string name="mapbox_attributionsDialogTitle">Mapbox Android SDK</string>
+ <string name="mapbox_attributionTelemetryTitle">Gör Mapbox kartor bättre</string>
+ <string name="mapbox_attributionTelemetryMessage">Du hjälper till att göra OpenStreetMap och Mapbox karttjänster bättre genom att bidra med anonymiserad användningsdata.</string>
+ <string name="mapbox_attributionTelemetryPositive">Godkänn</string>
+ <string name="mapbox_attributionTelemetryNegative">Avböj</string>
+ <string name="mapbox_attributionTelemetryNeutral">Visa mer information</string>
+ <string name="mapbox_offline_error_region_definition_invalid">Försedd OfflineRegionDefinition passar inte världens gränser: %s</string>
+
+ </resources>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values-vi/strings.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values-vi/strings.xml
new file mode 100644
index 0000000000..a0cad6487a
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values-vi/strings.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="mapbox_compassContentDescription">La bàn bản đồ. Kích hoạt để quay bản đồ lại hướng bắc.</string>
+ <string name="mapbox_attributionsIconContentDescription">Biểu tượng ghi công. Kích hoạt để xem hộp thoại ghi công.</string>
+ <string name="mapbox_myLocationViewContentDescription">Cái chỉ vị trí. Cái này chỉ vị trí của bạn trên bản đồ.</string>
+ <string name="mapbox_mapActionDescription">Đang xem bản đồ được xây dựng dùng Mapbox. Kéo hai ngón tay để cuộn. Chụm các ngón tay lại để phóng to. Tách các ngón tay ra để thu nhỏ.</string>
+ <string name="mapbox_attributionsDialogTitle">Mapbox Android SDK</string>
+ <string name="mapbox_attributionTelemetryTitle">Cải tiến các Bản đồ Mapbox</string>
+ <string name="mapbox_attributionTelemetryMessage">Bạn đang giúp cải tiến các bản đồ OpenStreetMap và Mapbox bằng cách đóng góp dữ liệu vô danh hóa về cách sử dụng.</string>
+ <string name="mapbox_attributionTelemetryPositive">Đồng ý</string>
+ <string name="mapbox_attributionTelemetryNegative">Phản đối</string>
+ <string name="mapbox_attributionTelemetryNeutral">Thông tin thêm</string>
+ <string name="mapbox_offline_error_region_definition_invalid">OfflineRegionDefinition được cung cấp không vừa thế giới: %s</string>
+
+ </resources>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values/arrays.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values/arrays.xml
deleted file mode 100644
index 5a5fd6cb4c..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/values/arrays.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <array name="mapbox_attribution_names">
- <item>&#169; Mapbox</item>
- <item>&#169; OpenStreetMap</item>
- <item>Improve this map</item>
- <item>Telemetry Settings</item>
- </array>
- <!-- If editing this array update MapView.ATTRIBUTION_INDEX_IMPROVE_THIS_MAP -->
- <array name="mapbox_attribution_links" formatted="false" translatable="false">
- <item>https://www.mapbox.com/about/maps/</item>
- <item>http://www.openstreetmap.org/about/</item>
- <item>https://www.mapbox.com/map-feedback/#/%1$f/%2$f/%3$d</item>
- <item>https://www.mapbox.com/telemetry/</item>
- </array>
-</resources>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml
index 738cae07be..e17f01d075 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml
@@ -64,6 +64,7 @@
<attr name="mapbox_uiCompassMarginRight" format="dimension"/>
<attr name="mapbox_uiCompassMarginBottom" format="dimension"/>
<attr name="mapbox_uiCompassFadeFacingNorth" format="boolean"/>
+ <attr name="mapbox_uiCompassDrawable" format="reference"/>
<!--Logo-->
<attr name="mapbox_uiLogo" format="boolean"/>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml
index df6983e11d..ce20cb9a8b 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml
@@ -4,10 +4,15 @@
<dimen name="mapbox_infowindow_margin">8dp</dimen>
<dimen name="mapbox_infowindow_offset">-2dp</dimen>
<dimen name="mapbox_infowindow_line_width">1.5dp</dimen>
- <dimen name="mapbox_seven_dp">7dp</dimen>
+ <dimen name="mapbox_attribution_icon_left_padding">@dimen/mapbox_two_dp</dimen>
+ <dimen name="mapbox_attribution_icon_top_padding">@dimen/mapbox_two_dp</dimen>
+ <dimen name="mapbox_attribution_icon_right_padding">@dimen/mapbox_two_dp</dimen>
+ <dimen name="mapbox_attribution_icon_bottom_padding">@dimen/mapbox_two_dp</dimen>
+ <dimen name="mapbox_two_dp">2dp</dimen>
+ <dimen name="mapbox_four_dp">4dp</dimen>
<dimen name="mapbox_eight_dp">8dp</dimen>
<dimen name="mapbox_ten_dp">10dp</dimen>
<dimen name="mapbox_sixteen_dp">16dp</dimen>
- <dimen name="mapbox_seventy_six_dp">76dp</dimen>
+ <dimen name="mapbox_ninety_five_dp">95dp</dimen>
<dimen name="mapbox_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 0d8e9bdc49..65fb3e14a3 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/values/strings.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values/strings.xml
@@ -10,17 +10,20 @@
<string name="mapbox_attributionTelemetryPositive">Agree</string>
<string name="mapbox_attributionTelemetryNegative">Disagree</string>
<string name="mapbox_attributionTelemetryNeutral">More info</string>
- <string name="mapbox_infoWindowTitle">Title</string>
- <string name="mapbox_infoWindowDescription">Description</string>
- <string name="mapbox_infoWindowAddress">Address</string>
+ <string name="mapbox_attributionErrorNoBrowser">No web browser installed on device, can\'t open web page.</string>
+ <string name="mapbox_offline_error_region_definition_invalid">Provided OfflineRegionDefinition doesn\'t fit the world bounds: %s</string>
+ <string name="mapbox_telemetrySettings">Telemetry Settings</string>
+ <string name="mapbox_telemetryLink" translatable="false">https://www.mapbox.com/telemetry/</string>
<!-- these are public -->
<!-- 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="mapbox_style_mapbox_streets">mapbox://styles/mapbox/streets-v9</string>
- <string name="mapbox_style_outdoors">mapbox://styles/mapbox/outdoors-v9</string>
- <string name="mapbox_style_light">mapbox://styles/mapbox/light-v9</string>
- <string name="mapbox_style_dark">mapbox://styles/mapbox/dark-v9</string>
- <string name="mapbox_style_satellite">mapbox://styles/mapbox/satellite-v9</string>
- <string name="mapbox_style_satellite_streets">mapbox://styles/mapbox/satellite-streets-v9</string>
+ <string name="mapbox_style_mapbox_streets" translatable="false">mapbox://styles/mapbox/streets-v10</string>
+ <string name="mapbox_style_outdoors" translatable="false">mapbox://styles/mapbox/outdoors-v10</string>
+ <string name="mapbox_style_light" translatable="false">mapbox://styles/mapbox/light-v9</string>
+ <string name="mapbox_style_dark" translatable="false">mapbox://styles/mapbox/dark-v9</string>
+ <string name="mapbox_style_satellite" translatable="false">mapbox://styles/mapbox/satellite-v9</string>
+ <string name="mapbox_style_satellite_streets" translatable="false">mapbox://styles/mapbox/satellite-streets-v10</string>
+ <string name="mapbox_style_traffic_day" translatable="false">mapbox://styles/mapbox/traffic-day-v2</string>
+ <string name="mapbox_style_traffic_night" translatable="false">mapbox://styles/mapbox/traffic-night-v2</string>
</resources>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/MapboxTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/MapboxTest.java
index 0c1f28515d..6ee5c157b9 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/MapboxTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/MapboxTest.java
@@ -4,7 +4,7 @@ import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
-import com.mapbox.mapboxsdk.exceptions.InvalidAccessTokenException;
+import com.mapbox.mapboxsdk.exceptions.MapboxConfigurationException;
import org.junit.Before;
import org.junit.Test;
@@ -39,7 +39,7 @@ public class MapboxTest {
assertSame(accessToken, Mapbox.getAccessToken());
}
- @Test(expected = InvalidAccessTokenException.class)
+ @Test(expected = MapboxConfigurationException.class)
public void testGetInvalidAccessToken() {
final String accessToken = "dummy";
injectMapboxSingleton(accessToken);
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/AnnotationTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/AnnotationTest.java
index 605e159b84..605e159b84 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/AnnotationTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/AnnotationTest.java
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/IconTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/IconTest.java
index 5f6f6b6c6d..5f6f6b6c6d 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/IconTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/IconTest.java
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/InfoWindowTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/InfoWindowTest.java
index 94b629860e..94b629860e 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/InfoWindowTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/InfoWindowTest.java
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerTest.java
index fa571e06b1..fa571e06b1 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerTest.java
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerViewTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerViewTest.java
index ebd30f5422..ebd30f5422 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerViewTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerViewTest.java
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/PolygonTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/PolygonTest.java
index 3933c68887..3933c68887 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/PolygonTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/PolygonTest.java
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/PolylineTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/PolylineTest.java
index 54bb0e8cf4..54bb0e8cf4 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/PolylineTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/PolylineTest.java
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java
index 0c5f3a4be2..0c5f3a4be2 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/constants/AppConstant.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/constants/AppConstant.java
index aaef7f8a51..cb654aa556 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/constants/AppConstant.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/constants/AppConstant.java
@@ -1,4 +1,4 @@
-package com.mapbox.mapboxsdk.testapp.model.constants;
+package com.mapbox.mapboxsdk.constants;
public class AppConstant {
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java
index 60573f4b74..8d9a360714 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java
@@ -11,10 +11,10 @@ import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
+import static junit.framework.Assert.assertNotNull;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -42,39 +42,39 @@ public class LatLngBoundsTest {
}
@Test(expected = InvalidLatLngBoundsException.class)
- public void testNoLatLngs() {
+ public void noLatLngs() {
new LatLngBounds.Builder().build();
}
@Test(expected = InvalidLatLngBoundsException.class)
- public void testOneLatLngs() {
+ public void oneLatLngs() {
new LatLngBounds.Builder().include(LAT_LNG_NULL_ISLAND).build();
}
@Test
- public void testLatitiudeSpan() {
+ public void latitiudeSpan() {
assertEquals("Span should be the same", 2, latLngBounds.getLatitudeSpan(), DELTA);
}
@Test
- public void testLongitudeSpan() {
+ public void longitudeSpan() {
assertEquals("Span should be the same", 2, latLngBounds.getLongitudeSpan(), DELTA);
}
@Test
- public void testCoordinateSpan() {
+ public void coordinateSpan() {
LatLngSpan latLngSpan = latLngBounds.getSpan();
assertEquals("LatLngSpan should be the same", new LatLngSpan(2, 2), latLngSpan);
}
@Test
- public void testCenter() {
+ public void center() {
LatLng center = latLngBounds.getCenter();
assertEquals("Center should match", new LatLng(1, 1), center);
}
@Test
- public void testEmptySpan() {
+ public void emptySpan() {
latLngBounds = new LatLngBounds.Builder()
.include(LAT_LNG_NOT_NULL_ISLAND)
.include(LAT_LNG_NOT_NULL_ISLAND)
@@ -83,7 +83,7 @@ public class LatLngBoundsTest {
}
@Test
- public void testNotEmptySpan() {
+ public void notEmptySpan() {
latLngBounds = new LatLngBounds.Builder()
.include(LAT_LNG_NOT_NULL_ISLAND)
.include(LAT_LNG_NULL_ISLAND)
@@ -92,7 +92,7 @@ public class LatLngBoundsTest {
}
@Test
- public void testToLatLngs() {
+ public void toLatLngs() {
latLngBounds = new LatLngBounds.Builder()
.include(LAT_LNG_NOT_NULL_ISLAND)
.include(LAT_LNG_NULL_ISLAND)
@@ -104,12 +104,12 @@ public class LatLngBoundsTest {
}
@Test
- public void testIncluding() {
+ public void include() {
assertTrue("LatLng should be included", latLngBounds.contains(new LatLng(1, 1)));
}
@Test
- public void testIncludes() {
+ public void includes() {
List<LatLng> points = new ArrayList<>();
points.add(LAT_LNG_NULL_ISLAND);
points.add(LAT_LNG_NOT_NULL_ISLAND);
@@ -127,17 +127,36 @@ public class LatLngBoundsTest {
}
@Test
- public void testNoIncluding() {
+ public void containsNot() {
assertFalse("LatLng should not be included", latLngBounds.contains(new LatLng(3, 1)));
}
@Test
+ public void containsBoundsInWorld() {
+ assertTrue("LatLngBounds should be contained in the world", LatLngBounds.world().contains(latLngBounds));
+ }
+
+ @Test
+ public void containsBounds() {
+ LatLngBounds inner = new LatLngBounds.Builder()
+ .include(new LatLng(-5, -5))
+ .include(new LatLng(5, 5))
+ .build();
+ LatLngBounds outer = new LatLngBounds.Builder()
+ .include(new LatLng(-10, -10))
+ .include(new LatLng(10, 10))
+ .build();
+ assertTrue(outer.contains(inner));
+ assertFalse(inner.contains(outer));
+ }
+
+ @Test
public void testHashCode() {
assertEquals(2147483647, latLngBounds.hashCode(), -1946419200);
}
@Test
- public void testEquality() {
+ public void equality() {
LatLngBounds latLngBounds = new LatLngBounds.Builder()
.include(LAT_LNG_NULL_ISLAND)
.include(LAT_LNG_NOT_NULL_ISLAND)
@@ -152,7 +171,7 @@ public class LatLngBoundsTest {
}
@Test
- public void testIntersect() {
+ public void intersect() {
LatLngBounds latLngBounds = new LatLngBounds.Builder()
.include(new LatLng(1, 1))
.include(LAT_LNG_NULL_ISLAND)
@@ -162,7 +181,7 @@ public class LatLngBoundsTest {
}
@Test
- public void testNoIntersect() {
+ public void intersectNot() {
LatLngBounds latLngBounds = new LatLngBounds.Builder()
.include(new LatLng(10, 10))
.include(new LatLng(9, 8))
@@ -171,7 +190,7 @@ public class LatLngBoundsTest {
}
@Test
- public void testInnerUnion() {
+ public void innerUnion() {
LatLngBounds latLngBounds = new LatLngBounds.Builder()
.include(new LatLng(1, 1))
.include(LAT_LNG_NULL_ISLAND)
@@ -180,7 +199,7 @@ public class LatLngBoundsTest {
}
@Test
- public void testOuterUnion() {
+ public void outerUnion() {
LatLngBounds latLngBounds = new LatLngBounds.Builder()
.include(new LatLng(10, 10))
.include(new LatLng(9, 8))
@@ -194,6 +213,66 @@ public class LatLngBoundsTest {
}
@Test
+ public void northWest() {
+ double minLat = 5;
+ double minLon = 6;
+ double maxLat = 20;
+ double maxLon = 21;
+
+ LatLngBounds latLngBounds = new LatLngBounds.Builder()
+ .include(new LatLng(minLat, minLon))
+ .include(new LatLng(maxLat, maxLon))
+ .build();
+
+ assertEquals("NorthWest should match", latLngBounds.getNorthWest(), new LatLng(maxLat, minLon));
+ }
+
+ @Test
+ public void southWest() {
+ double minLat = 5;
+ double minLon = 6;
+ double maxLat = 20;
+ double maxLon = 21;
+
+ LatLngBounds latLngBounds = new LatLngBounds.Builder()
+ .include(new LatLng(minLat, minLon))
+ .include(new LatLng(maxLat, maxLon))
+ .build();
+
+ assertEquals("SouthWest should match", latLngBounds.getSouthWest(), new LatLng(minLat, minLon));
+ }
+
+ @Test
+ public void northEast() {
+ double minLat = 5;
+ double minLon = 6;
+ double maxLat = 20;
+ double maxLon = 21;
+
+ LatLngBounds latLngBounds = new LatLngBounds.Builder()
+ .include(new LatLng(minLat, minLon))
+ .include(new LatLng(maxLat, maxLon))
+ .build();
+
+ assertEquals("NorthEast should match", latLngBounds.getNorthEast(), new LatLng(maxLat, maxLon));
+ }
+
+ @Test
+ public void southEast() {
+ double minLat = 5;
+ double minLon = 6;
+ double maxLat = 20;
+ double maxLon = 21;
+
+ LatLngBounds latLngBounds = new LatLngBounds.Builder()
+ .include(new LatLng(minLat, minLon))
+ .include(new LatLng(maxLat, maxLon))
+ .build();
+
+ assertEquals("SouthEast should match", latLngBounds.getSouthEast(), new LatLng(minLat, maxLon));
+ }
+
+ @Test
public void testParcelable() {
LatLngBounds latLngBounds = new LatLngBounds.Builder()
.include(new LatLng(10, 10))
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngSpanTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngSpanTest.java
index 12297247cf..12297247cf 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngSpanTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngSpanTest.java
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngTest.java
index 06fe1c91b9..06e93b9d2f 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngTest.java
@@ -6,6 +6,8 @@ import android.os.Parcelable;
import com.mapbox.mapboxsdk.utils.MockParcel;
import org.junit.Test;
+import org.junit.Rule;
+import org.junit.rules.ExpectedException;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
@@ -79,6 +81,79 @@ public class LatLngTest {
assertEquals("longitude should match", 3, latLng.getLongitude(), DELTA);
}
+ @Rule
+ public final ExpectedException exception = ExpectedException.none();
+
+ @Test
+ public void testConstructorChecksLatitudeNaN() {
+ exception.expect(IllegalArgumentException.class);
+ exception.expectMessage("latitude must not be NaN");
+ new LatLng(Double.NaN, 0);
+ }
+
+ @Test
+ public void testConstructorChecksLongitudeNaN() {
+ exception.expect(IllegalArgumentException.class);
+ exception.expectMessage("longitude must not be NaN");
+ new LatLng(0, Double.NaN);
+ }
+
+ @Test
+ public void testConstructorChecksLatitudeGreaterThan90() {
+ exception.expect(IllegalArgumentException.class);
+ exception.expectMessage("latitude must be between -90 and 90");
+ new LatLng(95, 0);
+ }
+
+ @Test
+ public void testConstructorChecksLatitudeLessThanThanNegative90() {
+ exception.expect(IllegalArgumentException.class);
+ exception.expectMessage("latitude must be between -90 and 90");
+ new LatLng(-95, 0);
+ }
+
+ @Test
+ public void testConstructorChecksLongitudeInfinity() {
+ exception.expect(IllegalArgumentException.class);
+ exception.expectMessage("longitude must not be infinite");
+ new LatLng(0, Double.POSITIVE_INFINITY);
+ }
+
+ @Test
+ public void testLatitudeSetterChecksNaN() {
+ exception.expect(IllegalArgumentException.class);
+ exception.expectMessage("latitude must not be NaN");
+ new LatLng().setLatitude(Double.NaN);
+ }
+
+ @Test
+ public void testLongitudeSetterChecksNaN() {
+ exception.expect(IllegalArgumentException.class);
+ exception.expectMessage("longitude must not be NaN");
+ new LatLng().setLongitude(Double.NaN);
+ }
+
+ @Test
+ public void testLatitudeSetterChecksGreaterThan90() {
+ exception.expect(IllegalArgumentException.class);
+ exception.expectMessage("latitude must be between -90 and 90");
+ new LatLng().setLatitude(95);
+ }
+
+ @Test
+ public void testLatitudeSetterChecksLessThanThanNegative90() {
+ exception.expect(IllegalArgumentException.class);
+ exception.expectMessage("latitude must be between -90 and 90");
+ new LatLng().setLatitude(-95);
+ }
+
+ @Test
+ public void testLongitudeSetterChecksInfinity() {
+ exception.expect(IllegalArgumentException.class);
+ exception.expectMessage("longitude must not be infinite");
+ new LatLng().setLongitude(Double.NEGATIVE_INFINITY);
+ }
+
@Test
public void testAltitudeSetter() {
LatLng latLng = new LatLng(1.2, 3.4);
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/ProjectedMetersTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/ProjectedMetersTest.java
index 00fd125a1a..00fd125a1a 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/ProjectedMetersTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/ProjectedMetersTest.java
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/VisibleRegionTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/VisibleRegionTest.java
index 12b779de5d..12b779de5d 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/VisibleRegionTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/VisibleRegionTest.java
diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/AnnotationManagerTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/AnnotationManagerTest.java
new file mode 100644
index 0000000000..0d592f9bb3
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/AnnotationManagerTest.java
@@ -0,0 +1,81 @@
+package com.mapbox.mapboxsdk.maps;
+
+import android.support.v4.util.LongSparseArray;
+
+import com.mapbox.mapboxsdk.annotations.Annotation;
+import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions;
+import com.mapbox.mapboxsdk.annotations.Marker;
+import com.mapbox.mapboxsdk.annotations.MarkerOptions;
+import com.mapbox.mapboxsdk.annotations.MarkerViewManager;
+import com.mapbox.mapboxsdk.geometry.LatLng;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static junit.framework.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class AnnotationManagerTest {
+
+ @Test
+ public void checksAddAMarker() throws Exception {
+ NativeMapView aNativeMapView = mock(NativeMapView.class);
+ MapView aMapView = mock(MapView.class);
+ LongSparseArray<Annotation> annotationsArray = new LongSparseArray<>();
+ MarkerViewManager aMarkerViewManager = mock(MarkerViewManager.class);
+ IconManager aIconManager = mock(IconManager.class);
+ Annotations annotations = new AnnotationContainer(aNativeMapView, annotationsArray);
+ Markers markers = new MarkerContainer(aNativeMapView, aMapView, annotationsArray, aIconManager, aMarkerViewManager);
+ Polygons polygons = new PolygonContainer(aNativeMapView, annotationsArray);
+ Polylines polylines = new PolylineContainer(aNativeMapView, annotationsArray);
+ AnnotationManager annotationManager = new AnnotationManager(aNativeMapView, aMapView, annotationsArray,
+ aMarkerViewManager, aIconManager, annotations, markers, polygons, polylines);
+ Marker aMarker = mock(Marker.class);
+ long aId = 5L;
+ when(aNativeMapView.addMarker(aMarker)).thenReturn(aId);
+ BaseMarkerOptions aMarkerOptions = mock(BaseMarkerOptions.class);
+ MapboxMap aMapboxMap = mock(MapboxMap.class);
+ when(aMarkerOptions.getMarker()).thenReturn(aMarker);
+
+ annotationManager.addMarker(aMarkerOptions, aMapboxMap);
+
+ assertEquals(aMarker, annotationManager.getAnnotations().get(0));
+ assertEquals(aMarker, annotationManager.getAnnotation(aId));
+ }
+
+ @Test
+ public void checksAddMarkers() throws Exception {
+ NativeMapView aNativeMapView = mock(NativeMapView.class);
+ MapView aMapView = mock(MapView.class);
+ LongSparseArray<Annotation> annotationsArray = new LongSparseArray<>();
+ MarkerViewManager aMarkerViewManager = mock(MarkerViewManager.class);
+ IconManager aIconManager = mock(IconManager.class);
+ Annotations annotations = new AnnotationContainer(aNativeMapView, annotationsArray);
+ Markers markers = new MarkerContainer(aNativeMapView, aMapView, annotationsArray, aIconManager, aMarkerViewManager);
+ Polygons polygons = new PolygonContainer(aNativeMapView, annotationsArray);
+ Polylines polylines = new PolylineContainer(aNativeMapView, annotationsArray);
+ AnnotationManager annotationManager = new AnnotationManager(aNativeMapView, aMapView, annotationsArray,
+ aMarkerViewManager, aIconManager, annotations, markers, polygons, polylines);
+ long firstId = 1L;
+ long secondId = 2L;
+ List<BaseMarkerOptions> markerList = new ArrayList<>();
+ MarkerOptions firstMarkerOption = new MarkerOptions().position(new LatLng()).title("first");
+ MarkerOptions secondMarkerOption = new MarkerOptions().position(new LatLng()).title("second");
+ markerList.add(firstMarkerOption);
+ markerList.add(secondMarkerOption);
+ MapboxMap aMapboxMap = mock(MapboxMap.class);
+ when(aNativeMapView.addMarker(any(Marker.class))).thenReturn(firstId, secondId);
+
+ annotationManager.addMarkers(markerList, aMapboxMap);
+
+ assertEquals(2, annotationManager.getAnnotations().size());
+ assertEquals("first", ((Marker) annotationManager.getAnnotations().get(0)).getTitle());
+ assertEquals("second", ((Marker) annotationManager.getAnnotations().get(1)).getTitle());
+ assertEquals("first", ((Marker) annotationManager.getAnnotation(firstId)).getTitle());
+ assertEquals("second", ((Marker) annotationManager.getAnnotation(secondId)).getTitle());
+ }
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java
index ce0cb00b0b..ce0cb00b0b 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/TrackingSettingsTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/TrackingSettingsTest.java
index de5f364a5b..de5f364a5b 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/TrackingSettingsTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/TrackingSettingsTest.java
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java
index fbe00b4dce..fbe00b4dce 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettingsTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettingsTest.java
index c9ce19dc85..c9ce19dc85 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettingsTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettingsTest.java
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/style/layers/FilterTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/layers/FilterTest.java
index 933bf05b39..933bf05b39 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/style/layers/FilterTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/layers/FilterTest.java
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/style/layers/FunctionTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/layers/FunctionTest.java
index bac1154d62..bac1154d62 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/style/layers/FunctionTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/layers/FunctionTest.java
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/telemetry/HttpTransportTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/telemetry/HttpTransportTest.java
index 94a6dc2194..94a6dc2194 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/telemetry/HttpTransportTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/telemetry/HttpTransportTest.java
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/utils/MockParcel.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/utils/MockParcel.java
index dd4c7b25ee..dd4c7b25ee 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/utils/MockParcel.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/utils/MockParcel.java
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/platform/android/MapboxGLAndroidSDK/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
index ca6ee9cea8..ca6ee9cea8 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
+++ b/platform/android/MapboxGLAndroidSDK/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/README.md b/platform/android/MapboxGLAndroidSDKTestApp/README.md
index 0acb509b3e..8bbc2b34c6 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/README.md
+++ b/platform/android/MapboxGLAndroidSDKTestApp/README.md
@@ -1,81 +1,11 @@
# Mapbox GL Test App
-## Testing
+## Building
-### Running Espresso tests on a device
-
-This test project comes with all the required Android Testing Support Library dependencies
-in the Gradle file. Tests are under the `app/src/androidTest` folder.
-
-Note that before running your tests, you might want to turn off animations on your test device.
-It's a known issue that leaving system animations turned on in a test device
-(window animation scale, transition animation scale, animator duration scale)
-might cause unexpected results, or may lead tests to fail.
-
-To create a new run configuration:
-* Click on Run -> Edit Configurations...
-* Click on the plus sign and then on "Android Tests"
-* Give a name to the configuration, e.g. `TestAppTests`
-* Choose the `MapboxGLAndroidSDKTestApp` module
-* Choose `android.support.test.runner.AndroidJUnitRunner` as the instrumentation runner
-* Click OK to save the new configuration
-
-You can now run this configuration from the main toolbar dropdown menu.
-
-### Running Espresso tests on AWS Device Farm
-
-On a terminal, within `mapbox-gl-native/android/java`,
-run the tests (`cC` stands for `connectedCheck`):
+To be able to run any Gradle commands, you'll need to create the configuration file by running
```
-$ ./gradlew cC -p MapboxGLAndroidSDKTestApp
+$ make android-configuration
```
-Then:
-* Go to your AWS Console and choose Device Farm.
-* Create a new project, e.g. `MapboxGLAndroidSDKTestApp`
-* On step 1, upload the APK in `mapbox-gl-native/android/java/MapboxGLAndroidSDKTestApp/build/outputs/apk/MapboxGLAndroidSDKTestApp-debug-unaligned.apk`
-* On step 2, choose Instrumentation, test filter is `com.mapbox.mapboxgl.testapp.MainActivityTest` and upload the APK in `mapbox-gl-native/android/java/MapboxGLAndroidSDKTestApp/build/outputs/apk/MapboxGLAndroidSDKTestApp-debug-androidTest-unaligned.apk`
-* On step 3, choose a device pool. E.g. Top Devices
-* On step 4, customize your device state (if needed)
-* Finally, confirm the configuration and run the tests.
-
-On Step 2, you can also separate by commas different classes: `com.mapbox.mapboxgl.testapp.MainActivityTest,com.mapbox.mapboxgl.testapp.MainActivityScreenTest`
-
-If you have no tests for your app, or want to test some random user behavior,
-you can just choose "Built-in: Fuzz" in step 2.
-
-### Running pure JUnit tests
-
-These tests run on a local JVM on your development machine and they are extremely fast to run
-(as compared to Espresso). These tests are located under `src/test/java`. To run them you switch
-to the Unit Tests build variant, then right click the corresponding test class or method
-and select "Run ...".
-
-You can also have a run configuration:
-* Click on Run -> Edit Configurations...
-* Click on "Junit Tests"
-* Give a name to the configuration, e.g. `JUnit tests`
-* As "Test Kind", choose "All in directory"
-* As folder, choose the following folder: `mapbox-gl-native/android/java/MapboxGLAndroidSDKTestApp/src/test/java`
-* Click OK to save the new configuration
-
-You can also run the tests from the command line with:
-
-```
-$ ./gradlew test --continue -p MapboxGLAndroidSDKTestApp
-```
-
-### Running the UI/Application Exerciser Monkey
-
-Similar to the "Built-in: Fuzz" test mentioned above, Android provides
-[Monkey](http://developer.android.com/tools/help/monkey.html),
-"a program that runs on your emulator or device and generates pseudo-random streams of user events
-such as clicks, touches, or gestures, as well as a number of system-level events."
-
-To exercise Monkey on the test app, install the package on the device (e.g. via Android Studio)
-and then:
-
-```
-$ adb shell monkey -p com.mapbox.mapboxgl.testapp -v 500
-```
+from the root folder.
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle
index 10baf2e108..7c263652af 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle
+++ b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle
@@ -27,14 +27,11 @@ android {
lintOptions {
checkAllWarnings true
warningsAsErrors true
+ disable 'MissingTranslation'
disable 'IconDensities'
disable 'InvalidPackage'
}
- testOptions {
- unitTests.returnDefaultValues = true
- }
-
buildTypes {
debug {
testCoverageEnabled = true
@@ -77,8 +74,6 @@ dependencies {
}
// Testing dependencies
- testCompile rootProject.ext.dep.junit
- testCompile rootProject.ext.dep.mockito
androidTestCompile rootProject.ext.dep.testSpoonRunner
androidTestCompile rootProject.ext.dep.supportAnnotations
androidTestCompile rootProject.ext.dep.testRunner
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/gradle-config.gradle b/platform/android/MapboxGLAndroidSDKTestApp/gradle-config.gradle
index 1068e5e69e..8346806633 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/gradle-config.gradle
+++ b/platform/android/MapboxGLAndroidSDKTestApp/gradle-config.gradle
@@ -5,14 +5,15 @@
task accessToken {
def tokenFile = new File("${projectDir}/src/main/res/values/developer-config.xml")
if (!tokenFile.exists()) {
+ String mapboxAccessToken = "$System.env.MAPBOX_ACCESS_TOKEN"
+ if (mapboxAccessToken == "null") {
+ System.out.println("You should set the MAPBOX_ACCESS_TOKEN environment variable.")
+ mapboxAccessToken = "YOUR_MAPBOX_ACCESS_TOKEN_GOES_HERE"
+ }
String tokenFileContents = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
"<resources>\n" +
- " <string name=\"mapbox_access_token\">" + "$System.env.MAPBOX_ACCESS_TOKEN" + "</string>\n" +
+ " <string name=\"mapbox_access_token\">" + mapboxAccessToken + "</string>\n" +
"</resources>"
-
- if (tokenFileContents == null) {
- throw new InvalidUserDataException("You must set the MAPBOX_ACCESS_TOKEN environment variable.")
- }
tokenFile.write(tokenFileContents)
}
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java
index 2cd077f510..a813b7f368 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java
@@ -3,10 +3,8 @@ package com.mapbox.mapboxsdk.maps;
import android.graphics.Color;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
-import android.support.test.espresso.Espresso;
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.annotations.BaseMarkerOptions;
@@ -19,24 +17,20 @@ import com.mapbox.mapboxsdk.annotations.PolylineOptions;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
import com.mapbox.mapboxsdk.exceptions.InvalidMarkerPositionException;
import com.mapbox.mapboxsdk.geometry.LatLng;
+import com.mapbox.mapboxsdk.geometry.LatLngBounds;
import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest;
import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity;
-import com.mapbox.mapboxsdk.testapp.utils.OnMapReadyIdlingResource;
import com.mapbox.mapboxsdk.testapp.utils.TestConstants;
import com.mapbox.mapboxsdk.testapp.utils.ViewUtils;
import org.hamcrest.Matcher;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Ignore;
-import org.junit.Rule;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
-import timber.log.Timber;
-
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;
@@ -52,27 +46,65 @@ import static org.junit.Assert.assertTrue;
* with the application UI-thread.
* </p>
*/
-public class MapboxMapTest {
+public class MapboxMapTest extends BaseActivityTest {
+
+ @Override
+ protected Class getActivityClass() {
+ return EspressoTestActivity.class;
+ }
- @Rule
- public final ActivityTestRule<EspressoTestActivity> rule = new ActivityTestRule<>(EspressoTestActivity.class);
+ @Test
+ public void testSanity() {
+ validateTestSetup();
+ assertNotNull("mapboxMap should not be null", mapboxMap);
+ }
- private OnMapReadyIdlingResource idlingResource;
- private EspressoTestActivity activity;
+ //
+ // Style wide transition options
+ //
- @Before
- public void beforeTest() {
- activity = rule.getActivity();
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- idlingResource = new OnMapReadyIdlingResource(activity);
- Espresso.registerIdlingResources(idlingResource);
+ @Test
+ public void testTransitionDuration() {
+ validateTestSetup();
+ onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
+ @Override
+ public void onViewAction(UiController uiController, View view) {
+ long transitionDuration = 600;
+ mapboxMap.setTransitionDuration(transitionDuration);
+ assertEquals("TransitionDuration should match", transitionDuration, mapboxMap.getTransitionDuration(), 0);
+ }
+ }));
}
@Test
- public void testSanity() {
+ public void testTransitionDelay() {
+ validateTestSetup();
+ onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
+ @Override
+ public void onViewAction(UiController uiController, View view) {
+ long transitionDelay = 50;
+ mapboxMap.setTransitionDelay(transitionDelay);
+ assertEquals("TransitionDelay should match", transitionDelay, mapboxMap.getTransitionDelay(), 0);
+ }
+ }));
+ }
+
+ //
+ // CameraForLatLngBounds
+ //
+ @Test
+ public void testCameraForLatLngBounds() {
ViewUtils.checkViewIsDisplayed(R.id.mapView);
- MapboxMap mapboxMap = activity.getMapboxMap();
- assertNotNull("mapboxMap should not be null", mapboxMap);
+ onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
+ @Override
+ public void onViewAction(UiController uiController, View view) {
+ // set
+ mapboxMap.setLatLngBoundsForCameraTarget(
+ new LatLngBounds.Builder().include(new LatLng()).include(new LatLng(1, 1)).build());
+ // reset
+ mapboxMap.setLatLngBoundsForCameraTarget(null);
+ }
+ }));
}
//
@@ -81,8 +113,7 @@ public class MapboxMapTest {
@Test
public void testMinZoom() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -94,8 +125,7 @@ public class MapboxMapTest {
@Test
public void testMaxZoom() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
final double zoom = 10;
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
@@ -109,8 +139,7 @@ public class MapboxMapTest {
@Test
@Ignore
public void testInitialZoomLevels() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -128,8 +157,7 @@ public class MapboxMapTest {
@Test
public void testTrackingSettings() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
assertNotNull("TrackingSettings should not be null", mapboxMap.getTrackingSettings());
}
@@ -139,8 +167,7 @@ public class MapboxMapTest {
@Test
public void testConcurrentInfoWindowEnabled() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -152,8 +179,7 @@ public class MapboxMapTest {
@Test
public void testConcurrentInfoWindowDisabled() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -165,8 +191,7 @@ public class MapboxMapTest {
@Test
public void testInfoWindowAdapter() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -190,8 +215,7 @@ public class MapboxMapTest {
@Test
@Ignore /* disabled due to enabling permissions during test #7177 */
public void testMyLocationEnabled() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -204,8 +228,7 @@ public class MapboxMapTest {
@Test
@Ignore /* can't create handler inside thread that not called Looper.prepare() */
public void testMyLocationDisabled() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -221,8 +244,7 @@ public class MapboxMapTest {
@Test
public void testFpsListener() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -240,8 +262,7 @@ public class MapboxMapTest {
@Test
public void testInfoWindowClickListener() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -259,8 +280,7 @@ public class MapboxMapTest {
@Test
public void testInfoWindowCloseListener() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -278,8 +298,7 @@ public class MapboxMapTest {
@Test
public void testInfoWindowLongClickListener() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -302,8 +321,7 @@ public class MapboxMapTest {
@Test
public void testAddMarker() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -321,8 +339,7 @@ public class MapboxMapTest {
@Test
public void testAddMarkers() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -341,8 +358,7 @@ public class MapboxMapTest {
@Test
public void testAddMarkersEmpty() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -355,8 +371,7 @@ public class MapboxMapTest {
@Test
public void testAddMarkersSingleMarker() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -372,8 +387,7 @@ public class MapboxMapTest {
@Test
public void testAddPolygon() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -386,8 +400,7 @@ public class MapboxMapTest {
@Test
public void testAddEmptyPolygon() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -400,8 +413,7 @@ public class MapboxMapTest {
@Test
public void testAddPolygons() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -423,8 +435,7 @@ public class MapboxMapTest {
@Test
public void addPolygonsEmpty() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -436,8 +447,7 @@ public class MapboxMapTest {
@Test
public void addPolygonsSingle() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -453,8 +463,7 @@ public class MapboxMapTest {
@Test
public void testAddPolyline() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -467,8 +476,7 @@ public class MapboxMapTest {
@Test
public void testAddEmptyPolyline() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -481,8 +489,7 @@ public class MapboxMapTest {
@Test
public void testAddPolylines() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -504,8 +511,7 @@ public class MapboxMapTest {
@Test
public void testAddPolylinesEmpty() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -517,8 +523,7 @@ public class MapboxMapTest {
@Test
public void testAddPolylinesSingle() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -534,8 +539,7 @@ public class MapboxMapTest {
@Test
public void testRemoveMarker() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -549,8 +553,7 @@ public class MapboxMapTest {
@Test
public void testRemovePolygon() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -564,8 +567,7 @@ public class MapboxMapTest {
@Test
public void testRemovePolyline() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -579,8 +581,7 @@ public class MapboxMapTest {
@Test
public void testRemoveAnnotation() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -594,8 +595,7 @@ public class MapboxMapTest {
@Test
public void testRemoveAnnotationById() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -610,8 +610,7 @@ public class MapboxMapTest {
@Test
public void testRemoveAnnotations() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -629,8 +628,7 @@ public class MapboxMapTest {
@Test
public void testClear() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -648,8 +646,7 @@ public class MapboxMapTest {
@Test
public void testRemoveAnnotationsByList() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -669,8 +666,7 @@ public class MapboxMapTest {
@Test
public void testGetAnnotationById() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -684,8 +680,7 @@ public class MapboxMapTest {
@Test
public void testGetAnnotations() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -696,8 +691,7 @@ public class MapboxMapTest {
@Test
public void testGetMarkers() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -708,8 +702,7 @@ public class MapboxMapTest {
@Test
public void testGetPolygons() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -720,8 +713,7 @@ public class MapboxMapTest {
@Test
public void testGetPolylines() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -732,8 +724,7 @@ public class MapboxMapTest {
@Test
public void testGetSelectedMarkers() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -744,8 +735,7 @@ public class MapboxMapTest {
@Test
public void testSelectMarker() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -759,8 +749,7 @@ public class MapboxMapTest {
@Test
public void testDeselectMarker() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -775,8 +764,7 @@ public class MapboxMapTest {
@Test
public void testDeselectMarkers() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
@Override
public void onViewAction(UiController uiController, View view) {
@@ -791,12 +779,6 @@ public class MapboxMapTest {
}));
}
- @After
- public void afterTest() {
- Timber.e("@After test: unregister idle resource");
- Espresso.unregisterIdlingResources(idlingResource);
- }
-
private class MapboxMapAction implements ViewAction {
private InvokeViewAction invokeViewAction;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseActivityTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseActivityTest.java
index 2f51140cd1..c029bc09c4 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseActivityTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseActivityTest.java
@@ -1,21 +1,29 @@
package com.mapbox.mapboxsdk.testapp.activity;
import android.app.Activity;
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
import android.support.test.espresso.Espresso;
import android.support.test.espresso.IdlingResourceTimeoutException;
+import android.support.test.espresso.UiController;
+import android.support.test.espresso.ViewAction;
import android.support.test.rule.ActivityTestRule;
-
-import timber.log.Timber;
+import android.view.View;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.utils.OnMapReadyIdlingResource;
-import com.mapbox.mapboxsdk.testapp.utils.ScreenshotUtil;
+import junit.framework.Assert;
+
+import org.hamcrest.Matcher;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
+import timber.log.Timber;
+
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
@@ -46,6 +54,16 @@ public abstract class BaseActivityTest {
}
}
+ protected void validateTestSetup() {
+ Assert.assertTrue("Device is not connected to the Internet.", isConnected(rule.getActivity()));
+ checkViewIsDisplayed(R.id.mapView);
+ Assert.assertNotNull(mapboxMap);
+ }
+
+ protected MapboxMap getMapboxMap() {
+ return mapboxMap;
+ }
+
protected abstract Class getActivityClass();
protected void checkViewIsDisplayed(int id) {
@@ -53,14 +71,15 @@ public abstract class BaseActivityTest {
.check(matches(isDisplayed()));
}
- protected void takeScreenshot(final String name) {
- final Activity activity = rule.getActivity();
- activity.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- ScreenshotUtil.take(activity, name);
- }
- });
+ protected void waitLoop() {
+ onView(withId(R.id.mapView)).perform(new LoopAction(500));
+ }
+
+ static boolean isConnected(Context context) {
+ ConnectivityManager connectivityManager
+ = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
+ return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}
@After
@@ -68,5 +87,29 @@ public abstract class BaseActivityTest {
Timber.e("@After test: unregister idle resource");
Espresso.unregisterIdlingResources(idlingResource);
}
+
+ private class LoopAction implements ViewAction {
+
+ private long loopTime;
+
+ public LoopAction(long loopTime) {
+ this.loopTime = loopTime;
+ }
+
+ @Override
+ public Matcher<View> getConstraints() {
+ return isDisplayed();
+ }
+
+ @Override
+ public String getDescription() {
+ return getClass().getSimpleName();
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ uiController.loopMainThreadForAtLeast(loopTime);
+ }
+ }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/activity.junit.ejs b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/activity.junit.ejs
index 3e3ef36c39..03d4de17f4 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/activity.junit.ejs
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/activity.junit.ejs
@@ -27,7 +27,7 @@ public class <%- activity %>Test extends BaseActivityTest {
@Test
public void testSanity() {
- onView(withId(R.id.mapView)).check(matches(isDisplayed()));
+ validateTestSetup();
}
@Override
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/MarkerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/MarkerTest.java
index 77025c8fa5..2f638ff651 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/MarkerTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/MarkerTest.java
@@ -1,9 +1,7 @@
package com.mapbox.mapboxsdk.testapp.annotations;
-import android.support.test.espresso.Espresso;
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.annotations.Marker;
@@ -11,16 +9,12 @@ import com.mapbox.mapboxsdk.annotations.MarkerOptions;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest;
import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity;
-import com.mapbox.mapboxsdk.testapp.utils.OnMapReadyIdlingResource;
import com.mapbox.mapboxsdk.testapp.utils.TestConstants;
-import com.mapbox.mapboxsdk.testapp.utils.ViewUtils;
import org.hamcrest.Matcher;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Ignore;
-import org.junit.Rule;
import org.junit.Test;
import static android.support.test.espresso.Espresso.onView;
@@ -30,25 +24,19 @@ import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static org.junit.Assert.assertEquals;
-public class MarkerTest {
+public class MarkerTest extends BaseActivityTest {
- @Rule
- public final ActivityTestRule<EspressoTestActivity> rule = new ActivityTestRule<>(EspressoTestActivity.class);
-
- private OnMapReadyIdlingResource idlingResource;
private Marker marker;
- @Before
- public void registerIdlingResource() {
- idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
- Espresso.registerIdlingResources(idlingResource);
+ @Override
+ protected Class getActivityClass() {
+ return EspressoTestActivity.class;
}
@Test
@Ignore
public void addMarkerTest() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
assertEquals("Markers should be empty", 0, mapboxMap.getMarkers().size());
MarkerOptions options = new MarkerOptions();
@@ -69,8 +57,7 @@ public class MarkerTest {
@Test
@Ignore
public void showInfoWindowTest() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
final MarkerOptions options = new MarkerOptions();
options.setPosition(new LatLng());
@@ -133,10 +120,4 @@ public class MarkerTest {
}
}
-
-
- @After
- public void unregisterIdlingResource() {
- Espresso.unregisterIdlingResources(idlingResource);
- }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/MarkerViewTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/MarkerViewTest.java
index 9351ed1c10..bee20c3150 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/MarkerViewTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/MarkerViewTest.java
@@ -1,27 +1,21 @@
package com.mapbox.mapboxsdk.testapp.annotations;
-import android.support.test.espresso.Espresso;
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.annotations.Marker;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest;
import com.mapbox.mapboxsdk.testapp.activity.annotation.MarkerViewActivity;
import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity;
import com.mapbox.mapboxsdk.testapp.model.annotations.TextMarkerViewOptions;
-import com.mapbox.mapboxsdk.testapp.utils.OnMapReadyIdlingResource;
import com.mapbox.mapboxsdk.testapp.utils.TestConstants;
-import com.mapbox.mapboxsdk.testapp.utils.ViewUtils;
import org.hamcrest.Matcher;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Ignore;
-import org.junit.Rule;
import org.junit.Test;
import static android.support.test.espresso.Espresso.onView;
@@ -31,25 +25,19 @@ import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static org.junit.Assert.assertEquals;
-public class MarkerViewTest {
+public class MarkerViewTest extends BaseActivityTest {
- @Rule
- public final ActivityTestRule<EspressoTestActivity> rule = new ActivityTestRule<>(EspressoTestActivity.class);
-
- private OnMapReadyIdlingResource idlingResource;
private Marker marker;
- @Before
- public void registerIdlingResource() {
- idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
- Espresso.registerIdlingResources(idlingResource);
+ @Override
+ protected Class getActivityClass() {
+ return EspressoTestActivity.class;
}
@Test
@Ignore
public void addMarkerViewTest() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
assertEquals("Markers should be empty", 0, mapboxMap.getMarkers().size());
TextMarkerViewOptions options = new TextMarkerViewOptions();
@@ -70,8 +58,7 @@ public class MarkerViewTest {
@Test
@Ignore
public void showInfoWindowTest() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
final TextMarkerViewOptions options = new TextMarkerViewOptions();
options.position(new LatLng());
@@ -139,9 +126,4 @@ public class MarkerViewTest {
uiController.loopMainThreadForAtLeast(250);
}
}
-
- @After
- public void unregisterIdlingResource() {
- Espresso.unregisterIdlingResources(idlingResource);
- }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/PolygonTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/PolygonTest.java
index 24b9b3bf01..325568bec4 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/PolygonTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/PolygonTest.java
@@ -1,10 +1,8 @@
package com.mapbox.mapboxsdk.testapp.annotations;
import android.graphics.Color;
-import android.support.test.espresso.Espresso;
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.annotations.Polygon;
@@ -12,15 +10,11 @@ import com.mapbox.mapboxsdk.annotations.PolygonOptions;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest;
import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity;
-import com.mapbox.mapboxsdk.testapp.utils.OnMapReadyIdlingResource;
-import com.mapbox.mapboxsdk.testapp.utils.ViewUtils;
import org.hamcrest.Matcher;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Ignore;
-import org.junit.Rule;
import org.junit.Test;
import static android.support.test.espresso.Espresso.onView;
@@ -28,26 +22,20 @@ import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static org.junit.Assert.assertEquals;
-public class PolygonTest {
+public class PolygonTest extends BaseActivityTest {
- @Rule
- public final ActivityTestRule<EspressoTestActivity> rule = new ActivityTestRule<>(EspressoTestActivity.class);
+ @Override
+ protected Class getActivityClass() {
+ return EspressoTestActivity.class;
+ }
- private OnMapReadyIdlingResource idlingResource;
private Polygon polygon;
- @Before
- public void registerIdlingResource() {
- idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
- Espresso.registerIdlingResources(idlingResource);
- }
-
@Test
@Ignore
/** native crash **/
public void addPolygonTest() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
LatLng latLngOne = new LatLng();
LatLng latLngTwo = new LatLng(1, 0);
LatLng latLngThree = new LatLng(1, 1);
@@ -97,9 +85,4 @@ public class PolygonTest {
polygon = mapboxMap.addPolygon(options);
}
}
-
- @After
- public void unregisterIdlingResource() {
- Espresso.unregisterIdlingResources(idlingResource);
- }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/PolylineTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/PolylineTest.java
index 607a4ad263..91553f7042 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/PolylineTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/PolylineTest.java
@@ -1,10 +1,8 @@
package com.mapbox.mapboxsdk.testapp.annotations;
import android.graphics.Color;
-import android.support.test.espresso.Espresso;
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.annotations.Polyline;
@@ -12,15 +10,11 @@ import com.mapbox.mapboxsdk.annotations.PolylineOptions;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest;
import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity;
-import com.mapbox.mapboxsdk.testapp.utils.OnMapReadyIdlingResource;
-import com.mapbox.mapboxsdk.testapp.utils.ViewUtils;
import org.hamcrest.Matcher;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Ignore;
-import org.junit.Rule;
import org.junit.Test;
import static android.support.test.espresso.Espresso.onView;
@@ -28,25 +22,19 @@ import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static org.junit.Assert.assertEquals;
-public class PolylineTest {
+public class PolylineTest extends BaseActivityTest {
- @Rule
- public final ActivityTestRule<EspressoTestActivity> rule = new ActivityTestRule<>(EspressoTestActivity.class);
-
- private OnMapReadyIdlingResource idlingResource;
private Polyline polyline;
- @Before
- public void registerIdlingResource() {
- idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
- Espresso.registerIdlingResources(idlingResource);
+ @Override
+ protected Class getActivityClass() {
+ return EspressoTestActivity.class;
}
@Ignore
@Test
public void addPolylineTest() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
LatLng latLngOne = new LatLng();
LatLng latLngTwo = new LatLng(1, 0);
@@ -92,9 +80,4 @@ public class PolylineTest {
polyline = mapboxMap.addPolyline(options);
}
}
-
- @After
- public void unregisterIdlingResource() {
- Espresso.unregisterIdlingResources(idlingResource);
- }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraAnimateTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraAnimateTest.java
index d4b0dbad72..af1a146ca2 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraAnimateTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraAnimateTest.java
@@ -1,10 +1,8 @@
package com.mapbox.mapboxsdk.testapp.camera;
import android.graphics.PointF;
-import android.support.test.espresso.Espresso;
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.camera.CameraPosition;
@@ -14,16 +12,12 @@ import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest;
import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity;
-import com.mapbox.mapboxsdk.testapp.utils.OnMapReadyIdlingResource;
import com.mapbox.mapboxsdk.testapp.utils.TestConstants;
-import com.mapbox.mapboxsdk.testapp.utils.ViewUtils;
import org.hamcrest.Matcher;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Ignore;
-import org.junit.Rule;
import org.junit.Test;
import static android.support.test.espresso.Espresso.onView;
@@ -31,24 +25,17 @@ import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static org.junit.Assert.assertEquals;
-public class CameraAnimateTest {
+public class CameraAnimateTest extends BaseActivityTest {
- @Rule
- public final ActivityTestRule<EspressoTestActivity> rule = new ActivityTestRule<>(EspressoTestActivity.class);
-
- private OnMapReadyIdlingResource idlingResource;
-
- @Before
- public void registerIdlingResource() {
- idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
- Espresso.registerIdlingResources(idlingResource);
+ @Override
+ protected Class getActivityClass() {
+ return EspressoTestActivity.class;
}
@Test
@Ignore
public void testAnimateToCameraPositionTarget() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
/*TODO remove zoom #6474*/
float zoom = 1.0f;
@@ -70,8 +57,7 @@ public class CameraAnimateTest {
@Test
@Ignore
public void testAnimateToCameraPositionTargetZoom() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
final float moveZoom = 15.5f;
final LatLng moveTarget = new LatLng(1.0000000001, 1.0000000003);
@@ -87,9 +73,9 @@ public class CameraAnimateTest {
}
@Test
+ @Ignore
public void testAnimateToCameraPosition() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
final LatLng moveTarget = new LatLng(1.0000000001, 1.0000000003);
final float moveZoom = 15.5f;
@@ -119,8 +105,7 @@ public class CameraAnimateTest {
@Test
@Ignore
public void testAnimateToBounds() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
final LatLng centerBounds = new LatLng(1, 1);
LatLng cornerOne = new LatLng();
@@ -148,8 +133,7 @@ public class CameraAnimateTest {
@Test
@Ignore
public void testAnimateToMoveBy() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
final PointF centerPoint = mapboxMap.getProjection().toScreenLocation(mapboxMap.getCameraPosition().target);
final LatLng moveTarget = new LatLng(2, 2);
@@ -168,8 +152,7 @@ public class CameraAnimateTest {
@Test
@Ignore
public void testAnimateToZoomIn() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
/*TODO fix zoom #6474*/
float zoom = 1.0f;
@@ -183,8 +166,7 @@ public class CameraAnimateTest {
@Test
@Ignore
public void testAnimateToZoomOut() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
/*TODO fix zoom #6474*/
float zoom = 10.0f;
@@ -199,8 +181,7 @@ public class CameraAnimateTest {
@Test
@Ignore
public void testAnimateToZoomBy() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
/*TODO fix zoom #6474*/
float zoom = 1.0f;
@@ -215,8 +196,7 @@ public class CameraAnimateTest {
@Test
@Ignore
public void testAnimateToZoomTo() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
/*TODO fix zoom #6474*/
final float zoomTo = 2.45f;
@@ -227,11 +207,6 @@ public class CameraAnimateTest {
TestConstants.ZOOM_DELTA);
}
- @After
- public void unregisterIdlingResource() {
- Espresso.unregisterIdlingResources(idlingResource);
- }
-
private class AnimateCameraAction implements ViewAction {
private MapboxMap mapboxMap;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraEaseTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraEaseTest.java
index 83e7d6084c..4fae894039 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraEaseTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraEaseTest.java
@@ -1,10 +1,8 @@
package com.mapbox.mapboxsdk.testapp.camera;
import android.graphics.PointF;
-import android.support.test.espresso.Espresso;
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.camera.CameraPosition;
@@ -14,16 +12,12 @@ import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest;
import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity;
-import com.mapbox.mapboxsdk.testapp.utils.OnMapReadyIdlingResource;
import com.mapbox.mapboxsdk.testapp.utils.TestConstants;
-import com.mapbox.mapboxsdk.testapp.utils.ViewUtils;
import org.hamcrest.Matcher;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Ignore;
-import org.junit.Rule;
import org.junit.Test;
import static android.support.test.espresso.Espresso.onView;
@@ -31,24 +25,17 @@ import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static org.junit.Assert.assertEquals;
-public class CameraEaseTest {
+public class CameraEaseTest extends BaseActivityTest {
- @Rule
- public final ActivityTestRule<EspressoTestActivity> rule = new ActivityTestRule<>(EspressoTestActivity.class);
-
- private OnMapReadyIdlingResource idlingResource;
-
- @Before
- public void registerIdlingResource() {
- idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
- Espresso.registerIdlingResources(idlingResource);
+ @Override
+ protected Class getActivityClass() {
+ return EspressoTestActivity.class;
}
@Test
@Ignore
public void testEaseToCameraPositionTarget() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
/*TODO remove zoom #6474*/
float zoom = 1.0f;
@@ -70,8 +57,7 @@ public class CameraEaseTest {
@Test
@Ignore
public void testEaseToCameraPositionTargetZoom() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
final float moveZoom = 15.5f;
final LatLng moveTarget = new LatLng(1.0000000001, 1.0000000003);
@@ -89,8 +75,7 @@ public class CameraEaseTest {
@Test
@Ignore
public void testEaseToCameraPosition() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
final LatLng moveTarget = new LatLng(1.0000000001, 1.0000000003);
final float moveZoom = 15.5f;
@@ -120,8 +105,7 @@ public class CameraEaseTest {
@Test
@Ignore
public void testEaseToBounds() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
final LatLng centerBounds = new LatLng(1, 1);
LatLng cornerOne = new LatLng();
@@ -149,8 +133,7 @@ public class CameraEaseTest {
@Test
@Ignore
public void testEaseToMoveBy() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
final PointF centerPoint = mapboxMap.getProjection().toScreenLocation(mapboxMap.getCameraPosition().target);
final LatLng moveTarget = new LatLng(2, 2);
@@ -169,8 +152,7 @@ public class CameraEaseTest {
@Test
@Ignore
public void testEaseToZoomIn() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
/*TODO fix zoom #6474*/
float zoom = 1.0f;
@@ -184,8 +166,7 @@ public class CameraEaseTest {
@Test
@Ignore
public void testEaseToZoomOut() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
/*TODO fix zoom #6474*/
float zoom = 10.0f;
@@ -199,8 +180,7 @@ public class CameraEaseTest {
@Test
@Ignore
public void testEaseToZoomBy() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
/*TODO fix zoom #6474*/
float zoom = 1.0f;
@@ -215,8 +195,7 @@ public class CameraEaseTest {
@Test
@Ignore
public void testEaseToZoomTo() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
/*TODO fix zoom #6474*/
final float zoomTo = 2.45f;
@@ -227,11 +206,6 @@ public class CameraEaseTest {
TestConstants.ZOOM_DELTA);
}
- @After
- public void unregisterIdlingResource() {
- Espresso.unregisterIdlingResources(idlingResource);
- }
-
private class EaseCameraAction implements ViewAction {
private MapboxMap mapboxMap;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraInternalApiTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraInternalApiTest.java
index 2d01347d22..883e76653d 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraInternalApiTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraInternalApiTest.java
@@ -3,7 +3,6 @@ package com.mapbox.mapboxsdk.testapp.camera;
import android.support.test.espresso.Espresso;
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.camera.CameraPosition;
@@ -11,16 +10,13 @@ import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapViewUtils;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest;
import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity;
-import com.mapbox.mapboxsdk.testapp.utils.OnMapReadyIdlingResource;
import com.mapbox.mapboxsdk.testapp.utils.TestConstants;
-import com.mapbox.mapboxsdk.testapp.utils.ViewUtils;
import org.hamcrest.Matcher;
import org.junit.After;
-import org.junit.Before;
import org.junit.Ignore;
-import org.junit.Rule;
import org.junit.Test;
import static android.support.test.espresso.Espresso.onView;
@@ -31,25 +27,17 @@ import static org.junit.Assert.assertEquals;
/**
* Tests camera transformations that aren't part of our public API
*/
-public class CameraInternalApiTest {
+public class CameraInternalApiTest extends BaseActivityTest {
- @Rule
- public final ActivityTestRule<EspressoTestActivity> rule = new ActivityTestRule<>(EspressoTestActivity.class);
-
- private OnMapReadyIdlingResource idlingResource;
-
- @Before
- public void registerIdlingResource() {
- idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
- Espresso.registerIdlingResources(idlingResource);
+ @Override
+ protected Class getActivityClass() {
+ return EspressoTestActivity.class;
}
@Test
@Ignore
public void testBearing() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- EspressoTestActivity activity = rule.getActivity();
- MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
CameraPosition initialPosition = new
CameraPosition.Builder().target(new LatLng()).zoom(1).bearing(0).tilt(0).build();
@@ -63,9 +51,7 @@ public class CameraInternalApiTest {
@Test
@Ignore
public void testTilt() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- EspressoTestActivity activity = rule.getActivity();
- MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
CameraPosition initialPosition = new CameraPosition.Builder().target(
new LatLng()).zoom(1).bearing(0).tilt(0).build();
@@ -79,9 +65,7 @@ public class CameraInternalApiTest {
@Test
@Ignore
public void testLatLng() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- EspressoTestActivity activity = rule.getActivity();
- MapboxMap mapboxMap = activity.getMapboxMap();
+ validateTestSetup();
CameraPosition initialPosition = new CameraPosition.Builder().target(
new LatLng()).zoom(1).bearing(0).tilt(0).build();
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraMoveTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraMoveTest.java
index becf9db7cb..ea8398fc8e 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraMoveTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraMoveTest.java
@@ -1,10 +1,8 @@
package com.mapbox.mapboxsdk.testapp.camera;
import android.graphics.PointF;
-import android.support.test.espresso.Espresso;
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.camera.CameraPosition;
@@ -14,16 +12,12 @@ import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest;
import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity;
-import com.mapbox.mapboxsdk.testapp.utils.OnMapReadyIdlingResource;
import com.mapbox.mapboxsdk.testapp.utils.TestConstants;
-import com.mapbox.mapboxsdk.testapp.utils.ViewUtils;
import org.hamcrest.Matcher;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Ignore;
-import org.junit.Rule;
import org.junit.Test;
import static android.support.test.espresso.Espresso.onView;
@@ -31,24 +25,17 @@ import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static org.junit.Assert.assertEquals;
-public class CameraMoveTest {
+public class CameraMoveTest extends BaseActivityTest {
- @Rule
- public final ActivityTestRule<EspressoTestActivity> rule = new ActivityTestRule<>(EspressoTestActivity.class);
-
- private OnMapReadyIdlingResource idlingResource;
-
- @Before
- public void registerIdlingResource() {
- idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
- Espresso.registerIdlingResources(idlingResource);
+ @Override
+ protected Class getActivityClass() {
+ return EspressoTestActivity.class;
}
@Test
@Ignore
public void testMoveToCameraPositionTarget() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
/*TODO remove zoom #6474*/
float zoom = 1.0f;
@@ -70,8 +57,7 @@ public class CameraMoveTest {
@Test
@Ignore
public void testMoveToCameraPositionTargetZoom() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
final float moveZoom = 15.5f;
final LatLng moveTarget = new LatLng(1.0000000001, 1.0000000003);
@@ -89,8 +75,7 @@ public class CameraMoveTest {
@Test
@Ignore
public void testMoveToCameraPosition() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
final LatLng moveTarget = new LatLng(1.0000000001, 1.0000000003);
final float moveZoom = 15.5f;
@@ -120,8 +105,7 @@ public class CameraMoveTest {
@Test
@Ignore
public void testMoveToBounds() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
final LatLng centerBounds = new LatLng(1, 1);
LatLng cornerOne = new LatLng();
@@ -149,8 +133,7 @@ public class CameraMoveTest {
@Test
@Ignore
public void testMoveToMoveBy() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
final PointF centerPoint = mapboxMap.getProjection().toScreenLocation(mapboxMap.getCameraPosition().target);
final LatLng moveTarget = new LatLng(2, 2);
@@ -169,8 +152,7 @@ public class CameraMoveTest {
@Test
@Ignore
public void testMoveToZoomIn() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
/*TODO fix zoom #6474*/
float zoom = 1.0f;
@@ -184,8 +166,7 @@ public class CameraMoveTest {
@Test
@Ignore
public void testMoveToZoomOut() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
/*TODO fix zoom #6474*/
float zoom = 10.0f;
@@ -200,8 +181,7 @@ public class CameraMoveTest {
@Test
@Ignore
public void testMoveToZoomBy() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
/*TODO fix zoom #6474*/
float zoom = 1.0f;
@@ -216,8 +196,7 @@ public class CameraMoveTest {
@Test
@Ignore
public void testMoveToZoomTo() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
/*TODO fix zoom #6474*/
final float zoomTo = 2.45f;
@@ -228,11 +207,6 @@ public class CameraMoveTest {
TestConstants.ZOOM_DELTA);
}
- @After
- public void unregisterIdlingResource() {
- Espresso.unregisterIdlingResources(idlingResource);
- }
-
private class MoveCameraAction implements ViewAction {
private MapboxMap mapboxMap;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/feature/QueryRenderedFeaturesBoxCountTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/feature/QueryRenderedFeaturesBoxCountTest.java
index f49296a164..5ef93c72b3 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/feature/QueryRenderedFeaturesBoxCountTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/feature/QueryRenderedFeaturesBoxCountTest.java
@@ -1,16 +1,10 @@
package com.mapbox.mapboxsdk.testapp.feature;
-import android.support.test.espresso.Espresso;
-import android.support.test.rule.ActivityTestRule;
-
import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest;
import com.mapbox.mapboxsdk.testapp.activity.feature.QueryRenderedFeaturesBoxCountActivity;
-import com.mapbox.mapboxsdk.testapp.utils.OnMapReadyIdlingResource;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Ignore;
-import org.junit.Rule;
import org.junit.Test;
import static android.support.test.espresso.Espresso.onView;
@@ -27,18 +21,11 @@ import static org.hamcrest.Matchers.not;
* Instrumentation test to validate if clicking on the blue rectangle from
* QueryRenderedFeaturesBoxSymbolCountActivity shows a Toast that 149 features were found.
*/
-public class QueryRenderedFeaturesBoxCountTest {
-
- @Rule
- public final ActivityTestRule<QueryRenderedFeaturesBoxCountActivity> rule =
- new ActivityTestRule<>(QueryRenderedFeaturesBoxCountActivity.class);
-
- private OnMapReadyIdlingResource idlingResource;
+public class QueryRenderedFeaturesBoxCountTest extends BaseActivityTest {
- @Before
- public void registerIdlingResource() {
- idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
- Espresso.registerIdlingResources(idlingResource);
+ @Override
+ protected Class getActivityClass() {
+ return QueryRenderedFeaturesBoxCountActivity.class;
}
@Test
@@ -53,9 +40,4 @@ public class QueryRenderedFeaturesBoxCountTest {
.check(matches(isDisplayed()));
}
- @After
- public void unregisterIdlingResource() {
- Espresso.unregisterIdlingResources(idlingResource);
- }
-
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/feature/QueryRenderedFeaturesHighlightTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/feature/QueryRenderedFeaturesHighlightTest.java
index 0333aba191..307700e847 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/feature/QueryRenderedFeaturesHighlightTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/feature/QueryRenderedFeaturesHighlightTest.java
@@ -1,22 +1,10 @@
package com.mapbox.mapboxsdk.testapp.feature;
-import android.support.test.espresso.Espresso;
-import android.support.test.espresso.ViewAction;
-import android.support.test.espresso.action.CoordinatesProvider;
-import android.support.test.espresso.action.GeneralClickAction;
-import android.support.test.espresso.action.Press;
-import android.support.test.espresso.action.Tap;
-import android.support.test.rule.ActivityTestRule;
-import android.view.View;
-
import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest;
import com.mapbox.mapboxsdk.testapp.activity.feature.QueryRenderedFeaturesBoxHighlightActivity;
-import com.mapbox.mapboxsdk.testapp.utils.OnMapReadyIdlingResource;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Ignore;
-import org.junit.Rule;
import org.junit.Test;
import static android.support.test.espresso.Espresso.onView;
@@ -32,18 +20,11 @@ import static org.hamcrest.Matchers.not;
/**
* Instrumentation test to validate if clicking box on screen highlights features.
*/
-public class QueryRenderedFeaturesHighlightTest {
-
- @Rule
- public final ActivityTestRule<QueryRenderedFeaturesBoxHighlightActivity> rule =
- new ActivityTestRule<>(QueryRenderedFeaturesBoxHighlightActivity.class);
-
- private OnMapReadyIdlingResource idlingResource;
+public class QueryRenderedFeaturesHighlightTest extends BaseActivityTest {
- @Before
- public void registerIdlingResource() {
- idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
- Espresso.registerIdlingResources(idlingResource);
+ @Override
+ protected Class getActivityClass() {
+ return QueryRenderedFeaturesBoxHighlightActivity.class;
}
@Test
@@ -58,24 +39,4 @@ public class QueryRenderedFeaturesHighlightTest {
.check(matches(isDisplayed()));
}
- @After
- public void unregisterIdlingResource() {
- Espresso.unregisterIdlingResources(idlingResource);
- }
-
- private static ViewAction clickXY(final float x, final float y) {
- return new GeneralClickAction(
- Tap.SINGLE,
- new CoordinatesProvider() {
- @Override
- public float[] calculateCoordinates(View view) {
- final int[] screenPos = new int[2];
- view.getLocationOnScreen(screenPos);
- final float screenX = screenPos[0] + x;
- final float screenY = screenPos[1] + y;
- return new float[] {screenX, screenY};
- }
- },
- Press.FINGER);
- }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/feature/QueryRenderedFeaturesPropertiesTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/feature/QueryRenderedFeaturesPropertiesTest.java
index 01eb9c8b44..8e6987b712 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/feature/QueryRenderedFeaturesPropertiesTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/feature/QueryRenderedFeaturesPropertiesTest.java
@@ -1,25 +1,19 @@
package com.mapbox.mapboxsdk.testapp.feature;
import android.graphics.PointF;
-import android.support.test.espresso.Espresso;
import android.support.test.espresso.ViewAction;
import android.support.test.espresso.action.CoordinatesProvider;
import android.support.test.espresso.action.GeneralClickAction;
import android.support.test.espresso.action.Press;
import android.support.test.espresso.action.Tap;
-import android.support.test.rule.ActivityTestRule;
import android.view.View;
import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest;
import com.mapbox.mapboxsdk.testapp.activity.feature.QueryRenderedFeaturesPropertiesActivity;
-import com.mapbox.mapboxsdk.testapp.utils.OnMapReadyIdlingResource;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Ignore;
-import org.junit.Rule;
import org.junit.Test;
import static android.support.test.espresso.Espresso.onView;
@@ -31,35 +25,22 @@ import static android.support.test.espresso.matcher.ViewMatchers.withText;
/**
* Instrumentation test to validate if clicking center of screen returns the correct features.
*/
-public class QueryRenderedFeaturesPropertiesTest {
+public class QueryRenderedFeaturesPropertiesTest extends BaseActivityTest {
- @Rule
- public final ActivityTestRule<QueryRenderedFeaturesPropertiesActivity> rule =
- new ActivityTestRule<>(QueryRenderedFeaturesPropertiesActivity.class);
-
- private OnMapReadyIdlingResource idlingResource;
-
- @Before
- public void registerIdlingResource() {
- idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
- Espresso.registerIdlingResources(idlingResource);
+ @Override
+ protected Class getActivityClass() {
+ return QueryRenderedFeaturesPropertiesActivity.class;
}
@Test
@Ignore
public void testCountFeatures() {
- MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
LatLng centerScreen = mapboxMap.getCameraPosition().target;
PointF centerPixel = mapboxMap.getProjection().toScreenLocation(centerScreen);
onView(withId(R.id.mapView)).perform(clickXY(centerPixel.x, centerPixel.y));
onView(withText("Found 4 features")).check(matches(isDisplayed()));
}
- @After
- public void unregisterIdlingResource() {
- Espresso.unregisterIdlingResources(idlingResource);
- }
-
private static ViewAction clickXY(final float x, final float y) {
return new GeneralClickAction(
Tap.SINGLE,
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/feature/QueryRenderedSymbolBoxCountTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/feature/QueryRenderedSymbolBoxCountTest.java
index ea80e8689a..a31c3db89e 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/feature/QueryRenderedSymbolBoxCountTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/feature/QueryRenderedSymbolBoxCountTest.java
@@ -1,16 +1,10 @@
package com.mapbox.mapboxsdk.testapp.feature;
-import android.support.test.espresso.Espresso;
-import android.support.test.rule.ActivityTestRule;
-
import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest;
import com.mapbox.mapboxsdk.testapp.activity.feature.QueryRenderedFeaturesBoxSymbolCountActivity;
-import com.mapbox.mapboxsdk.testapp.utils.OnMapReadyIdlingResource;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Ignore;
-import org.junit.Rule;
import org.junit.Test;
import static android.support.test.espresso.Espresso.onView;
@@ -27,18 +21,11 @@ import static org.hamcrest.Matchers.not;
* Instrumentation test to validate if clicking on the blue rectangle from
* QueryRenderedFeaturesBoxSymbolCountActivity shows a Toast that 2 symbols were found.
*/
-public class QueryRenderedSymbolBoxCountTest {
-
- @Rule
- public final ActivityTestRule<QueryRenderedFeaturesBoxSymbolCountActivity> rule =
- new ActivityTestRule<>(QueryRenderedFeaturesBoxSymbolCountActivity.class);
-
- private OnMapReadyIdlingResource idlingResource;
+public class QueryRenderedSymbolBoxCountTest extends BaseActivityTest {
- @Before
- public void registerIdlingResource() {
- idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
- Espresso.registerIdlingResources(idlingResource);
+ @Override
+ protected Class getActivityClass() {
+ return QueryRenderedFeaturesBoxSymbolCountActivity.class;
}
@Test
@@ -52,11 +39,5 @@ public class QueryRenderedSymbolBoxCountTest {
.inRoot(withDecorView(not(is(rule.getActivity().getWindow().getDecorView()))))
.check(matches(isDisplayed()));
}
-
- @After
- public void unregisterIdlingResource() {
- Espresso.unregisterIdlingResources(idlingResource);
- }
-
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/AttributionTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/AttributionTest.java
index fa1451092a..d37c6db2d5 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/AttributionTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/AttributionTest.java
@@ -3,25 +3,27 @@ package com.mapbox.mapboxsdk.testapp.maps.widgets;
import android.app.Instrumentation;
import android.content.Intent;
import android.net.Uri;
-import android.support.test.espresso.Espresso;
import android.support.test.espresso.UiController;
import android.support.test.espresso.ViewAction;
import android.support.test.espresso.intent.Intents;
-import android.support.test.rule.ActivityTestRule;
+import android.text.Html;
+import android.text.SpannableStringBuilder;
+import android.text.TextUtils;
+import android.text.style.URLSpan;
import android.view.View;
import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.style.sources.Source;
import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest;
import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity;
-import com.mapbox.mapboxsdk.testapp.utils.OnMapReadyIdlingResource;
-import com.mapbox.mapboxsdk.testapp.utils.ViewUtils;
import org.hamcrest.Matcher;
import org.junit.After;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
+import static android.support.test.espresso.Espresso.onData;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
@@ -32,32 +34,28 @@ import static android.support.test.espresso.intent.matcher.IntentMatchers.hasDat
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
-import static org.hamcrest.Matchers.allOf;
+import static org.hamcrest.CoreMatchers.allOf;
+import static org.hamcrest.CoreMatchers.anything;
import static org.hamcrest.core.IsNot.not;
-public class AttributionTest {
+public class AttributionTest extends BaseActivityTest {
- @Rule
- public final ActivityTestRule<EspressoTestActivity> rule = new ActivityTestRule<>(EspressoTestActivity.class);
+ private URLSpan[] urlSpans;
- private OnMapReadyIdlingResource idlingResource;
-
- private String[] dialogTexts;
- private String[] dialogLinks;
+ @Override
+ protected Class getActivityClass() {
+ return EspressoTestActivity.class;
+ }
@Before
public void beforeTest() {
- idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
- Espresso.registerIdlingResources(idlingResource);
+ super.beforeTest();
Intents.init();
- dialogTexts = rule.getActivity().getResources().getStringArray(R.array.mapbox_attribution_names);
- dialogLinks = rule.getActivity().getResources().getStringArray(R.array.mapbox_attribution_links);
}
@Test
public void testDisabled() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
// Default
onView(withId(R.id.attributionView)).check(matches(isDisplayed()));
@@ -69,65 +67,97 @@ public class AttributionTest {
}
@Test
- public void testMapboxLink() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
+ public void testMapboxStreetsMapboxAttributionLink() {
+ validateTestSetup();
+ if (urlSpans == null) {
+ buildUrlSpans();
+ }
// click on View to open dialog
onView(withId(R.id.attributionView)).perform(click());
onView(withText(R.string.mapbox_attributionsDialogTitle)).check(matches(isDisplayed()));
- // click on link and validate browser opening
- Matcher<Intent> expectedIntent = allOf(hasAction(Intent.ACTION_VIEW), hasData(Uri.parse(dialogLinks[0])));
+ // test for trigger url intent
+ Matcher<Intent> expectedIntent = allOf(hasAction(Intent.ACTION_VIEW), hasData(Uri.parse(urlSpans[0].getURL())));
intending(expectedIntent).respondWith(new Instrumentation.ActivityResult(0, null));
- onView(withText(dialogTexts[0])).perform(click());
+
+ // click item and test for url
+ onData(anything()).inAdapterView(withId(R.id.select_dialog_listview)).atPosition(0).perform(click());
intended(expectedIntent);
}
@Test
- public void testOpenStreetMapLink() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
+ public void testMapboxStreetsOpenStreetMapAttributionLink() {
+ validateTestSetup();
+ if (urlSpans == null) {
+ buildUrlSpans();
+ }
// click on View to open dialog
onView(withId(R.id.attributionView)).perform(click());
onView(withText(R.string.mapbox_attributionsDialogTitle)).check(matches(isDisplayed()));
- // click on link and validate browser opening
- Matcher<Intent> expectedIntent = allOf(hasAction(Intent.ACTION_VIEW), hasData(Uri.parse(dialogLinks[1])));
+ // test for trigger url intent
+ Matcher<Intent> expectedIntent = allOf(hasAction(Intent.ACTION_VIEW), hasData(Uri.parse(urlSpans[1].getURL())));
intending(expectedIntent).respondWith(new Instrumentation.ActivityResult(0, null));
- onView(withText(dialogTexts[1])).perform(click());
+
+ // click item and test for url
+ onData(anything()).inAdapterView(withId(R.id.select_dialog_listview)).atPosition(1).perform(click());
+ intended(expectedIntent);
}
@Test
public void testImproveMapLink() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ if (urlSpans == null) {
+ buildUrlSpans();
+ }
// click on View to open dialog
onView(withId(R.id.attributionView)).perform(click());
onView(withText(R.string.mapbox_attributionsDialogTitle)).check(matches(isDisplayed()));
- // click on Mapbox link and validate browser opening
- Matcher<Intent> expectedIntent = allOf(hasAction(Intent.ACTION_VIEW), hasData(Uri.parse(dialogLinks[3])));
+ // test for trigger url intent
+ Matcher<Intent> expectedIntent = hasAction(Intent.ACTION_VIEW);
intending(expectedIntent).respondWith(new Instrumentation.ActivityResult(0, null));
- onView(withText(dialogTexts[3])).perform(click());
+
+ // click item and test for url
+ onData(anything()).inAdapterView(withId(R.id.select_dialog_listview)).atPosition(2).perform(click());
+ intended(expectedIntent);
}
@Test
public void testTelemetryDialog() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
// click on View to open dialog
onView(withId(R.id.attributionView)).perform(click());
onView(withText(R.string.mapbox_attributionsDialogTitle)).check(matches(isDisplayed()));
// click on item to open second dialog
- onView(withText(dialogTexts[3])).perform(click());
+ onView(withText(R.string.mapbox_telemetrySettings)).perform(click());
onView(withText(R.string.mapbox_attributionTelemetryTitle)).check(matches(isDisplayed()));
}
@After
public void afterTest() {
+ super.afterTest();
Intents.release();
- Espresso.unregisterIdlingResources(idlingResource);
+ }
+
+ private void buildUrlSpans() {
+ onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
+ @Override
+ public void onViewAction(UiController uiController, View view) {
+ for (Source source : mapboxMap.getSources()) {
+ String attributionSource = source.getAttribution();
+ if (!TextUtils.isEmpty(attributionSource)) {
+ SpannableStringBuilder htmlBuilder = (SpannableStringBuilder) Html.fromHtml(attributionSource);
+ urlSpans = htmlBuilder.getSpans(0, htmlBuilder.length(), URLSpan.class);
+ }
+ }
+ }
+ }));
}
private class DisableAction implements ViewAction {
@@ -153,4 +183,32 @@ public class AttributionTest {
mapboxMap.getUiSettings().setAttributionEnabled(false);
}
}
+
+ private class MapboxMapAction implements ViewAction {
+
+ private InvokeViewAction invokeViewAction;
+
+ MapboxMapAction(InvokeViewAction invokeViewAction) {
+ this.invokeViewAction = invokeViewAction;
+ }
+
+ @Override
+ public Matcher<View> getConstraints() {
+ return isDisplayed();
+ }
+
+ @Override
+ public String getDescription() {
+ return getClass().getSimpleName();
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ invokeViewAction.onViewAction(uiController, view);
+ }
+ }
+
+ interface InvokeViewAction {
+ void onViewAction(UiController uiController, View view);
+ }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/CompassViewTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/CompassViewTest.java
index 02fec41f65..f15605042b 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/CompassViewTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/CompassViewTest.java
@@ -1,9 +1,7 @@
package com.mapbox.mapboxsdk.testapp.maps.widgets;
-import android.support.test.espresso.Espresso;
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.camera.CameraPosition;
@@ -12,16 +10,12 @@ import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest;
import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity;
-import com.mapbox.mapboxsdk.testapp.utils.OnMapReadyIdlingResource;
import com.mapbox.mapboxsdk.testapp.utils.TestConstants;
-import com.mapbox.mapboxsdk.testapp.utils.ViewUtils;
import org.hamcrest.Matcher;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Ignore;
-import org.junit.Rule;
import org.junit.Test;
import static android.support.test.espresso.Espresso.onView;
@@ -32,29 +26,22 @@ import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
-public class CompassViewTest {
+public class CompassViewTest extends BaseActivityTest {
- @Rule
- public final ActivityTestRule<EspressoTestActivity> rule = new ActivityTestRule<>(EspressoTestActivity.class);
-
- private OnMapReadyIdlingResource idlingResource;
-
- @Before
- public void registerIdlingResource() {
- idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
- Espresso.registerIdlingResources(idlingResource);
+ @Override
+ protected Class getActivityClass() {
+ return EspressoTestActivity.class;
}
@Test
public void testDefault() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
onView(withId(R.id.compassView)).check(matches(not(isDisplayed())));
}
@Test
public void testVisible() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MoveCameraAction(mapboxMap,
CameraUpdateFactory.newCameraPosition(
@@ -66,15 +53,14 @@ public class CompassViewTest {
)
)
);
-
+ waitLoop();
onView(withId(R.id.compassView)).check(matches(isDisplayed()));
}
@Test
@Ignore // 10-31-2016 click action is not working
public void testClick() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new MoveCameraAction(mapboxMap,
CameraUpdateFactory.newCameraPosition(
@@ -87,6 +73,7 @@ public class CompassViewTest {
)
);
+ waitLoop();
onView(withId(R.id.compassView)).perform(click());
onView(withId(R.id.mapView)).perform(new WaitAction(3000));
onView(withId(R.id.compassView)).check(matches(not(isDisplayed())));
@@ -95,11 +82,6 @@ public class CompassViewTest {
assertEquals("Camera bearing should face north, ", 0, cameraPosition.bearing, TestConstants.BEARING_DELTA);
}
- @After
- public void unregisterIdlingResource() {
- Espresso.unregisterIdlingResources(idlingResource);
- }
-
private class WaitAction implements ViewAction {
private long waitTime;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/LogoTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/LogoTest.java
index f12b2bf160..0c189aa316 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/LogoTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/LogoTest.java
@@ -1,21 +1,15 @@
package com.mapbox.mapboxsdk.testapp.maps.widgets;
-import android.support.test.espresso.Espresso;
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.maps.MapboxMap;
import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest;
import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity;
-import com.mapbox.mapboxsdk.testapp.utils.OnMapReadyIdlingResource;
-import com.mapbox.mapboxsdk.testapp.utils.ViewUtils;
import org.hamcrest.Matcher;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
import static android.support.test.espresso.Espresso.onView;
@@ -24,40 +18,28 @@ import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static org.hamcrest.Matchers.not;
-public class LogoTest {
+public class LogoTest extends BaseActivityTest {
- @Rule
- public final ActivityTestRule<EspressoTestActivity> rule = new ActivityTestRule<>(EspressoTestActivity.class);
-
- private OnMapReadyIdlingResource idlingResource;
-
- @Before
- public void registerIdlingResource() {
- idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
- Espresso.registerIdlingResources(idlingResource);
+ @Override
+ protected Class getActivityClass() {
+ return EspressoTestActivity.class;
}
@Test
public void testDefault() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
onView(withId(R.id.logoView)).check(matches(isDisplayed()));
}
@Test
public void testDisabled() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.logoView))
.perform(new DisableAction(mapboxMap))
.check(matches(not(isDisplayed())));
}
- @After
- public void unregisterIdlingResource() {
- Espresso.unregisterIdlingResources(idlingResource);
- }
-
private class DisableAction implements ViewAction {
private MapboxMap mapboxMap;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/MyLocationViewTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/MyLocationViewTest.java
index c8a983351b..efd67db356 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/MyLocationViewTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/MyLocationViewTest.java
@@ -5,10 +5,8 @@ import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
-import android.support.test.espresso.Espresso;
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.camera.CameraPosition;
@@ -20,17 +18,13 @@ import com.mapbox.mapboxsdk.location.LocationSource;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.widgets.MyLocationView;
import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest;
import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity;
-import com.mapbox.mapboxsdk.testapp.utils.OnMapReadyIdlingResource;
-import com.mapbox.mapboxsdk.testapp.utils.ViewUtils;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Ignore;
-import org.junit.Rule;
import org.junit.Test;
import static android.support.test.espresso.Espresso.onView;
@@ -49,24 +43,17 @@ import static org.hamcrest.Matchers.not;
* {@link com.mapbox.mapboxsdk.maps.TrackingSettings#setMyBearingTrackingMode(int)}.
* </p>
*/
-public class MyLocationViewTest {
+public class MyLocationViewTest extends BaseActivityTest {
- @Rule
- public final ActivityTestRule<EspressoTestActivity> rule = new ActivityTestRule<>(EspressoTestActivity.class);
-
- private OnMapReadyIdlingResource idlingResource;
-
- @Before
- public void beforeTest() {
- idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
- Espresso.registerIdlingResources(idlingResource);
+ @Override
+ protected Class getActivityClass() {
+ return EspressoTestActivity.class;
}
@Test
@Ignore // requires runtime permissions, disabled for CI
public void testEnabled() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.userLocationView)).check(matches(not(isDisplayed())));
onView(withId(R.id.mapView)).perform(new ToggleLocationAction(mapboxMap, true));
onView(withId(R.id.userLocationView)).check(matches(isDisplayed()));
@@ -79,8 +66,7 @@ public class MyLocationViewTest {
// requires runtime permissions, disabled for CI + issue with android.support.test.espresso.AppNotIdleException:
// Looped for 5049 iterations over 60 SECONDS.
public void testTracking() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
- MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
onView(withId(R.id.userLocationView)).check(matches(not(isDisplayed())));
onView(withId(R.id.mapView)).perform(new EnableLocationTrackingAction(mapboxMap));
onView(withId(R.id.userLocationView)).check(matches(isDisplayed()));
@@ -91,11 +77,6 @@ public class MyLocationViewTest {
R.drawable.mapbox_mylocation_icon_bearing, true)));
}
- @After
- public void afterTest() {
- Espresso.unregisterIdlingResources(idlingResource);
- }
-
private class ToggleLocationAction implements ViewAction {
private MapboxMap mapboxMap;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BackgroundLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BackgroundLayerTest.java
index 510f477bce..851660f06e 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BackgroundLayerTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BackgroundLayerTest.java
@@ -22,6 +22,7 @@ import com.mapbox.mapboxsdk.style.layers.BackgroundLayer;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.activity.style.RuntimeStyleTestActivity;
import com.mapbox.mapboxsdk.testapp.utils.OnMapReadyIdlingResource;
+import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest;
import org.junit.After;
import org.junit.Before;
@@ -36,34 +37,31 @@ import static org.junit.Assert.*;
import static com.mapbox.mapboxsdk.style.layers.Property.*;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.*;
+import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
+import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity;
+
/**
* Basic smoke tests for BackgroundLayer
*/
@RunWith(AndroidJUnit4.class)
-public class BackgroundLayerTest extends BaseStyleTest {
-
- @Rule
- public final ActivityTestRule<RuntimeStyleTestActivity> rule = new ActivityTestRule<>(RuntimeStyleTestActivity.class);
+public class BackgroundLayerTest extends BaseActivityTest {
private BackgroundLayer layer;
- private OnMapReadyIdlingResource idlingResource;
-
- private MapboxMap mapboxMap;
-
- @Before
- public void setup() {
- idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
- Espresso.registerIdlingResources(idlingResource);
- mapboxMap = rule.getActivity().getMapboxMap();
+ @Override
+ protected Class getActivityClass() {
+ return EspressoTestActivity.class;
+ }
+ private void setupLayer(){
Timber.i("Retrieving layer");
layer = mapboxMap.getLayerAs("background");
}
@Test
public void testSetVisibility() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("Visibility");
assertNotNull(layer);
@@ -76,8 +74,22 @@ public class BackgroundLayerTest extends BaseStyleTest {
}
@Test
+ public void testBackgroundColorTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("background-colorTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setBackgroundColorTransition(options);
+ assertEquals(layer.getBackgroundColorTransition(), options);
+ }
+
+ @Test
public void testBackgroundColorAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("background-color");
assertNotNull(layer);
@@ -88,7 +100,8 @@ public class BackgroundLayerTest extends BaseStyleTest {
@Test
public void testBackgroundColorAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("background-color");
assertNotNull(layer);
@@ -114,7 +127,8 @@ public class BackgroundLayerTest extends BaseStyleTest {
@Test
public void testBackgroundColorAsIntConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("background-color");
assertNotNull(layer);
@@ -124,8 +138,22 @@ public class BackgroundLayerTest extends BaseStyleTest {
}
@Test
+ public void testBackgroundPatternTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("background-patternTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setBackgroundPatternTransition(options);
+ assertEquals(layer.getBackgroundPatternTransition(), options);
+ }
+
+ @Test
public void testBackgroundPatternAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("background-pattern");
assertNotNull(layer);
@@ -136,7 +164,8 @@ public class BackgroundLayerTest extends BaseStyleTest {
@Test
public void testBackgroundPatternAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("background-pattern");
assertNotNull(layer);
@@ -160,8 +189,22 @@ public class BackgroundLayerTest extends BaseStyleTest {
}
@Test
+ public void testBackgroundOpacityTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("background-opacityTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setBackgroundOpacityTransition(options);
+ assertEquals(layer.getBackgroundOpacityTransition(), options);
+ }
+
+ @Test
public void testBackgroundOpacityAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("background-opacity");
assertNotNull(layer);
@@ -172,7 +215,8 @@ public class BackgroundLayerTest extends BaseStyleTest {
@Test
public void testBackgroundOpacityAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("background-opacity");
assertNotNull(layer);
@@ -196,9 +240,4 @@ public class BackgroundLayerTest extends BaseStyleTest {
assertEquals(1, ((ExponentialStops) layer.getBackgroundOpacity().getFunction().getStops()).size());
}
-
- @After
- public void unregisterIntentServiceIdlingResource() {
- Espresso.unregisterIdlingResources(idlingResource);
- }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BaseStyleTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BaseStyleTest.java
index 620e15579f..3d56752150 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BaseStyleTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BaseStyleTest.java
@@ -1,44 +1,15 @@
package com.mapbox.mapboxsdk.testapp.style;
-import android.app.Activity;
-
-import com.mapbox.mapboxsdk.testapp.utils.ScreenshotUtil;
-
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.assertion.ViewAssertions.matches;
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest;
+import com.mapbox.mapboxsdk.testapp.activity.style.RuntimeStyleTestActivity;
/**
* Base Test class for Style tests
*/
-public class BaseStyleTest {
-
- protected static final String HOME_BUTTON_STRING = "Navigate up";
-
- /*
- * Shortcuts for common UI tests
- */
-
- protected void checkViewIsDisplayed(int id) {
- onView(withId(id))
- .check(matches(isDisplayed()));
- }
-
- /*
- * Screenshots logic
- */
-
- protected void takeNamedScreenshot(final Activity activity, final String name) {
-
- // Screenshots need to be taken on the UI thread
- activity.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- ScreenshotUtil.take(activity, name);
- }
- });
+public class BaseStyleTest extends BaseActivityTest {
+ @Override
+ protected Class getActivityClass() {
+ return RuntimeStyleTestActivity.class;
}
-
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerTest.java
index a8f35356b5..bf31a935f8 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerTest.java
@@ -22,6 +22,7 @@ import com.mapbox.mapboxsdk.style.layers.CircleLayer;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.activity.style.RuntimeStyleTestActivity;
import com.mapbox.mapboxsdk.testapp.utils.OnMapReadyIdlingResource;
+import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest;
import org.junit.After;
import org.junit.Before;
@@ -36,27 +37,23 @@ import static org.junit.Assert.*;
import static com.mapbox.mapboxsdk.style.layers.Property.*;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.*;
+import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
+import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity;
+
/**
* Basic smoke tests for CircleLayer
*/
@RunWith(AndroidJUnit4.class)
-public class CircleLayerTest extends BaseStyleTest {
-
- @Rule
- public final ActivityTestRule<RuntimeStyleTestActivity> rule = new ActivityTestRule<>(RuntimeStyleTestActivity.class);
+public class CircleLayerTest extends BaseActivityTest {
private CircleLayer layer;
- private OnMapReadyIdlingResource idlingResource;
-
- private MapboxMap mapboxMap;
-
- @Before
- public void setup() {
- idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
- Espresso.registerIdlingResources(idlingResource);
- mapboxMap = rule.getActivity().getMapboxMap();
+ @Override
+ protected Class getActivityClass() {
+ return EspressoTestActivity.class;
+ }
+ private void setupLayer(){
if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
Timber.i("Adding layer");
layer = new CircleLayer("my-layer", "composite");
@@ -69,7 +66,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testSetVisibility() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("Visibility");
assertNotNull(layer);
@@ -82,8 +80,38 @@ public class CircleLayerTest extends BaseStyleTest {
}
@Test
+ public void testSourceLayer() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("SourceLayer");
+ assertNotNull(layer);
+
+ // Get initial
+ assertEquals(layer.getSourceLayer(), "composite");
+
+ // Set
+ final String sourceLayer = "test";
+ layer.setSourceLayer(sourceLayer);
+ assertEquals(layer.getSourceLayer(), sourceLayer);
+ }
+
+ @Test
+ public void testCircleRadiusTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("circle-radiusTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setCircleRadiusTransition(options);
+ assertEquals(layer.getCircleRadiusTransition(), options);
+ }
+
+ @Test
public void testCircleRadiusAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-radius");
assertNotNull(layer);
@@ -94,7 +122,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCircleRadiusAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-radius");
assertNotNull(layer);
@@ -120,7 +149,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCircleRadiusAsIdentitySourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-radius");
assertNotNull(layer);
@@ -139,7 +169,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCircleRadiusAsExponentialSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-radius");
assertNotNull(layer);
@@ -165,7 +196,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCircleRadiusAsCategoricalSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-radius");
assertNotNull(layer);
@@ -194,7 +226,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCircleRadiusAsCompositeFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-radius");
assertNotNull(layer);
@@ -227,8 +260,22 @@ public class CircleLayerTest extends BaseStyleTest {
}
@Test
+ public void testCircleColorTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("circle-colorTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setCircleColorTransition(options);
+ assertEquals(layer.getCircleColorTransition(), options);
+ }
+
+ @Test
public void testCircleColorAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-color");
assertNotNull(layer);
@@ -239,7 +286,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCircleColorAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-color");
assertNotNull(layer);
@@ -265,7 +313,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCircleColorAsIdentitySourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-color");
assertNotNull(layer);
@@ -284,7 +333,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCircleColorAsExponentialSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-color");
assertNotNull(layer);
@@ -310,7 +360,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCircleColorAsCategoricalSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-color");
assertNotNull(layer);
@@ -339,7 +390,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCircleColorAsIntConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-color");
assertNotNull(layer);
@@ -349,8 +401,22 @@ public class CircleLayerTest extends BaseStyleTest {
}
@Test
+ public void testCircleBlurTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("circle-blurTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setCircleBlurTransition(options);
+ assertEquals(layer.getCircleBlurTransition(), options);
+ }
+
+ @Test
public void testCircleBlurAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-blur");
assertNotNull(layer);
@@ -361,7 +427,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCircleBlurAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-blur");
assertNotNull(layer);
@@ -387,7 +454,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCircleBlurAsIdentitySourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-blur");
assertNotNull(layer);
@@ -406,7 +474,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCircleBlurAsExponentialSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-blur");
assertNotNull(layer);
@@ -432,7 +501,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCircleBlurAsCategoricalSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-blur");
assertNotNull(layer);
@@ -461,7 +531,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCircleBlurAsCompositeFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-blur");
assertNotNull(layer);
@@ -494,8 +565,22 @@ public class CircleLayerTest extends BaseStyleTest {
}
@Test
+ public void testCircleOpacityTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("circle-opacityTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setCircleOpacityTransition(options);
+ assertEquals(layer.getCircleOpacityTransition(), options);
+ }
+
+ @Test
public void testCircleOpacityAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-opacity");
assertNotNull(layer);
@@ -506,7 +591,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCircleOpacityAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-opacity");
assertNotNull(layer);
@@ -532,7 +618,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCircleOpacityAsIdentitySourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-opacity");
assertNotNull(layer);
@@ -551,7 +638,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCircleOpacityAsExponentialSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-opacity");
assertNotNull(layer);
@@ -577,7 +665,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCircleOpacityAsCategoricalSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-opacity");
assertNotNull(layer);
@@ -606,7 +695,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCircleOpacityAsCompositeFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-opacity");
assertNotNull(layer);
@@ -639,8 +729,22 @@ public class CircleLayerTest extends BaseStyleTest {
}
@Test
+ public void testCircleTranslateTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("circle-translateTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setCircleTranslateTransition(options);
+ assertEquals(layer.getCircleTranslateTransition(), options);
+ }
+
+ @Test
public void testCircleTranslateAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-translate");
assertNotNull(layer);
@@ -651,7 +755,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCircleTranslateAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-translate");
assertNotNull(layer);
@@ -677,7 +782,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCircleTranslateAnchorAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-translate-anchor");
assertNotNull(layer);
@@ -688,7 +794,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCircleTranslateAnchorAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-translate-anchor");
assertNotNull(layer);
@@ -713,7 +820,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCirclePitchScaleAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-pitch-scale");
assertNotNull(layer);
@@ -724,7 +832,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCirclePitchScaleAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-pitch-scale");
assertNotNull(layer);
@@ -748,8 +857,22 @@ public class CircleLayerTest extends BaseStyleTest {
}
@Test
+ public void testCircleStrokeWidthTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("circle-stroke-widthTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setCircleStrokeWidthTransition(options);
+ assertEquals(layer.getCircleStrokeWidthTransition(), options);
+ }
+
+ @Test
public void testCircleStrokeWidthAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-stroke-width");
assertNotNull(layer);
@@ -760,7 +883,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCircleStrokeWidthAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-stroke-width");
assertNotNull(layer);
@@ -786,7 +910,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCircleStrokeWidthAsIdentitySourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-stroke-width");
assertNotNull(layer);
@@ -805,7 +930,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCircleStrokeWidthAsExponentialSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-stroke-width");
assertNotNull(layer);
@@ -831,7 +957,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCircleStrokeWidthAsCategoricalSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-stroke-width");
assertNotNull(layer);
@@ -860,7 +987,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCircleStrokeWidthAsCompositeFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-stroke-width");
assertNotNull(layer);
@@ -893,8 +1021,22 @@ public class CircleLayerTest extends BaseStyleTest {
}
@Test
+ public void testCircleStrokeColorTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("circle-stroke-colorTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setCircleStrokeColorTransition(options);
+ assertEquals(layer.getCircleStrokeColorTransition(), options);
+ }
+
+ @Test
public void testCircleStrokeColorAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-stroke-color");
assertNotNull(layer);
@@ -905,7 +1047,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCircleStrokeColorAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-stroke-color");
assertNotNull(layer);
@@ -931,7 +1074,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCircleStrokeColorAsIdentitySourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-stroke-color");
assertNotNull(layer);
@@ -950,7 +1094,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCircleStrokeColorAsExponentialSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-stroke-color");
assertNotNull(layer);
@@ -976,7 +1121,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCircleStrokeColorAsCategoricalSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-stroke-color");
assertNotNull(layer);
@@ -1005,7 +1151,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCircleStrokeColorAsIntConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-stroke-color");
assertNotNull(layer);
@@ -1015,8 +1162,22 @@ public class CircleLayerTest extends BaseStyleTest {
}
@Test
+ public void testCircleStrokeOpacityTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("circle-stroke-opacityTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setCircleStrokeOpacityTransition(options);
+ assertEquals(layer.getCircleStrokeOpacityTransition(), options);
+ }
+
+ @Test
public void testCircleStrokeOpacityAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-stroke-opacity");
assertNotNull(layer);
@@ -1027,7 +1188,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCircleStrokeOpacityAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-stroke-opacity");
assertNotNull(layer);
@@ -1053,7 +1215,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCircleStrokeOpacityAsIdentitySourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-stroke-opacity");
assertNotNull(layer);
@@ -1072,7 +1235,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCircleStrokeOpacityAsExponentialSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-stroke-opacity");
assertNotNull(layer);
@@ -1098,7 +1262,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCircleStrokeOpacityAsCategoricalSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-stroke-opacity");
assertNotNull(layer);
@@ -1127,7 +1292,8 @@ public class CircleLayerTest extends BaseStyleTest {
@Test
public void testCircleStrokeOpacityAsCompositeFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("circle-stroke-opacity");
assertNotNull(layer);
@@ -1159,9 +1325,4 @@ public class CircleLayerTest extends BaseStyleTest {
assertEquals(0.9f, stop.out, 0.001f);
}
-
- @After
- public void unregisterIntentServiceIdlingResource() {
- Espresso.unregisterIdlingResources(idlingResource);
- }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillExtrusionLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillExtrusionLayerTest.java
new file mode 100644
index 0000000000..fec9a6c119
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillExtrusionLayerTest.java
@@ -0,0 +1,760 @@
+// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
+
+package com.mapbox.mapboxsdk.testapp.style;
+
+import android.graphics.Color;
+import android.support.test.espresso.Espresso;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import timber.log.Timber;
+
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.style.functions.CompositeFunction;
+import com.mapbox.mapboxsdk.style.functions.CameraFunction;
+import com.mapbox.mapboxsdk.style.functions.SourceFunction;
+import com.mapbox.mapboxsdk.style.functions.stops.CategoricalStops;
+import com.mapbox.mapboxsdk.style.functions.stops.ExponentialStops;
+import com.mapbox.mapboxsdk.style.functions.stops.IdentityStops;
+import com.mapbox.mapboxsdk.style.functions.stops.IntervalStops;
+import com.mapbox.mapboxsdk.style.functions.stops.Stop;
+import com.mapbox.mapboxsdk.style.functions.stops.Stops;
+import com.mapbox.mapboxsdk.style.layers.FillExtrusionLayer;
+import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.style.RuntimeStyleTestActivity;
+import com.mapbox.mapboxsdk.testapp.utils.OnMapReadyIdlingResource;
+import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest;
+
+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.functions.Function.*;
+import static com.mapbox.mapboxsdk.style.functions.stops.Stop.stop;
+import static com.mapbox.mapboxsdk.style.functions.stops.Stops.*;
+import static org.junit.Assert.*;
+import static com.mapbox.mapboxsdk.style.layers.Property.*;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.*;
+
+import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
+import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity;
+
+/**
+ * Basic smoke tests for FillExtrusionLayer
+ */
+@RunWith(AndroidJUnit4.class)
+public class FillExtrusionLayerTest extends BaseActivityTest {
+
+ private FillExtrusionLayer layer;
+
+ @Override
+ protected Class getActivityClass() {
+ return EspressoTestActivity.class;
+ }
+
+ private void setupLayer(){
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Timber.i("Adding layer");
+ layer = new FillExtrusionLayer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ // Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
+ }
+ }
+
+ @Test
+ public void testSetVisibility() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("Visibility");
+ assertNotNull(layer);
+
+ // Get initial
+ assertEquals(layer.getVisibility().getValue(), VISIBLE);
+
+ // Set
+ layer.setProperties(visibility(NONE));
+ assertEquals(layer.getVisibility().getValue(), NONE);
+ }
+
+ @Test
+ public void testSourceLayer() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("SourceLayer");
+ assertNotNull(layer);
+
+ // Get initial
+ assertEquals(layer.getSourceLayer(), "composite");
+
+ // Set
+ final String sourceLayer = "test";
+ layer.setSourceLayer(sourceLayer);
+ assertEquals(layer.getSourceLayer(), sourceLayer);
+ }
+
+ @Test
+ public void testFillExtrusionOpacityTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("fill-extrusion-opacityTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setFillExtrusionOpacityTransition(options);
+ assertEquals(layer.getFillExtrusionOpacityTransition(), options);
+ }
+
+ @Test
+ public void testFillExtrusionOpacityAsConstant() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("fill-extrusion-opacity");
+ assertNotNull(layer);
+
+ // Set and Get
+ layer.setProperties(fillExtrusionOpacity(0.3f));
+ assertEquals((Float) layer.getFillExtrusionOpacity().getValue(), (Float) 0.3f);
+ }
+
+ @Test
+ public void testFillExtrusionOpacityAsCameraFunction() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("fill-extrusion-opacity");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ fillExtrusionOpacity(
+ zoom(
+ exponential(
+ stop(2, fillExtrusionOpacity(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getFillExtrusionOpacity());
+ assertNotNull(layer.getFillExtrusionOpacity().getFunction());
+ assertEquals(CameraFunction.class, layer.getFillExtrusionOpacity().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getFillExtrusionOpacity().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getFillExtrusionOpacity().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getFillExtrusionOpacity().getFunction().getStops()).size());
+ }
+
+ @Test
+ public void testFillExtrusionColorTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("fill-extrusion-colorTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setFillExtrusionColorTransition(options);
+ assertEquals(layer.getFillExtrusionColorTransition(), options);
+ }
+
+ @Test
+ public void testFillExtrusionColorAsConstant() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("fill-extrusion-color");
+ assertNotNull(layer);
+
+ // Set and Get
+ layer.setProperties(fillExtrusionColor("rgba(0, 0, 0, 1)"));
+ assertEquals((String) layer.getFillExtrusionColor().getValue(), (String) "rgba(0, 0, 0, 1)");
+ }
+
+ @Test
+ public void testFillExtrusionColorAsCameraFunction() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("fill-extrusion-color");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ fillExtrusionColor(
+ zoom(
+ exponential(
+ stop(2, fillExtrusionColor("rgba(0, 0, 0, 1)"))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getFillExtrusionColor());
+ assertNotNull(layer.getFillExtrusionColor().getFunction());
+ assertEquals(CameraFunction.class, layer.getFillExtrusionColor().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getFillExtrusionColor().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getFillExtrusionColor().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getFillExtrusionColor().getFunction().getStops()).size());
+ }
+
+ @Test
+ public void testFillExtrusionColorAsIdentitySourceFunction() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("fill-extrusion-color");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ fillExtrusionColor(property("FeaturePropertyA", Stops.<String>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getFillExtrusionColor());
+ assertNotNull(layer.getFillExtrusionColor().getFunction());
+ assertEquals(SourceFunction.class, layer.getFillExtrusionColor().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getFillExtrusionColor().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getFillExtrusionColor().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testFillExtrusionColorAsExponentialSourceFunction() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("fill-extrusion-color");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ fillExtrusionColor(
+ property(
+ "FeaturePropertyA",
+ exponential(
+ stop(Color.RED, fillExtrusionColor(Color.RED))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getFillExtrusionColor());
+ assertNotNull(layer.getFillExtrusionColor().getFunction());
+ assertEquals(SourceFunction.class, layer.getFillExtrusionColor().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getFillExtrusionColor().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getFillExtrusionColor().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testFillExtrusionColorAsCategoricalSourceFunction() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("fill-extrusion-color");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ fillExtrusionColor(
+ property(
+ "FeaturePropertyA",
+ categorical(
+ stop("valueA", fillExtrusionColor(Color.RED))
+ )
+ ).withDefaultValue(fillExtrusionColor(Color.GREEN))
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getFillExtrusionColor());
+ assertNotNull(layer.getFillExtrusionColor().getFunction());
+ assertEquals(SourceFunction.class, layer.getFillExtrusionColor().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getFillExtrusionColor().getFunction()).getProperty());
+ assertEquals(CategoricalStops.class, layer.getFillExtrusionColor().getFunction().getStops().getClass());
+ assertNotNull(((SourceFunction) layer.getFillExtrusionColor().getFunction()).getDefaultValue());
+ assertNotNull(((SourceFunction) layer.getFillExtrusionColor().getFunction()).getDefaultValue().getValue());
+ assertEquals(Color.GREEN, (int) ((SourceFunction) layer.getFillExtrusionColor().getFunction()).getDefaultValue().getColorInt());
+ }
+
+ @Test
+ public void testFillExtrusionColorAsIntConstant() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("fill-extrusion-color");
+ assertNotNull(layer);
+
+ // Set and Get
+ layer.setProperties(fillExtrusionColor(Color.RED));
+ assertEquals(layer.getFillExtrusionColorAsInt(), Color.RED);
+ }
+
+ @Test
+ public void testFillExtrusionTranslateTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("fill-extrusion-translateTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setFillExtrusionTranslateTransition(options);
+ assertEquals(layer.getFillExtrusionTranslateTransition(), options);
+ }
+
+ @Test
+ public void testFillExtrusionTranslateAsConstant() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("fill-extrusion-translate");
+ assertNotNull(layer);
+
+ // Set and Get
+ layer.setProperties(fillExtrusionTranslate(new Float[]{0f,0f}));
+ assertEquals((Float[]) layer.getFillExtrusionTranslate().getValue(), (Float[]) new Float[]{0f,0f});
+ }
+
+ @Test
+ public void testFillExtrusionTranslateAsCameraFunction() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("fill-extrusion-translate");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ fillExtrusionTranslate(
+ zoom(
+ exponential(
+ stop(2, fillExtrusionTranslate(new Float[]{0f,0f}))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getFillExtrusionTranslate());
+ assertNotNull(layer.getFillExtrusionTranslate().getFunction());
+ assertEquals(CameraFunction.class, layer.getFillExtrusionTranslate().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getFillExtrusionTranslate().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getFillExtrusionTranslate().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getFillExtrusionTranslate().getFunction().getStops()).size());
+ }
+
+ @Test
+ public void testFillExtrusionTranslateAnchorAsConstant() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("fill-extrusion-translate-anchor");
+ assertNotNull(layer);
+
+ // Set and Get
+ layer.setProperties(fillExtrusionTranslateAnchor(FILL_EXTRUSION_TRANSLATE_ANCHOR_MAP));
+ assertEquals((String) layer.getFillExtrusionTranslateAnchor().getValue(), (String) FILL_EXTRUSION_TRANSLATE_ANCHOR_MAP);
+ }
+
+ @Test
+ public void testFillExtrusionTranslateAnchorAsCameraFunction() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("fill-extrusion-translate-anchor");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ fillExtrusionTranslateAnchor(
+ zoom(
+ interval(
+ stop(2, fillExtrusionTranslateAnchor(FILL_EXTRUSION_TRANSLATE_ANCHOR_MAP))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getFillExtrusionTranslateAnchor());
+ assertNotNull(layer.getFillExtrusionTranslateAnchor().getFunction());
+ assertEquals(CameraFunction.class, layer.getFillExtrusionTranslateAnchor().getFunction().getClass());
+ assertEquals(IntervalStops.class, layer.getFillExtrusionTranslateAnchor().getFunction().getStops().getClass());
+ assertEquals(1, ((IntervalStops) layer.getFillExtrusionTranslateAnchor().getFunction().getStops()).size());
+ }
+
+ @Test
+ public void testFillExtrusionPatternTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("fill-extrusion-patternTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setFillExtrusionPatternTransition(options);
+ assertEquals(layer.getFillExtrusionPatternTransition(), options);
+ }
+
+ @Test
+ public void testFillExtrusionPatternAsConstant() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("fill-extrusion-pattern");
+ assertNotNull(layer);
+
+ // Set and Get
+ layer.setProperties(fillExtrusionPattern("pedestrian-polygon"));
+ assertEquals((String) layer.getFillExtrusionPattern().getValue(), (String) "pedestrian-polygon");
+ }
+
+ @Test
+ public void testFillExtrusionPatternAsCameraFunction() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("fill-extrusion-pattern");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ fillExtrusionPattern(
+ zoom(
+ interval(
+ stop(2, fillExtrusionPattern("pedestrian-polygon"))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getFillExtrusionPattern());
+ assertNotNull(layer.getFillExtrusionPattern().getFunction());
+ assertEquals(CameraFunction.class, layer.getFillExtrusionPattern().getFunction().getClass());
+ assertEquals(IntervalStops.class, layer.getFillExtrusionPattern().getFunction().getStops().getClass());
+ assertEquals(1, ((IntervalStops) layer.getFillExtrusionPattern().getFunction().getStops()).size());
+ }
+
+ @Test
+ public void testFillExtrusionHeightTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("fill-extrusion-heightTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setFillExtrusionHeightTransition(options);
+ assertEquals(layer.getFillExtrusionHeightTransition(), options);
+ }
+
+ @Test
+ public void testFillExtrusionHeightAsConstant() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("fill-extrusion-height");
+ assertNotNull(layer);
+
+ // Set and Get
+ layer.setProperties(fillExtrusionHeight(0.3f));
+ assertEquals((Float) layer.getFillExtrusionHeight().getValue(), (Float) 0.3f);
+ }
+
+ @Test
+ public void testFillExtrusionHeightAsCameraFunction() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("fill-extrusion-height");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ fillExtrusionHeight(
+ zoom(
+ exponential(
+ stop(2, fillExtrusionHeight(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getFillExtrusionHeight());
+ assertNotNull(layer.getFillExtrusionHeight().getFunction());
+ assertEquals(CameraFunction.class, layer.getFillExtrusionHeight().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getFillExtrusionHeight().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getFillExtrusionHeight().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getFillExtrusionHeight().getFunction().getStops()).size());
+ }
+
+ @Test
+ public void testFillExtrusionHeightAsIdentitySourceFunction() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("fill-extrusion-height");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ fillExtrusionHeight(property("FeaturePropertyA", Stops.<Float>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getFillExtrusionHeight());
+ assertNotNull(layer.getFillExtrusionHeight().getFunction());
+ assertEquals(SourceFunction.class, layer.getFillExtrusionHeight().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getFillExtrusionHeight().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getFillExtrusionHeight().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testFillExtrusionHeightAsExponentialSourceFunction() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("fill-extrusion-height");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ fillExtrusionHeight(
+ property(
+ "FeaturePropertyA",
+ exponential(
+ stop(0.3f, fillExtrusionHeight(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getFillExtrusionHeight());
+ assertNotNull(layer.getFillExtrusionHeight().getFunction());
+ assertEquals(SourceFunction.class, layer.getFillExtrusionHeight().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getFillExtrusionHeight().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getFillExtrusionHeight().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testFillExtrusionHeightAsCategoricalSourceFunction() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("fill-extrusion-height");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ fillExtrusionHeight(
+ property(
+ "FeaturePropertyA",
+ categorical(
+ stop(1.0f, fillExtrusionHeight(0.3f))
+ )
+ ).withDefaultValue(fillExtrusionHeight(0.3f))
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getFillExtrusionHeight());
+ assertNotNull(layer.getFillExtrusionHeight().getFunction());
+ assertEquals(SourceFunction.class, layer.getFillExtrusionHeight().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getFillExtrusionHeight().getFunction()).getProperty());
+ assertEquals(CategoricalStops.class, layer.getFillExtrusionHeight().getFunction().getStops().getClass());
+ assertNotNull(((SourceFunction) layer.getFillExtrusionHeight().getFunction()).getDefaultValue());
+ assertNotNull(((SourceFunction) layer.getFillExtrusionHeight().getFunction()).getDefaultValue().getValue());
+ assertEquals(0.3f, ((SourceFunction) layer.getFillExtrusionHeight().getFunction()).getDefaultValue().getValue());
+ }
+
+ @Test
+ public void testFillExtrusionHeightAsCompositeFunction() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("fill-extrusion-height");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ fillExtrusionHeight(
+ composite(
+ "FeaturePropertyA",
+ exponential(
+ stop(0, 0.3f, fillExtrusionHeight(0.9f))
+ ).withBase(0.5f)
+ ).withDefaultValue(fillExtrusionHeight(0.3f))
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getFillExtrusionHeight());
+ assertNotNull(layer.getFillExtrusionHeight().getFunction());
+ assertEquals(CompositeFunction.class, layer.getFillExtrusionHeight().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((CompositeFunction) layer.getFillExtrusionHeight().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getFillExtrusionHeight().getFunction().getStops().getClass());
+ assertEquals(1, ((ExponentialStops) layer.getFillExtrusionHeight().getFunction().getStops()).size());
+
+ ExponentialStops<Stop.CompositeValue<Float, Float>, Float> stops =
+ (ExponentialStops<Stop.CompositeValue<Float, Float>, Float>) layer.getFillExtrusionHeight().getFunction().getStops();
+ Stop<Stop.CompositeValue<Float, Float>, Float> stop = stops.iterator().next();
+ assertEquals(0f, stop.in.zoom, 0.001);
+ assertEquals(0.3f, stop.in.value, 0.001f);
+ assertEquals(0.9f, stop.out, 0.001f);
+ }
+
+ @Test
+ public void testFillExtrusionBaseTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("fill-extrusion-baseTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setFillExtrusionBaseTransition(options);
+ assertEquals(layer.getFillExtrusionBaseTransition(), options);
+ }
+
+ @Test
+ public void testFillExtrusionBaseAsConstant() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("fill-extrusion-base");
+ assertNotNull(layer);
+
+ // Set and Get
+ layer.setProperties(fillExtrusionBase(0.3f));
+ assertEquals((Float) layer.getFillExtrusionBase().getValue(), (Float) 0.3f);
+ }
+
+ @Test
+ public void testFillExtrusionBaseAsCameraFunction() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("fill-extrusion-base");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ fillExtrusionBase(
+ zoom(
+ exponential(
+ stop(2, fillExtrusionBase(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getFillExtrusionBase());
+ assertNotNull(layer.getFillExtrusionBase().getFunction());
+ assertEquals(CameraFunction.class, layer.getFillExtrusionBase().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getFillExtrusionBase().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getFillExtrusionBase().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getFillExtrusionBase().getFunction().getStops()).size());
+ }
+
+ @Test
+ public void testFillExtrusionBaseAsIdentitySourceFunction() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("fill-extrusion-base");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ fillExtrusionBase(property("FeaturePropertyA", Stops.<Float>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getFillExtrusionBase());
+ assertNotNull(layer.getFillExtrusionBase().getFunction());
+ assertEquals(SourceFunction.class, layer.getFillExtrusionBase().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getFillExtrusionBase().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getFillExtrusionBase().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testFillExtrusionBaseAsExponentialSourceFunction() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("fill-extrusion-base");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ fillExtrusionBase(
+ property(
+ "FeaturePropertyA",
+ exponential(
+ stop(0.3f, fillExtrusionBase(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getFillExtrusionBase());
+ assertNotNull(layer.getFillExtrusionBase().getFunction());
+ assertEquals(SourceFunction.class, layer.getFillExtrusionBase().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getFillExtrusionBase().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getFillExtrusionBase().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testFillExtrusionBaseAsCategoricalSourceFunction() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("fill-extrusion-base");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ fillExtrusionBase(
+ property(
+ "FeaturePropertyA",
+ categorical(
+ stop(1.0f, fillExtrusionBase(0.3f))
+ )
+ ).withDefaultValue(fillExtrusionBase(0.3f))
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getFillExtrusionBase());
+ assertNotNull(layer.getFillExtrusionBase().getFunction());
+ assertEquals(SourceFunction.class, layer.getFillExtrusionBase().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getFillExtrusionBase().getFunction()).getProperty());
+ assertEquals(CategoricalStops.class, layer.getFillExtrusionBase().getFunction().getStops().getClass());
+ assertNotNull(((SourceFunction) layer.getFillExtrusionBase().getFunction()).getDefaultValue());
+ assertNotNull(((SourceFunction) layer.getFillExtrusionBase().getFunction()).getDefaultValue().getValue());
+ assertEquals(0.3f, ((SourceFunction) layer.getFillExtrusionBase().getFunction()).getDefaultValue().getValue());
+ }
+
+ @Test
+ public void testFillExtrusionBaseAsCompositeFunction() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("fill-extrusion-base");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ fillExtrusionBase(
+ composite(
+ "FeaturePropertyA",
+ exponential(
+ stop(0, 0.3f, fillExtrusionBase(0.9f))
+ ).withBase(0.5f)
+ ).withDefaultValue(fillExtrusionBase(0.3f))
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getFillExtrusionBase());
+ assertNotNull(layer.getFillExtrusionBase().getFunction());
+ assertEquals(CompositeFunction.class, layer.getFillExtrusionBase().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((CompositeFunction) layer.getFillExtrusionBase().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getFillExtrusionBase().getFunction().getStops().getClass());
+ assertEquals(1, ((ExponentialStops) layer.getFillExtrusionBase().getFunction().getStops()).size());
+
+ ExponentialStops<Stop.CompositeValue<Float, Float>, Float> stops =
+ (ExponentialStops<Stop.CompositeValue<Float, Float>, Float>) layer.getFillExtrusionBase().getFunction().getStops();
+ Stop<Stop.CompositeValue<Float, Float>, Float> stop = stops.iterator().next();
+ assertEquals(0f, stop.in.zoom, 0.001);
+ assertEquals(0.3f, stop.in.value, 0.001f);
+ assertEquals(0.9f, stop.out, 0.001f);
+ }
+
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerTest.java
index a1d362f0f9..b6b6578839 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerTest.java
@@ -22,6 +22,7 @@ import com.mapbox.mapboxsdk.style.layers.FillLayer;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.activity.style.RuntimeStyleTestActivity;
import com.mapbox.mapboxsdk.testapp.utils.OnMapReadyIdlingResource;
+import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest;
import org.junit.After;
import org.junit.Before;
@@ -36,27 +37,23 @@ import static org.junit.Assert.*;
import static com.mapbox.mapboxsdk.style.layers.Property.*;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.*;
+import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
+import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity;
+
/**
* Basic smoke tests for FillLayer
*/
@RunWith(AndroidJUnit4.class)
-public class FillLayerTest extends BaseStyleTest {
-
- @Rule
- public final ActivityTestRule<RuntimeStyleTestActivity> rule = new ActivityTestRule<>(RuntimeStyleTestActivity.class);
+public class FillLayerTest extends BaseActivityTest {
private FillLayer layer;
- private OnMapReadyIdlingResource idlingResource;
-
- private MapboxMap mapboxMap;
-
- @Before
- public void setup() {
- idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
- Espresso.registerIdlingResources(idlingResource);
- mapboxMap = rule.getActivity().getMapboxMap();
+ @Override
+ protected Class getActivityClass() {
+ return EspressoTestActivity.class;
+ }
+ private void setupLayer(){
if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
Timber.i("Adding layer");
layer = new FillLayer("my-layer", "composite");
@@ -69,7 +66,8 @@ public class FillLayerTest extends BaseStyleTest {
@Test
public void testSetVisibility() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("Visibility");
assertNotNull(layer);
@@ -82,8 +80,25 @@ public class FillLayerTest extends BaseStyleTest {
}
@Test
+ public void testSourceLayer() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("SourceLayer");
+ assertNotNull(layer);
+
+ // Get initial
+ assertEquals(layer.getSourceLayer(), "composite");
+
+ // Set
+ final String sourceLayer = "test";
+ layer.setSourceLayer(sourceLayer);
+ assertEquals(layer.getSourceLayer(), sourceLayer);
+ }
+
+ @Test
public void testFillAntialiasAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("fill-antialias");
assertNotNull(layer);
@@ -94,7 +109,8 @@ public class FillLayerTest extends BaseStyleTest {
@Test
public void testFillAntialiasAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("fill-antialias");
assertNotNull(layer);
@@ -118,8 +134,22 @@ public class FillLayerTest extends BaseStyleTest {
}
@Test
+ public void testFillOpacityTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("fill-opacityTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setFillOpacityTransition(options);
+ assertEquals(layer.getFillOpacityTransition(), options);
+ }
+
+ @Test
public void testFillOpacityAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("fill-opacity");
assertNotNull(layer);
@@ -130,7 +160,8 @@ public class FillLayerTest extends BaseStyleTest {
@Test
public void testFillOpacityAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("fill-opacity");
assertNotNull(layer);
@@ -156,7 +187,8 @@ public class FillLayerTest extends BaseStyleTest {
@Test
public void testFillOpacityAsIdentitySourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("fill-opacity");
assertNotNull(layer);
@@ -175,7 +207,8 @@ public class FillLayerTest extends BaseStyleTest {
@Test
public void testFillOpacityAsExponentialSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("fill-opacity");
assertNotNull(layer);
@@ -201,7 +234,8 @@ public class FillLayerTest extends BaseStyleTest {
@Test
public void testFillOpacityAsCategoricalSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("fill-opacity");
assertNotNull(layer);
@@ -230,7 +264,8 @@ public class FillLayerTest extends BaseStyleTest {
@Test
public void testFillOpacityAsCompositeFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("fill-opacity");
assertNotNull(layer);
@@ -263,8 +298,22 @@ public class FillLayerTest extends BaseStyleTest {
}
@Test
+ public void testFillColorTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("fill-colorTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setFillColorTransition(options);
+ assertEquals(layer.getFillColorTransition(), options);
+ }
+
+ @Test
public void testFillColorAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("fill-color");
assertNotNull(layer);
@@ -275,7 +324,8 @@ public class FillLayerTest extends BaseStyleTest {
@Test
public void testFillColorAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("fill-color");
assertNotNull(layer);
@@ -301,7 +351,8 @@ public class FillLayerTest extends BaseStyleTest {
@Test
public void testFillColorAsIdentitySourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("fill-color");
assertNotNull(layer);
@@ -320,7 +371,8 @@ public class FillLayerTest extends BaseStyleTest {
@Test
public void testFillColorAsExponentialSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("fill-color");
assertNotNull(layer);
@@ -346,7 +398,8 @@ public class FillLayerTest extends BaseStyleTest {
@Test
public void testFillColorAsCategoricalSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("fill-color");
assertNotNull(layer);
@@ -375,7 +428,8 @@ public class FillLayerTest extends BaseStyleTest {
@Test
public void testFillColorAsIntConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("fill-color");
assertNotNull(layer);
@@ -385,8 +439,22 @@ public class FillLayerTest extends BaseStyleTest {
}
@Test
+ public void testFillOutlineColorTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("fill-outline-colorTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setFillOutlineColorTransition(options);
+ assertEquals(layer.getFillOutlineColorTransition(), options);
+ }
+
+ @Test
public void testFillOutlineColorAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("fill-outline-color");
assertNotNull(layer);
@@ -397,7 +465,8 @@ public class FillLayerTest extends BaseStyleTest {
@Test
public void testFillOutlineColorAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("fill-outline-color");
assertNotNull(layer);
@@ -423,7 +492,8 @@ public class FillLayerTest extends BaseStyleTest {
@Test
public void testFillOutlineColorAsIdentitySourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("fill-outline-color");
assertNotNull(layer);
@@ -442,7 +512,8 @@ public class FillLayerTest extends BaseStyleTest {
@Test
public void testFillOutlineColorAsExponentialSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("fill-outline-color");
assertNotNull(layer);
@@ -468,7 +539,8 @@ public class FillLayerTest extends BaseStyleTest {
@Test
public void testFillOutlineColorAsCategoricalSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("fill-outline-color");
assertNotNull(layer);
@@ -497,7 +569,8 @@ public class FillLayerTest extends BaseStyleTest {
@Test
public void testFillOutlineColorAsIntConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("fill-outline-color");
assertNotNull(layer);
@@ -507,8 +580,22 @@ public class FillLayerTest extends BaseStyleTest {
}
@Test
+ public void testFillTranslateTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("fill-translateTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setFillTranslateTransition(options);
+ assertEquals(layer.getFillTranslateTransition(), options);
+ }
+
+ @Test
public void testFillTranslateAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("fill-translate");
assertNotNull(layer);
@@ -519,7 +606,8 @@ public class FillLayerTest extends BaseStyleTest {
@Test
public void testFillTranslateAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("fill-translate");
assertNotNull(layer);
@@ -545,7 +633,8 @@ public class FillLayerTest extends BaseStyleTest {
@Test
public void testFillTranslateAnchorAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("fill-translate-anchor");
assertNotNull(layer);
@@ -556,7 +645,8 @@ public class FillLayerTest extends BaseStyleTest {
@Test
public void testFillTranslateAnchorAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("fill-translate-anchor");
assertNotNull(layer);
@@ -580,8 +670,22 @@ public class FillLayerTest extends BaseStyleTest {
}
@Test
+ public void testFillPatternTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("fill-patternTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setFillPatternTransition(options);
+ assertEquals(layer.getFillPatternTransition(), options);
+ }
+
+ @Test
public void testFillPatternAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("fill-pattern");
assertNotNull(layer);
@@ -592,7 +696,8 @@ public class FillLayerTest extends BaseStyleTest {
@Test
public void testFillPatternAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("fill-pattern");
assertNotNull(layer);
@@ -615,9 +720,4 @@ public class FillLayerTest extends BaseStyleTest {
assertEquals(1, ((IntervalStops) layer.getFillPattern().getFunction().getStops()).size());
}
-
- @After
- public void unregisterIntentServiceIdlingResource() {
- Espresso.unregisterIdlingResources(idlingResource);
- }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/GeoJsonSourceTests.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/GeoJsonSourceTests.java
new file mode 100644
index 0000000000..be2fc9ab9c
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/GeoJsonSourceTests.java
@@ -0,0 +1,188 @@
+package com.mapbox.mapboxsdk.testapp.style;
+
+import android.content.res.Resources;
+import android.support.annotation.RawRes;
+import android.support.test.espresso.UiController;
+import android.support.test.espresso.ViewAction;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.View;
+
+import com.mapbox.mapboxsdk.style.layers.CircleLayer;
+import com.mapbox.mapboxsdk.style.layers.Layer;
+import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
+import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest;
+import com.mapbox.mapboxsdk.testapp.activity.style.RuntimeStyleTestActivity;
+import com.mapbox.services.commons.geojson.Feature;
+import com.mapbox.services.commons.geojson.FeatureCollection;
+import com.mapbox.services.commons.geojson.Point;
+
+import org.hamcrest.Matcher;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+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 android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static org.junit.Assert.fail;
+
+/**
+ * Tests for {@link GeoJsonSource}
+ */
+@RunWith(AndroidJUnit4.class)
+public class GeoJsonSourceTests extends BaseActivityTest {
+
+ @Override
+ protected Class getActivityClass() {
+ return RuntimeStyleTestActivity.class;
+ }
+
+ @Test
+ public void testFeatureCollection() {
+ validateTestSetup();
+ onView(withId(R.id.mapView)).perform(new BaseViewAction() {
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ GeoJsonSource source = new GeoJsonSource("source", FeatureCollection
+ .fromJson(readRawResource(rule.getActivity().getResources(), R.raw.test_feature_collection)));
+ mapboxMap.addSource(source);
+
+ mapboxMap.addLayer(new CircleLayer("layer", source.getId()));
+ }
+
+ });
+ }
+
+ @Test
+ public void testPointGeometry() {
+ validateTestSetup();
+ onView(withId(R.id.mapView)).perform(new BaseViewAction() {
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ GeoJsonSource source = new GeoJsonSource("source", Point.fromCoordinates(new double[] {0d, 0d}));
+ mapboxMap.addSource(source);
+
+ mapboxMap.addLayer(new CircleLayer("layer", source.getId()));
+ }
+
+ });
+ }
+
+ @Test
+ public void testFeatureProperties() {
+ validateTestSetup();
+ onView(withId(R.id.mapView)).perform(new BaseViewAction() {
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ GeoJsonSource source = new GeoJsonSource("source",
+ readRawResource(rule.getActivity().getResources(), R.raw.test_feature_properties));
+ mapboxMap.addSource(source);
+
+ mapboxMap.addLayer(new CircleLayer("layer", source.getId()));
+ }
+
+ });
+ }
+
+ @Test
+ public void testPointFeature() {
+ testFeatureFromResource(R.raw.test_point_feature);
+ }
+
+ @Test
+ public void testLineStringFeature() {
+ testFeatureFromResource(R.raw.test_line_string_feature);
+ }
+
+ @Test
+ public void testPolygonFeature() {
+ testFeatureFromResource(R.raw.test_polygon_feature);
+ }
+
+ @Test
+ public void testPolygonWithHoleFeature() {
+ testFeatureFromResource(R.raw.test_polygon_with_hole_feature);
+ }
+
+ @Test
+ public void testMultiPointFeature() {
+ testFeatureFromResource(R.raw.test_multi_point_feature);
+ }
+
+ @Test
+ public void testMultiLineStringFeature() {
+ testFeatureFromResource(R.raw.test_multi_line_string_feature);
+ }
+
+ @Test
+ public void testMultiPolygonFeature() {
+ testFeatureFromResource(R.raw.test_multi_polygon_feature);
+ }
+
+ protected void testFeatureFromResource(final @RawRes int resource) {
+ validateTestSetup();
+ onView(withId(R.id.mapView)).perform(new BaseViewAction() {
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ GeoJsonSource source = new GeoJsonSource("source");
+ mapboxMap.addSource(source);
+ Layer layer = new CircleLayer("layer", source.getId());
+ mapboxMap.addLayer(layer);
+
+ source.setGeoJson(Feature.fromJson(
+ readRawResource(rule.getActivity().getResources(), resource)));
+
+ mapboxMap.removeLayer(layer);
+ mapboxMap.removeSource(source);
+ }
+
+ });
+ }
+
+ private String readRawResource(Resources resources, @RawRes int rawResource) {
+ InputStream is = resources.openRawResource(rawResource);
+ Writer writer = new StringWriter();
+ char[] buffer = new char[1024];
+ try {
+ try {
+ Reader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
+ int numRead;
+ while ((numRead = reader.read(buffer)) != -1) {
+ writer.write(buffer, 0, numRead);
+ }
+ } finally {
+ is.close();
+ }
+ } catch (IOException err) {
+ fail(err.getMessage());
+ }
+
+ return writer.toString();
+ }
+
+ public abstract class BaseViewAction implements ViewAction {
+
+ @Override
+ public Matcher<View> getConstraints() {
+ return isDisplayed();
+ }
+
+ @Override
+ public String getDescription() {
+ return getClass().getSimpleName();
+ }
+
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java
index 466873f9e5..1c23dd366b 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java
@@ -22,6 +22,7 @@ import com.mapbox.mapboxsdk.style.layers.LineLayer;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.activity.style.RuntimeStyleTestActivity;
import com.mapbox.mapboxsdk.testapp.utils.OnMapReadyIdlingResource;
+import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest;
import org.junit.After;
import org.junit.Before;
@@ -36,27 +37,23 @@ import static org.junit.Assert.*;
import static com.mapbox.mapboxsdk.style.layers.Property.*;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.*;
+import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
+import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity;
+
/**
* Basic smoke tests for LineLayer
*/
@RunWith(AndroidJUnit4.class)
-public class LineLayerTest extends BaseStyleTest {
-
- @Rule
- public final ActivityTestRule<RuntimeStyleTestActivity> rule = new ActivityTestRule<>(RuntimeStyleTestActivity.class);
+public class LineLayerTest extends BaseActivityTest {
private LineLayer layer;
- private OnMapReadyIdlingResource idlingResource;
-
- private MapboxMap mapboxMap;
-
- @Before
- public void setup() {
- idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
- Espresso.registerIdlingResources(idlingResource);
- mapboxMap = rule.getActivity().getMapboxMap();
+ @Override
+ protected Class getActivityClass() {
+ return EspressoTestActivity.class;
+ }
+ private void setupLayer(){
if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
Timber.i("Adding layer");
layer = new LineLayer("my-layer", "composite");
@@ -69,7 +66,8 @@ public class LineLayerTest extends BaseStyleTest {
@Test
public void testSetVisibility() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("Visibility");
assertNotNull(layer);
@@ -82,8 +80,25 @@ public class LineLayerTest extends BaseStyleTest {
}
@Test
+ public void testSourceLayer() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("SourceLayer");
+ assertNotNull(layer);
+
+ // Get initial
+ assertEquals(layer.getSourceLayer(), "composite");
+
+ // Set
+ final String sourceLayer = "test";
+ layer.setSourceLayer(sourceLayer);
+ assertEquals(layer.getSourceLayer(), sourceLayer);
+ }
+
+ @Test
public void testLineCapAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-cap");
assertNotNull(layer);
@@ -94,7 +109,8 @@ public class LineLayerTest extends BaseStyleTest {
@Test
public void testLineCapAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-cap");
assertNotNull(layer);
@@ -119,7 +135,8 @@ public class LineLayerTest extends BaseStyleTest {
@Test
public void testLineJoinAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-join");
assertNotNull(layer);
@@ -130,7 +147,8 @@ public class LineLayerTest extends BaseStyleTest {
@Test
public void testLineJoinAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-join");
assertNotNull(layer);
@@ -155,7 +173,8 @@ public class LineLayerTest extends BaseStyleTest {
@Test
public void testLineMiterLimitAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-miter-limit");
assertNotNull(layer);
@@ -166,7 +185,8 @@ public class LineLayerTest extends BaseStyleTest {
@Test
public void testLineMiterLimitAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-miter-limit");
assertNotNull(layer);
@@ -192,7 +212,8 @@ public class LineLayerTest extends BaseStyleTest {
@Test
public void testLineRoundLimitAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-round-limit");
assertNotNull(layer);
@@ -203,7 +224,8 @@ public class LineLayerTest extends BaseStyleTest {
@Test
public void testLineRoundLimitAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-round-limit");
assertNotNull(layer);
@@ -228,8 +250,22 @@ public class LineLayerTest extends BaseStyleTest {
}
@Test
+ public void testLineOpacityTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("line-opacityTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setLineOpacityTransition(options);
+ assertEquals(layer.getLineOpacityTransition(), options);
+ }
+
+ @Test
public void testLineOpacityAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-opacity");
assertNotNull(layer);
@@ -240,7 +276,8 @@ public class LineLayerTest extends BaseStyleTest {
@Test
public void testLineOpacityAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-opacity");
assertNotNull(layer);
@@ -266,7 +303,8 @@ public class LineLayerTest extends BaseStyleTest {
@Test
public void testLineOpacityAsIdentitySourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-opacity");
assertNotNull(layer);
@@ -285,7 +323,8 @@ public class LineLayerTest extends BaseStyleTest {
@Test
public void testLineOpacityAsExponentialSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-opacity");
assertNotNull(layer);
@@ -311,7 +350,8 @@ public class LineLayerTest extends BaseStyleTest {
@Test
public void testLineOpacityAsCategoricalSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-opacity");
assertNotNull(layer);
@@ -340,7 +380,8 @@ public class LineLayerTest extends BaseStyleTest {
@Test
public void testLineOpacityAsCompositeFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-opacity");
assertNotNull(layer);
@@ -373,8 +414,22 @@ public class LineLayerTest extends BaseStyleTest {
}
@Test
+ public void testLineColorTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("line-colorTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setLineColorTransition(options);
+ assertEquals(layer.getLineColorTransition(), options);
+ }
+
+ @Test
public void testLineColorAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-color");
assertNotNull(layer);
@@ -385,7 +440,8 @@ public class LineLayerTest extends BaseStyleTest {
@Test
public void testLineColorAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-color");
assertNotNull(layer);
@@ -411,7 +467,8 @@ public class LineLayerTest extends BaseStyleTest {
@Test
public void testLineColorAsIdentitySourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-color");
assertNotNull(layer);
@@ -430,7 +487,8 @@ public class LineLayerTest extends BaseStyleTest {
@Test
public void testLineColorAsExponentialSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-color");
assertNotNull(layer);
@@ -456,7 +514,8 @@ public class LineLayerTest extends BaseStyleTest {
@Test
public void testLineColorAsCategoricalSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-color");
assertNotNull(layer);
@@ -485,7 +544,8 @@ public class LineLayerTest extends BaseStyleTest {
@Test
public void testLineColorAsIntConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-color");
assertNotNull(layer);
@@ -495,8 +555,22 @@ public class LineLayerTest extends BaseStyleTest {
}
@Test
+ public void testLineTranslateTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("line-translateTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setLineTranslateTransition(options);
+ assertEquals(layer.getLineTranslateTransition(), options);
+ }
+
+ @Test
public void testLineTranslateAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-translate");
assertNotNull(layer);
@@ -507,7 +581,8 @@ public class LineLayerTest extends BaseStyleTest {
@Test
public void testLineTranslateAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-translate");
assertNotNull(layer);
@@ -533,7 +608,8 @@ public class LineLayerTest extends BaseStyleTest {
@Test
public void testLineTranslateAnchorAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-translate-anchor");
assertNotNull(layer);
@@ -544,7 +620,8 @@ public class LineLayerTest extends BaseStyleTest {
@Test
public void testLineTranslateAnchorAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-translate-anchor");
assertNotNull(layer);
@@ -568,8 +645,22 @@ public class LineLayerTest extends BaseStyleTest {
}
@Test
+ public void testLineWidthTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("line-widthTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setLineWidthTransition(options);
+ assertEquals(layer.getLineWidthTransition(), options);
+ }
+
+ @Test
public void testLineWidthAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-width");
assertNotNull(layer);
@@ -580,7 +671,8 @@ public class LineLayerTest extends BaseStyleTest {
@Test
public void testLineWidthAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-width");
assertNotNull(layer);
@@ -605,8 +697,22 @@ public class LineLayerTest extends BaseStyleTest {
}
@Test
+ public void testLineGapWidthTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("line-gap-widthTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setLineGapWidthTransition(options);
+ assertEquals(layer.getLineGapWidthTransition(), options);
+ }
+
+ @Test
public void testLineGapWidthAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-gap-width");
assertNotNull(layer);
@@ -617,7 +723,8 @@ public class LineLayerTest extends BaseStyleTest {
@Test
public void testLineGapWidthAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-gap-width");
assertNotNull(layer);
@@ -643,7 +750,8 @@ public class LineLayerTest extends BaseStyleTest {
@Test
public void testLineGapWidthAsIdentitySourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-gap-width");
assertNotNull(layer);
@@ -662,7 +770,8 @@ public class LineLayerTest extends BaseStyleTest {
@Test
public void testLineGapWidthAsExponentialSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-gap-width");
assertNotNull(layer);
@@ -688,7 +797,8 @@ public class LineLayerTest extends BaseStyleTest {
@Test
public void testLineGapWidthAsCategoricalSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-gap-width");
assertNotNull(layer);
@@ -717,7 +827,8 @@ public class LineLayerTest extends BaseStyleTest {
@Test
public void testLineGapWidthAsCompositeFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-gap-width");
assertNotNull(layer);
@@ -750,8 +861,22 @@ public class LineLayerTest extends BaseStyleTest {
}
@Test
+ public void testLineOffsetTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("line-offsetTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setLineOffsetTransition(options);
+ assertEquals(layer.getLineOffsetTransition(), options);
+ }
+
+ @Test
public void testLineOffsetAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-offset");
assertNotNull(layer);
@@ -762,7 +887,8 @@ public class LineLayerTest extends BaseStyleTest {
@Test
public void testLineOffsetAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-offset");
assertNotNull(layer);
@@ -788,7 +914,8 @@ public class LineLayerTest extends BaseStyleTest {
@Test
public void testLineOffsetAsIdentitySourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-offset");
assertNotNull(layer);
@@ -807,7 +934,8 @@ public class LineLayerTest extends BaseStyleTest {
@Test
public void testLineOffsetAsExponentialSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-offset");
assertNotNull(layer);
@@ -833,7 +961,8 @@ public class LineLayerTest extends BaseStyleTest {
@Test
public void testLineOffsetAsCategoricalSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-offset");
assertNotNull(layer);
@@ -862,7 +991,8 @@ public class LineLayerTest extends BaseStyleTest {
@Test
public void testLineOffsetAsCompositeFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-offset");
assertNotNull(layer);
@@ -895,8 +1025,22 @@ public class LineLayerTest extends BaseStyleTest {
}
@Test
+ public void testLineBlurTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("line-blurTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setLineBlurTransition(options);
+ assertEquals(layer.getLineBlurTransition(), options);
+ }
+
+ @Test
public void testLineBlurAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-blur");
assertNotNull(layer);
@@ -907,7 +1051,8 @@ public class LineLayerTest extends BaseStyleTest {
@Test
public void testLineBlurAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-blur");
assertNotNull(layer);
@@ -933,7 +1078,8 @@ public class LineLayerTest extends BaseStyleTest {
@Test
public void testLineBlurAsIdentitySourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-blur");
assertNotNull(layer);
@@ -952,7 +1098,8 @@ public class LineLayerTest extends BaseStyleTest {
@Test
public void testLineBlurAsExponentialSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-blur");
assertNotNull(layer);
@@ -978,7 +1125,8 @@ public class LineLayerTest extends BaseStyleTest {
@Test
public void testLineBlurAsCategoricalSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-blur");
assertNotNull(layer);
@@ -1007,7 +1155,8 @@ public class LineLayerTest extends BaseStyleTest {
@Test
public void testLineBlurAsCompositeFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-blur");
assertNotNull(layer);
@@ -1040,8 +1189,22 @@ public class LineLayerTest extends BaseStyleTest {
}
@Test
+ public void testLineDasharrayTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("line-dasharrayTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setLineDasharrayTransition(options);
+ assertEquals(layer.getLineDasharrayTransition(), options);
+ }
+
+ @Test
public void testLineDasharrayAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-dasharray");
assertNotNull(layer);
@@ -1052,7 +1215,8 @@ public class LineLayerTest extends BaseStyleTest {
@Test
public void testLineDasharrayAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-dasharray");
assertNotNull(layer);
@@ -1076,8 +1240,22 @@ public class LineLayerTest extends BaseStyleTest {
}
@Test
+ public void testLinePatternTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("line-patternTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setLinePatternTransition(options);
+ assertEquals(layer.getLinePatternTransition(), options);
+ }
+
+ @Test
public void testLinePatternAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-pattern");
assertNotNull(layer);
@@ -1088,7 +1266,8 @@ public class LineLayerTest extends BaseStyleTest {
@Test
public void testLinePatternAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("line-pattern");
assertNotNull(layer);
@@ -1111,9 +1290,4 @@ public class LineLayerTest extends BaseStyleTest {
assertEquals(1, ((IntervalStops) layer.getLinePattern().getFunction().getStops()).size());
}
-
- @After
- public void unregisterIntentServiceIdlingResource() {
- Espresso.unregisterIdlingResources(idlingResource);
- }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RasterLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RasterLayerTest.java
index eb2155f545..2a0d3401fb 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RasterLayerTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RasterLayerTest.java
@@ -22,6 +22,7 @@ import com.mapbox.mapboxsdk.style.layers.RasterLayer;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.activity.style.RuntimeStyleTestActivity;
import com.mapbox.mapboxsdk.testapp.utils.OnMapReadyIdlingResource;
+import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest;
import org.junit.After;
import org.junit.Before;
@@ -36,27 +37,23 @@ import static org.junit.Assert.*;
import static com.mapbox.mapboxsdk.style.layers.Property.*;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.*;
+import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
+import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity;
+
/**
* Basic smoke tests for RasterLayer
*/
@RunWith(AndroidJUnit4.class)
-public class RasterLayerTest extends BaseStyleTest {
-
- @Rule
- public final ActivityTestRule<RuntimeStyleTestActivity> rule = new ActivityTestRule<>(RuntimeStyleTestActivity.class);
+public class RasterLayerTest extends BaseActivityTest {
private RasterLayer layer;
- private OnMapReadyIdlingResource idlingResource;
-
- private MapboxMap mapboxMap;
-
- @Before
- public void setup() {
- idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
- Espresso.registerIdlingResources(idlingResource);
- mapboxMap = rule.getActivity().getMapboxMap();
+ @Override
+ protected Class getActivityClass() {
+ return EspressoTestActivity.class;
+ }
+ private void setupLayer(){
if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
Timber.i("Adding layer");
layer = new RasterLayer("my-layer", "composite");
@@ -69,7 +66,8 @@ public class RasterLayerTest extends BaseStyleTest {
@Test
public void testSetVisibility() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("Visibility");
assertNotNull(layer);
@@ -82,8 +80,22 @@ public class RasterLayerTest extends BaseStyleTest {
}
@Test
+ public void testRasterOpacityTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("raster-opacityTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setRasterOpacityTransition(options);
+ assertEquals(layer.getRasterOpacityTransition(), options);
+ }
+
+ @Test
public void testRasterOpacityAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("raster-opacity");
assertNotNull(layer);
@@ -94,7 +106,8 @@ public class RasterLayerTest extends BaseStyleTest {
@Test
public void testRasterOpacityAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("raster-opacity");
assertNotNull(layer);
@@ -119,8 +132,22 @@ public class RasterLayerTest extends BaseStyleTest {
}
@Test
+ public void testRasterHueRotateTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("raster-hue-rotateTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setRasterHueRotateTransition(options);
+ assertEquals(layer.getRasterHueRotateTransition(), options);
+ }
+
+ @Test
public void testRasterHueRotateAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("raster-hue-rotate");
assertNotNull(layer);
@@ -131,7 +158,8 @@ public class RasterLayerTest extends BaseStyleTest {
@Test
public void testRasterHueRotateAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("raster-hue-rotate");
assertNotNull(layer);
@@ -156,8 +184,22 @@ public class RasterLayerTest extends BaseStyleTest {
}
@Test
+ public void testRasterBrightnessMinTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("raster-brightness-minTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setRasterBrightnessMinTransition(options);
+ assertEquals(layer.getRasterBrightnessMinTransition(), options);
+ }
+
+ @Test
public void testRasterBrightnessMinAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("raster-brightness-min");
assertNotNull(layer);
@@ -168,7 +210,8 @@ public class RasterLayerTest extends BaseStyleTest {
@Test
public void testRasterBrightnessMinAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("raster-brightness-min");
assertNotNull(layer);
@@ -193,8 +236,22 @@ public class RasterLayerTest extends BaseStyleTest {
}
@Test
+ public void testRasterBrightnessMaxTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("raster-brightness-maxTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setRasterBrightnessMaxTransition(options);
+ assertEquals(layer.getRasterBrightnessMaxTransition(), options);
+ }
+
+ @Test
public void testRasterBrightnessMaxAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("raster-brightness-max");
assertNotNull(layer);
@@ -205,7 +262,8 @@ public class RasterLayerTest extends BaseStyleTest {
@Test
public void testRasterBrightnessMaxAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("raster-brightness-max");
assertNotNull(layer);
@@ -230,8 +288,22 @@ public class RasterLayerTest extends BaseStyleTest {
}
@Test
+ public void testRasterSaturationTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("raster-saturationTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setRasterSaturationTransition(options);
+ assertEquals(layer.getRasterSaturationTransition(), options);
+ }
+
+ @Test
public void testRasterSaturationAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("raster-saturation");
assertNotNull(layer);
@@ -242,7 +314,8 @@ public class RasterLayerTest extends BaseStyleTest {
@Test
public void testRasterSaturationAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("raster-saturation");
assertNotNull(layer);
@@ -267,8 +340,22 @@ public class RasterLayerTest extends BaseStyleTest {
}
@Test
+ public void testRasterContrastTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("raster-contrastTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setRasterContrastTransition(options);
+ assertEquals(layer.getRasterContrastTransition(), options);
+ }
+
+ @Test
public void testRasterContrastAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("raster-contrast");
assertNotNull(layer);
@@ -279,7 +366,8 @@ public class RasterLayerTest extends BaseStyleTest {
@Test
public void testRasterContrastAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("raster-contrast");
assertNotNull(layer);
@@ -304,8 +392,22 @@ public class RasterLayerTest extends BaseStyleTest {
}
@Test
+ public void testRasterFadeDurationTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("raster-fade-durationTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setRasterFadeDurationTransition(options);
+ assertEquals(layer.getRasterFadeDurationTransition(), options);
+ }
+
+ @Test
public void testRasterFadeDurationAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("raster-fade-duration");
assertNotNull(layer);
@@ -316,7 +418,8 @@ public class RasterLayerTest extends BaseStyleTest {
@Test
public void testRasterFadeDurationAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("raster-fade-duration");
assertNotNull(layer);
@@ -340,9 +443,4 @@ public class RasterLayerTest extends BaseStyleTest {
assertEquals(1, ((ExponentialStops) layer.getRasterFadeDuration().getFunction().getStops()).size());
}
-
- @After
- public void unregisterIntentServiceIdlingResource() {
- Espresso.unregisterIdlingResources(idlingResource);
- }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleTests.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleTests.java
index bf90949ffd..a1c46903bf 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleTests.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleTests.java
@@ -5,11 +5,9 @@ import android.graphics.PointF;
import android.support.test.espresso.Espresso;
import android.support.test.espresso.UiController;
import android.support.test.espresso.ViewAction;
-import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.view.View;
-import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.style.layers.CannotAddLayerException;
import com.mapbox.mapboxsdk.style.layers.CircleLayer;
import com.mapbox.mapboxsdk.style.layers.FillLayer;
@@ -17,22 +15,23 @@ import com.mapbox.mapboxsdk.style.layers.Layer;
import com.mapbox.mapboxsdk.style.layers.Property;
import com.mapbox.mapboxsdk.style.layers.PropertyFactory;
import com.mapbox.mapboxsdk.style.sources.CannotAddSourceException;
+import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
+import com.mapbox.mapboxsdk.style.sources.RasterSource;
import com.mapbox.mapboxsdk.style.sources.Source;
import com.mapbox.mapboxsdk.style.sources.VectorSource;
import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest;
import com.mapbox.mapboxsdk.testapp.activity.style.RuntimeStyleTestActivity;
-import com.mapbox.mapboxsdk.testapp.utils.OnMapReadyIdlingResource;
-import com.mapbox.mapboxsdk.testapp.utils.ViewUtils;
import junit.framework.Assert;
import org.hamcrest.Matcher;
import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.net.MalformedURLException;
+import java.net.URL;
import java.util.List;
import timber.log.Timber;
@@ -50,28 +49,20 @@ import static org.junit.Assert.fail;
* Basic smoke tests for Layer and Source
*/
@RunWith(AndroidJUnit4.class)
-public class RuntimeStyleTests {
+public class RuntimeStyleTests extends BaseActivityTest {
- @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);
+ @Override
+ protected Class getActivityClass() {
+ return RuntimeStyleTestActivity.class;
}
@Test
public void testListLayers() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new BaseViewAction() {
@Override
public void perform(UiController uiController, View view) {
- MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
-
List<Layer> layers = mapboxMap.getLayers();
assertNotNull(layers);
assertTrue(layers.size() > 0);
@@ -85,18 +76,16 @@ public class RuntimeStyleTests {
@Test
public void testGetAddRemoveLayer() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new AddRemoveLayerAction());
}
@Test
public void testAddLayerAbove() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new BaseViewAction() {
@Override
public void perform(UiController uiController, View view) {
- MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
-
List<Layer> layers = mapboxMap.getLayers();
Source source = mapboxMap.getSources().get(0);
@@ -126,13 +115,11 @@ public class RuntimeStyleTests {
@Test
public void testRemoveLayerAt() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new BaseViewAction() {
@Override
public void perform(UiController uiController, View view) {
- MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
-
// Remove by index
Layer firstLayer = mapboxMap.getLayers().get(0);
Layer removed = mapboxMap.removeLayerAt(0);
@@ -148,12 +135,10 @@ public class RuntimeStyleTests {
}
public void testAddLayerAt() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new BaseViewAction() {
@Override
public void perform(UiController uiController, View view) {
- MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
-
List<Layer> layers = mapboxMap.getLayers();
Source source = mapboxMap.getSources().get(0);
@@ -184,13 +169,11 @@ public class RuntimeStyleTests {
@Test
public void testListSources() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new BaseViewAction() {
@Override
public void perform(UiController uiController, View view) {
- MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
-
List<Source> sources = mapboxMap.getSources();
assertNotNull(sources);
assertTrue(sources.size() > 0);
@@ -204,26 +187,52 @@ public class RuntimeStyleTests {
@Test
public void testAddRemoveSource() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
-
- MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ validateTestSetup();
mapboxMap.addSource(new VectorSource("my-source", "mapbox://mapbox.mapbox-terrain-v2"));
mapboxMap.removeSource("my-source");
onView(withId(R.id.mapView)).perform(new AddRemoveSourceAction());
}
+ @Test
+ public void testVectorSourceUrlGetter() {
+ validateTestSetup();
+
+ VectorSource source = new VectorSource("my-source", "mapbox://mapbox.mapbox-terrain-v2");
+ mapboxMap.addSource(source);
+ assertEquals("mapbox://mapbox.mapbox-terrain-v2", source.getUrl());
+ }
+
+ @Test
+ public void testRasterSourceUrlGetter() {
+ validateTestSetup();
+
+ RasterSource source = new RasterSource("my-source", "mapbox://mapbox.mapbox-terrain-v2");
+ mapboxMap.addSource(source);
+ assertEquals("mapbox://mapbox.mapbox-terrain-v2", source.getUrl());
+ }
+
+ @Test
+ public void testGeoJsonSourceUrlGetter() throws MalformedURLException {
+ validateTestSetup();
+
+ GeoJsonSource source = new GeoJsonSource("my-source");
+ mapboxMap.addSource(source);
+ assertNull(source.getUrl());
+ source.setUrl(new URL("http://mapbox.com/my-file.json"));
+ assertEquals("http://mapbox.com/my-file.json", source.getUrl());
+ }
+
/**
* https://github.com/mapbox/mapbox-gl-native/issues/7973
*/
@Test
public void testQueryRenderedFeaturesInputHandling() {
- ViewUtils.checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
onView(withId(R.id.mapView)).perform(new BaseViewAction() {
@Override
public void perform(UiController uiController, View view) {
- MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
String[] layerIds = new String[600];
for (int i = 0; i < layerIds.length; i++) {
layerIds[i] = "layer-" + i;
@@ -238,8 +247,6 @@ public class RuntimeStyleTests {
@Override
public void perform(UiController uiController, View view) {
- MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
-
// Get initial
assertNotNull(mapboxMap.getLayer("building"));
@@ -283,8 +290,6 @@ public class RuntimeStyleTests {
@Override
public void perform(UiController uiController, View view) {
- MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
-
// Add initial source
mapboxMap.addSource(new VectorSource("my-source", "mapbox://mapbox.mapbox-terrain-v2"));
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleTimingTests.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleTimingTests.java
index 400c5fbc3c..75c8b57787 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleTimingTests.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleTimingTests.java
@@ -1,16 +1,10 @@
package com.mapbox.mapboxsdk.testapp.style;
-import android.support.test.espresso.Espresso;
-import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
-import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest;
import com.mapbox.mapboxsdk.testapp.activity.style.RuntimeStyleTimingTestActivity;
-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;
@@ -18,28 +12,16 @@ 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 BaseStyleTest {
+public class RuntimeStyleTimingTests extends BaseActivityTest {
- @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);
+ @Override
+ protected Class getActivityClass() {
+ return RuntimeStyleTimingTestActivity.class;
}
@Test
public void testGetAddRemoveLayer() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
// 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/testapp/style/SymbolLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java
index c90af339b1..737a66713a 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java
@@ -22,6 +22,7 @@ import com.mapbox.mapboxsdk.style.layers.SymbolLayer;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.activity.style.RuntimeStyleTestActivity;
import com.mapbox.mapboxsdk.testapp.utils.OnMapReadyIdlingResource;
+import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest;
import org.junit.After;
import org.junit.Before;
@@ -36,27 +37,23 @@ import static org.junit.Assert.*;
import static com.mapbox.mapboxsdk.style.layers.Property.*;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.*;
+import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
+import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity;
+
/**
* Basic smoke tests for SymbolLayer
*/
@RunWith(AndroidJUnit4.class)
-public class SymbolLayerTest extends BaseStyleTest {
-
- @Rule
- public final ActivityTestRule<RuntimeStyleTestActivity> rule = new ActivityTestRule<>(RuntimeStyleTestActivity.class);
+public class SymbolLayerTest extends BaseActivityTest {
private SymbolLayer layer;
- private OnMapReadyIdlingResource idlingResource;
-
- private MapboxMap mapboxMap;
-
- @Before
- public void setup() {
- idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
- Espresso.registerIdlingResources(idlingResource);
- mapboxMap = rule.getActivity().getMapboxMap();
+ @Override
+ protected Class getActivityClass() {
+ return EspressoTestActivity.class;
+ }
+ private void setupLayer(){
if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
Timber.i("Adding layer");
layer = new SymbolLayer("my-layer", "composite");
@@ -69,7 +66,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testSetVisibility() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("Visibility");
assertNotNull(layer);
@@ -82,8 +80,25 @@ public class SymbolLayerTest extends BaseStyleTest {
}
@Test
+ public void testSourceLayer() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("SourceLayer");
+ assertNotNull(layer);
+
+ // Get initial
+ assertEquals(layer.getSourceLayer(), "composite");
+
+ // Set
+ final String sourceLayer = "test";
+ layer.setSourceLayer(sourceLayer);
+ assertEquals(layer.getSourceLayer(), sourceLayer);
+ }
+
+ @Test
public void testSymbolPlacementAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("symbol-placement");
assertNotNull(layer);
@@ -94,7 +109,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testSymbolPlacementAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("symbol-placement");
assertNotNull(layer);
@@ -119,7 +135,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testSymbolSpacingAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("symbol-spacing");
assertNotNull(layer);
@@ -130,7 +147,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testSymbolSpacingAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("symbol-spacing");
assertNotNull(layer);
@@ -156,7 +174,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testSymbolAvoidEdgesAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("symbol-avoid-edges");
assertNotNull(layer);
@@ -167,7 +186,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testSymbolAvoidEdgesAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("symbol-avoid-edges");
assertNotNull(layer);
@@ -192,7 +212,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconAllowOverlapAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-allow-overlap");
assertNotNull(layer);
@@ -203,7 +224,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconAllowOverlapAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-allow-overlap");
assertNotNull(layer);
@@ -228,7 +250,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconIgnorePlacementAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-ignore-placement");
assertNotNull(layer);
@@ -239,7 +262,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconIgnorePlacementAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-ignore-placement");
assertNotNull(layer);
@@ -264,7 +288,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconOptionalAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-optional");
assertNotNull(layer);
@@ -275,7 +300,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconOptionalAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-optional");
assertNotNull(layer);
@@ -300,7 +326,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconRotationAlignmentAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-rotation-alignment");
assertNotNull(layer);
@@ -311,7 +338,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconRotationAlignmentAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-rotation-alignment");
assertNotNull(layer);
@@ -336,7 +364,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconSizeAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-size");
assertNotNull(layer);
@@ -347,7 +376,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconSizeAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-size");
assertNotNull(layer);
@@ -372,8 +402,121 @@ public class SymbolLayerTest extends BaseStyleTest {
}
@Test
+ public void testIconSizeAsIdentitySourceFunction() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("icon-size");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ iconSize(property("FeaturePropertyA", Stops.<Float>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getIconSize());
+ assertNotNull(layer.getIconSize().getFunction());
+ assertEquals(SourceFunction.class, layer.getIconSize().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconSize().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getIconSize().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testIconSizeAsExponentialSourceFunction() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("icon-size");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ iconSize(
+ property(
+ "FeaturePropertyA",
+ exponential(
+ stop(0.3f, iconSize(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconSize());
+ assertNotNull(layer.getIconSize().getFunction());
+ assertEquals(SourceFunction.class, layer.getIconSize().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconSize().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getIconSize().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testIconSizeAsCategoricalSourceFunction() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("icon-size");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ iconSize(
+ property(
+ "FeaturePropertyA",
+ categorical(
+ stop(1.0f, iconSize(0.3f))
+ )
+ ).withDefaultValue(iconSize(0.3f))
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconSize());
+ assertNotNull(layer.getIconSize().getFunction());
+ assertEquals(SourceFunction.class, layer.getIconSize().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconSize().getFunction()).getProperty());
+ assertEquals(CategoricalStops.class, layer.getIconSize().getFunction().getStops().getClass());
+ assertNotNull(((SourceFunction) layer.getIconSize().getFunction()).getDefaultValue());
+ assertNotNull(((SourceFunction) layer.getIconSize().getFunction()).getDefaultValue().getValue());
+ assertEquals(0.3f, ((SourceFunction) layer.getIconSize().getFunction()).getDefaultValue().getValue());
+ }
+
+ @Test
+ public void testIconSizeAsCompositeFunction() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("icon-size");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ iconSize(
+ composite(
+ "FeaturePropertyA",
+ exponential(
+ stop(0, 0.3f, iconSize(0.9f))
+ ).withBase(0.5f)
+ ).withDefaultValue(iconSize(0.3f))
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconSize());
+ assertNotNull(layer.getIconSize().getFunction());
+ assertEquals(CompositeFunction.class, layer.getIconSize().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((CompositeFunction) layer.getIconSize().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getIconSize().getFunction().getStops().getClass());
+ assertEquals(1, ((ExponentialStops) layer.getIconSize().getFunction().getStops()).size());
+
+ ExponentialStops<Stop.CompositeValue<Float, Float>, Float> stops =
+ (ExponentialStops<Stop.CompositeValue<Float, Float>, Float>) layer.getIconSize().getFunction().getStops();
+ Stop<Stop.CompositeValue<Float, Float>, Float> stop = stops.iterator().next();
+ assertEquals(0f, stop.in.zoom, 0.001);
+ assertEquals(0.3f, stop.in.value, 0.001f);
+ assertEquals(0.9f, stop.out, 0.001f);
+ }
+
+ @Test
public void testIconTextFitAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-text-fit");
assertNotNull(layer);
@@ -384,7 +527,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconTextFitAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-text-fit");
assertNotNull(layer);
@@ -409,7 +553,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconTextFitPaddingAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-text-fit-padding");
assertNotNull(layer);
@@ -420,7 +565,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconTextFitPaddingAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-text-fit-padding");
assertNotNull(layer);
@@ -446,7 +592,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconImageAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-image");
assertNotNull(layer);
@@ -457,7 +604,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconImageAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-image");
assertNotNull(layer);
@@ -481,8 +629,56 @@ public class SymbolLayerTest extends BaseStyleTest {
}
@Test
+ public void testIconImageAsIdentitySourceFunction() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("icon-image");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ iconImage(property("FeaturePropertyA", Stops.<String>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getIconImage());
+ assertNotNull(layer.getIconImage().getFunction());
+ assertEquals(SourceFunction.class, layer.getIconImage().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconImage().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getIconImage().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testIconImageAsIntervalSourceFunction() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("icon-image");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ iconImage(
+ property(
+ "FeaturePropertyA",
+ interval(
+ stop(1, iconImage("undefined"))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconImage());
+ assertNotNull(layer.getIconImage().getFunction());
+ assertEquals(SourceFunction.class, layer.getIconImage().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconImage().getFunction()).getProperty());
+ assertEquals(IntervalStops.class, layer.getIconImage().getFunction().getStops().getClass());
+ }
+
+ @Test
public void testIconRotateAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-rotate");
assertNotNull(layer);
@@ -493,7 +689,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconRotateAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-rotate");
assertNotNull(layer);
@@ -519,7 +716,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconRotateAsIdentitySourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-rotate");
assertNotNull(layer);
@@ -538,7 +736,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconRotateAsExponentialSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-rotate");
assertNotNull(layer);
@@ -564,7 +763,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconRotateAsCategoricalSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-rotate");
assertNotNull(layer);
@@ -593,7 +793,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconRotateAsCompositeFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-rotate");
assertNotNull(layer);
@@ -627,7 +828,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconPaddingAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-padding");
assertNotNull(layer);
@@ -638,7 +840,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconPaddingAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-padding");
assertNotNull(layer);
@@ -664,7 +867,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconKeepUprightAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-keep-upright");
assertNotNull(layer);
@@ -675,7 +879,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconKeepUprightAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-keep-upright");
assertNotNull(layer);
@@ -700,7 +905,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconOffsetAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-offset");
assertNotNull(layer);
@@ -711,7 +917,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconOffsetAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-offset");
assertNotNull(layer);
@@ -737,7 +944,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconOffsetAsIdentitySourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-offset");
assertNotNull(layer);
@@ -756,7 +964,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconOffsetAsIntervalSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-offset");
assertNotNull(layer);
@@ -782,7 +991,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextPitchAlignmentAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-pitch-alignment");
assertNotNull(layer);
@@ -793,7 +1003,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextPitchAlignmentAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-pitch-alignment");
assertNotNull(layer);
@@ -818,7 +1029,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextRotationAlignmentAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-rotation-alignment");
assertNotNull(layer);
@@ -829,7 +1041,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextRotationAlignmentAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-rotation-alignment");
assertNotNull(layer);
@@ -854,7 +1067,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextFieldAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-field");
assertNotNull(layer);
@@ -865,7 +1079,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextFieldAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-field");
assertNotNull(layer);
@@ -890,7 +1105,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextFieldAsIdentitySourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-field");
assertNotNull(layer);
@@ -909,7 +1125,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextFieldAsIntervalSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-field");
assertNotNull(layer);
@@ -935,7 +1152,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextFontAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-font");
assertNotNull(layer);
@@ -946,7 +1164,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextFontAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-font");
assertNotNull(layer);
@@ -971,7 +1190,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextSizeAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-size");
assertNotNull(layer);
@@ -982,7 +1202,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextSizeAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-size");
assertNotNull(layer);
@@ -1007,8 +1228,121 @@ public class SymbolLayerTest extends BaseStyleTest {
}
@Test
+ public void testTextSizeAsIdentitySourceFunction() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("text-size");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ textSize(property("FeaturePropertyA", Stops.<Float>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getTextSize());
+ assertNotNull(layer.getTextSize().getFunction());
+ assertEquals(SourceFunction.class, layer.getTextSize().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextSize().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getTextSize().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testTextSizeAsExponentialSourceFunction() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("text-size");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ textSize(
+ property(
+ "FeaturePropertyA",
+ exponential(
+ stop(0.3f, textSize(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextSize());
+ assertNotNull(layer.getTextSize().getFunction());
+ assertEquals(SourceFunction.class, layer.getTextSize().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextSize().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getTextSize().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testTextSizeAsCategoricalSourceFunction() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("text-size");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ textSize(
+ property(
+ "FeaturePropertyA",
+ categorical(
+ stop(1.0f, textSize(0.3f))
+ )
+ ).withDefaultValue(textSize(0.3f))
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextSize());
+ assertNotNull(layer.getTextSize().getFunction());
+ assertEquals(SourceFunction.class, layer.getTextSize().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextSize().getFunction()).getProperty());
+ assertEquals(CategoricalStops.class, layer.getTextSize().getFunction().getStops().getClass());
+ assertNotNull(((SourceFunction) layer.getTextSize().getFunction()).getDefaultValue());
+ assertNotNull(((SourceFunction) layer.getTextSize().getFunction()).getDefaultValue().getValue());
+ assertEquals(0.3f, ((SourceFunction) layer.getTextSize().getFunction()).getDefaultValue().getValue());
+ }
+
+ @Test
+ public void testTextSizeAsCompositeFunction() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("text-size");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ textSize(
+ composite(
+ "FeaturePropertyA",
+ exponential(
+ stop(0, 0.3f, textSize(0.9f))
+ ).withBase(0.5f)
+ ).withDefaultValue(textSize(0.3f))
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextSize());
+ assertNotNull(layer.getTextSize().getFunction());
+ assertEquals(CompositeFunction.class, layer.getTextSize().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((CompositeFunction) layer.getTextSize().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getTextSize().getFunction().getStops().getClass());
+ assertEquals(1, ((ExponentialStops) layer.getTextSize().getFunction().getStops()).size());
+
+ ExponentialStops<Stop.CompositeValue<Float, Float>, Float> stops =
+ (ExponentialStops<Stop.CompositeValue<Float, Float>, Float>) layer.getTextSize().getFunction().getStops();
+ Stop<Stop.CompositeValue<Float, Float>, Float> stop = stops.iterator().next();
+ assertEquals(0f, stop.in.zoom, 0.001);
+ assertEquals(0.3f, stop.in.value, 0.001f);
+ assertEquals(0.9f, stop.out, 0.001f);
+ }
+
+ @Test
public void testTextMaxWidthAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-max-width");
assertNotNull(layer);
@@ -1019,7 +1353,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextMaxWidthAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-max-width");
assertNotNull(layer);
@@ -1045,7 +1380,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextLineHeightAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-line-height");
assertNotNull(layer);
@@ -1056,7 +1392,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextLineHeightAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-line-height");
assertNotNull(layer);
@@ -1082,7 +1419,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextLetterSpacingAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-letter-spacing");
assertNotNull(layer);
@@ -1093,7 +1431,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextLetterSpacingAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-letter-spacing");
assertNotNull(layer);
@@ -1119,7 +1458,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextJustifyAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-justify");
assertNotNull(layer);
@@ -1130,7 +1470,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextJustifyAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-justify");
assertNotNull(layer);
@@ -1155,7 +1496,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextAnchorAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-anchor");
assertNotNull(layer);
@@ -1166,7 +1508,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextAnchorAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-anchor");
assertNotNull(layer);
@@ -1191,7 +1534,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextMaxAngleAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-max-angle");
assertNotNull(layer);
@@ -1202,7 +1546,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextMaxAngleAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-max-angle");
assertNotNull(layer);
@@ -1228,7 +1573,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextRotateAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-rotate");
assertNotNull(layer);
@@ -1239,7 +1585,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextRotateAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-rotate");
assertNotNull(layer);
@@ -1264,8 +1611,121 @@ public class SymbolLayerTest extends BaseStyleTest {
}
@Test
+ public void testTextRotateAsIdentitySourceFunction() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("text-rotate");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ textRotate(property("FeaturePropertyA", Stops.<Float>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getTextRotate());
+ assertNotNull(layer.getTextRotate().getFunction());
+ assertEquals(SourceFunction.class, layer.getTextRotate().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextRotate().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getTextRotate().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testTextRotateAsExponentialSourceFunction() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("text-rotate");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ textRotate(
+ property(
+ "FeaturePropertyA",
+ exponential(
+ stop(0.3f, textRotate(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextRotate());
+ assertNotNull(layer.getTextRotate().getFunction());
+ assertEquals(SourceFunction.class, layer.getTextRotate().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextRotate().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getTextRotate().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testTextRotateAsCategoricalSourceFunction() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("text-rotate");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ textRotate(
+ property(
+ "FeaturePropertyA",
+ categorical(
+ stop(1.0f, textRotate(0.3f))
+ )
+ ).withDefaultValue(textRotate(0.3f))
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextRotate());
+ assertNotNull(layer.getTextRotate().getFunction());
+ assertEquals(SourceFunction.class, layer.getTextRotate().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextRotate().getFunction()).getProperty());
+ assertEquals(CategoricalStops.class, layer.getTextRotate().getFunction().getStops().getClass());
+ assertNotNull(((SourceFunction) layer.getTextRotate().getFunction()).getDefaultValue());
+ assertNotNull(((SourceFunction) layer.getTextRotate().getFunction()).getDefaultValue().getValue());
+ assertEquals(0.3f, ((SourceFunction) layer.getTextRotate().getFunction()).getDefaultValue().getValue());
+ }
+
+ @Test
+ public void testTextRotateAsCompositeFunction() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("text-rotate");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ textRotate(
+ composite(
+ "FeaturePropertyA",
+ exponential(
+ stop(0, 0.3f, textRotate(0.9f))
+ ).withBase(0.5f)
+ ).withDefaultValue(textRotate(0.3f))
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextRotate());
+ assertNotNull(layer.getTextRotate().getFunction());
+ assertEquals(CompositeFunction.class, layer.getTextRotate().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((CompositeFunction) layer.getTextRotate().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getTextRotate().getFunction().getStops().getClass());
+ assertEquals(1, ((ExponentialStops) layer.getTextRotate().getFunction().getStops()).size());
+
+ ExponentialStops<Stop.CompositeValue<Float, Float>, Float> stops =
+ (ExponentialStops<Stop.CompositeValue<Float, Float>, Float>) layer.getTextRotate().getFunction().getStops();
+ Stop<Stop.CompositeValue<Float, Float>, Float> stop = stops.iterator().next();
+ assertEquals(0f, stop.in.zoom, 0.001);
+ assertEquals(0.3f, stop.in.value, 0.001f);
+ assertEquals(0.9f, stop.out, 0.001f);
+ }
+
+ @Test
public void testTextPaddingAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-padding");
assertNotNull(layer);
@@ -1276,7 +1736,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextPaddingAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-padding");
assertNotNull(layer);
@@ -1302,7 +1763,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextKeepUprightAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-keep-upright");
assertNotNull(layer);
@@ -1313,7 +1775,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextKeepUprightAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-keep-upright");
assertNotNull(layer);
@@ -1338,7 +1801,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextTransformAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-transform");
assertNotNull(layer);
@@ -1349,7 +1813,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextTransformAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-transform");
assertNotNull(layer);
@@ -1374,7 +1839,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextTransformAsIdentitySourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-transform");
assertNotNull(layer);
@@ -1393,7 +1859,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextTransformAsIntervalSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-transform");
assertNotNull(layer);
@@ -1419,7 +1886,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextOffsetAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-offset");
assertNotNull(layer);
@@ -1430,7 +1898,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextOffsetAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-offset");
assertNotNull(layer);
@@ -1455,8 +1924,56 @@ public class SymbolLayerTest extends BaseStyleTest {
}
@Test
+ public void testTextOffsetAsIdentitySourceFunction() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("text-offset");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ textOffset(property("FeaturePropertyA", Stops.<Float[]>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getTextOffset());
+ assertNotNull(layer.getTextOffset().getFunction());
+ assertEquals(SourceFunction.class, layer.getTextOffset().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextOffset().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getTextOffset().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testTextOffsetAsIntervalSourceFunction() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("text-offset");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ textOffset(
+ property(
+ "FeaturePropertyA",
+ interval(
+ stop(1, textOffset(new Float[]{0f,0f}))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextOffset());
+ assertNotNull(layer.getTextOffset().getFunction());
+ assertEquals(SourceFunction.class, layer.getTextOffset().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextOffset().getFunction()).getProperty());
+ assertEquals(IntervalStops.class, layer.getTextOffset().getFunction().getStops().getClass());
+ }
+
+ @Test
public void testTextAllowOverlapAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-allow-overlap");
assertNotNull(layer);
@@ -1467,7 +1984,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextAllowOverlapAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-allow-overlap");
assertNotNull(layer);
@@ -1492,7 +2010,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextIgnorePlacementAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-ignore-placement");
assertNotNull(layer);
@@ -1503,7 +2022,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextIgnorePlacementAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-ignore-placement");
assertNotNull(layer);
@@ -1528,7 +2048,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextOptionalAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-optional");
assertNotNull(layer);
@@ -1539,7 +2060,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextOptionalAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-optional");
assertNotNull(layer);
@@ -1563,8 +2085,22 @@ public class SymbolLayerTest extends BaseStyleTest {
}
@Test
+ public void testIconOpacityTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("icon-opacityTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setIconOpacityTransition(options);
+ assertEquals(layer.getIconOpacityTransition(), options);
+ }
+
+ @Test
public void testIconOpacityAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-opacity");
assertNotNull(layer);
@@ -1575,7 +2111,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconOpacityAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-opacity");
assertNotNull(layer);
@@ -1601,7 +2138,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconOpacityAsIdentitySourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-opacity");
assertNotNull(layer);
@@ -1620,7 +2158,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconOpacityAsExponentialSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-opacity");
assertNotNull(layer);
@@ -1646,7 +2185,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconOpacityAsCategoricalSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-opacity");
assertNotNull(layer);
@@ -1675,7 +2215,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconOpacityAsCompositeFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-opacity");
assertNotNull(layer);
@@ -1708,8 +2249,22 @@ public class SymbolLayerTest extends BaseStyleTest {
}
@Test
+ public void testIconColorTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("icon-colorTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setIconColorTransition(options);
+ assertEquals(layer.getIconColorTransition(), options);
+ }
+
+ @Test
public void testIconColorAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-color");
assertNotNull(layer);
@@ -1720,7 +2275,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconColorAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-color");
assertNotNull(layer);
@@ -1746,7 +2302,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconColorAsIdentitySourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-color");
assertNotNull(layer);
@@ -1765,7 +2322,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconColorAsExponentialSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-color");
assertNotNull(layer);
@@ -1791,7 +2349,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconColorAsCategoricalSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-color");
assertNotNull(layer);
@@ -1820,7 +2379,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconColorAsIntConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-color");
assertNotNull(layer);
@@ -1830,8 +2390,22 @@ public class SymbolLayerTest extends BaseStyleTest {
}
@Test
+ public void testIconHaloColorTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("icon-halo-colorTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setIconHaloColorTransition(options);
+ assertEquals(layer.getIconHaloColorTransition(), options);
+ }
+
+ @Test
public void testIconHaloColorAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-halo-color");
assertNotNull(layer);
@@ -1842,7 +2416,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconHaloColorAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-halo-color");
assertNotNull(layer);
@@ -1868,7 +2443,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconHaloColorAsIdentitySourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-halo-color");
assertNotNull(layer);
@@ -1887,7 +2463,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconHaloColorAsExponentialSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-halo-color");
assertNotNull(layer);
@@ -1913,7 +2490,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconHaloColorAsCategoricalSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-halo-color");
assertNotNull(layer);
@@ -1942,7 +2520,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconHaloColorAsIntConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-halo-color");
assertNotNull(layer);
@@ -1952,8 +2531,22 @@ public class SymbolLayerTest extends BaseStyleTest {
}
@Test
+ public void testIconHaloWidthTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("icon-halo-widthTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setIconHaloWidthTransition(options);
+ assertEquals(layer.getIconHaloWidthTransition(), options);
+ }
+
+ @Test
public void testIconHaloWidthAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-halo-width");
assertNotNull(layer);
@@ -1964,7 +2557,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconHaloWidthAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-halo-width");
assertNotNull(layer);
@@ -1990,7 +2584,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconHaloWidthAsIdentitySourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-halo-width");
assertNotNull(layer);
@@ -2009,7 +2604,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconHaloWidthAsExponentialSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-halo-width");
assertNotNull(layer);
@@ -2035,7 +2631,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconHaloWidthAsCategoricalSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-halo-width");
assertNotNull(layer);
@@ -2064,7 +2661,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconHaloWidthAsCompositeFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-halo-width");
assertNotNull(layer);
@@ -2097,8 +2695,22 @@ public class SymbolLayerTest extends BaseStyleTest {
}
@Test
+ public void testIconHaloBlurTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("icon-halo-blurTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setIconHaloBlurTransition(options);
+ assertEquals(layer.getIconHaloBlurTransition(), options);
+ }
+
+ @Test
public void testIconHaloBlurAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-halo-blur");
assertNotNull(layer);
@@ -2109,7 +2721,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconHaloBlurAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-halo-blur");
assertNotNull(layer);
@@ -2135,7 +2748,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconHaloBlurAsIdentitySourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-halo-blur");
assertNotNull(layer);
@@ -2154,7 +2768,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconHaloBlurAsExponentialSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-halo-blur");
assertNotNull(layer);
@@ -2180,7 +2795,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconHaloBlurAsCategoricalSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-halo-blur");
assertNotNull(layer);
@@ -2209,7 +2825,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconHaloBlurAsCompositeFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-halo-blur");
assertNotNull(layer);
@@ -2242,8 +2859,22 @@ public class SymbolLayerTest extends BaseStyleTest {
}
@Test
+ public void testIconTranslateTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("icon-translateTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setIconTranslateTransition(options);
+ assertEquals(layer.getIconTranslateTransition(), options);
+ }
+
+ @Test
public void testIconTranslateAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-translate");
assertNotNull(layer);
@@ -2254,7 +2885,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconTranslateAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-translate");
assertNotNull(layer);
@@ -2280,7 +2912,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconTranslateAnchorAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-translate-anchor");
assertNotNull(layer);
@@ -2291,7 +2924,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testIconTranslateAnchorAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("icon-translate-anchor");
assertNotNull(layer);
@@ -2315,8 +2949,22 @@ public class SymbolLayerTest extends BaseStyleTest {
}
@Test
+ public void testTextOpacityTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("text-opacityTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setTextOpacityTransition(options);
+ assertEquals(layer.getTextOpacityTransition(), options);
+ }
+
+ @Test
public void testTextOpacityAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-opacity");
assertNotNull(layer);
@@ -2327,7 +2975,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextOpacityAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-opacity");
assertNotNull(layer);
@@ -2353,7 +3002,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextOpacityAsIdentitySourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-opacity");
assertNotNull(layer);
@@ -2372,7 +3022,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextOpacityAsExponentialSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-opacity");
assertNotNull(layer);
@@ -2398,7 +3049,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextOpacityAsCategoricalSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-opacity");
assertNotNull(layer);
@@ -2427,7 +3079,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextOpacityAsCompositeFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-opacity");
assertNotNull(layer);
@@ -2460,8 +3113,22 @@ public class SymbolLayerTest extends BaseStyleTest {
}
@Test
+ public void testTextColorTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("text-colorTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setTextColorTransition(options);
+ assertEquals(layer.getTextColorTransition(), options);
+ }
+
+ @Test
public void testTextColorAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-color");
assertNotNull(layer);
@@ -2472,7 +3139,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextColorAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-color");
assertNotNull(layer);
@@ -2498,7 +3166,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextColorAsIdentitySourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-color");
assertNotNull(layer);
@@ -2517,7 +3186,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextColorAsExponentialSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-color");
assertNotNull(layer);
@@ -2543,7 +3213,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextColorAsCategoricalSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-color");
assertNotNull(layer);
@@ -2572,7 +3243,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextColorAsIntConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-color");
assertNotNull(layer);
@@ -2582,8 +3254,22 @@ public class SymbolLayerTest extends BaseStyleTest {
}
@Test
+ public void testTextHaloColorTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("text-halo-colorTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setTextHaloColorTransition(options);
+ assertEquals(layer.getTextHaloColorTransition(), options);
+ }
+
+ @Test
public void testTextHaloColorAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-halo-color");
assertNotNull(layer);
@@ -2594,7 +3280,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextHaloColorAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-halo-color");
assertNotNull(layer);
@@ -2620,7 +3307,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextHaloColorAsIdentitySourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-halo-color");
assertNotNull(layer);
@@ -2639,7 +3327,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextHaloColorAsExponentialSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-halo-color");
assertNotNull(layer);
@@ -2665,7 +3354,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextHaloColorAsCategoricalSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-halo-color");
assertNotNull(layer);
@@ -2694,7 +3384,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextHaloColorAsIntConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-halo-color");
assertNotNull(layer);
@@ -2704,8 +3395,22 @@ public class SymbolLayerTest extends BaseStyleTest {
}
@Test
+ public void testTextHaloWidthTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("text-halo-widthTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setTextHaloWidthTransition(options);
+ assertEquals(layer.getTextHaloWidthTransition(), options);
+ }
+
+ @Test
public void testTextHaloWidthAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-halo-width");
assertNotNull(layer);
@@ -2716,7 +3421,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextHaloWidthAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-halo-width");
assertNotNull(layer);
@@ -2742,7 +3448,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextHaloWidthAsIdentitySourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-halo-width");
assertNotNull(layer);
@@ -2761,7 +3468,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextHaloWidthAsExponentialSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-halo-width");
assertNotNull(layer);
@@ -2787,7 +3495,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextHaloWidthAsCategoricalSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-halo-width");
assertNotNull(layer);
@@ -2816,7 +3525,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextHaloWidthAsCompositeFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-halo-width");
assertNotNull(layer);
@@ -2849,8 +3559,22 @@ public class SymbolLayerTest extends BaseStyleTest {
}
@Test
+ public void testTextHaloBlurTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("text-halo-blurTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setTextHaloBlurTransition(options);
+ assertEquals(layer.getTextHaloBlurTransition(), options);
+ }
+
+ @Test
public void testTextHaloBlurAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-halo-blur");
assertNotNull(layer);
@@ -2861,7 +3585,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextHaloBlurAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-halo-blur");
assertNotNull(layer);
@@ -2887,7 +3612,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextHaloBlurAsIdentitySourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-halo-blur");
assertNotNull(layer);
@@ -2906,7 +3632,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextHaloBlurAsExponentialSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-halo-blur");
assertNotNull(layer);
@@ -2932,7 +3659,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextHaloBlurAsCategoricalSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-halo-blur");
assertNotNull(layer);
@@ -2961,7 +3689,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextHaloBlurAsCompositeFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-halo-blur");
assertNotNull(layer);
@@ -2994,8 +3723,22 @@ public class SymbolLayerTest extends BaseStyleTest {
}
@Test
+ public void testTextTranslateTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("text-translateTransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.setTextTranslateTransition(options);
+ assertEquals(layer.getTextTranslateTransition(), options);
+ }
+
+ @Test
public void testTextTranslateAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-translate");
assertNotNull(layer);
@@ -3006,7 +3749,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextTranslateAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-translate");
assertNotNull(layer);
@@ -3032,7 +3776,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextTranslateAnchorAsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-translate-anchor");
assertNotNull(layer);
@@ -3043,7 +3788,8 @@ public class SymbolLayerTest extends BaseStyleTest {
@Test
public void testTextTranslateAnchorAsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("text-translate-anchor");
assertNotNull(layer);
@@ -3066,9 +3812,4 @@ public class SymbolLayerTest extends BaseStyleTest {
assertEquals(1, ((IntervalStops) layer.getTextTranslateAnchor().getFunction().getStops()).size());
}
-
- @After
- public void unregisterIntentServiceIdlingResource() {
- Espresso.unregisterIdlingResources(idlingResource);
- }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs
index 3dc88d29bb..02aedadfa5 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs
@@ -26,6 +26,7 @@ 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.utils.OnMapReadyIdlingResource;
+import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest;
import org.junit.After;
import org.junit.Before;
@@ -40,27 +41,23 @@ import static org.junit.Assert.*;
import static com.mapbox.mapboxsdk.style.layers.Property.*;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.*;
+import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
+import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity;
+
/**
* Basic smoke tests for <%- camelize(type) %>Layer
*/
@RunWith(AndroidJUnit4.class)
-public class <%- camelize(type) %>LayerTest extends BaseStyleTest {
-
- @Rule
- public final ActivityTestRule<RuntimeStyleTestActivity> rule = new ActivityTestRule<>(RuntimeStyleTestActivity.class);
+public class <%- camelize(type) %>LayerTest extends BaseActivityTest {
private <%- camelize(type) %>Layer layer;
- private OnMapReadyIdlingResource idlingResource;
-
- private MapboxMap mapboxMap;
-
- @Before
- public void setup() {
- idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
- Espresso.registerIdlingResources(idlingResource);
- mapboxMap = rule.getActivity().getMapboxMap();
+ @Override
+ protected Class getActivityClass() {
+ return EspressoTestActivity.class;
+ }
+ private void setupLayer(){
<% if (type === 'background') { -%>
Timber.i("Retrieving layer");
layer = mapboxMap.getLayerAs("background");
@@ -78,7 +75,8 @@ public class <%- camelize(type) %>LayerTest extends BaseStyleTest {
@Test
public void testSetVisibility() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("Visibility");
assertNotNull(layer);
@@ -89,11 +87,45 @@ public class <%- camelize(type) %>LayerTest extends BaseStyleTest {
layer.setProperties(visibility(NONE));
assertEquals(layer.getVisibility().getValue(), NONE);
}
+<% if (!(type === 'background' || type === 'raster')) { -%>
+
+ @Test
+ public void testSourceLayer() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("SourceLayer");
+ assertNotNull(layer);
+
+ // Get initial
+ assertEquals(layer.getSourceLayer(), "composite");
+ // Set
+ final String sourceLayer = "test";
+ layer.setSourceLayer(sourceLayer);
+ assertEquals(layer.getSourceLayer(), sourceLayer);
+ }
+<% } -%>
<% for (const property of properties) { -%>
+<% if (property.transition) { -%>
+
+ @Test
+ public void test<%- camelize(property.name) %>Transition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("<%- property.name %>TransitionOptions");
+ assertNotNull(layer);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ layer.set<%- camelize(property.name) %>Transition(options);
+ assertEquals(layer.get<%- camelize(property.name) %>Transition(), options);
+ }
+<% } -%>
+
@Test
public void test<%- camelize(property.name) %>AsConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("<%- property.name %>");
assertNotNull(layer);
@@ -105,7 +137,8 @@ public class <%- camelize(type) %>LayerTest extends BaseStyleTest {
@Test
public void test<%- camelize(property.name) %>AsCameraFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("<%- property.name %>");
assertNotNull(layer);
@@ -144,7 +177,8 @@ public class <%- camelize(type) %>LayerTest extends BaseStyleTest {
@Test
public void test<%- camelize(property.name) %>AsIdentitySourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("<%- property.name %>");
assertNotNull(layer);
@@ -164,7 +198,8 @@ public class <%- camelize(type) %>LayerTest extends BaseStyleTest {
@Test
public void test<%- camelize(property.name) %>AsIntervalSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("<%- property.name %>");
assertNotNull(layer);
@@ -195,7 +230,8 @@ public class <%- camelize(type) %>LayerTest extends BaseStyleTest {
@Test
public void test<%- camelize(property.name) %>AsIntervalSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("<%- property.name %>");
assertNotNull(layer);
@@ -226,7 +262,8 @@ public class <%- camelize(type) %>LayerTest extends BaseStyleTest {
@Test
public void test<%- camelize(property.name) %>AsExponentialSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("<%- property.name %>");
assertNotNull(layer);
@@ -256,7 +293,8 @@ public class <%- camelize(type) %>LayerTest extends BaseStyleTest {
@Test
public void test<%- camelize(property.name) %>AsCategoricalSourceFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("<%- property.name %>");
assertNotNull(layer);
@@ -296,7 +334,8 @@ public class <%- camelize(type) %>LayerTest extends BaseStyleTest {
@Test
public void test<%- camelize(property.name) %>AsCompositeFunction() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("<%- property.name %>");
assertNotNull(layer);
@@ -338,7 +377,8 @@ public class <%- camelize(type) %>LayerTest extends BaseStyleTest {
@Test
public void test<%- camelize(property.name) %>AsIntConstant() {
- checkViewIsDisplayed(R.id.mapView);
+ validateTestSetup();
+ setupLayer();
Timber.i("<%- property.name %>");
assertNotNull(layer);
@@ -347,11 +387,6 @@ public class <%- camelize(type) %>LayerTest extends BaseStyleTest {
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/utils/ScreenshotUtil.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/ScreenshotUtil.java
deleted file mode 100644
index 77bfc519bf..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/ScreenshotUtil.java
+++ /dev/null
@@ -1,137 +0,0 @@
-package com.mapbox.mapboxsdk.testapp.utils;
-
-import android.app.Activity;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.os.Environment;
-
-import timber.log.Timber;
-
-import android.view.TextureView;
-import android.view.View;
-import android.view.ViewGroup;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.UUID;
-
-/**
- * The built-in Fuzz Suite on AWS Device Farm takes screenshots after every test. However,
- * this doesn't happen with Espresso unless we manually do it. This class fixes it.
- */
-public class ScreenshotUtil {
-
- // Where to store the files. This path is required by AWS Device Farm:
- // http://docs.aws.amazon.com/devicefarm/latest/developerguide/test-types-android-instrumentation.html
- // #test-types-android-instrumentation-screenshots
- private static final String SCREENSHOT_FOLDER = "test-screenshots";
-
- // Image type and quality
- private static final String DEFAULT_IMAGE_EXTENSION = ".png";
- private static final Bitmap.CompressFormat DEFAULT_IMAGE_FORMAT = Bitmap.CompressFormat.PNG;
- private static final int DEFAULT_IMAGE_QUALITY = 100;
-
- public static void take(Activity activity, String testName) {
-
- // Check if storage is available
- if (!isExternalStorageWritable()) {
- Timber.d("External storage is not available.");
- return;
- }
-
- // Get a bitmap from the activity root view. When the drawing cache is enabled,
- // the next call to getDrawingCache() will draw the view in a bitmap.
- View rootView = activity.getWindow().getDecorView().getRootView();
- // rootView.setDrawingCacheEnabled(true);r
- // rootView.setDrawingCacheEnabled(false);
-
- Bitmap bitmap = null;
-
- // Add the SurfaceView bit (see getAllTextureViews() below)
- List<TextureView> tilingViews = getAllTextureViews(rootView);
- if (tilingViews.size() > 0) {
- bitmap = Bitmap.createBitmap(tilingViews.get(0).getHeight(), tilingViews.get(0).getWidth(),
- Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(bitmap);
- for (TextureView TextureView : tilingViews) {
- Bitmap b = TextureView.getBitmap(TextureView.getWidth(), TextureView.getHeight());
- int[] location = new int[2];
- TextureView.getLocationInWindow(location);
- int[] location2 = new int[2];
- TextureView.getLocationOnScreen(location2);
- canvas.drawBitmap(b, 0, 0, null);
- }
- }
-
- // Save the bitmap in external storage
- String uniqueAbsolutePath = getUniqueAbsolutePath(testName);
- File outputFile = new File(uniqueAbsolutePath);
- OutputStream outputStream = null;
- try {
- outputStream = new FileOutputStream(outputFile);
- bitmap.compress(DEFAULT_IMAGE_FORMAT, DEFAULT_IMAGE_QUALITY, outputStream);
- outputStream.flush();
- } catch (Exception exception) {
-
- exception.printStackTrace();
- } finally {
- if (outputStream != null) {
- try {
- outputStream.close();
- } catch (IOException ioException) {
- ioException.printStackTrace();
- }
- }
- }
- }
-
- /*
- * The classic way of taking a screenshot (above) doesn't work with TextureView, this fixes it:
- * http://stackoverflow.com/questions/19704060/screen-capture-textureview-is-black-using-drawingcache
- */
-
- public static List<TextureView> getAllTextureViews(View view) {
- List<TextureView> tilingViews = new ArrayList<TextureView>();
- if (view instanceof TextureView) {
- tilingViews.add((TextureView) view);
- } else if (view instanceof ViewGroup) {
- ViewGroup viewGroup = (ViewGroup) view;
- for (int i = 0; i < viewGroup.getChildCount(); i++) {
- tilingViews.addAll(getAllTextureViews(viewGroup.getChildAt(i)));
- }
- }
-
- return tilingViews;
- }
-
- /*
- * Utils
- */
-
- public static boolean isExternalStorageWritable() {
- // Checks if external storage is available for read and write
- String state = Environment.getExternalStorageState();
- return Environment.MEDIA_MOUNTED.equals(state);
- }
-
- private static String getUniqueAbsolutePath(String testName) {
- // A screenshot after every test vs. manual tests
- String filename = UUID.randomUUID().toString() + DEFAULT_IMAGE_EXTENSION;
- if (testName != null && !testName.isEmpty()) {
- filename = testName + DEFAULT_IMAGE_EXTENSION;
- }
-
- String externalPath = Environment.getExternalStorageDirectory().toString();
- String path = externalPath + File.separator + SCREENSHOT_FOLDER;
- File dir = new File(path);
- dir.mkdirs();
- path += File.separator + filename;
- Timber.d("Screenshot path: " + path);
- return path;
- }
-
-}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
index e6d118692e..9ede763533 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
@@ -247,6 +247,17 @@
android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
+ android:name=".activity.userlocation.CustomLocationEngineActivity"
+ android:description="@string/description_custom_location_engine"
+ android:label="@string/activity_custom_location_engine">
+ <meta-data
+ android:name="@string/category"
+ android:value="@string/category_userlocation"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
+ </activity>
+ <activity
android:name=".activity.annotation.PolygonActivity"
android:description="@string/description_polygon"
android:label="@string/activity_polygon">
@@ -437,6 +448,28 @@
android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
+ android:name=".activity.style.FillExtrusionActivity"
+ android:description="@string/description_fill_extrusion_layer"
+ android:label="@string/activity_fill_extrusion_layer">
+ <meta-data
+ android:name="@string/category"
+ android:value="@string/category_style"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
+ </activity>
+ <activity
+ android:name=".activity.style.BuildingFillExtrusionActivity"
+ android:description="@string/description_building_fill_extrusion_layer"
+ android:label="@string/activity_building_fill_extrusion_layer">
+ <meta-data
+ android:name="@string/category"
+ android:value="@string/category_style"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
+ </activity>
+ <activity
android:name=".activity.style.SymbolLayerActivity"
android:description="@string/description_symbol_layer"
android:label="@string/activity_symbol_layer">
@@ -592,14 +625,41 @@
android:name="android.support.PARENT_ACTIVITY"
android:value=".activity.FeatureOverviewActivity"/>
</activity>
+ <activity
+ android:name=".activity.maplayout.LatLngBoundsForCameraActivity"
+ android:description="@string/description_restricted_bounds"
+ android:label="@string/activity_restricted_bounds">
+ <meta-data
+ android:name="@string/category"
+ android:value="@string/category_maplayout"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
+ </activity>
+
+ <!-- Storage -->
+ <activity
+ android:name=".activity.storage.UrlTransformActivity"
+ android:description="@string/description_url_transform"
+ android:label="@string/activity_url_transform">
+ <meta-data
+ android:name="@string/category"
+ android:value="@string/category_storage"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
+ </activity>
+
<!-- For Instrumentation tests -->
<activity
android:name=".activity.style.RuntimeStyleTestActivity"
android:screenOrientation="portrait"/>
- <activity android:name=".activity.style.RuntimeStyleTimingTestActivity"
+ <activity
+ android:name=".activity.style.RuntimeStyleTimingTestActivity"
android:screenOrientation="portrait"/>
- <activity android:name=".activity.espresso.EspressoTestActivity"
+ <activity
+ android:name=".activity.espresso.EspressoTestActivity"
android:screenOrientation="portrait"/>
<!-- Configuration Settings -->
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapboxApplication.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapboxApplication.java
index e344343627..deee312bb3 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapboxApplication.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapboxApplication.java
@@ -2,8 +2,11 @@ package com.mapbox.mapboxsdk.testapp;
import android.app.Application;
import android.os.StrictMode;
+import android.text.TextUtils;
+import android.util.Log;
import com.mapbox.mapboxsdk.Mapbox;
+import com.mapbox.mapboxsdk.testapp.utils.TokenUtils;
import com.squareup.leakcanary.LeakCanary;
import timber.log.Timber;
@@ -18,6 +21,13 @@ import static timber.log.Timber.DebugTree;
*/
public class MapboxApplication extends Application {
+ private static final String LOG_TAG = MapboxApplication.class.getSimpleName();
+ private static final String DEFAULT_MAPBOX_ACCESS_TOKEN = "YOUR_MAPBOX_ACCESS_TOKEN_GOES_HERE";
+ private static final String ACCESS_TOKEN_NOT_SET_MESSAGE = "In order to run the Test App you need to set a valid "
+ + "access token. During development, you can set the MAPBOX_ACCESS_TOKEN environment variable for the SDK to "
+ + "automatically include it in the Test App. Otherwise, you can manually include it in the "
+ + "res/values/developer-config.xml file in the MapboxGLAndroidSDKTestApp folder.";
+
@Override
public void onCreate() {
super.onCreate();
@@ -43,7 +53,12 @@ public class MapboxApplication extends Application {
.penaltyDeath()
.build());
- Mapbox.getInstance(getApplicationContext(), getString(R.string.mapbox_access_token));
+ String mapboxAccessToken = TokenUtils.getMapboxAccessToken(getApplicationContext());
+ if (TextUtils.isEmpty(mapboxAccessToken) || mapboxAccessToken.equals(DEFAULT_MAPBOX_ACCESS_TOKEN)) {
+ Log.w(LOG_TAG, ACCESS_TOKEN_NOT_SET_MESSAGE);
+ }
+
+ Mapbox.getInstance(getApplicationContext(), mapboxAccessToken);
}
private void initializeLogger() {
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 e8e1c17816..074be98f5c 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
@@ -8,6 +8,7 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.os.AsyncTask;
+import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.StringRes;
@@ -132,7 +133,7 @@ public class FeatureOverviewActivity extends AppCompatActivity {
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
- if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ if (!isRuntimePermissionsRequired() || isPermissionAccepted(grantResults)) {
startFeature(features.get(requestCode));
} else {
Snackbar.make(
@@ -142,6 +143,14 @@ public class FeatureOverviewActivity extends AppCompatActivity {
}
}
+ private boolean isRuntimePermissionsRequired() {
+ return android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
+ }
+
+ private boolean isPermissionAccepted(@NonNull int[] grantResults) {
+ return grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED;
+ }
+
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
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 a2245a28e0..b51d717f33 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
@@ -18,6 +18,7 @@ import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.testapp.R;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import static com.mapbox.mapboxsdk.testapp.activity.annotation.PolygonActivity.Config.BLUE_COLOR;
@@ -26,6 +27,7 @@ import static com.mapbox.mapboxsdk.testapp.activity.annotation.PolygonActivity.C
import static com.mapbox.mapboxsdk.testapp.activity.annotation.PolygonActivity.Config.NO_ALPHA;
import static com.mapbox.mapboxsdk.testapp.activity.annotation.PolygonActivity.Config.PARTIAL_ALPHA;
import static com.mapbox.mapboxsdk.testapp.activity.annotation.PolygonActivity.Config.RED_COLOR;
+import static com.mapbox.mapboxsdk.testapp.activity.annotation.PolygonActivity.Config.STAR_SHAPE_HOLES;
import static com.mapbox.mapboxsdk.testapp.activity.annotation.PolygonActivity.Config.STAR_SHAPE_POINTS;
/**
@@ -43,7 +45,8 @@ public class PolygonActivity extends AppCompatActivity implements OnMapReadyCall
private boolean fullAlpha = true;
private boolean visible = true;
private boolean color = true;
- private boolean allPoints;
+ private boolean allPoints = true;
+ private boolean holes = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -140,6 +143,10 @@ public class PolygonActivity extends AppCompatActivity implements OnMapReadyCall
color = !color;
polygon.setFillColor(color ? BLUE_COLOR : RED_COLOR);
return true;
+ case R.id.action_id_holes:
+ holes = !holes;
+ polygon.setHoles(holes ? STAR_SHAPE_HOLES : Collections.<List<LatLng>>emptyList());
+ return true;
default:
return super.onOptionsItemSelected(item);
}
@@ -179,5 +186,27 @@ public class PolygonActivity extends AppCompatActivity implements OnMapReadyCall
static final List<LatLng> BROKEN_SHAPE_POINTS =
STAR_SHAPE_POINTS.subList(0, STAR_SHAPE_POINTS.size() - 3);
+
+ static final List<? extends List<LatLng>> STAR_SHAPE_HOLES = new ArrayList<List<LatLng>>() {
+ {
+ add(new ArrayList<>(new ArrayList<LatLng>() {
+ {
+ add(new LatLng(45.521743, -122.669091));
+ add(new LatLng(45.530483, -122.676833));
+ add(new LatLng(45.520483, -122.676833));
+ add(new LatLng(45.521743, -122.669091));
+ }
+ }));
+ add(new ArrayList<>(new ArrayList<LatLng>() {
+ {
+ add(new LatLng(45.529743, -122.662791));
+ add(new LatLng(45.525543, -122.662791));
+ add(new LatLng(45.525543, -122.660));
+ add(new LatLng(45.527743, -122.660));
+ add(new LatLng(45.529743, -122.662791));
+ }
+ }));
+ }
+ };
}
}
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 ba861131a2..d81538f323 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
@@ -59,10 +59,10 @@ public class LatLngBoundsActivity extends AppCompatActivity implements OnMapRead
private void moveToBounds(LatLngBounds latLngBounds, int[] padding) {
mapboxMap.clear();
- mapboxMap.addMarker(new MarkerOptions().position(new LatLng(latLngBounds.getLatNorth(),latLngBounds.getLonEast())));
- mapboxMap.addMarker(new MarkerOptions().position(new LatLng(latLngBounds.getLatSouth(), latLngBounds.getLonEast())));
- mapboxMap.addMarker(new MarkerOptions().position(new LatLng(latLngBounds.getLatSouth(), latLngBounds.getLonWest())));
- mapboxMap.addMarker(new MarkerOptions().position(new LatLng(latLngBounds.getLatNorth(), latLngBounds.getLonWest())));
+ mapboxMap.addMarker(new MarkerOptions().position(latLngBounds.getNorthEast()));
+ mapboxMap.addMarker(new MarkerOptions().position(latLngBounds.getSouthEast()));
+ mapboxMap.addMarker(new MarkerOptions().position(latLngBounds.getSouthWest()));
+ mapboxMap.addMarker(new MarkerOptions().position(latLngBounds.getNorthWest()));
CameraUpdate update =
CameraUpdateFactory.newLatLngBounds(latLngBounds,
padding[0],
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/LatLngBoundsForCameraActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/LatLngBoundsForCameraActivity.java
new file mode 100644
index 0000000000..9ac87deb0d
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/LatLngBoundsForCameraActivity.java
@@ -0,0 +1,109 @@
+package com.mapbox.mapboxsdk.testapp.activity.maplayout;
+
+import android.graphics.Color;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import com.mapbox.mapboxsdk.annotations.PolygonOptions;
+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;
+
+/**
+ * Test Activity showcasing restricting user gestures to a bounds around Iceland.
+ */
+public class LatLngBoundsForCameraActivity extends AppCompatActivity implements OnMapReadyCallback {
+
+ private static final LatLngBounds ICELAND_BOUNDS = new LatLngBounds.Builder()
+ .include(new LatLng(66.852863, -25.985652))
+ .include(new LatLng(62.985661, -12.626277))
+ .build();
+
+ private MapView mapView;
+ private MapboxMap mapboxMap;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_restricted_bounds);
+
+ mapView = (MapView) findViewById(R.id.mapView);
+ mapView.onCreate(savedInstanceState);
+ mapView.getMapAsync(this);
+ }
+
+ @Override
+ public void onMapReady(MapboxMap mapboxMap) {
+ this.mapboxMap = mapboxMap;
+ mapboxMap.setLatLngBoundsForCameraTarget(ICELAND_BOUNDS);
+ mapboxMap.setMinZoomPreference(2);
+ showBoundsArea();
+ showCrosshair();
+ }
+
+ private void showBoundsArea() {
+ PolygonOptions boundsArea = new PolygonOptions()
+ .add(ICELAND_BOUNDS.getNorthWest())
+ .add(ICELAND_BOUNDS.getNorthEast())
+ .add(ICELAND_BOUNDS.getSouthEast())
+ .add(ICELAND_BOUNDS.getSouthWest());
+ boundsArea.alpha(0.25f);
+ boundsArea.fillColor(Color.RED);
+ mapboxMap.addPolygon(boundsArea);
+ }
+
+ private void showCrosshair() {
+ View crosshair = new View(this);
+ crosshair.setLayoutParams(new FrameLayout.LayoutParams(10, 10, Gravity.CENTER));
+ crosshair.setBackgroundColor(Color.BLUE);
+ mapView.addView(crosshair);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ mapView.onStart();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mapView.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ mapView.onPause();
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ mapView.onStop();
+ }
+
+ @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/storage/UrlTransformActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/storage/UrlTransformActivity.java
new file mode 100644
index 0000000000..74b43e0257
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/storage/UrlTransformActivity.java
@@ -0,0 +1,104 @@
+package com.mapbox.mapboxsdk.testapp.activity.storage;
+
+import android.app.Activity;
+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.storage.FileSource;
+import com.mapbox.mapboxsdk.storage.Resource;
+import com.mapbox.mapboxsdk.testapp.R;
+
+import timber.log.Timber;
+
+/**
+ * Test activity showcasing the url transform
+ */
+public class UrlTransformActivity extends AppCompatActivity {
+
+ private MapView mapView;
+ private MapboxMap mapboxMap;
+
+ /**
+ * Be sure to use an isolated class so the activity is not leaked when
+ * the activity goes out of scope (static class in this case).
+ * <p>
+ * Alternatively, unregister the callback in {@link Activity#onDestroy()}
+ */
+ private static final class Transform implements FileSource.ResourceTransformCallback {
+ @Override
+ public String onURL(@Resource.Kind int kind, String url) {
+ Timber.i("[%s] Could be rewriting %s", Thread.currentThread().getName(), url);
+ return url;
+ }
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_data_driven_style);
+
+ // Initialize map as normal
+ mapView = (MapView) findViewById(R.id.mapView);
+ mapView.onCreate(savedInstanceState);
+
+ // Get a handle to the file source and set the resource transform
+ FileSource.getInstance(UrlTransformActivity.this).setResourceTransform(new Transform());
+
+ mapView.getMapAsync(new OnMapReadyCallback() {
+ @Override
+ public void onMapReady(MapboxMap map) {
+ Timber.i("Map loaded");
+ mapboxMap = map;
+ }
+ });
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ mapView.onStart();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mapView.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ mapView.onPause();
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ mapView.onStop();
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ mapView.onSaveInstanceState(outState);
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+
+ // Example of how to reset the transform callback
+ FileSource.getInstance(UrlTransformActivity.this).setResourceTransform(null);
+
+ 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/BuildingFillExtrusionActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/BuildingFillExtrusionActivity.java
new file mode 100644
index 0000000000..f444aa40f0
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/BuildingFillExtrusionActivity.java
@@ -0,0 +1,95 @@
+package com.mapbox.mapboxsdk.testapp.activity.style;
+
+import android.graphics.Color;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+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.functions.Function;
+import com.mapbox.mapboxsdk.style.functions.stops.IdentityStops;
+import com.mapbox.mapboxsdk.style.layers.FillExtrusionLayer;
+import com.mapbox.mapboxsdk.testapp.R;
+
+import static com.mapbox.mapboxsdk.style.layers.Filter.eq;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillExtrusionBase;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillExtrusionColor;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillExtrusionHeight;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillExtrusionOpacity;
+
+/**
+ * Test activity showing 3D buildings with a FillExtrusion Layer
+ */
+public class BuildingFillExtrusionActivity extends AppCompatActivity {
+
+ private MapView mapView;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_building_layer);
+ mapView = (MapView) findViewById(R.id.mapView);
+ mapView.onCreate(savedInstanceState);
+ mapView.getMapAsync(new OnMapReadyCallback() {
+ @Override
+ public void onMapReady(@NonNull final MapboxMap map) {
+ FillExtrusionLayer fillExtrusionLayer = new FillExtrusionLayer("3d-buildings", "composite");
+ fillExtrusionLayer.setSourceLayer("building");
+ fillExtrusionLayer.setFilter(eq("extrude", "true"));
+ fillExtrusionLayer.setMinZoom(15);
+ fillExtrusionLayer.setProperties(
+ fillExtrusionColor(Color.LTGRAY),
+ fillExtrusionHeight(Function.property("height", new IdentityStops<Float>())),
+ fillExtrusionBase(Function.property("min_height", new IdentityStops<Float>())),
+ fillExtrusionOpacity(0.6f)
+ );
+ map.addLayer(fillExtrusionLayer);
+ }
+ });
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ mapView.onStart();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mapView.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ mapView.onPause();
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ mapView.onStop();
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ mapView.onSaveInstanceState(outState);
+ }
+
+ @Override
+ public void onLowMemory() {
+ super.onLowMemory();
+ mapView.onLowMemory();
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ mapView.onDestroy();
+ }
+
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/CircleLayerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/CircleLayerActivity.java
index 7628d6391e..2238d1d5fe 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/CircleLayerActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/CircleLayerActivity.java
@@ -10,6 +10,7 @@ import android.view.View;
import com.mapbox.mapboxsdk.camera.CameraPosition;
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;
@@ -34,18 +35,19 @@ import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleRadius;
* Uses bus stop data from Singapore as a source and allows to filter into 1 specific route with a line layer.
* </p>
*/
-public class CircleLayerActivity extends AppCompatActivity {
-
- private static final String[] STOPS_FOR_ROUTE = new String[] {"99009", "99131", "99049", "99039", "99029", "99019",
- "98079", "98069", "97099", "97089", "97079", "97069", "97209", "97059", "97049", "97039", "97019", "96069",
- "96059", "96049", "96099", "96089", "96079", "85079", "85089", "85069", "85059", "85099", "84069", "84059",
- "84049", "84039", "84029", "84019", "83099", "83079", "83059", "83049", "83029", "82069", "82049", "82029",
- "82109", "81069", "81049", "81029", "80089", "80069", "80049", "80039", "80029", "01319", "01219", "01129",
- "01059", "01119", "01019", "04159", "04149", "04229", "04239", "05059", "05049", "05039", "05019", "10589"};
+public class CircleLayerActivity extends AppCompatActivity implements View.OnClickListener {
private MapView mapView;
private MapboxMap mapboxMap;
+
+ private FloatingActionButton styleFab;
+ private FloatingActionButton routeFab;
+
private CircleLayer layer;
+ private GeoJsonSource source;
+
+ private int currentStyleIndex = 0;
+ private boolean isLoadingStyle = true;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -56,58 +58,131 @@ public class CircleLayerActivity extends AppCompatActivity {
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(new OnMapReadyCallback() {
@Override
- public void onMapReady(@NonNull final MapboxMap map) {
+ public void onMapReady(@NonNull
+ final MapboxMap map) {
mapboxMap = map;
- try {
- mapboxMap.addSource(new GeoJsonSource("bus_stop",
- new URL("https://raw.githubusercontent.com/cheeaun/busrouter-sg/master/data/2/bus-stops.geojson")));
- } catch (MalformedURLException malformedUrlException) {
- Timber.e("That's not an url... ", malformedUrlException);
- }
-
- layer = new CircleLayer("stops_layer", "bus_stop");
- layer.setProperties(
- circleColor(Color.parseColor("#FF9800")),
- circleRadius(1.0f)
- );
-
- mapboxMap.addLayer(layer);
-
- FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
- fab.setColorFilter(ContextCompat.getColor(CircleLayerActivity.this, R.color.primary));
- fab.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
-
- // filter out stops for our route
- layer.setFilter(in("number", (Object[]) STOPS_FOR_ROUTE));
-
- // add route as a line
- try {
- mapboxMap.addSource(new GeoJsonSource("bus_route",
- new URL("https://gist.githubusercontent.com/tobrun/7fbc0fe7e9ffea509f7608cda2601d5d/raw/"
- + "a4b8cc289020f91fa2e1553524820054395e36f5/line.geojson")));
- } catch (MalformedURLException malformedUrlException) {
- Timber.e("That's not an url... ", malformedUrlException);
- }
- LineLayer lineLayer = new LineLayer("route_layer", "bus_route");
- mapboxMap.addLayerBelow(lineLayer, "stops_layer");
-
- // move camera to start route
- mapboxMap.animateCamera(CameraUpdateFactory.newCameraPosition(
- new CameraPosition.Builder()
- .target(new LatLng(1.3896777, 103.9874997))
- .bearing(225)
- .tilt(45)
- .zoom(13)
- .build()
- ), 1750);
- }
- });
+ addBusStopSource();
+ addBusStopCircleLayer();
+ initFloatingActionButtons();
+ isLoadingStyle = false;
}
});
}
+ private void addBusStopSource() {
+ try {
+ source = new GeoJsonSource("bus_stop",
+ new URL("https://raw.githubusercontent.com/cheeaun/busrouter-sg/master/data/2/bus-stops.geojson"));
+ } catch (MalformedURLException exception) {
+ Timber.e("That's not an url... ", exception);
+ }
+ mapboxMap.addSource(source);
+ }
+
+ private void addBusStopCircleLayer() {
+ layer = new CircleLayer("stops_layer", "bus_stop");
+ layer.setProperties(
+ circleColor(Color.parseColor("#FF9800")),
+ circleRadius(2.0f)
+ );
+ mapboxMap.addLayer(layer);
+ }
+
+ private void initFloatingActionButtons() {
+ routeFab = (FloatingActionButton) findViewById(R.id.fab_route);
+ routeFab.setColorFilter(ContextCompat.getColor(CircleLayerActivity.this, R.color.primary));
+ routeFab.setOnClickListener(CircleLayerActivity.this);
+
+ styleFab = (FloatingActionButton) findViewById(R.id.fab_style);
+ styleFab.setOnClickListener(CircleLayerActivity.this);
+ }
+
+ @Override
+ public void onClick(View view) {
+ if (isLoadingStyle) {
+ return;
+ }
+
+ if (view.getId() == R.id.fab_route) {
+ showBusRoute();
+ } else if (view.getId() == R.id.fab_style) {
+ changeMapStyle();
+ }
+ }
+
+ private void showBusRoute() {
+ removeFabs();
+ applyBusRouteFilterToBusStopSource();
+ addBusRouteSource();
+ addBusRouteLayer();
+ }
+
+ private void removeFabs() {
+ routeFab.setVisibility(View.GONE);
+ styleFab.setVisibility(View.GONE);
+ }
+
+ private void applyBusRouteFilterToBusStopSource() {
+ layer.setFilter(in("number", (Object[]) Data.STOPS_FOR_ROUTE));
+ }
+
+ private void addBusRouteSource() {
+ try {
+ mapboxMap.addSource(new GeoJsonSource("bus_route",
+ new URL("https://gist.githubusercontent.com/tobrun/7fbc0fe7e9ffea509f7608cda2601d5d/raw/"
+ + "a4b8cc289020f91fa2e1553524820054395e36f5/line.geojson")));
+ } catch (MalformedURLException malformedUrlException) {
+ Timber.e("That's not an url... ", malformedUrlException);
+ }
+ }
+
+ private void addBusRouteLayer() {
+ LineLayer lineLayer = new LineLayer("route_layer", "bus_route");
+ mapboxMap.addLayerBelow(lineLayer, "stops_layer");
+ mapboxMap.animateCamera(CameraUpdateFactory.newCameraPosition(
+ new CameraPosition.Builder()
+ .target(new LatLng(1.3896777, 103.9874997))
+ .bearing(225)
+ .tilt(45)
+ .zoom(13)
+ .build()
+ ), 1750);
+ }
+
+ private void changeMapStyle() {
+ isLoadingStyle = true;
+ removeBusStop();
+ loadNewStyle();
+ }
+
+ private void removeBusStop() {
+ mapboxMap.removeLayer(layer);
+ mapboxMap.removeSource(source);
+ }
+
+ private void loadNewStyle() {
+ mapboxMap.setStyleUrl(getNextStyle(), new MapboxMap.OnStyleLoadedListener() {
+ @Override
+ public void onStyleLoaded(String style) {
+ addBusStop();
+ isLoadingStyle = false;
+ }
+ });
+ }
+
+ private void addBusStop() {
+ mapboxMap.addLayer(layer);
+ mapboxMap.addSource(source);
+ }
+
+ private String getNextStyle() {
+ currentStyleIndex++;
+ if (currentStyleIndex == Data.STYLES.length) {
+ currentStyleIndex = 0;
+ }
+ return Data.STYLES[currentStyleIndex];
+ }
+
@Override
protected void onStart() {
super.onStart();
@@ -149,4 +224,22 @@ public class CircleLayerActivity extends AppCompatActivity {
super.onDestroy();
mapView.onDestroy();
}
+
+ private static class Data {
+ private static final String[] STOPS_FOR_ROUTE = new String[] {"99009", "99131", "99049", "99039", "99029", "99019",
+ "98079", "98069", "97099", "97089", "97079", "97069", "97209", "97059", "97049", "97039", "97019", "96069",
+ "96059", "96049", "96099", "96089", "96079", "85079", "85089", "85069", "85059", "85099", "84069", "84059",
+ "84049", "84039", "84029", "84019", "83099", "83079", "83059", "83049", "83029", "82069", "82049", "82029",
+ "82109", "81069", "81049", "81029", "80089", "80069", "80049", "80039", "80029", "01319", "01219", "01129",
+ "01059", "01119", "01019", "04159", "04149", "04229", "04239", "05059", "05049", "05039", "05019", "10589"};
+
+ private static final String[] STYLES = new String[] {
+ Style.MAPBOX_STREETS,
+ Style.OUTDOORS,
+ Style.LIGHT,
+ Style.DARK,
+ Style.SATELLITE,
+ Style.SATELLITE_STREETS
+ };
+ }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/FillExtrusionActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/FillExtrusionActivity.java
new file mode 100644
index 0000000000..9a7790c6e5
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/FillExtrusionActivity.java
@@ -0,0 +1,135 @@
+package com.mapbox.mapboxsdk.testapp.activity.style;
+
+import android.graphics.Color;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v7.app.AppCompatActivity;
+
+import com.mapbox.mapboxsdk.camera.CameraPosition;
+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.FillExtrusionLayer;
+import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
+import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.services.commons.geojson.Polygon;
+
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillExtrusionColor;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillExtrusionHeight;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillExtrusionOpacity;
+
+/**
+ * Test activity showcasing fill extrusions
+ */
+public class FillExtrusionActivity extends AppCompatActivity {
+
+ private MapView mapView;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_fill_extrusion_layer);
+
+ mapView = (MapView) findViewById(R.id.mapView);
+ mapView.onCreate(savedInstanceState);
+ mapView.getMapAsync(new OnMapReadyCallback() {
+ @Override
+ public void onMapReady(@NonNull
+ final MapboxMap map) {
+ Polygon domTower = Polygon.fromCoordinates(new double[][][] {
+ new double[][] {
+ new double[] {
+ 5.12112557888031,
+ 52.09071040847704
+ },
+ new double[] {
+ 5.121227502822875,
+ 52.09053901776669
+ },
+ new double[] {
+ 5.121484994888306,
+ 52.090601641371805
+ },
+ new double[] {
+ 5.1213884353637695,
+ 52.090766439912635
+ },
+ new double[] {
+ 5.12112557888031,
+ 52.09071040847704
+ }
+ }
+ });
+
+ GeoJsonSource source = new GeoJsonSource("extrusion-source", domTower);
+ map.addSource(source);
+
+ map.addLayer(
+ new FillExtrusionLayer("extrusion-layer", source.getId())
+ .withProperties(
+ fillExtrusionHeight(40f),
+ fillExtrusionOpacity(0.5f),
+ fillExtrusionColor(Color.RED)
+ )
+ );
+
+ map.animateCamera(
+ CameraUpdateFactory.newCameraPosition(
+ new CameraPosition.Builder()
+ .target(new LatLng(52.09071040847704, 5.12112557888031))
+ .tilt(45.0)
+ .zoom(18)
+ .build()
+ ),
+ 10000
+ );
+ }
+ });
+ }
+
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ mapView.onStart();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mapView.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ mapView.onPause();
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ mapView.onStop();
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ mapView.onSaveInstanceState(outState);
+ }
+
+ @Override
+ public void onLowMemory() {
+ super.onLowMemory();
+ mapView.onLowMemory();
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ mapView.onDestroy();
+ }
+
+}
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
index af42b7a0fe..f6754af0f9 100644
--- 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
@@ -17,12 +17,15 @@ import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.style.functions.Function;
import com.mapbox.mapboxsdk.style.functions.stops.ExponentialStops;
import com.mapbox.mapboxsdk.style.functions.stops.Stop;
+import com.mapbox.mapboxsdk.style.layers.CircleLayer;
import com.mapbox.mapboxsdk.style.layers.FillLayer;
import com.mapbox.mapboxsdk.style.layers.Layer;
import com.mapbox.mapboxsdk.style.layers.LineLayer;
import com.mapbox.mapboxsdk.style.layers.Property;
import com.mapbox.mapboxsdk.style.layers.PropertyValue;
import com.mapbox.mapboxsdk.style.layers.RasterLayer;
+import com.mapbox.mapboxsdk.style.layers.SymbolLayer;
+import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
import com.mapbox.mapboxsdk.style.sources.RasterSource;
import com.mapbox.mapboxsdk.style.sources.Source;
@@ -40,6 +43,7 @@ import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import timber.log.Timber;
@@ -95,6 +99,9 @@ public class RuntimeStyleActivity extends AppCompatActivity {
// Center and Zoom (Amsterdam, zoomed to streets)
mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(52.379189, 4.899431), 14));
+
+ mapboxMap.setTransitionDuration(250);
+ mapboxMap.setTransitionDelay(50);
}
});
}
@@ -257,10 +264,9 @@ public class RuntimeStyleActivity extends AppCompatActivity {
}
private void setWaterColor() {
- Layer water = mapboxMap.getLayer("water");
+ FillLayer water = mapboxMap.getLayerAs("water");
if (water != null) {
- mapboxMap.setTransitionDuration(5);
- mapboxMap.setTransitionDelay(1);
+ water.setFillColorTransition(new TransitionOptions(7500, 1000));
water.setProperties(
visibility(VISIBLE),
fillColor(Color.RED)
@@ -405,7 +411,25 @@ public class RuntimeStyleActivity extends AppCompatActivity {
lineWidth(20f)
);
- mapboxMap.addLayer(layer);
+ // adding layers below "road" layers
+ List<Layer> layers = mapboxMap.getLayers();
+ Layer latestLayer = null;
+ Collections.reverse(layers);
+ for (Layer currentLayer : layers) {
+ if (currentLayer instanceof FillLayer && ((FillLayer) currentLayer).getSourceLayer().equals("road")) {
+ latestLayer = currentLayer;
+ } else if (currentLayer instanceof CircleLayer && ((CircleLayer) currentLayer).getSourceLayer().equals("road")) {
+ latestLayer = currentLayer;
+ } else if (currentLayer instanceof SymbolLayer && ((SymbolLayer) currentLayer).getSourceLayer().equals("road")) {
+ latestLayer = currentLayer;
+ } else if (currentLayer instanceof LineLayer && ((LineLayer) currentLayer).getSourceLayer().equals("road")) {
+ latestLayer = currentLayer;
+ }
+ }
+
+ if (latestLayer != null) {
+ mapboxMap.addLayerBelow(layer, latestLayer.getId());
+ }
// Need to get a fresh handle
layer = mapboxMap.getLayerAs("terrainLayer");
@@ -510,7 +534,8 @@ public class RuntimeStyleActivity extends AppCompatActivity {
if (states != null) {
states.setFilter(eq("name", "Texas"));
-
+ states.setFillOpacityTransition(new TransitionOptions(2500, 0));
+ states.setFillColorTransition(new TransitionOptions(2500, 0));
states.setProperties(
fillColor(Color.RED),
fillOpacity(0.25f)
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/BaseLocationActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/BaseLocationActivity.java
new file mode 100644
index 0000000000..a8d1772cb2
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/BaseLocationActivity.java
@@ -0,0 +1,49 @@
+package com.mapbox.mapboxsdk.testapp.activity.userlocation;
+
+import android.Manifest;
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.annotation.UiThread;
+import android.support.v4.app.ActivityCompat;
+import android.support.v7.app.AppCompatActivity;
+
+import com.mapbox.services.android.telemetry.permissions.PermissionsManager;
+
+public abstract class BaseLocationActivity extends AppCompatActivity {
+
+ private static final int PERMISSIONS_LOCATION = 0;
+
+ @UiThread
+ protected final void toggleGps(boolean enableGps) {
+ if (enableGps) {
+ if (!PermissionsManager.areLocationPermissionsGranted(this)) {
+ ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.ACCESS_COARSE_LOCATION,
+ Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSIONS_LOCATION);
+ } else {
+ enableLocation(true);
+ }
+ } else {
+ enableLocation(false);
+ }
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+ if (requestCode == PERMISSIONS_LOCATION) {
+ if (!isRuntimePermissionsRequired() || isPermissionAccepted(grantResults)) {
+ enableLocation(true);
+ }
+ }
+ }
+
+ private boolean isPermissionAccepted(int[] grantResults) {
+ return grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED;
+ }
+
+ private boolean isRuntimePermissionsRequired() {
+ return android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
+ }
+
+ protected abstract void enableLocation(boolean enabled);
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/CustomLocationEngineActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/CustomLocationEngineActivity.java
new file mode 100644
index 0000000000..660404f144
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/CustomLocationEngineActivity.java
@@ -0,0 +1,100 @@
+package com.mapbox.mapboxsdk.testapp.activity.userlocation;
+
+import android.os.Bundle;
+import android.support.design.widget.FloatingActionButton;
+import android.view.View;
+
+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.services.android.telemetry.location.LocationEngine;
+
+public class CustomLocationEngineActivity extends BaseLocationActivity {
+
+ private MapView mapView;
+ private MapboxMap mapboxMap;
+ private FloatingActionButton locationToggleFab;
+
+ private LocationEngine locationServices;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_custom_location_engine);
+
+ locationServices = new MockLocationEngine();
+
+ mapView = (MapView) findViewById(R.id.mapView);
+ mapView.onCreate(savedInstanceState);
+ mapView.getMapAsync(new OnMapReadyCallback() {
+ @Override
+ public void onMapReady(MapboxMap map) {
+ mapboxMap = map;
+ mapboxMap.setLocationSource(locationServices);
+ }
+ });
+
+ locationToggleFab = (FloatingActionButton) findViewById(R.id.fabLocationToggle);
+ locationToggleFab.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ if (mapboxMap != null) {
+ toggleGps(!mapboxMap.isMyLocationEnabled());
+ }
+ }
+ });
+ }
+
+ @Override
+ protected void enableLocation(boolean enabled) {
+ mapboxMap.setMyLocationEnabled(enabled);
+ if (enabled) {
+ locationToggleFab.setImageResource(R.drawable.ic_location_disabled);
+ } else {
+ locationToggleFab.setImageResource(R.drawable.ic_my_location);
+ }
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ mapView.onStart();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mapView.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ mapView.onPause();
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ mapView.onStop();
+ }
+
+ @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/MockLocationEngine.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MockLocationEngine.java
new file mode 100644
index 0000000000..b87c723fda
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MockLocationEngine.java
@@ -0,0 +1,93 @@
+package com.mapbox.mapboxsdk.testapp.activity.userlocation;
+
+
+import android.location.Location;
+import android.os.Handler;
+
+import com.mapbox.services.android.telemetry.location.LocationEngine;
+import com.mapbox.services.android.telemetry.location.LocationEngineListener;
+
+/**
+ * Sample LocationEngine that provides mocked locations simulating GPS updates
+ */
+public class MockLocationEngine extends LocationEngine {
+
+ // Mocked data
+ private static final int UPDATE_INTERVAL_MS = 1000;
+ private static final double[][] locations = new double[][] {
+ new double[] {39.489309, -0.360415},
+ new double[] {39.492469, -0.358777},
+ new double[] {40.393285, -3.707260},
+ new double[] {40.394374, -3.707767},
+ new double[] {40.398012, -3.715943},
+ new double[] {40.416913, -3.703861}};
+
+ private Handler handler;
+ int currentIndex;
+
+ public MockLocationEngine() {
+ super();
+ }
+
+ @Override
+ public void activate() {
+ currentIndex = 0;
+
+ // "Connection" is immediate here
+ for (LocationEngineListener listener : locationListeners) {
+ listener.onConnected();
+ }
+ }
+
+ @Override
+ public void deactivate() {
+ handler = null;
+ }
+
+ @Override
+ public boolean isConnected() {
+ return true; // Always connected
+ }
+
+ @Override
+ public Location getLastLocation() {
+ return getNextLocation();
+ }
+
+ @Override
+ public void requestLocationUpdates() {
+ // Fake regular updates with a handler
+ handler = new Handler();
+ handler.postDelayed(new LocationUpdateRunnable(), UPDATE_INTERVAL_MS);
+ }
+
+ @Override
+ public void removeLocationUpdates() {
+ handler.removeCallbacksAndMessages(null);
+ }
+
+ private Location getNextLocation() {
+ // Build the next location and rotate the index
+ Location location = new Location(MockLocationEngine.class.getSimpleName());
+ location.setLatitude(locations[currentIndex][0]);
+ location.setLongitude(locations[currentIndex][1]);
+ currentIndex = (currentIndex == locations.length - 1 ? 0 : currentIndex + 1);
+ return location;
+ }
+
+ private class LocationUpdateRunnable implements Runnable {
+ @Override
+ public void run() {
+ // Notify of an update
+ Location location = getNextLocation();
+ for (LocationEngineListener listener : locationListeners) {
+ listener.onLocationChanged(location);
+ }
+
+ if (handler != null) {
+ // Schedule the next update
+ handler.postDelayed(new LocationUpdateRunnable(), UPDATE_INTERVAL_MS);
+ }
+ }
+ }
+}
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 d31bd1fa51..5560f81fa9 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,15 +1,10 @@
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.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
-import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.ViewGroup;
@@ -27,9 +22,7 @@ import com.mapbox.services.android.telemetry.location.LocationEngineListener;
/**
* Test activity showcasing how to change the MyLocationView drawable.
*/
-public class MyLocationDrawableActivity extends AppCompatActivity implements LocationEngineListener {
-
- private static final int PERMISSIONS_LOCATION = 0;
+public class MyLocationDrawableActivity extends BaseLocationActivity implements LocationEngineListener {
private MapView mapView;
private MapboxMap mapboxMap;
@@ -71,24 +64,8 @@ public class MyLocationDrawableActivity extends AppCompatActivity implements Loc
});
}
- 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);
- }
- }
-
- private void enableLocation(boolean enabled) {
+ @Override
+ protected void enableLocation(boolean enabled) {
if (enabled) {
mapboxMap.setMyLocationEnabled(true);
Location location = mapboxMap.getMyLocation();
@@ -103,15 +80,6 @@ public class MyLocationDrawableActivity extends AppCompatActivity implements Loc
}
@Override
- public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
- if (requestCode == PERMISSIONS_LOCATION) {
- if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
- enableLocation(true);
- }
- }
- }
-
- @Override
public void onConnected() {
// Nothing
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationTintActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationTintActivity.java
index 0417b1829f..a219b369f6 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationTintActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationTintActivity.java
@@ -1,18 +1,13 @@
package com.mapbox.mapboxsdk.testapp.activity.userlocation;
-import android.Manifest;
import android.app.Activity;
-import android.content.pm.PackageManager;
import android.graphics.Color;
import android.location.Location;
import android.os.Bundle;
import android.support.annotation.IdRes;
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.AppCompatActivity;
import android.view.View;
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
@@ -30,14 +25,12 @@ import com.mapbox.services.android.telemetry.location.LocationEngineListener;
/**
* Test activity showcasing how to tint the MyLocationView.
*/
-public class MyLocationTintActivity extends AppCompatActivity implements LocationEngineListener {
+public class MyLocationTintActivity extends BaseLocationActivity implements LocationEngineListener {
private MapView mapView;
private MapboxMap mapboxMap;
private boolean firstRun;
- private static final int PERMISSIONS_LOCATION = 0;
-
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -180,25 +173,8 @@ public class MyLocationTintActivity extends AppCompatActivity implements Locatio
mapView.onSaveInstanceState(outState);
}
- @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);
- }
- }
-
- private void enableLocation(boolean enabled) {
+ @Override
+ protected void enableLocation(boolean enabled) {
if (enabled) {
mapboxMap.setMyLocationEnabled(true);
if (mapboxMap.getMyLocation() != null) {
@@ -211,15 +187,6 @@ public class MyLocationTintActivity extends AppCompatActivity implements Locatio
}
}
- @Override
- public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
- if (requestCode == PERMISSIONS_LOCATION) {
- if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
- enableLocation(true);
- }
- }
- }
-
private static class ViewUtils {
public static void attachClickListener(
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationToggleActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationToggleActivity.java
index 9e98d8c6b9..ac6c346a88 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationToggleActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationToggleActivity.java
@@ -1,14 +1,8 @@
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.UiThread;
import android.support.design.widget.FloatingActionButton;
-import android.support.v4.app.ActivityCompat;
-import android.support.v7.app.AppCompatActivity;
import android.view.View;
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
@@ -20,9 +14,8 @@ import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.services.android.telemetry.location.LocationEngine;
import com.mapbox.services.android.telemetry.location.LocationEngineListener;
-import com.mapbox.services.android.telemetry.permissions.PermissionsManager;
-public class MyLocationToggleActivity extends AppCompatActivity {
+public class MyLocationToggleActivity extends BaseLocationActivity {
private MapView mapView;
private MapboxMap mapboxMap;
@@ -31,8 +24,6 @@ public class MyLocationToggleActivity extends AppCompatActivity {
private LocationEngine locationServices;
private LocationEngineListener locationListener;
- private static final int PERMISSIONS_LOCATION = 0;
-
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -107,21 +98,8 @@ public class MyLocationToggleActivity extends AppCompatActivity {
mapView.onLowMemory();
}
- @UiThread
- public void toggleGps(boolean enableGps) {
- if (enableGps) {
- if (!PermissionsManager.areLocationPermissionsGranted(this)) {
- ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.ACCESS_COARSE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSIONS_LOCATION);
- } else {
- enableLocation(true);
- }
- } else {
- enableLocation(false);
- }
- }
-
- private void enableLocation(boolean enabled) {
+ @Override
+ protected void enableLocation(boolean enabled) {
if (enabled) {
// To move the camera instantly, we attempt to get the last known location and either
// ease or animate the camera to that position depending on the zoom level.
@@ -156,14 +134,4 @@ public class MyLocationToggleActivity extends AppCompatActivity {
}
mapboxMap.setMyLocationEnabled(enabled);
}
-
- @Override
- public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
- if (requestCode == PERMISSIONS_LOCATION) {
- if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
- enableLocation(true);
- }
- }
- }
-
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/TokenUtils.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/TokenUtils.java
new file mode 100644
index 0000000000..e08fdb9154
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/TokenUtils.java
@@ -0,0 +1,37 @@
+package com.mapbox.mapboxsdk.testapp.utils;
+
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+
+import com.mapbox.mapboxsdk.Mapbox;
+
+public class TokenUtils {
+
+ /**
+ * <p>
+ * Returns the Mapbox access token set in the app resources.
+ * </p>
+ * It will first search for a token in the Mapbox object. If not found it
+ * will then attempt to load the access token from the
+ * {@code res/values/dev.xml} development file.
+ *
+ * @param context The {@link Context} of the {@link android.app.Activity} or {@link android.app.Fragment}.
+ * @return The Mapbox access token or null if not found.
+ */
+ public static String getMapboxAccessToken(@NonNull Context context) {
+ try {
+ // Read out AndroidManifest
+ String token = Mapbox.getAccessToken();
+ if (token == null || token.isEmpty()) {
+ throw new IllegalArgumentException();
+ }
+ return token;
+ } catch (Exception exception) {
+ // Use fallback on string resource, used for development
+ int tokenResId = context.getResources()
+ .getIdentifier("mapbox_access_token", "string", context.getPackageName());
+ return tokenResId != 0 ? context.getString(tokenResId) : null;
+ }
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_building_layer.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_building_layer.xml
new file mode 100644
index 0000000000..d9a10871b5
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_building_layer.xml
@@ -0,0 +1,18 @@
+<?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">
+
+ <com.mapbox.mapboxsdk.maps.MapView
+ android:id="@id/mapView"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ app:mapbox_cameraTargetLat="40.7135"
+ app:mapbox_cameraTargetLng="-74.0066"
+ app:mapbox_cameraTilt="45"
+ app:mapbox_cameraZoom="15"
+ app:mapbox_styleUrl="@string/mapbox_style_mapbox_streets"/>
+
+</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_circle_layer.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_circle_layer.xml
index 8a21bef8a8..6e8a4e5eb2 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_circle_layer.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_circle_layer.xml
@@ -1,36 +1,41 @@
<?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" />
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
<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:mapbox_cameraTargetLat="1.350057"
app:mapbox_cameraTargetLng="103.849218"
- app:mapbox_styleUrl="@string/mapbox_style_dark"
- app:mapbox_cameraZoom="10"/>
+ app:mapbox_cameraZoom="10"
+ app:mapbox_styleUrl="@string/mapbox_style_mapbox_streets"/>
<android.support.design.widget.FloatingActionButton
- android:id="@id/fab"
+ android:id="@+id/fab_route"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
- android:layout_margin="@dimen/fab_margin"
+ android:layout_marginBottom="@dimen/fab_margin"
+ android:layout_marginRight="@dimen/fab_margin"
android:src="@drawable/ic_directions_bus_black"
- app:backgroundTint="@android:color/white" />
+ app:backgroundTint="@android:color/white"/>
+
+ <android.support.design.widget.FloatingActionButton
+ android:id="@+id/fab_style"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_above="@id/fab_route"
+ android:layout_alignParentEnd="true"
+ android:layout_alignParentRight="true"
+ android:layout_marginBottom="@dimen/fab_margin"
+ android:layout_marginRight="@dimen/fab_margin"
+ android:src="@drawable/ic_layers"
+ app:backgroundTint="@color/primary"/>
</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_custom_location_engine.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_custom_location_engine.xml
new file mode 100644
index 0000000000..e9f461c7ee
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_custom_location_engine.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.design.widget.CoordinatorLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ 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"
+ app:mapbox_cameraTargetLat="40.416872"
+ app:mapbox_cameraTargetLng="-3.703807"
+ app:mapbox_cameraZoom="4"/>
+
+ <android.support.design.widget.FloatingActionButton
+ android:id="@+id/fabLocationToggle"
+ 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_my_location"
+ tools:backgroundTint="@color/primary"/>
+
+</android.support.design.widget.CoordinatorLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_fill_extrusion_layer.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_fill_extrusion_layer.xml
new file mode 100644
index 0000000000..304841dc69
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_fill_extrusion_layer.xml
@@ -0,0 +1,17 @@
+<?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">
+
+ <com.mapbox.mapboxsdk.maps.MapView
+ android:id="@id/mapView"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ app:mapbox_cameraTargetLat="52.090710"
+ app:mapbox_cameraTargetLng="5.121125"
+ app:mapbox_cameraZoom="10"
+ app:mapbox_styleUrl="@string/mapbox_style_mapbox_streets"/>
+
+</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_multi_map.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_multi_map.xml
index 0b3fd9acdf..599ae3fa1c 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_multi_map.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_multi_map.xml
@@ -23,7 +23,7 @@
android:layout_weight="0.5"
mapbox:center_latitude="38.913187"
mapbox:center_longitude="-77.032546"
- mapbox:style_url="mapbox://styles/mapbox/streets-v9"
+ mapbox:style_url="mapbox://styles/mapbox/streets-v10"
mapbox:zoom="12"/>
<!-- SF -->
@@ -35,7 +35,7 @@
android:layout_weight="0.5"
mapbox:center_latitude="37.775732"
mapbox:center_longitude="-122.413985"
- mapbox:style_url="mapbox://styles/mapbox/outdoors-v9"
+ mapbox:style_url="mapbox://styles/mapbox/outdoors-v10"
mapbox:zoom="13"/>
</LinearLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_restricted_bounds.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_restricted_bounds.xml
new file mode 100644
index 0000000000..e17807201b
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_restricted_bounds.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.design.widget.CoordinatorLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ 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"
+ app:mapbox_cameraTargetLat="64.840048"
+ app:mapbox_cameraTargetLng="-18.910457"
+ app:mapbox_cameraZoom="4"
+ app:mapbox_styleUrl="@string/mapbox_style_satellite_streets"/>
+
+</android.support.design.widget.CoordinatorLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/fragment_dialog_map.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/fragment_dialog_map.xml
index 8241d0264f..afebfa1c47 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/fragment_dialog_map.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/fragment_dialog_map.xml
@@ -13,6 +13,6 @@
mapbox:mapbox_cameraTargetLng="-122.3421"
mapbox:mapbox_cameraZoom="11"
mapbox:mapbox_renderTextureMode="true"
- mapbox:mapbox_styleUrl="mapbox://styles/mapbox/streets-v9" />
+ mapbox:mapbox_styleUrl="mapbox://styles/mapbox/streets-v10" />
</LinearLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_polygon.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_polygon.xml
index a7fdf56be5..f2cd9aedbc 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_polygon.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_polygon.xml
@@ -17,4 +17,8 @@
android:id="@+id/action_id_color"
android:title="@string/action_color_polygon"
mapbox:showAsAction="never" />
+ <item
+ android:id="@+id/action_id_holes"
+ android:title="@string/action_holes_polygon"
+ mapbox:showAsAction="never" />
</menu>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/test_feature_collection.geojson b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/test_feature_collection.geojson
new file mode 100644
index 0000000000..4a0d1968cf
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/test_feature_collection.geojson
@@ -0,0 +1,26 @@
+{
+ "type": "FeatureCollection",
+ "features": [
+ {
+ "type": "Feature",
+ "geometry": {
+ "type": "Point",
+ "coordinates": [
+ 5.1080,
+ 52.0962
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "properties": {},
+ "geometry": {
+ "type": "Point",
+ "coordinates": [
+ 5.1090,
+ 52.0962
+ ]
+ }
+ }
+ ]
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/test_feature_properties.geojson b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/test_feature_properties.geojson
new file mode 100644
index 0000000000..751c0a4939
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/test_feature_properties.geojson
@@ -0,0 +1,21 @@
+{
+ "type": "Feature",
+ "id": 1,
+ "properties": {
+ "null_prop": null,
+ "integer_prop": 10000,
+ "float_prop": 10000.10,
+ "string_prop": "my_string",
+ "bool_prop": true,
+ "object_prop": {
+ "nested_string_prop": "my_string"
+ }
+ },
+ "geometry": {
+ "type": "Point",
+ "coordinates": [
+ 5.112419128417969,
+ 52.09622422366772
+ ]
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/test_line_string_feature.geojson b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/test_line_string_feature.geojson
new file mode 100644
index 0000000000..c63c23d87a
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/test_line_string_feature.geojson
@@ -0,0 +1,17 @@
+{
+ "type": "Feature",
+ "properties": {},
+ "geometry": {
+ "type": "LineString",
+ "coordinates": [
+ [
+ 5.1080,
+ 52.0960
+ ],
+ [
+ 5.1080,
+ 52.0970
+ ]
+ ]
+ }
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/test_multi_line_string_feature.geojson b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/test_multi_line_string_feature.geojson
new file mode 100644
index 0000000000..cae631d987
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/test_multi_line_string_feature.geojson
@@ -0,0 +1,29 @@
+{
+ "type": "Feature",
+ "properties": {},
+ "geometry": {
+ "type": "MultiLineString",
+ "coordinates": [
+ [
+ [
+ 5.1080,
+ 52.0960
+ ],
+ [
+ 5.1080,
+ 52.0970
+ ]
+ ],
+ [
+ [
+ 5.1090,
+ 52.0960
+ ],
+ [
+ 5.1090,
+ 52.0970
+ ]
+ ]
+ ]
+ }
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/test_multi_point_feature.geojson b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/test_multi_point_feature.geojson
new file mode 100644
index 0000000000..6be05156e7
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/test_multi_point_feature.geojson
@@ -0,0 +1,17 @@
+{
+ "type": "Feature",
+ "properties": {},
+ "geometry": {
+ "type": "MultiPoint",
+ "coordinates": [
+ [
+ 5.1080,
+ 52.0960
+ ],
+ [
+ 5.1080,
+ 52.0970
+ ]
+ ]
+ }
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/test_multi_polygon_feature.geojson b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/test_multi_polygon_feature.geojson
new file mode 100644
index 0000000000..469a054c4e
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/test_multi_polygon_feature.geojson
@@ -0,0 +1,49 @@
+{
+ "type": "Feature",
+ "properties": {},
+ "geometry": {
+ "type": "MultiPolygon",
+ "coordinates": [
+ [
+ [
+ [
+ 5.112419128417969,
+ 52.09622422366772
+ ],
+ [
+ 5.112419128417969,
+ 52.094062282906954
+ ],
+ [
+ 5.115251541137695,
+ 52.094747787662364
+ ],
+ [
+ 5.112419128417969,
+ 52.09622422366772
+ ]
+ ]
+ ],
+ [
+ [
+ [
+ 5.11662483215332,
+ 52.09485324899753
+ ],
+ [
+ 5.11662483215332,
+ 52.09306037239377
+ ],
+ [
+ 5.120058059692383,
+ 52.093376767618174
+ ],
+ [
+ 5.11662483215332,
+ 52.09485324899753
+ ]
+ ]
+ ]
+ ]
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/test_point_feature.geojson b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/test_point_feature.geojson
new file mode 100644
index 0000000000..ae069de151
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/test_point_feature.geojson
@@ -0,0 +1,11 @@
+{
+ "type": "Feature",
+ "properties": {},
+ "geometry": {
+ "type": "Point",
+ "coordinates": [
+ 5.1080,
+ 52.0962
+ ]
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/test_polygon_feature.geojson b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/test_polygon_feature.geojson
new file mode 100644
index 0000000000..2fc9f88669
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/test_polygon_feature.geojson
@@ -0,0 +1,27 @@
+{
+ "type": "Feature",
+ "properties": {},
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 5.112419128417969,
+ 52.09622422366772
+ ],
+ [
+ 5.112419128417969,
+ 52.094062282906954
+ ],
+ [
+ 5.115251541137695,
+ 52.094747787662364
+ ],
+ [
+ 5.112419128417969,
+ 52.09622422366772
+ ]
+ ]
+ ]
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/test_polygon_with_hole_feature.geojson b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/test_polygon_with_hole_feature.geojson
new file mode 100644
index 0000000000..1008e2e937
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/test_polygon_with_hole_feature.geojson
@@ -0,0 +1,45 @@
+{
+ "type": "Feature",
+ "properties": {},
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 5.112419128417969,
+ 52.09622422366772
+ ],
+ [
+ 5.112419128417969,
+ 52.094062282906954
+ ],
+ [
+ 5.115251541137695,
+ 52.094747787662364
+ ],
+ [
+ 5.112419128417969,
+ 52.09622422366772
+ ]
+ ],
+ [
+ [
+ 5.1127249002456665,
+ 52.094362192533545
+ ],
+ [
+ 5.114580988883972,
+ 52.0948104053602
+ ],
+ [
+ 5.11263906955719,
+ 52.095845232479846
+ ],
+ [
+ 5.1127249002456665,
+ 52.094362192533545
+ ]
+ ]
+ ]
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml
index f15ee20be6..5b6cbb8c42 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml
@@ -28,6 +28,7 @@
<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_location_engine">Custom location engine</string>
<string name="activity_custom_layer">Custom Layer</string>
<string name="activity_map_padding">Map Padding</string>
<string name="activity_debug_mode">Debug Mode</string>
@@ -54,12 +55,17 @@
<string name="activity_simple_map">Simple Map</string>
<string name="activity_map_in_dialog">Dialog with map</string>
<string name="activity_marker_view_rectangle">Marker views in rectangle</string>
+ <string name="activity_url_transform">Url transform</string>
+ <string name="activity_restricted_bounds">Restrict camera to a bounds</string>
+ <string name="activity_fill_extrusion_layer">Fill extrusions</string>
+ <string name="activity_building_fill_extrusion_layer">Building layer</string>
<!--Description-->
<string name="description_user_location_tracking">Tracks the location of the user</string>
<string name="description_user_location_customization">Customize the location of the user</string>
<string name="description_user_location_dot_color">Customize the user location color</string>
<string name="description_user_location_toggle">Toggle location of the user on and off</string>
+ <string name="description_custom_location_engine">Customize location engine</string>
<string name="description_custom_layer">Overlay a custom native layer on the map</string>
<string name="description_info_window_adapter">Learn how to create a custom InfoWindow</string>
<string name="description_cameraposition">CameraPosition capabilities</string>
@@ -107,6 +113,10 @@
<string name="description_map_in_dialog">Display a map inside a dialog fragment</string>
<string name="description_marker_view_rectangle">Marker Views within a rectangle</string>
<string name="description_circle_layer">Show bus stops and route in Singapore</string>
+ <string name="description_url_transform">Transform urls on the fly</string>
+ <string name="description_restricted_bounds">Limit viewport to Iceland</string>
+ <string name="description_fill_extrusion_layer">Shows how to add 3D extruded shapes</string>
+ <string name="description_building_fill_extrusion_layer">Shows how to show 3D extruded buildings</string>
<!--Categories-->
<string name="category">category</string>
@@ -122,6 +132,7 @@
<string name="category_userlocation">User Location</string>
<string name="category_style">Styling</string>
<string name="category_features">Features</string>
+ <string name="category_storage">Storage</string>
<!--Actions-->
<string name="action_remove_polylines">Remove polylines</string>
@@ -129,6 +140,7 @@
<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_holes_polygon">Change holes</string>
<string name="action_width_polyline">Change width</string>
<!--Menu-->
diff --git a/platform/android/MapboxGLAndroidSDKWearTestApp/build.gradle b/platform/android/MapboxGLAndroidSDKWearTestApp/build.gradle
index e08d5a9a03..6ac8961421 100644
--- a/platform/android/MapboxGLAndroidSDKWearTestApp/build.gradle
+++ b/platform/android/MapboxGLAndroidSDKWearTestApp/build.gradle
@@ -12,6 +12,10 @@ android {
versionName rootProject.ext.versionName
}
+ lintOptions {
+ disable 'MissingTranslation'
+ }
+
buildTypes {
debug {
testCoverageEnabled = true
diff --git a/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/res/layout/activity_simple_mapview.xml b/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/res/layout/activity_simple_mapview.xml
index 8f260c46ff..44374f2c6c 100644
--- a/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/res/layout/activity_simple_mapview.xml
+++ b/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/res/layout/activity_simple_mapview.xml
@@ -15,7 +15,7 @@
android:layout_height="match_parent"
mapbox:mapbox_cameraTargetLat="40.73581"
mapbox:mapbox_cameraTargetLng="-73.99155"
- mapbox:mapbox_styleUrl="mapbox://styles/mapbox/streets-v9"
+ mapbox:mapbox_styleUrl="mapbox://styles/mapbox/streets-v10"
mapbox:mapbox_cameraZoom="11"
mapbox:mapbox_uiZoomControls="false"/>
diff --git a/platform/android/README.md b/platform/android/README.md
index 67e08b963b..7c28433d96 100644
--- a/platform/android/README.md
+++ b/platform/android/README.md
@@ -4,49 +4,86 @@
A library based on [Mapbox GL Native](../../README.md) for embedding interactive map views with scalable, customizable vector maps into Java applications on Android devices.
+## Getting Started
+
+Alright. So, actually, you may be in the wrong place. From here on in, this README is going to be for people who are interested in working on and improving on Mapbox GL Native for Android.
+
+**To view our current API documentation, see our [JavaDoc](https://www.mapbox.com/android-sdk/api).**
+
**To install and use the Mapbox Android SDK in an application, see the [Mapbox Android SDK website](https://www.mapbox.com/android-sdk/).**
[![](https://www.mapbox.com/android-sdk/images/splash.png)](https://www.mapbox.com/android-sdk/)
-## Contributing to the SDK
+### Setup environment
**These instructions are for developers interested in making code-level contributions to the SDK itself. If you instead want to use the SDK in your app, see above.**
-Building the SDK yourself requires [a number of dependencies and steps](../../INSTALL.md) that are unnecessary for developing production applications.
+#### Getting the source
+
+Clone the git repository
+
+```bash
+git clone https://github.com/mapbox/mapbox-gl-native.git
+cd mapbox-gl-native
+```
+
+#### Installing dependencies
+
+These dependencies are required for all operating systems and all platform targets.
+
+- Latest stable [Android Studio](https://developer.android.com/studio/index.html)
+- Update Android SDK with latest
+ - Android SDK Build-Tools
+ - Android Platform-Tools
+ - Android SDK Tools
+ - CMake
+ - NDK
+ - LLDB
+
+- Modern C++ compiler that supports -std=c++14
+ - clang++ 3.5 or later or
+ - g++-5 or later
+- [cURL](https://curl.haxx.se) (for build only)
+- [Node.js](https://nodejs.org/) or later (for build only)
+- [pkg-config](https://wiki.freedesktop.org/www/Software/pkg-config/) (for build only)
+
+##### Additional Dependencies for Linux
+
+_These instructions were tested on Ubuntu 16.04 LTS (aka Xenial Xerus)._
+
+```
+$ sudo apt-get install -y build-essential curl lib32stdc++6 lib32z1 pkg-config python
+```
+
+##### Additional Dependencies for macOS
+
+- Apple Command Line Tools (available at [Apple Developer](https://developer.apple.com/download/more/))
+- [xcpretty](https://github.com/supermarin/xcpretty) (`gem install xcpretty`)
-* [Contributing on Linux](CONTRIBUTING_LINUX.md)
-* [Contributing on macOS](CONTRIBUTING_MACOS.md)
-### Setting up the Android emulator
+#### Open project in Android Studio
-The Mapbox Android SDK requires Android 4.0.3+ (API level 15+).
+##### macOS
-If you want to run the test app in the emulator, we recommend the x86 build because it will run a lot faster.
+Execute the following to generate the required build files and open the project with Android Studio:
-First ensure you have an `MAPBOX_ACCESS_TOKEN` environment variable set, as described below. Then, create an x86 build:
+```
+make aproj
+```
- make android-lib-x86
+##### linux
-In Android Studio, create an x86 AVD (Android Virtual Device):
+Open Android Studio project in `/platform/android`, run `make android-configuration` in the root folder of the project.
-- Open AVD Manager via the Tools menu -> Android -> AVD Manager
-- Click "Create Virtual Device" at the bottom on AVD Manager window
-- Select one of the device profiles, for example the Nexus 4
-- Click "Next"
-- Select a Lollipop or Kitkat release with ABI of x86. If the line is greyed out click Download to download the OS files.
-- Click "Next"
-- Under "Emulated Performance" check "Host GPU" and uncheck "Store a snapshot for faster startup"
-- Click "Finish"
-- Close the AVD Manager
-Now when you run or debug the Android project you will see a window "Choose Device". Select your new AVD from drop down under "Launch emulator". If you select "Use same device for future launches" Android Studio will remember the selection and not ask again.
+##### Setting Mapbox Access Token
-### Running Mapbox GL Native on a hardware Android device
+_The test application (used for development purposes) uses Mapbox vector tiles, which require a Mapbox account and API access token. Obtain a free access token on the [Mapbox account page](https://www.mapbox.com/studio/account/tokens/)._
-The Mapbox Android SDK requires Android 4.0.3+ (API level 15+).
+With the first gradle invocation, gradle will take the value of the `MAPBOX_ACCESS_TOKEN` environment variable and save it to `MapboxGLAndroidSDKTestApp/src/main/res/values/developer-config.xml`. If the environement variable wasn't set, you can edit `developer-config.xml` manually and add your access token to the `mapbox_access_token` resource.
-First read the [Google documentation](http://developer.android.com/tools/device.html) to set up your device and your OS to connect to the device.
+#### Running project
-When you plug your device in and then run or debug the Android project you will see a window "Choose Device". Choose your device from the "Choose a running device" list.
+Run the configuration for the `MapboxGLAndroidSDKTestApp` module and select a device or emulator to deploy on. Based on the selected device, the c++ code will be compiled for the related processor architecture. You can see the project compiling in the `View > Tool Windows > Gradle Console`.
-If your device does not show up, double check the [Google documentation](http://developer.android.com/tools/device.html).
+More information about building and distributing this project in [DISTRIBUTE.md][https://github.com/mapbox/mapbox-gl-native/blob/master/platform/android/DISTRIBUTE.md].
diff --git a/platform/android/TESTS.md b/platform/android/TESTS.md
new file mode 100644
index 0000000000..f0bdeb2dce
--- /dev/null
+++ b/platform/android/TESTS.md
@@ -0,0 +1,117 @@
+# Mapbox GL Test App
+
+## Testing
+
+### Running Espresso tests on a device
+
+This test project comes with all the required Android Testing Support Library dependencies
+in the Gradle file. Tests are under the `app/src/androidTest` folder.
+
+Note that before running your tests, you might want to turn off animations on your test device.
+It's a known issue that leaving system animations turned on in a test device
+(window animation scale, transition animation scale, animator duration scale)
+might cause unexpected results, or may lead tests to fail.
+
+To create a new run configuration:
+* Click on Run -> Edit Configurations...
+* Click on the plus sign and then on "Android Tests"
+* Give a name to the configuration, e.g. `TestAppTests`
+* Choose the `MapboxGLAndroidSDKTestApp` module
+* Choose `android.support.test.runner.AndroidJUnitRunner` as the instrumentation runner
+* Click OK to save the new configuration
+
+You can now run this configuration from the main toolbar dropdown menu.
+
+### Running Espresso tests on Firebase within AS
+
+Tests are under the `app/src/androidTest` folder.
+
+1) _Sign In_ with your Google account.
+
+![Firebase Tests AS 1][1]
+
+2) Or _Add Account_ if you want to sign in with a different account.
+
+![Firebase Tests AS 2][2]
+
+3) Select the test configuration you want to run and click _Play_ button.
+
+4) Click on _Cloud Testing_ tab. You need to create a project in Firebase and define a _Matrix configuration_ previously (see
+[Firebase Test Lab for Android guide](https://firebase.google.com/docs/test-lab/overview)). Select your template (e.g. _Nexus 5 (3)_).
+
+5) Select your _Cloud project_ (e.g. _android-gl-native (android-gl-native)_).
+
+![Firebase Tests AS 3-5][3]
+
+6) Click on _OK_ button to run the tests.
+
+![Firebase Tests AS 6][4]
+
+7) When tests finish the results will appear within AS.
+
+![Firebase Tests AS 7][5]
+
+### Running Espresso tests on AWS Device Farm
+
+On a terminal, within `mapbox-gl-native/android/java`,
+run the tests (`cC` stands for `connectedCheck`):
+
+```
+$ ./gradlew -Pmapbox.abis=all cC -p MapboxGLAndroidSDKTestApp
+```
+
+Then:
+* Go to your AWS Console and choose Device Farm.
+* Create a new project, e.g. `MapboxGLAndroidSDKTestApp`
+* On step 1, upload the APK in `mapbox-gl-native/android/java/MapboxGLAndroidSDKTestApp/build/outputs/apk/MapboxGLAndroidSDKTestApp-debug-unaligned.apk`
+* On step 2, choose Instrumentation, test filter is `com.mapbox.mapboxgl.testapp.MainActivityTest` and upload the APK in `mapbox-gl-native/android/java/MapboxGLAndroidSDKTestApp/build/outputs/apk/MapboxGLAndroidSDKTestApp-debug-androidTest-unaligned.apk`
+* On step 3, choose a device pool. E.g. Top Devices
+* On step 4, customize your device state (if needed)
+* Finally, confirm the configuration and run the tests.
+
+On Step 2, you can also separate by commas different classes: `com.mapbox.mapboxgl.testapp.MainActivityTest,com.mapbox.mapboxgl.testapp.MainActivityScreenTest`
+
+If you have no tests for your app, or want to test some random user behavior,
+you can just choose "Built-in: Fuzz" in step 2.
+
+### Running pure JUnit tests
+
+These tests run on a local JVM on your development machine and they are extremely fast to run
+(as compared to Espresso). These tests are located under `src/test/java`. To run them you switch
+to the Unit Tests build variant, then right click the corresponding test class or method
+and select "Run ...".
+
+You can also have a run configuration:
+* Click on Run -> Edit Configurations...
+* Click on "Junit Tests"
+* Give a name to the configuration, e.g. `JUnit tests`
+* As "Test Kind", choose "All in directory"
+* As folder, choose the following folder: `mapbox-gl-native/android/java/MapboxGLAndroidSDKTestApp/src/test/java`
+* Click OK to save the new configuration
+
+You can also run the tests from the command line with:
+
+```
+$ ./gradlew -Pmapbox.abis=none test -p MapboxGLAndroidSDKTestApp
+```
+
+### Running the UI/Application Exerciser Monkey
+
+Similar to the "Built-in: Fuzz" test mentioned above, Android provides
+[Monkey](http://developer.android.com/tools/help/monkey.html),
+"a program that runs on your emulator or device and generates pseudo-random streams of user events
+such as clicks, touches, or gestures, as well as a number of system-level events."
+
+To exercise Monkey on the test app, install the package on the device (e.g. via Android Studio)
+and then:
+
+```
+$ adb shell monkey -p com.mapbox.mapboxgl.testapp -v 500
+```
+
+
+[1]: ./art/tests/FirebaseTestsAS_1.png
+[2]: ./art/tests/FirebaseTestsAS_2.png
+[3]: ./art/tests/FirebaseTestsAS_3-5.png
+[4]: ./art/tests/FirebaseTestsAS_6.png
+[5]: ./art/tests/FirebaseTestsAS_7.png
diff --git a/platform/android/art/tests/FirebaseTestsAS_1.png b/platform/android/art/tests/FirebaseTestsAS_1.png
new file mode 100644
index 0000000000..5bdd9907fb
--- /dev/null
+++ b/platform/android/art/tests/FirebaseTestsAS_1.png
Binary files differ
diff --git a/platform/android/art/tests/FirebaseTestsAS_2.png b/platform/android/art/tests/FirebaseTestsAS_2.png
new file mode 100644
index 0000000000..a482a01785
--- /dev/null
+++ b/platform/android/art/tests/FirebaseTestsAS_2.png
Binary files differ
diff --git a/platform/android/art/tests/FirebaseTestsAS_3-5.png b/platform/android/art/tests/FirebaseTestsAS_3-5.png
new file mode 100644
index 0000000000..760acb05c3
--- /dev/null
+++ b/platform/android/art/tests/FirebaseTestsAS_3-5.png
Binary files differ
diff --git a/platform/android/art/tests/FirebaseTestsAS_6.png b/platform/android/art/tests/FirebaseTestsAS_6.png
new file mode 100644
index 0000000000..2c1ad8be39
--- /dev/null
+++ b/platform/android/art/tests/FirebaseTestsAS_6.png
Binary files differ
diff --git a/platform/android/art/tests/FirebaseTestsAS_7.png b/platform/android/art/tests/FirebaseTestsAS_7.png
new file mode 100644
index 0000000000..f7db39728a
--- /dev/null
+++ b/platform/android/art/tests/FirebaseTestsAS_7.png
Binary files differ
diff --git a/platform/android/bitrise.yml b/platform/android/bitrise.yml
index de1095409e..dcd4d4fb50 100644
--- a/platform/android/bitrise.yml
+++ b/platform/android/bitrise.yml
@@ -14,68 +14,25 @@ workflows:
primary:
steps:
- script:
- title: Check for skipping CI
- inputs:
- - content: |-
- #!/bin/bash
-
- if [[ -n "$(echo $GIT_CLONE_COMMIT_MESSAGE_SUBJECT | sed -n '/\[skip ci\]/p')" ||
- -n "$(echo $GIT_CLONE_COMMIT_MESSAGE_SUBJECT | sed -n '/\[ci skip\]/p')" ||
- -n "$(echo $GIT_CLONE_COMMIT_MESSAGE_BODY | sed -n 's/\[skip ci\]/p')" ||
- -n "$(echo $GIT_CLONE_COMMIT_MESSAGE_BODY | sed -n 's/\[ci skip\]/p')" ]]; then
- envman add --key SKIPCI --value true
- else
- envman add --key SKIPCI --value false
- fi
- - script:
- title: Run Checkstyle
- run_if: '{{enveq "SKIPCI" "false"}}'
- inputs:
- - content: |-
- #!/bin/bash
- # Run checkstyle gradle task on all modules
- cd platform/android && ./gradlew checkstyle
- - script:
- title: Configure Google Cloud SDK
- run_if: '{{enveq "SKIPCI" "false"}}'
- inputs:
- - content: |-
- #!/bin/bash
- # Install python tools for pip
- sudo apt-get install -y gcc python-dev python-setuptools
- sudo easy_install -U pip
- sudo pip uninstall crcmod
- sudo pip install -U crcmod
-
- # Install Google Cloud SDK for Firebase
- export CLOUD_SDK_REPO="cloud-sdk-$(lsb_release -c -s)"
- echo "deb http://packages.cloud.google.com/apt $CLOUD_SDK_REPO main" | sudo tee /etc/apt/sources.list.d/google-cloud-sdk.list
- curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
- sudo apt-get update && sudo apt-get install -y google-cloud-sdk
-
- # Get authentication secret
- echo "Downloading Google Cloud authentication:"
- wget -O secret.json "$BITRISEIO_GCLOUD_SERVICE_ACCOUNT_JSON_URL"
- - script:
title: Build libmapbox-gl.so for armeabi-v7a
- run_if: '{{enveq "SKIPCI" "false"}}'
inputs:
- content: |-
#!/bin/bash
echo "Compile libmapbox-gl.so for armeabi-v7a abi:"
- export BUILDTYPE=Debug
- make android-lib-arm-v7
+ ccache -z
+ BUILDTYPE=Debug make android-lib-arm-v7
+ ccache -s
- script:
title: Compile Core tests
- run_if: '{{enveq "SKIPCI" "false"}}'
inputs:
- content: |-
#!/bin/bash
echo "Compiling core tests:"
+ ccache -z
BUILDTYPE=Debug make android-test-lib-arm-v7
+ ccache -s
- script:
title: Run local JVM Unit tests on phone module
- run_if: '{{enveq "SKIPCI" "false"}}'
inputs:
- content: |-
#!/bin/bash
@@ -83,7 +40,6 @@ workflows:
make run-android-unit-test
- script:
title: Run local JVM Unit tests on wear module
- run_if: '{{enveq "SKIPCI" "false"}}'
inputs:
- content: |-
#!/bin/bash
@@ -91,23 +47,35 @@ workflows:
make run-android-wear-unit-test
- script:
title: Generate Espresso sanity tests
- run_if: '{{enveq "SKIPCI" "false"}}'
inputs:
- content: |-
#!/bin/bash
echo "Generate these test locally by executing:"
make test-code-android
- script:
+ title: Run Checkstyle
+ inputs:
+ - content: |-
+ #!/bin/bash
+ # Run checkstyle gradle task on all modules
+ make android-checkstyle
+ - script:
title: Run Firebase instrumentation tests
- run_if: '{{enveq "SKIPCI" "false"}}'
+ run_if: '{{getenv "BITRISEIO_GCLOUD_SERVICE_ACCOUNT_JSON_URL" | ne ""}}'
inputs:
- content: |-
#!/bin/bash
+ set -euo pipefail
+ echo "Downloading Google Cloud authentication:"
+ wget -O secret.json "$BITRISEIO_GCLOUD_SERVICE_ACCOUNT_JSON_URL"
+
echo "Downloading Mapbox accesstoken for running tests:"
wget -O platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/developer-config.xml "$BITRISEIO_TEST_ACCESS_TOKEN_UI_TEST_URL"
echo "Build seperate test apk:"
- make android-ui-test
+ ccache -z
+ make android-ui-test-arm-v7
+ ccache -s
echo "Run tests on firebase:"
gcloud auth activate-service-account --key-file secret.json --project android-gl-native
@@ -115,11 +83,12 @@ workflows:
gcloud beta test android run --type instrumentation --app platform/android/MapboxGLAndroidSDKTestApp/build/outputs/apk/MapboxGLAndroidSDKTestApp-debug.apk --test platform/android/MapboxGLAndroidSDKTestApp/build/outputs/apk/MapboxGLAndroidSDKTestApp-debug-androidTest.apk --device-ids shamu --os-version-ids 22 --locales en --orientations portrait --timeout 15m --test-targets "class com.mapbox.mapboxsdk.testapp.maps.widgets.AttributionTest"
- script:
title: Download Firebase results
- run_if: '{{enveq "SKIPCI" "false"}}'
is_always_run: true
+ run_if: '{{getenv "BITRISEIO_GCLOUD_SERVICE_ACCOUNT_JSON_URL" | ne ""}}'
inputs:
- content: |-
#!/bin/bash
+ set -euo pipefail
mkdir -p platform/android/MapboxGLAndroidSDKTestApp/build/outputs/apk
echo "The details from Firebase will be downloaded, zipped and attached as a build artefact."
@@ -131,13 +100,11 @@ workflows:
find platform/android/MapboxGLAndroidSDKTestApp/build/outputs/apk -type f -name "logcat" -print0 | xargs -0 -Imylogcat mv -i mylogcat ./
cat logcat | ndk-stack -sym build/android-arm-v7/Debug
- deploy-to-bitrise-io:
- run_if: '{{enveq "SKIPCI" "false"}}'
inputs:
- deploy_path: platform/android/MapboxGLAndroidSDKTestApp/build/outputs/apk
- is_compress: 'true'
- notify_user_groups: none
- slack:
- run_if: '{{enveq "SKIPCI" "false"}}'
title: Post to Slack
inputs:
- webhook_url: "$SLACK_HOOK_URL"
@@ -157,13 +124,6 @@ workflows:
scheduled:
steps:
- script:
- title: Configure AWS-CLI
- inputs:
- - content: |-
- #!/bin/bash
- apt-get install -y python-pip python-dev build-essential
- pip install awscli
- - script:
title: Download maven credentials
inputs:
- content: |-
@@ -181,15 +141,21 @@ workflows:
inputs:
- content: |-
#!/bin/bash
- echo "Compile libmapbox-gl.so for all supported abi's and create an aar file:"
- BUILDTYPE=Release make apackage
+ echo "Compile libmapbox-gl.so for all supportd abi's:"
+ BUILDTYPE=Release make android-lib-arm-v5
+ BUILDTYPE=Release make android-lib-arm-v7
+ BUILDTYPE=Release make android-lib-arm-v8
+ BUILDTYPE=Release make android-lib-x86
+ BUILDTYPE=Release make android-lib-mips
+ BUILDTYPE=Release make android-lib-mips-64
+ cd platform/android && ./gradlew -Pmapbox.abis=armeabi-v7a MapboxGLAndroidSDK:assembleRelease
- script:
title: Publish to maven
inputs:
- content: |-
#!/bin/bash
echo "Upload aar file to maven:"
- cd platform/android && ./gradlew :MapboxGLAndroidSDK:uploadArchives
+ make run-android-upload-archives
- slack:
title: Post to Slack
inputs:
@@ -231,7 +197,7 @@ workflows:
- content: |-
#!/bin/bash
echo "Run tests on device farm:"
- cd platform/android && ./gradlew devicefarmUpload
+ make run-android-ui-test-aws
- slack:
title: Post to Slack
inputs:
@@ -260,7 +226,6 @@ workflows:
echo "Compile libmapbox-gl.so for all supportd abi's:"
export BUILDTYPE=Release
make apackage
- cd platform/android && ./gradlew :MapboxGLAndroidSDK:assembleRelease
- script:
title: Log metrics
inputs:
diff --git a/platform/android/build.gradle b/platform/android/build.gradle
index 52336d7441..120c0219e4 100644
--- a/platform/android/build.gradle
+++ b/platform/android/build.gradle
@@ -21,3 +21,6 @@ task wrapper(type: Wrapper) {
apply from: rootProject.file('dependencies.gradle')
+// Load build system information. If this file does not exist, run
+// `make platform/android/configuration.gradle`
+apply from: rootProject.file('configuration.gradle')
diff --git a/platform/android/config.cmake b/platform/android/config.cmake
index c2bc20771d..c111744ed0 100644
--- a/platform/android/config.cmake
+++ b/platform/android/config.cmake
@@ -16,42 +16,32 @@ if ((ANDROID_ABI STREQUAL "armeabi") OR (ANDROID_ABI STREQUAL "armeabi-v7a") OR
endif()
mason_use(jni.hpp VERSION 3.0.0 HEADER_ONLY)
-mason_use(libzip VERSION 1.1.3)
mason_use(nunicode VERSION 1.7.1)
mason_use(sqlite VERSION 3.14.2)
mason_use(gtest VERSION 1.8.0)
mason_use(icu VERSION 58.1-min-size)
-set(ANDROID_SDK_PROJECT_DIR ${CMAKE_SOURCE_DIR}/platform/android/MapboxGLAndroidSDK)
-set(ANDROID_JNI_TARGET_DIR ${ANDROID_SDK_PROJECT_DIR}/src/main/jniLibs/${ANDROID_ABI})
-set(ANDROID_ASSETS_TARGET_DIR ${ANDROID_SDK_PROJECT_DIR}/src/main/assets)
-set(ANDROID_TEST_APP_JNI_TARGET_DIR ${CMAKE_SOURCE_DIR}/platform/android/MapboxGLAndroidSDKTestApp/src/main/jniLibs/${ANDROID_ABI})
-
-if (NOT DEFINED ANDROID_TOOLCHAIN_PREFIX)
- set(ANDROID_TOOLCHAIN_PREFIX "${MASON_XC_ROOT}/bin/${ANDROID_TOOLCHAIN}-")
-endif()
-
## mbgl core ##
macro(mbgl_platform_core)
-
target_sources(mbgl-core
# Loop
- PRIVATE platform/android/src/thread.cpp
PRIVATE platform/android/src/async_task.cpp
PRIVATE platform/android/src/run_loop.cpp
PRIVATE platform/android/src/run_loop_impl.hpp
PRIVATE platform/android/src/timer.cpp
# File source
- PRIVATE platform/android/src/asset_file_source.cpp
PRIVATE platform/android/src/http_file_source.cpp
+ PRIVATE platform/android/src/asset_manager.hpp
+ PRIVATE platform/android/src/asset_manager_file_source.cpp
+ PRIVATE platform/android/src/asset_manager_file_source.hpp
PRIVATE platform/default/default_file_source.cpp
+ PRIVATE platform/default/asset_file_source.cpp
PRIVATE platform/default/local_file_source.cpp
PRIVATE platform/default/online_file_source.cpp
# Offline
- # PRIVATE include/mbgl/storage/offline.hpp
PRIVATE platform/default/mbgl/storage/offline.cpp
PRIVATE platform/default/mbgl/storage/offline_database.cpp
PRIVATE platform/default/mbgl/storage/offline_database.hpp
@@ -62,6 +52,7 @@ macro(mbgl_platform_core)
# Misc
PRIVATE platform/android/src/logging_android.cpp
+ PRIVATE platform/android/src/thread.cpp
PRIVATE platform/default/string_stdlib.cpp
PRIVATE platform/default/bidi.cpp
PRIVATE platform/default/utf.cpp
@@ -79,129 +70,6 @@ macro(mbgl_platform_core)
PRIVATE platform/default/mbgl/util/shared_thread_pool.hpp
PRIVATE platform/default/mbgl/util/default_thread_pool.cpp
PRIVATE platform/default/mbgl/util/default_thread_pool.hpp
-
- # Conversion C++ -> Java
- platform/android/src/conversion/constant.hpp
- platform/android/src/conversion/conversion.hpp
- platform/android/src/style/conversion/function.hpp
- platform/android/src/style/conversion/property_value.hpp
- platform/android/src/style/conversion/types.hpp
- platform/android/src/style/conversion/types_string_values.hpp
- platform/android/src/map/camera_position.cpp
- platform/android/src/map/camera_position.hpp
-
- # Style conversion Java -> C++
- platform/android/src/style/android_conversion.hpp
- platform/android/src/style/conversion/geojson.hpp
- platform/android/src/style/value.cpp
- platform/android/src/style/value.hpp
- platform/android/src/style/conversion/url_or_tileset.hpp
-
- # Style
- platform/android/src/style/layers/background_layer.cpp
- platform/android/src/style/layers/background_layer.hpp
- platform/android/src/style/layers/circle_layer.cpp
- platform/android/src/style/layers/circle_layer.hpp
- platform/android/src/style/layers/custom_layer.cpp
- platform/android/src/style/layers/custom_layer.hpp
- platform/android/src/style/layers/fill_layer.cpp
- platform/android/src/style/layers/fill_layer.hpp
- platform/android/src/style/layers/layer.cpp
- platform/android/src/style/layers/layer.hpp
- platform/android/src/style/layers/layers.cpp
- platform/android/src/style/layers/layers.hpp
- platform/android/src/style/layers/line_layer.cpp
- platform/android/src/style/layers/line_layer.hpp
- platform/android/src/style/layers/raster_layer.cpp
- platform/android/src/style/layers/raster_layer.hpp
- platform/android/src/style/layers/symbol_layer.cpp
- platform/android/src/style/layers/symbol_layer.hpp
- platform/android/src/style/layers/unknown_layer.cpp
- platform/android/src/style/layers/unknown_layer.hpp
- platform/android/src/style/sources/geojson_source.cpp
- platform/android/src/style/sources/geojson_source.hpp
- platform/android/src/style/sources/source.cpp
- platform/android/src/style/sources/source.hpp
- platform/android/src/style/sources/sources.cpp
- platform/android/src/style/sources/sources.hpp
- platform/android/src/style/sources/raster_source.cpp
- platform/android/src/style/sources/raster_source.hpp
- platform/android/src/style/sources/unknown_source.cpp
- platform/android/src/style/sources/unknown_source.hpp
- platform/android/src/style/sources/vector_source.cpp
- platform/android/src/style/sources/vector_source.hpp
- platform/android/src/style/functions/stop.cpp
- platform/android/src/style/functions/stop.hpp
- platform/android/src/style/functions/categorical_stops.cpp
- platform/android/src/style/functions/categorical_stops.hpp
- platform/android/src/style/functions/exponential_stops.cpp
- platform/android/src/style/functions/exponential_stops.hpp
- platform/android/src/style/functions/identity_stops.cpp
- platform/android/src/style/functions/identity_stops.hpp
- platform/android/src/style/functions/interval_stops.cpp
- platform/android/src/style/functions/interval_stops.hpp
-
- # FileSource holder
- platform/android/src/file_source.cpp
- platform/android/src/file_source.hpp
-
- # Connectivity
- platform/android/src/connectivity_listener.cpp
- platform/android/src/connectivity_listener.hpp
-
- # Native map
- platform/android/src/native_map_view.cpp
- platform/android/src/native_map_view.hpp
-
- # Java core classes
- platform/android/src/java/util.cpp
- platform/android/src/java/util.hpp
-
- # Graphics
- platform/android/src/graphics/pointf.cpp
- platform/android/src/graphics/pointf.hpp
- platform/android/src/graphics/rectf.cpp
- platform/android/src/graphics/rectf.hpp
-
- # Geometry
- platform/android/src/geometry/feature.cpp
- platform/android/src/geometry/feature.hpp
- platform/android/src/geometry/lat_lng.cpp
- platform/android/src/geometry/lat_lng.hpp
- platform/android/src/geometry/lat_lng_bounds.cpp
- platform/android/src/geometry/lat_lng_bounds.hpp
- platform/android/src/geometry/projected_meters.cpp
- platform/android/src/geometry/projected_meters.hpp
-
- # Annotation
- platform/android/src/annotation/marker.cpp
- platform/android/src/annotation/marker.hpp
- platform/android/src/annotation/polygon.cpp
- platform/android/src/annotation/polygon.hpp
- platform/android/src/annotation/polyline.cpp
- platform/android/src/annotation/polyline.hpp
-
- # Offline
- platform/android/src/offline/offline_manager.cpp
- platform/android/src/offline/offline_manager.hpp
- platform/android/src/offline/offline_region.cpp
- platform/android/src/offline/offline_region.hpp
- platform/android/src/offline/offline_region_definition.cpp
- platform/android/src/offline/offline_region_definition.hpp
- platform/android/src/offline/offline_region_error.cpp
- platform/android/src/offline/offline_region_error.hpp
- platform/android/src/offline/offline_region_status.cpp
- platform/android/src/offline/offline_region_status.hpp
-
- # Main jni bindings
- platform/android/src/attach_env.cpp
- platform/android/src/attach_env.hpp
- platform/android/src/java_types.cpp
- platform/android/src/java_types.hpp
-
- # Main entry point
- platform/android/src/jni.hpp
- platform/android/src/jni.cpp
)
target_include_directories(mbgl-core
@@ -210,11 +78,10 @@ macro(mbgl_platform_core)
target_add_mason_package(mbgl-core PUBLIC sqlite)
target_add_mason_package(mbgl-core PUBLIC nunicode)
- target_add_mason_package(mbgl-core PUBLIC libzip)
target_add_mason_package(mbgl-core PUBLIC geojson)
target_add_mason_package(mbgl-core PUBLIC jni.hpp)
target_add_mason_package(mbgl-core PUBLIC rapidjson)
- target_add_mason_package(mbgl-core PUBLIC icu)
+ target_add_mason_package(mbgl-core PRIVATE icu)
target_compile_options(mbgl-core
PRIVATE -fvisibility=hidden
@@ -231,93 +98,222 @@ macro(mbgl_platform_core)
PUBLIC -lstdc++
PUBLIC -latomic
PUBLIC -lz
- PUBLIC -Wl,--gc-sections
)
endmacro()
## Main library ##
-add_library(mapbox-gl SHARED
- platform/android/src/main.cpp
+add_library(mbgl-android STATIC
+ # Conversion C++ -> Java
+ platform/android/src/conversion/constant.hpp
+ platform/android/src/conversion/conversion.hpp
+ platform/android/src/style/conversion/function.hpp
+ platform/android/src/style/conversion/property_value.hpp
+ platform/android/src/style/conversion/types.hpp
+ platform/android/src/style/conversion/types_string_values.hpp
+ platform/android/src/map/camera_position.cpp
+ platform/android/src/map/camera_position.hpp
+
+ # Style conversion Java -> C++
+ platform/android/src/style/android_conversion.hpp
+ platform/android/src/style/conversion/geojson.hpp
+ platform/android/src/style/value.cpp
+ platform/android/src/style/value.hpp
+ platform/android/src/style/conversion/url_or_tileset.hpp
+
+ # Style
+ platform/android/src/style/transition_options.cpp
+ platform/android/src/style/transition_options.hpp
+ platform/android/src/style/layers/background_layer.cpp
+ platform/android/src/style/layers/background_layer.hpp
+ platform/android/src/style/layers/circle_layer.cpp
+ platform/android/src/style/layers/circle_layer.hpp
+ platform/android/src/style/layers/custom_layer.cpp
+ platform/android/src/style/layers/custom_layer.hpp
+ platform/android/src/style/layers/fill_extrusion_layer.cpp
+ platform/android/src/style/layers/fill_extrusion_layer.hpp
+ platform/android/src/style/layers/fill_layer.cpp
+ platform/android/src/style/layers/fill_layer.hpp
+ platform/android/src/style/layers/layer.cpp
+ platform/android/src/style/layers/layer.hpp
+ platform/android/src/style/layers/layers.cpp
+ platform/android/src/style/layers/layers.hpp
+ platform/android/src/style/layers/line_layer.cpp
+ platform/android/src/style/layers/line_layer.hpp
+ platform/android/src/style/layers/raster_layer.cpp
+ platform/android/src/style/layers/raster_layer.hpp
+ platform/android/src/style/layers/symbol_layer.cpp
+ platform/android/src/style/layers/symbol_layer.hpp
+ platform/android/src/style/layers/unknown_layer.cpp
+ platform/android/src/style/layers/unknown_layer.hpp
+ platform/android/src/style/sources/geojson_source.cpp
+ platform/android/src/style/sources/geojson_source.hpp
+ platform/android/src/style/sources/source.cpp
+ platform/android/src/style/sources/source.hpp
+ platform/android/src/style/sources/sources.cpp
+ platform/android/src/style/sources/sources.hpp
+ platform/android/src/style/sources/raster_source.cpp
+ platform/android/src/style/sources/raster_source.hpp
+ platform/android/src/style/sources/unknown_source.cpp
+ platform/android/src/style/sources/unknown_source.hpp
+ platform/android/src/style/sources/vector_source.cpp
+ platform/android/src/style/sources/vector_source.hpp
+ platform/android/src/style/functions/stop.cpp
+ platform/android/src/style/functions/stop.hpp
+ platform/android/src/style/functions/categorical_stops.cpp
+ platform/android/src/style/functions/categorical_stops.hpp
+ platform/android/src/style/functions/exponential_stops.cpp
+ platform/android/src/style/functions/exponential_stops.hpp
+ platform/android/src/style/functions/identity_stops.cpp
+ platform/android/src/style/functions/identity_stops.hpp
+ platform/android/src/style/functions/interval_stops.cpp
+ platform/android/src/style/functions/interval_stops.hpp
+
+ # FileSource holder
+ platform/android/src/file_source.cpp
+ platform/android/src/file_source.hpp
+
+ # Connectivity
+ platform/android/src/connectivity_listener.cpp
+ platform/android/src/connectivity_listener.hpp
+
+ # Native map
+ platform/android/src/native_map_view.cpp
+ platform/android/src/native_map_view.hpp
+
+ # Java core classes
+ platform/android/src/java/util.cpp
+ platform/android/src/java/util.hpp
+
+ # Graphics
+ platform/android/src/graphics/pointf.cpp
+ platform/android/src/graphics/pointf.hpp
+ platform/android/src/graphics/rectf.cpp
+ platform/android/src/graphics/rectf.hpp
+
+ # GeoJSON
+ platform/android/src/geojson/feature.cpp
+ platform/android/src/geojson/feature.hpp
+ platform/android/src/geojson/feature_collection.cpp
+ platform/android/src/geojson/feature_collection.hpp
+ platform/android/src/geojson/geometry.cpp
+ platform/android/src/geojson/geometry.hpp
+ platform/android/src/geojson/line_string.cpp
+ platform/android/src/geojson/line_string.hpp
+ platform/android/src/geojson/multi_line_string.cpp
+ platform/android/src/geojson/multi_line_string.hpp
+ platform/android/src/geojson/multi_point.cpp
+ platform/android/src/geojson/multi_point.hpp
+ platform/android/src/geojson/multi_polygon.cpp
+ platform/android/src/geojson/multi_polygon.hpp
+ platform/android/src/geojson/point.cpp
+ platform/android/src/geojson/point.hpp
+ platform/android/src/geojson/polygon.cpp
+ platform/android/src/geojson/polygon.hpp
+ platform/android/src/geojson/position.cpp
+ platform/android/src/geojson/position.hpp
+
+ # Geometry
+ platform/android/src/geometry/lat_lng.cpp
+ platform/android/src/geometry/lat_lng.hpp
+ platform/android/src/geometry/lat_lng_bounds.cpp
+ platform/android/src/geometry/lat_lng_bounds.hpp
+ platform/android/src/geometry/projected_meters.cpp
+ platform/android/src/geometry/projected_meters.hpp
+
+ # GSon
+ platform/android/src/gson/json_array.cpp
+ platform/android/src/gson/json_array.hpp
+ platform/android/src/gson/json_element.cpp
+ platform/android/src/gson/json_element.hpp
+ platform/android/src/gson/json_object.cpp
+ platform/android/src/gson/json_object.hpp
+ platform/android/src/gson/json_primitive.cpp
+ platform/android/src/gson/json_primitive.hpp
+
+ # Annotation
+ platform/android/src/annotation/marker.cpp
+ platform/android/src/annotation/marker.hpp
+ platform/android/src/annotation/polygon.cpp
+ platform/android/src/annotation/polygon.hpp
+ platform/android/src/annotation/polyline.cpp
+ platform/android/src/annotation/polyline.hpp
+
+ # Offline
+ platform/android/src/offline/offline_manager.cpp
+ platform/android/src/offline/offline_manager.hpp
+ platform/android/src/offline/offline_region.cpp
+ platform/android/src/offline/offline_region.hpp
+ platform/android/src/offline/offline_region_definition.cpp
+ platform/android/src/offline/offline_region_definition.hpp
+ platform/android/src/offline/offline_region_error.cpp
+ platform/android/src/offline/offline_region_error.hpp
+ platform/android/src/offline/offline_region_status.cpp
+ platform/android/src/offline/offline_region_status.hpp
+
+ # Main jni bindings
+ platform/android/src/attach_env.cpp
+ platform/android/src/attach_env.hpp
+ platform/android/src/java_types.cpp
+ platform/android/src/java_types.hpp
+
+ # Main entry point
+ platform/android/src/jni.hpp
+ platform/android/src/jni.cpp
)
-target_compile_options(mapbox-gl
+target_compile_options(mbgl-android
PRIVATE -fvisibility=hidden
PRIVATE -ffunction-sections
PRIVATE -fdata-sections
)
-target_link_libraries(mapbox-gl
+target_link_libraries(mbgl-android
PUBLIC mbgl-core
- PUBLIC -Wl,--gc-sections
- PUBLIC -Wl,--version-script=${CMAKE_SOURCE_DIR}/platform/android/version-script
)
-# Create a stripped version of the library and copy it to the JNIDIR.
-add_custom_command(TARGET mapbox-gl POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E make_directory ${ANDROID_JNI_TARGET_DIR}
- COMMAND ${ANDROID_TOOLCHAIN_PREFIX}strip $<TARGET_FILE:mapbox-gl> -o ${ANDROID_JNI_TARGET_DIR}/$<TARGET_FILE_NAME:mapbox-gl>)
-
-## Test library ##
-
-add_library(mbgl-test SHARED
- # Actual tests
- ${MBGL_TEST_FILES}
-
- # Main test entry point
- platform/android/src/test/main.jni.cpp
+## Shared library
+add_library(mapbox-gl SHARED
+ platform/android/src/main.cpp
)
-add_dependencies(mbgl-test
- mapbox-gl
+target_link_libraries(mapbox-gl
+ PRIVATE mbgl-android
+ PRIVATE -Wl,--gc-sections
+ PRIVATE -Wl,--version-script=${CMAKE_SOURCE_DIR}/platform/android/version-script
)
-target_sources(mbgl-test
- # Headless view
- PRIVATE platform/default/mbgl/gl/headless_backend.cpp
- PRIVATE platform/default/mbgl/gl/headless_backend.hpp
- PRIVATE platform/default/mbgl/gl/offscreen_view.cpp
- PRIVATE platform/default/mbgl/gl/offscreen_view.hpp
+## Test library ##
- PRIVATE platform/linux/src/headless_backend_egl.cpp
- PRIVATE platform/linux/src/headless_display_egl.cpp
-)
+set(MBGL_TEST_TARGET_TYPE "library")
+macro(mbgl_platform_test)
+ target_sources(mbgl-test
+ PRIVATE platform/default/mbgl/test/main.cpp
-target_compile_options(mbgl-test
- PRIVATE -fvisibility=hidden
-)
+ # Main test entry point
+ platform/android/src/test/main.jni.cpp
-target_compile_definitions(mbgl-test
- PRIVATE MBGL_ASSET_ZIP=1
-)
+ # Headless view
+ platform/default/mbgl/gl/headless_backend.cpp
+ platform/default/mbgl/gl/headless_backend.hpp
+ platform/default/mbgl/gl/offscreen_view.cpp
+ platform/default/mbgl/gl/offscreen_view.hpp
-target_include_directories(mbgl-test
- PRIVATE include
- PRIVATE src # TODO: eliminate
- PRIVATE test/include
- PRIVATE test/src
- PRIVATE platform/default
-)
+ platform/linux/src/headless_backend_egl.cpp
+ platform/linux/src/headless_display_egl.cpp
+ )
-target_link_libraries(mbgl-test
- PRIVATE mbgl-core
-)
+ target_compile_options(mbgl-test
+ PRIVATE -fvisibility=hidden
+ )
-target_add_mason_package(mbgl-test PRIVATE geometry)
-target_add_mason_package(mbgl-test PRIVATE variant)
-target_add_mason_package(mbgl-test PRIVATE unique_resource)
-target_add_mason_package(mbgl-test PRIVATE rapidjson)
-target_add_mason_package(mbgl-test PRIVATE gtest)
-target_add_mason_package(mbgl-test PRIVATE pixelmatch)
-target_add_mason_package(mbgl-test PRIVATE boost)
-target_add_mason_package(mbgl-test PRIVATE geojson)
-target_add_mason_package(mbgl-test PRIVATE geojsonvt)
-
-add_custom_command(TARGET mbgl-test POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/stripped
- COMMAND ${ANDROID_TOOLCHAIN_PREFIX}strip $<TARGET_FILE:mapbox-gl> -o ${CMAKE_CURRENT_BINARY_DIR}/stripped/$<TARGET_FILE_NAME:mapbox-gl>
- COMMAND ${ANDROID_TOOLCHAIN_PREFIX}strip $<TARGET_FILE:mbgl-test> -o ${CMAKE_CURRENT_BINARY_DIR}/stripped/$<TARGET_FILE_NAME:mbgl-test>)
+ target_link_libraries(mbgl-test
+ PRIVATE mbgl-android
+ PRIVATE -Wl,--gc-sections
+ PRIVATE -Wl,--version-script=${CMAKE_SOURCE_DIR}/platform/android/version-script
+ )
+endmacro()
## Custom layer example ##
@@ -332,11 +328,7 @@ target_compile_options(example-custom-layer
)
target_link_libraries(example-custom-layer
- PRIVATE mapbox-gl
- PUBLIC -Wl,--gc-sections
- PUBLIC -Wl,--version-script=${CMAKE_SOURCE_DIR}/platform/android/version-script
+ PRIVATE mbgl-core
+ PRIVATE -Wl,--gc-sections
+ PRIVATE -Wl,--version-script=${CMAKE_SOURCE_DIR}/platform/android/version-script
)
-
-add_custom_command(TARGET example-custom-layer POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E make_directory ${ANDROID_TEST_APP_JNI_TARGET_DIR}
- COMMAND ${ANDROID_TOOLCHAIN_PREFIX}strip $<TARGET_FILE:example-custom-layer> -o ${ANDROID_TEST_APP_JNI_TARGET_DIR}/$<TARGET_FILE_NAME:example-custom-layer>)
diff --git a/platform/android/dependencies.gradle b/platform/android/dependencies.gradle
index c4ace641c3..738f571c09 100644
--- a/platform/android/dependencies.gradle
+++ b/platform/android/dependencies.gradle
@@ -7,7 +7,7 @@ ext {
versionCode = 11
versionName = "5.0.0"
- supportLibVersion = "25.2.0"
+ supportLibVersion = "25.3.1"
leakCanaryVersion = '1.5'
wearableVersion = '2.0.0'
@@ -16,12 +16,12 @@ ext {
dep = [
// mapbox
- mapboxJavaServices : 'com.mapbox.mapboxsdk:mapbox-java-services:2.0.0@jar',
- mapboxJavaGeoJSON : 'com.mapbox.mapboxsdk:mapbox-java-geojson:2.0.0@jar',
- mapboxAndroidTelemetry : 'com.mapbox.mapboxsdk:mapbox-android-telemetry:2.0.0@aar',
+ mapboxJavaServices : 'com.mapbox.mapboxsdk:mapbox-java-services:2.1.0@jar',
+ mapboxJavaGeoJSON : 'com.mapbox.mapboxsdk:mapbox-java-geojson:2.1.0@jar',
+ mapboxAndroidTelemetry : 'com.mapbox.mapboxsdk:mapbox-android-telemetry:2.1.0@aar',
// mapzen lost
- lost : 'com.mapzen.android:lost:2.1.2',
+ lost : 'com.mapzen.android:lost:2.2.0',
// unit test
junit : 'junit:junit:4.12',
diff --git a/platform/android/scripts/debug.sh b/platform/android/scripts/debug.sh
deleted file mode 100755
index c3390b4ce1..0000000000
--- a/platform/android/scripts/debug.sh
+++ /dev/null
@@ -1,42 +0,0 @@
-#!/usr/bin/env bash
-
-set -e
-set -o pipefail
-
-# Automation of https://github.com/mapbox/mapbox-gl-native/wiki/Android-debugging-with-remote-GDB
-
-export MASON_ANDROID_ARCH=x86
-export MASON_ANDROID_PLATFORM=9
-export MASON_ANDROID_NDK_VERSION=r13b
-
-export MASON_XC_ROOT=`scripts/mason.sh PREFIX android-ndk VERSION ${MASON_ANDROID_ARCH}-${MASON_ANDROID_PLATFORM}-${MASON_ANDROID_NDK_VERSION}`
-source ${MASON_XC_ROOT}/toolchain.sh
-
-if [[ $1 == '--prepare' ]]; then
- mkdir -p ~/.android/debugging/{vendor,system}_lib
- adb pull /system/lib ~/.android/debugging/system_lib
- adb pull /vendor/lib ~/.android/debugging/vendor_lib
- adb pull /system/bin/app_process ~/.android/debugging
- adb pull /system/bin/app_process32 ~/.android/debugging
- adb pull /system/bin/linker ~/.android/debugging
-
- if [[ ${MASON_ANDROID_ARCH} == 'arm-v8' || ${MASON_ANDROID_ARCH} == 'x86-64' || ${MASON_ANDROID_ARCH} == 'mips-64' ]]; then
- adb pull /system/bin/app_process64 ~/.android/debugging
- adb pull /system/bin/linker64 ~/.android/debugging
- fi
-
- cp ${MASON_XC_ROOT}/prebuilt/gdbserver/gdbserver \
- platform/android/MapboxGLAndroidSDK/src/main/jniLibs/${ANDROID_ABI}/gdbserver.so
-fi
-
-adb install -r -t -d -g platform/android/MapboxGLAndroidSDKTestApp/build/outputs/apk/MapboxGLAndroidSDKTestApp-debug.apk
-adb shell am start -n "com.mapbox.mapboxsdk.testapp/com.mapbox.mapboxsdk.testapp.activity.FeatureOverviewActivity" \
- -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
-
-adb forward tcp:5039 tcp:5039
-adb shell run-as com.mapbox.mapboxsdk.testapp '/data/data/com.mapbox.mapboxsdk.testapp/lib/gdbserver.so \
- --attach :5039 `pgrep com.mapbox.mapboxsdk.testapp`' &
-
-${MASON_XC_ROOT}/bin/gdb \
- -ex "target remote :5039" \
- -ex "set solib-search-path ~/.android/debugging:~/.android/debugging/system_lib:~/.android/debugging/vendor_lib:~/.android/debugging/vendor_lib/egl:./build/android-${MASON_ANDROID_ARCH}-${MASON_ANDROID_PLATFORM}/Debug/lib.target/"
diff --git a/platform/android/scripts/generate-style-code.js b/platform/android/scripts/generate-style-code.js
index 09563f3b9d..5d8fc4cc6d 100644
--- a/platform/android/scripts/generate-style-code.js
+++ b/platform/android/scripts/generate-style-code.js
@@ -34,9 +34,6 @@ var layers = Object.keys(spec.layer.type.values).map((type) => {
};
});
-// XXX Remove fill-extrusion layer for now
-layers = _(layers).filter(layer => layer.type != "fill-extrusion").value();
-
// Process all layer properties
const layoutProperties = _(layers).map('layoutProperties').flatten().value();
const paintProperties = _(layers).map('paintProperties').flatten().value();
diff --git a/platform/android/scripts/generate-test-code.js b/platform/android/scripts/generate-test-code.js
index 2fd98f701f..b054e4a2e7 100644
--- a/platform/android/scripts/generate-test-code.js
+++ b/platform/android/scripts/generate-test-code.js
@@ -14,7 +14,7 @@ global.camelize = function (str) {
}
-const excludeActivities = ["RealTimeGeoJsonActivity","UpdateMetadataActivity","CarDrivingActivity","MyLocationTrackingModeActivity","MyLocationToggleActivity","MyLocationTintActivity","MyLocationDrawableActivity","DoubleMapActivity", "LocationPickerActivity","GeoJsonClusteringActivity","RuntimeStyleTestActivity", "AnimatedMarkerActivity", "ViewPagerActivity","MapFragmentActivity","SupportMapFragmentActivity","SnapshotActivity","NavigationDrawerActivity", "QueryRenderedFeaturesBoxHighlightActivity", "MultiMapActivity", "MapInDialogActivity", "SimpleMapActivity"];
+const excludeActivities = ["DeleteRegionActivity","RealTimeGeoJsonActivity","UpdateMetadataActivity","CarDrivingActivity","MyLocationTrackingModeActivity","MyLocationToggleActivity","MyLocationTintActivity","MyLocationDrawableActivity","DoubleMapActivity", "LocationPickerActivity","GeoJsonClusteringActivity","RuntimeStyleTestActivity", "AnimatedMarkerActivity", "ViewPagerActivity","MapFragmentActivity","SupportMapFragmentActivity","SnapshotActivity","NavigationDrawerActivity", "QueryRenderedFeaturesBoxHighlightActivity", "MultiMapActivity", "MapInDialogActivity", "SimpleMapActivity"];
const appBasePath = 'platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity';
const testBasePath = 'platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/gen';
const subPackages = fs.readdirSync(appBasePath);
diff --git a/platform/android/scripts/metrics.sh b/platform/android/scripts/metrics.sh
index 37d8c1de65..974ee5e8db 100755
--- a/platform/android/scripts/metrics.sh
+++ b/platform/android/scripts/metrics.sh
@@ -4,12 +4,12 @@ set -e
set -o pipefail
# Track individual architectures
-scripts/log_binary_size.sh "platform/android/MapboxGLAndroidSDK/src/main/jniLibs/armeabi/libmapbox-gl.so" "Platform=Android,Arch=arm-v5"
-scripts/log_binary_size.sh "platform/android/MapboxGLAndroidSDK/src/main/jniLibs/armeabi-v7a/libmapbox-gl.so" "Platform=Android,Arch=arm-v7"
-scripts/log_binary_size.sh "platform/android/MapboxGLAndroidSDK/src/main/jniLibs/arm64-v8a/libmapbox-gl.so" "Platform=Android,Arch=arm-v8"
-scripts/log_binary_size.sh "platform/android/MapboxGLAndroidSDK/src/main/jniLibs/x86/libmapbox-gl.so" "Platform=Android,Arch=x86"
-scripts/log_binary_size.sh "platform/android/MapboxGLAndroidSDK/src/main/jniLibs/x86_64/libmapbox-gl.so" "Platform=Android,Arch=x86_64"
-scripts/log_binary_size.sh "platform/android/MapboxGLAndroidSDK/src/main/jniLibs/mips/libmapbox-gl.so" "Platform=Android,Arch=mips"
+scripts/log_binary_size.sh "platform/android/MapboxGLAndroidSDK/build/intermediates/bundles/default/jni/armeabi/libmapbox-gl.so" "Platform=Android,Arch=arm-v5"
+scripts/log_binary_size.sh "platform/android/MapboxGLAndroidSDK/build/intermediates/bundles/default/jni/armeabi-v7a/libmapbox-gl.so" "Platform=Android,Arch=arm-v7"
+scripts/log_binary_size.sh "platform/android/MapboxGLAndroidSDK/build/intermediates/bundles/default/jni/arm64-v8a/libmapbox-gl.so" "Platform=Android,Arch=arm-v8"
+scripts/log_binary_size.sh "platform/android/MapboxGLAndroidSDK/build/intermediates/bundles/default/jni/x86/libmapbox-gl.so" "Platform=Android,Arch=x86"
+scripts/log_binary_size.sh "platform/android/MapboxGLAndroidSDK/build/intermediates/bundles/default/jni/x86_64/libmapbox-gl.so" "Platform=Android,Arch=x86_64"
+scripts/log_binary_size.sh "platform/android/MapboxGLAndroidSDK/build/intermediates/bundles/default/jni/mips/libmapbox-gl.so" "Platform=Android,Arch=mips"
# Track overall library size
-scripts/log_binary_size.sh "platform/android/MapboxGLAndroidSDK/build/outputs/aar/MapboxGLAndroidSDK-release.aar" "Platform=Android,Arch=Archive"
+scripts/log_binary_size.sh "platform/android/MapboxGLAndroidSDK/build/outputs/aar/MapboxGLAndroidSDK-release.aar" "Platform=Android,Arch=Archive"
diff --git a/platform/android/scripts/ndk.sh b/platform/android/scripts/ndk.sh
deleted file mode 100755
index 96a314a3c2..0000000000
--- a/platform/android/scripts/ndk.sh
+++ /dev/null
@@ -1,111 +0,0 @@
-#!/usr/bin/env bash
-
-set -e
-set -o pipefail
-set -u
-
-# This script produces an env.sh file, which contains the paths to CMake, and the flags required to
-# create a build. It first tries to use the Android NDK, but falls back to installing it via Mason.
-
-function error { >&2 echo -e "\033[1m\033[31m$@\033[0m"; }
-function warning { >&2 echo -e "\033[1m\033[33m$@\033[0m"; }
-function status { >&2 echo -e "\033[1m\033[36m$@\033[0m"; }
-function info { >&2 echo -e "\033[1m\033[32m$@\033[0m"; }
-
-if [ "$#" -ne 3 ]; then
- error "Usage: $0 <short arch> <long arch> <api level>"
-fi
-
-NDK_ANDROID_VERSION=$1-$3
-ANDROID_NATIVE_API_LEVEL=$3
-ANDROID_ABI=$2
-
-function mason_ndk {
- local CMAKE=${CMAKE:-cmake}
- MASON_XC_ROOT="`${CMAKE} -P cmake/mason.cmake PREFIX android-ndk VERSION ${NDK_ANDROID_VERSION}-r13b`"
-
- local TOOLCHAIN="${MASON_XC_ROOT}/toolchain.cmake"
- if [ ! -f "${TOOLCHAIN}" ]; then
- error "Can't find CMake toolchain file at ${TOOLCHAIN}."
- exit 1
- fi
-
- info "Using Mason-provided Android NDK at ${MASON_XC_ROOT}"
- echo CMAKE=\"${CMAKE}\"
- echo CMAKE_GENERATOR=\"Ninja\"
- echo CMAKE_ARGS=\" \
- -DCMAKE_MAKE_PROGRAM=`pwd`/${NINJA} \
- -DMASON_XC_ROOT=${MASON_XC_ROOT} \
- -DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN} \
- \"
-}
-
-function system_ndk {
- if [[ ${USE_MASON_NDK:-} ]]; then
- return 1
- fi
-
- if [ -f platform/android/local.properties ]; then
- local SDK_DIR=$(sed -n -e 's/^sdk.dir=\(.*\)$/\1/p' platform/android/local.properties)
- fi
-
- if [ ! -d "${SDK_DIR:-}" ]; then
- if [ ! -z "${ANDROID_HOME:-}" ]; then
- local SDK_DIR="${ANDROID_HOME}"
- else
- error "Can't find the Android SDK. Set \$ANDROID_HOME to the SDK path."
- exit 1
- fi
- fi
-
- local NDK_DIR="${ANDROID_NDK_HOME:-${SDK_DIR}/ndk-bundle}"
- if [ ! -d "${NDK_DIR}" ]; then
- warning "Can't find the Android NDK. If it is installed, set \$ANDROID_NDK_HOME to the NDK path."
- return 1
- fi
-
- # Try to install CMake if it's not installed yet.
- mkdir -p "${SDK_DIR}/cmake"
- local CMAKE_VERSION=/$(ls "${SDK_DIR}/cmake" | sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n | tail -n 1)
- local CMAKE="${SDK_DIR}/cmake${CMAKE_VERSION:-}/bin/cmake"
- if [ ! -f "${CMAKE}" ]; then
- status "Trying to install CMake..."
- mkdir -p "${SDK_DIR}/licenses"
- echo "8933bad161af4178b1185d1a37fbf41ea5269c55" > "${SDK_DIR}/licenses/android-sdk-license"
- "${SDK_DIR}/tools/bin/sdkmanager" --list | grep cmake | tail -n 1 | cut -d \| -f 1 | xargs "${SDK_DIR}/tools/bin/sdkmanager" >&2
- CMAKE_VERSION=/$(ls "${SDK_DIR}/cmake" | sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n | tail -n 1)
- CMAKE="${SDK_DIR}/cmake${CMAKE_VERSION:-}/bin/cmake"
- if [ ! -f "${CMAKE}" ]; then
- error "Can't find CMake at ${CMAKE}."
- return 1
- fi
- fi
-
- local NINJA="${SDK_DIR}/cmake${CMAKE_VERSION:-}/bin/ninja"
- if [ ! -f "${NINJA}" ]; then
- error "Can't find Ninja at ${NINJA}."
- return 1
- fi
-
- local TOOLCHAIN="${NDK_DIR}/build/cmake/android.toolchain.cmake"
- if [ ! -f "${TOOLCHAIN}" ]; then
- error "Can't find CMake toolchain file at ${TOOLCHAIN}."
- return 1
- fi
-
- info "Using system-provided Android NDK at ${NDK_DIR}"
- echo CMAKE=\"${CMAKE}\"
- echo CMAKE_GENERATOR=\"Android Gradle - Ninja\"
- echo CMAKE_ARGS=\" \
- -DANDROID_ABI=${ANDROID_ABI} \
- -DANDROID_NDK=${NDK_DIR} \
- -DCMAKE_MAKE_PROGRAM=${NINJA} \
- -DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN} \
- -DANDROID_NATIVE_API_LEVEL=${ANDROID_NATIVE_API_LEVEL} \
- -DANDROID_TOOLCHAIN=clang \
- -DANDROID_STL=c++_static \
- -DANDROID_CPP_FEATURES=rtti\;exceptions \
- \"
-}
-
-system_ndk || mason_ndk
diff --git a/platform/android/src/annotation/polygon.cpp b/platform/android/src/annotation/polygon.cpp
index ba82fc34dc..fbd849432a 100644
--- a/platform/android/src/annotation/polygon.cpp
+++ b/platform/android/src/annotation/polygon.cpp
@@ -9,13 +9,26 @@ jni::Class<Polygon> Polygon::javaClass;
mbgl::FillAnnotation Polygon::toAnnotation(jni::JNIEnv& env, jni::Object<Polygon> polygon) {
auto points = Polygon::getPoints(env, polygon);
+ auto holes = Polygon::getHoles(env, polygon);
- mbgl::FillAnnotation annotation { mbgl::Polygon<double> { MultiPoint::toGeometry<mbgl::LinearRing<double>>(env, points) } };
+ mbgl::Polygon<double> geometry { MultiPoint::toGeometry<mbgl::LinearRing<double>>(env, points) };
+
+ auto jHoleListsArray = java::util::List::toArray<java::util::List>(env, holes);
+ std::size_t jHoleListsSize = jHoleListsArray.Length(env);
+ for (std::size_t i = 0; i < jHoleListsSize; i++) {
+ auto jHoleList = jHoleListsArray.Get(env, i);
+ geometry.push_back(MultiPoint::toGeometry<mbgl::LinearRing<double>>(env, jHoleList));
+ jni::DeleteLocalRef(env, jHoleList);
+ }
+ jni::DeleteLocalRef(env, jHoleListsArray);
+
+ mbgl::FillAnnotation annotation { geometry };
annotation.opacity = { Polygon::getOpacity(env, polygon) };
annotation.color = { Polygon::getFillColor(env, polygon) };
annotation.outlineColor = { Polygon::getOutlineColor(env, polygon) };
jni::DeleteLocalRef(env, points);
+ jni::DeleteLocalRef(env, holes);
return annotation;
}
@@ -25,6 +38,11 @@ jni::Object<java::util::List> Polygon::getPoints(jni::JNIEnv& env, jni::Object<P
return polygon.Get(env, field);
}
+jni::Object<java::util::List> Polygon::getHoles(jni::JNIEnv& env, jni::Object<Polygon> polygon) {
+ static auto field = Polygon::javaClass.GetField<jni::Object<java::util::List>>(env, "holes");
+ return polygon.Get(env, field);
+}
+
float Polygon::getOpacity(jni::JNIEnv& env, jni::Object<Polygon> polygon) {
static auto field = Polygon::javaClass.GetField<float>(env, "alpha");
return polygon.Get(env, field);
diff --git a/platform/android/src/annotation/polygon.hpp b/platform/android/src/annotation/polygon.hpp
index 658aa5344b..a98b2822cf 100644
--- a/platform/android/src/annotation/polygon.hpp
+++ b/platform/android/src/annotation/polygon.hpp
@@ -28,6 +28,8 @@ private:
static jni::Object<java::util::List> getPoints(jni::JNIEnv&, jni::Object<Polygon>);
+ static jni::Object<java::util::List> getHoles(jni::JNIEnv&, jni::Object<Polygon>);
+
static float getOpacity(jni::JNIEnv&, jni::Object<Polygon>);
static mbgl::Color getFillColor(jni::JNIEnv&, jni::Object<Polygon>);
diff --git a/platform/android/src/asset_file_source.cpp b/platform/android/src/asset_file_source.cpp
deleted file mode 100644
index c72b86af5c..0000000000
--- a/platform/android/src/asset_file_source.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-#include <mbgl/storage/asset_file_source.hpp>
-#include <mbgl/storage/response.hpp>
-#include <mbgl/util/util.hpp>
-#include <mbgl/util/thread.hpp>
-#include <mbgl/util/url.hpp>
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wshadow"
-#include <zip.h>
-#pragma GCC diagnostic pop
-
-namespace {
-
-struct ZipHolder {
- ZipHolder(struct zip* archive_) : archive(archive_) {}
-
- ~ZipHolder() {
- if (archive) ::zip_close(archive);
- }
-
- struct zip* archive;
-};
-
-struct ZipFileHolder {
- ZipFileHolder(struct zip_file* file_) : file(file_) {}
-
- ~ZipFileHolder() {
- if (file) ::zip_fclose(file);
- }
-
- struct zip_file* file;
-};
-
-}
-
-namespace mbgl {
-
-class AssetFileRequest : public AsyncRequest {
-public:
- AssetFileRequest(std::unique_ptr<WorkRequest> workRequest_)
- : workRequest(std::move(workRequest_)) {
- }
-
- std::unique_ptr<WorkRequest> workRequest;
-};
-
-class AssetFileSource::Impl {
-public:
- Impl(const std::string& root_)
- : root(root_) {
- }
-
- void request(const std::string& url, FileSource::Callback callback) {
- ZipHolder archive = ::zip_open(root.c_str(), 0, nullptr);
- if (!archive.archive) {
- reportError(Response::Error::Reason::Other, "Could not open zip archive", callback);
- return;
- }
-
- struct zip_stat stat;
- ::zip_stat_init(&stat);
-
- std::string path = std::string("assets/") + mbgl::util::percentDecode(url.substr(8));
-
- int ret = ::zip_stat(archive.archive, path.c_str(), 0, &stat);
- if (ret < 0 || !(stat.valid & ZIP_STAT_SIZE)) {
- reportError(Response::Error::Reason::NotFound, "Could not stat file in zip archive", callback);
- return;
- }
-
- ZipFileHolder file = ::zip_fopen(archive.archive, path.c_str(), 0);
- if (!file.file) {
- reportError(Response::Error::Reason::NotFound, "Could not open file in zip archive", callback);
- return;
- }
-
- std::shared_ptr<std::string> buf = std::make_shared<std::string>();
- buf->resize(stat.size);
-
- ret = ::zip_fread(file.file, &buf->front(), stat.size);
- if (ret < 0) {
- reportError(Response::Error::Reason::Other, "Could not read file in zip archive", callback);
- return;
- }
-
- Response response;
- response.data = buf;
- callback(response);
- }
-
- void reportError(Response::Error::Reason reason, const char * message, FileSource::Callback callback) {
- Response response;
- response.error = std::make_unique<Response::Error>(reason, message);
- callback(response);
- }
-
-private:
- std::string root;
-};
-
-AssetFileSource::AssetFileSource(const std::string& root)
- : thread(std::make_unique<util::Thread<Impl>>(
- util::ThreadContext{"AssetFileSource", util::ThreadPriority::Low},
- root)) {
-}
-
-AssetFileSource::~AssetFileSource() = default;
-
-std::unique_ptr<AsyncRequest> AssetFileSource::request(const Resource& resource, Callback callback) {
- return thread->invokeWithCallback(&Impl::request, resource.url, callback);
-}
-
-}
diff --git a/platform/android/src/asset_manager.hpp b/platform/android/src/asset_manager.hpp
new file mode 100644
index 0000000000..b87d189514
--- /dev/null
+++ b/platform/android/src/asset_manager.hpp
@@ -0,0 +1,14 @@
+#pragma once
+
+namespace mbgl {
+namespace android {
+
+class AssetManager {
+public:
+ static constexpr auto Name() {
+ return "android/content/res/AssetManager";
+ };
+};
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/asset_manager_file_source.cpp b/platform/android/src/asset_manager_file_source.cpp
new file mode 100644
index 0000000000..6a3113d696
--- /dev/null
+++ b/platform/android/src/asset_manager_file_source.cpp
@@ -0,0 +1,53 @@
+#include "asset_manager_file_source.hpp"
+
+#include <mbgl/storage/response.hpp>
+#include <mbgl/util/util.hpp>
+#include <mbgl/util/thread.hpp>
+#include <mbgl/util/url.hpp>
+
+#include <android/asset_manager.h>
+#include <android/asset_manager_jni.h>
+
+namespace mbgl {
+
+class AssetManagerFileSource::Impl {
+public:
+ Impl(AAssetManager* assetManager_) : assetManager(assetManager_) {
+ }
+
+ void request(const std::string& url, FileSource::Callback callback) {
+ // Note: AssetManager already prepends "assets" to the filename.
+ const std::string path = mbgl::util::percentDecode(url.substr(8));
+
+ Response response;
+
+ if (AAsset* asset = AAssetManager_open(assetManager, path.c_str(), AASSET_MODE_BUFFER)) {
+ response.data = std::make_shared<std::string>(
+ reinterpret_cast<const char*>(AAsset_getBuffer(asset)), AAsset_getLength64(asset));
+ AAsset_close(asset);
+ } else {
+ response.error = std::make_unique<Response::Error>(Response::Error::Reason::NotFound,
+ "Could not read asset");
+ }
+
+ callback(response);
+ }
+
+private:
+ AAssetManager* assetManager;
+};
+
+AssetManagerFileSource::AssetManagerFileSource(jni::JNIEnv& env, jni::Object<android::AssetManager> assetManager_)
+ : assetManager(assetManager_.NewGlobalRef(env)),
+ thread(std::make_unique<util::Thread<Impl>>(
+ util::ThreadContext{"AssetManagerFileSource", util::ThreadPriority::Low},
+ AAssetManager_fromJava(&env, jni::Unwrap(**assetManager)))) {
+}
+
+AssetManagerFileSource::~AssetManagerFileSource() = default;
+
+std::unique_ptr<AsyncRequest> AssetManagerFileSource::request(const Resource& resource, Callback callback) {
+ return thread->invokeWithCallback(&Impl::request, resource.url, callback);
+}
+
+} // namespace mbgl
diff --git a/platform/android/src/asset_manager_file_source.hpp b/platform/android/src/asset_manager_file_source.hpp
new file mode 100644
index 0000000000..7a447a2c61
--- /dev/null
+++ b/platform/android/src/asset_manager_file_source.hpp
@@ -0,0 +1,28 @@
+#pragma once
+
+#include <mbgl/storage/file_source.hpp>
+
+#include "asset_manager.hpp"
+
+#include <jni/jni.hpp>
+
+namespace mbgl {
+
+namespace util {
+template <typename T> class Thread;
+} // namespace util
+
+class AssetManagerFileSource : public FileSource {
+public:
+ AssetManagerFileSource(jni::JNIEnv&, jni::Object<android::AssetManager>);
+ ~AssetManagerFileSource() override;
+
+ std::unique_ptr<AsyncRequest> request(const Resource&, Callback) override;
+
+private:
+ jni::UniqueObject<android::AssetManager> assetManager;
+ class Impl;
+ std::unique_ptr<util::Thread<Impl>> thread;
+};
+
+} // namespace mbgl
diff --git a/platform/android/src/file_source.cpp b/platform/android/src/file_source.cpp
index 20715bf920..16c09b7b52 100644
--- a/platform/android/src/file_source.cpp
+++ b/platform/android/src/file_source.cpp
@@ -2,21 +2,24 @@
#include <mbgl/util/logging.hpp>
-#include <string>
-
+#include "asset_manager_file_source.hpp"
#include "jni/generic_global_ref_deleter.hpp"
+#include <string>
namespace mbgl {
namespace android {
// FileSource //
-FileSource::FileSource(jni::JNIEnv& _env, jni::String accessToken, jni::String _cachePath, jni::String _apkPath) {
+FileSource::FileSource(jni::JNIEnv& _env,
+ jni::String accessToken,
+ jni::String _cachePath,
+ jni::Object<AssetManager> assetManager) {
// Create a core default file source
fileSource = std::make_unique<mbgl::DefaultFileSource>(
jni::Make<std::string>(_env, _cachePath) + "/mbgl-offline.db",
- jni::Make<std::string>(_env, _apkPath));
+ std::make_unique<AssetManagerFileSource>(_env, assetManager));
// Set access token
fileSource->setAccessToken(jni::Make<std::string>(_env, accessToken));
@@ -80,7 +83,7 @@ void FileSource::registerNative(jni::JNIEnv& env) {
// Register the peer
jni::RegisterNativePeer<FileSource>(
env, FileSource::javaClass, "nativePtr",
- std::make_unique<FileSource, JNIEnv&, jni::String, jni::String, jni::String>,
+ std::make_unique<FileSource, JNIEnv&, jni::String, jni::String, jni::Object<AssetManager>>,
"initialize",
"finalize",
METHOD(&FileSource::getAccessToken, "getAccessToken"),
diff --git a/platform/android/src/file_source.hpp b/platform/android/src/file_source.hpp
index 073e393e05..55e70f34d9 100644
--- a/platform/android/src/file_source.hpp
+++ b/platform/android/src/file_source.hpp
@@ -2,6 +2,8 @@
#include <mbgl/storage/default_file_source.hpp>
+#include "asset_manager.hpp"
+
#include <jni/jni.hpp>
namespace mbgl {
@@ -23,7 +25,7 @@ public:
static jni::Class<ResourceTransformCallback> javaClass;
};
- FileSource(jni::JNIEnv&, jni::String, jni::String, jni::String);
+ FileSource(jni::JNIEnv&, jni::String, jni::String, jni::Object<AssetManager>);
~FileSource();
diff --git a/platform/android/src/geometry/conversion/feature.hpp b/platform/android/src/geojson/conversion/feature.hpp
index 921138e859..86aa5fc03c 100644
--- a/platform/android/src/geometry/conversion/feature.hpp
+++ b/platform/android/src/geojson/conversion/feature.hpp
@@ -170,8 +170,8 @@ struct Converter<jni::jobject*, std::unordered_map<std::string, mbgl::Value>> {
template <>
-struct Converter<jni::Object<Feature>, mbgl::Feature> {
- Result<jni::Object<Feature>> operator()(jni::JNIEnv& env, const mbgl::Feature& value) const {
+struct Converter<jni::Object<android::geojson::Feature>, mbgl::Feature> {
+ Result<jni::Object<android::geojson::Feature>> operator()(jni::JNIEnv& env, const mbgl::Feature& value) const {
// Convert Id
FeatureIdVisitor idEvaluator;
@@ -179,13 +179,13 @@ struct Converter<jni::Object<Feature>, mbgl::Feature> {
auto jid = jni::Make<jni::String>(env, id);
// Convert properties
- auto properties = jni::Object<JsonObject>(*convert<jni::jobject*>(env, value.properties));
+ auto properties = jni::Object<gson::JsonObject>(*convert<jni::jobject*>(env, value.properties));
// Convert geometry
- auto geometry = jni::Object<Geometry>(*convert<jni::jobject*>(env, value.geometry));
+ auto geometry = jni::Object<android::geojson::Geometry>(*convert<jni::jobject*>(env, value.geometry));
// Create feature
- auto feature = Feature::fromGeometry(env, geometry, properties, jid);
+ auto feature = android::geojson::Feature::fromGeometry(env, geometry, properties, jid);
//Cleanup
jni::DeleteLocalRef(env, jid);
@@ -197,13 +197,13 @@ struct Converter<jni::Object<Feature>, mbgl::Feature> {
};
template <>
-struct Converter<jni::Array<jni::Object<Feature>>, std::vector<mbgl::Feature>> {
- Result<jni::Array<jni::Object<Feature>>> operator()(jni::JNIEnv& env, const std::vector<mbgl::Feature>& value) const {
-
+struct Converter<jni::Array<jni::Object<android::geojson::Feature>>, std::vector<mbgl::Feature>> {
+ Result<jni::Array<jni::Object<android::geojson::Feature>>> operator()(jni::JNIEnv& env, const std::vector<mbgl::Feature>& value) const {
+ using namespace mbgl::android::geojson;
auto features = jni::Array<jni::Object<Feature>>::New(env, value.size(), Feature::javaClass);
for(size_t i = 0; i < value.size(); i = i + 1) {
- auto converted = *convert<jni::Object<Feature>, mbgl::Feature>(env, value.at(i));
+ auto converted = *convert<jni::Object<android::geojson::Feature>, mbgl::Feature>(env, value.at(i));
features.Set(env, i, converted);
jni::DeleteLocalRef(env, converted);
}
diff --git a/platform/android/src/geometry/conversion/geometry.hpp b/platform/android/src/geojson/conversion/geometry.hpp
index 2ca63e2c11..2ca63e2c11 100644
--- a/platform/android/src/geometry/conversion/geometry.hpp
+++ b/platform/android/src/geojson/conversion/geometry.hpp
diff --git a/platform/android/src/geojson/feature.cpp b/platform/android/src/geojson/feature.cpp
new file mode 100644
index 0000000000..a6b387cd15
--- /dev/null
+++ b/platform/android/src/geojson/feature.cpp
@@ -0,0 +1,63 @@
+#include "feature.hpp"
+
+#include "geometry.hpp"
+
+namespace mbgl {
+namespace android {
+namespace geojson {
+
+mbgl::Feature Feature::convert(jni::JNIEnv& env, jni::Object<Feature> jFeature) {
+ // Convert
+ auto jGeometry = getGeometry(env, jFeature);
+ auto jProperties = Feature::getProperties(env, jFeature);
+
+ std::experimental::optional<mapbox::geometry::identifier> id;
+ auto jId = Feature::getId(env, jFeature);
+ if (jId) {
+ id = { jni::Make<std::string>(env, jId) };
+ }
+
+ auto feature = mbgl::Feature {
+ Geometry::convert(env, jGeometry),
+ gson::JsonObject::convert(env, jProperties),
+ id
+ };
+
+ // Cleanup
+ jni::DeleteLocalRef(env, jGeometry);
+ jni::DeleteLocalRef(env, jProperties);
+ jni::DeleteLocalRef(env, jId);
+
+ return feature;
+}
+
+jni::Object<Geometry> Feature::getGeometry(jni::JNIEnv& env, jni::Object<Feature> jFeature) {
+ static auto method = Feature::javaClass.GetMethod<jni::Object<Geometry> ()>(env, "getGeometry");
+ return jFeature.Call(env, method);
+}
+
+jni::Object<gson::JsonObject> Feature::getProperties(jni::JNIEnv& env, jni::Object<Feature> jFeature) {
+ static auto method = Feature::javaClass.GetMethod<jni::Object<gson::JsonObject> ()>(env, "getProperties");
+ return jFeature.Call(env, method);
+}
+
+jni::String Feature::getId(jni::JNIEnv& env, jni::Object<Feature> jFeature) {
+ static auto method = Feature::javaClass.GetMethod<jni::String ()>(env, "getId");
+ return jFeature.Call(env, method);
+}
+
+jni::Object<Feature> Feature::fromGeometry(jni::JNIEnv& env, jni::Object<Geometry> geometry, jni::Object<gson::JsonObject> properties, jni::String id) {
+ static auto method = Feature::javaClass.GetStaticMethod<jni::Object<Feature> (jni::Object<Geometry>, jni::Object<gson::JsonObject>, jni::String)>(env, "fromGeometry");
+ return Feature::javaClass.Call(env, method, geometry, properties, id);
+}
+
+void Feature::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ Feature::javaClass = *jni::Class<Feature>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<Feature> Feature::javaClass;
+
+} // namespace geojson
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geometry/feature.hpp b/platform/android/src/geojson/feature.hpp
index 7f2733430c..b5d856cc42 100644
--- a/platform/android/src/geometry/feature.hpp
+++ b/platform/android/src/geojson/feature.hpp
@@ -1,7 +1,8 @@
#pragma once
-#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/feature.hpp>
#include <mbgl/util/geometry.hpp>
+#include <mbgl/util/noncopyable.hpp>
#include <jni/jni.hpp>
@@ -10,13 +11,22 @@
namespace mbgl {
namespace android {
+namespace geojson {
class Feature : private mbgl::util::noncopyable {
public:
static constexpr auto Name() { return "com/mapbox/services/commons/geojson/Feature"; };
- static jni::Object<Feature> fromGeometry(jni::JNIEnv&, jni::Object<Geometry>, jni::Object<JsonObject>, jni::String);
+ static jni::Object<Feature> fromGeometry(jni::JNIEnv&, jni::Object<Geometry>, jni::Object<gson::JsonObject>, jni::String);
+
+ static mbgl::Feature convert(jni::JNIEnv&, jni::Object<Feature>);
+
+ static jni::Object<Geometry> getGeometry(jni::JNIEnv&, jni::Object<Feature>);
+
+ static jni::String getId(jni::JNIEnv&, jni::Object<Feature>);
+
+ static jni::Object<gson::JsonObject> getProperties(jni::JNIEnv&, jni::Object<Feature>);
static jni::Class<Feature> javaClass;
@@ -24,6 +34,6 @@ public:
};
-
+} // namespace geojson
} // namespace android
} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geojson/feature_collection.cpp b/platform/android/src/geojson/feature_collection.cpp
new file mode 100644
index 0000000000..2f156532ae
--- /dev/null
+++ b/platform/android/src/geojson/feature_collection.cpp
@@ -0,0 +1,40 @@
+#include "feature_collection.hpp"
+
+#include "feature.hpp"
+
+namespace mbgl {
+namespace android {
+namespace geojson {
+
+mbgl::FeatureCollection FeatureCollection::convert(jni::JNIEnv& env, jni::Object<FeatureCollection> jCollection) {
+ auto jFeatureList = FeatureCollection::getFeatures(env, jCollection);
+ auto jFeatures = java::util::List::toArray<Feature>(env, jFeatureList);
+ auto size = size_t(jFeatures.Length(env));
+
+ auto collection = mbgl::FeatureCollection();
+ collection.reserve(size);
+
+ for (size_t i = 0; i < size; i++) {
+ auto jFeature = jFeatures.Get(env, i);
+ collection.push_back(Feature::convert(env, jFeature));
+ jni::DeleteLocalRef(env, jFeature);
+ }
+
+ return collection;
+}
+
+jni::Object<java::util::List> FeatureCollection::getFeatures(jni::JNIEnv& env, jni::Object<FeatureCollection> jCollection) {
+ static auto method = FeatureCollection::javaClass.GetMethod<jni::Object<java::util::List> ()>(env, "getFeatures");
+ return jCollection.Call(env, method);
+}
+
+void FeatureCollection::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ javaClass = *jni::Class<FeatureCollection>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<FeatureCollection> FeatureCollection::javaClass;
+
+} // namespace geojson
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geojson/feature_collection.hpp b/platform/android/src/geojson/feature_collection.hpp
new file mode 100644
index 0000000000..8e9717e82b
--- /dev/null
+++ b/platform/android/src/geojson/feature_collection.hpp
@@ -0,0 +1,29 @@
+#pragma once
+
+#include "../java/util.hpp"
+
+#include <mbgl/util/geojson.hpp>
+#include <mbgl/util/noncopyable.hpp>
+
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+namespace geojson {
+
+class FeatureCollection : private mbgl::util::noncopyable {
+public:
+ static constexpr auto Name() { return "com/mapbox/services/commons/geojson/FeatureCollection"; };
+
+ static mbgl::FeatureCollection convert(jni::JNIEnv&, jni::Object<FeatureCollection>);
+
+ static jni::Object<java::util::List> getFeatures(jni::JNIEnv&, jni::Object<FeatureCollection>);
+
+ static jni::Class<FeatureCollection> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+};
+
+} // namespace geojson
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geojson/geometry.cpp b/platform/android/src/geojson/geometry.cpp
new file mode 100644
index 0000000000..33bb4ee3db
--- /dev/null
+++ b/platform/android/src/geojson/geometry.cpp
@@ -0,0 +1,52 @@
+#include "geometry.hpp"
+
+#include "point.hpp"
+#include "multi_point.hpp"
+#include "line_string.hpp"
+#include "multi_line_string.hpp"
+#include "polygon.hpp"
+#include "multi_polygon.hpp"
+
+#include <string>
+
+namespace mbgl {
+namespace android {
+namespace geojson {
+
+mapbox::geojson::geometry Geometry::convert(jni::JNIEnv &env, jni::Object<Geometry> jGeometry) {
+ auto type = Geometry::getType(env, jGeometry);
+ if (type == Point::Type()) {
+ return { Point::convert(env, jni::Object<Point>(jGeometry.Get())) };
+ } else if (type == MultiPoint::Type()) {
+ return { MultiPoint::convert(env, jni::Object<MultiPoint>(jGeometry.Get())) };
+ } else if (type == LineString::Type()) {
+ return { LineString::convert(env, jni::Object<LineString>(jGeometry.Get())) };
+ } else if (type == MultiLineString::Type()) {
+ return { MultiLineString::convert(env, jni::Object<MultiLineString>(jGeometry.Get())) };
+ } else if (type == Polygon::Type()) {
+ return { Polygon::convert(env, jni::Object<Polygon>(jGeometry.Get())) };
+ } else if (type == MultiPolygon::Type()) {
+ return { MultiPolygon::convert(env, jni::Object<MultiPolygon>(jGeometry.Get())) };
+ }
+
+ throw std::runtime_error(std::string {"Unsupported GeoJSON type: " } + type);
+}
+
+std::string Geometry::getType(jni::JNIEnv &env, jni::Object<Geometry> jGeometry) {
+ static auto method = Geometry::javaClass.GetMethod<jni::String ()>(env, "getType");
+ auto jType = jGeometry.Call(env, method);
+ auto type = jni::Make<std::string>(env, jType);
+ jni::DeleteLocalRef(env, jType);
+ return type;
+}
+
+void Geometry::registerNative(jni::JNIEnv &env) {
+ // Lookup the class
+ javaClass = *jni::Class<Geometry>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<Geometry> Geometry::javaClass;
+
+} // namespace geojson
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geojson/geometry.hpp b/platform/android/src/geojson/geometry.hpp
new file mode 100644
index 0000000000..bdcff6bb3e
--- /dev/null
+++ b/platform/android/src/geojson/geometry.hpp
@@ -0,0 +1,27 @@
+#pragma once
+
+#include <mbgl/util/geojson.hpp>
+#include <mbgl/util/noncopyable.hpp>
+
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+namespace geojson {
+
+class Geometry : private mbgl::util::noncopyable {
+public:
+ static constexpr auto Name() { return "com/mapbox/services/commons/geojson/Geometry"; };
+
+ static mapbox::geojson::geometry convert(jni::JNIEnv&, jni::Object<Geometry>);
+
+ static std::string getType(jni::JNIEnv&, jni::Object<Geometry>);
+
+ static jni::Class<Geometry> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+};
+
+} // namespace geojson
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geojson/line_string.cpp b/platform/android/src/geojson/line_string.cpp
new file mode 100644
index 0000000000..d0719f2538
--- /dev/null
+++ b/platform/android/src/geojson/line_string.cpp
@@ -0,0 +1,54 @@
+#include "line_string.hpp"
+
+#include "position.hpp"
+
+namespace mbgl {
+namespace android {
+namespace geojson {
+
+mapbox::geojson::line_string LineString::convert(jni::JNIEnv &env, jni::Object<LineString> jLineString) {
+ mapbox::geojson::line_string lineString;
+
+ if (jLineString) {
+ auto jPositionList = LineString::getCoordinates(env, jLineString);
+ lineString = LineString::convert(env, jPositionList);
+ jni::DeleteLocalRef(env, jPositionList);
+ }
+
+ return lineString;
+}
+
+mapbox::geojson::line_string LineString::convert(jni::JNIEnv &env, jni::Object<java::util::List/*<Position>*/> jPositionList) {
+ mapbox::geojson::line_string lineString;
+
+ if (jPositionList) {
+ auto jPositionArray = java::util::List::toArray<Position>(env, jPositionList);
+
+ auto size = jPositionArray.Length(env);
+ for (std::size_t i = 0; i < size; i++) {
+ auto jPosition = jPositionArray.Get(env, i);
+ lineString.push_back(Position::convert(env, jPosition));
+ jni::DeleteLocalRef(env, jPosition);
+ }
+
+ jni::DeleteLocalRef(env, jPositionArray);
+ }
+
+ return lineString;
+}
+
+jni::Object<java::util::List> LineString::getCoordinates(jni::JNIEnv &env, jni::Object<LineString> jLineString) {
+ static auto method = LineString::javaClass.GetMethod<jni::Object<java::util::List> ()>(env, "getCoordinates");
+ return jLineString.Call(env, method);
+}
+
+void LineString::registerNative(jni::JNIEnv &env) {
+ // Lookup the class
+ javaClass = *jni::Class<LineString>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<LineString> LineString::javaClass;
+
+} // namespace geojson
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geojson/line_string.hpp b/platform/android/src/geojson/line_string.hpp
new file mode 100644
index 0000000000..d3be68d0a5
--- /dev/null
+++ b/platform/android/src/geojson/line_string.hpp
@@ -0,0 +1,34 @@
+#pragma once
+
+#include <mbgl/util/geojson.hpp>
+#include <mbgl/util/noncopyable.hpp>
+
+#include <jni/jni.hpp>
+
+#include "../java/util.hpp"
+
+namespace mbgl {
+namespace android {
+namespace geojson {
+
+
+class LineString : private mbgl::util::noncopyable {
+public:
+ static constexpr auto Name() { return "com/mapbox/services/commons/geojson/LineString"; };
+
+ static constexpr auto Type() { return "LineString"; };
+
+ static mapbox::geojson::line_string convert(jni::JNIEnv&, jni::Object<LineString>);
+
+ static mapbox::geojson::line_string convert(jni::JNIEnv&, jni::Object<java::util::List/*<Position>*/>);
+
+ static jni::Object<java::util::List> getCoordinates(jni::JNIEnv&, jni::Object<LineString>);
+
+ static jni::Class<LineString> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+};
+
+} // namespace geojson
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geojson/multi_line_string.cpp b/platform/android/src/geojson/multi_line_string.cpp
new file mode 100644
index 0000000000..b676144bf5
--- /dev/null
+++ b/platform/android/src/geojson/multi_line_string.cpp
@@ -0,0 +1,56 @@
+#include "multi_line_string.hpp"
+
+#include "line_string.hpp"
+
+namespace mbgl {
+namespace android {
+namespace geojson {
+
+mapbox::geojson::multi_line_string MultiLineString::convert(jni::JNIEnv &env, jni::Object<MultiLineString> jMultiLineString) {
+ mapbox::geojson::multi_line_string multiLineString;
+
+ if (jMultiLineString) {
+ auto jPositionListsList = MultiLineString::getCoordinates(env, jMultiLineString);
+ multiLineString = MultiLineString::convert(env, jPositionListsList);
+ jni::DeleteLocalRef(env, jPositionListsList);
+ }
+
+ return multiLineString;
+}
+
+mapbox::geojson::multi_line_string MultiLineString::convert(jni::JNIEnv &env, jni::Object<java::util::List/*<java::util::List<Position>>*/> jPositionListsList) {
+ mapbox::geojson::multi_line_string multiLineString;
+
+ if (jPositionListsList) {
+ auto jPositionListsArray = java::util::List::toArray<java::util::List>(env, jPositionListsList);
+
+ auto size = jPositionListsArray.Length(env);
+ multiLineString.reserve(size);
+
+ for (std::size_t i = 0; i < size; i++) {
+ auto jPositionList = jPositionListsArray.Get(env, i);
+ multiLineString.push_back(LineString::convert(env, jPositionList));
+ jni::DeleteLocalRef(env, jPositionList);
+ }
+
+ jni::DeleteLocalRef(env, jPositionListsArray);
+ }
+
+ return multiLineString;
+}
+
+jni::Object<java::util::List> MultiLineString::getCoordinates(jni::JNIEnv &env, jni::Object<MultiLineString> jLineString) {
+ static auto method = MultiLineString::javaClass.GetMethod<jni::Object<java::util::List> ()>(env, "getCoordinates");
+ return jLineString.Call(env, method);
+}
+
+void MultiLineString::registerNative(jni::JNIEnv &env) {
+ // Lookup the class
+ javaClass = *jni::Class<MultiLineString>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<MultiLineString> MultiLineString::javaClass;
+
+} // namespace geojson
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geojson/multi_line_string.hpp b/platform/android/src/geojson/multi_line_string.hpp
new file mode 100644
index 0000000000..af33fe72d6
--- /dev/null
+++ b/platform/android/src/geojson/multi_line_string.hpp
@@ -0,0 +1,33 @@
+#pragma once
+
+#include <mbgl/util/geojson.hpp>
+#include <mbgl/util/noncopyable.hpp>
+
+#include <jni/jni.hpp>
+
+#include "../java/util.hpp"
+
+namespace mbgl {
+namespace android {
+namespace geojson {
+
+class MultiLineString : private mbgl::util::noncopyable {
+public:
+ static constexpr auto Name() { return "com/mapbox/services/commons/geojson/MultiLineString"; };
+
+ static constexpr auto Type() { return "MultiLineString"; };
+
+ static mapbox::geojson::multi_line_string convert(jni::JNIEnv&, jni::Object<MultiLineString>);
+
+ static mapbox::geojson::multi_line_string convert(jni::JNIEnv&, jni::Object<java::util::List/*<java::util::List<Position>>*/>);
+
+ static jni::Object<java::util::List> getCoordinates(jni::JNIEnv&, jni::Object<MultiLineString>);
+
+ static jni::Class<MultiLineString> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+};
+
+} // namespace geojson
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geojson/multi_point.cpp b/platform/android/src/geojson/multi_point.cpp
new file mode 100644
index 0000000000..f3acdb1ea6
--- /dev/null
+++ b/platform/android/src/geojson/multi_point.cpp
@@ -0,0 +1,37 @@
+#include "multi_point.hpp"
+
+#include "line_string.hpp"
+
+#include "util.hpp"
+
+namespace mbgl {
+namespace android {
+namespace geojson {
+
+mapbox::geojson::multi_point MultiPoint::convert(jni::JNIEnv &env, jni::Object<MultiPoint> jMultiPoint) {
+ mapbox::geojson::multi_point multiPoint;
+
+ if (jMultiPoint) {
+ auto jPositionListsList = MultiPoint::getCoordinates(env, jMultiPoint);
+ multiPoint = convertExplicit<mapbox::geojson::multi_point>(LineString::convert(env, jPositionListsList));
+ jni::DeleteLocalRef(env, jPositionListsList);
+ }
+
+ return multiPoint;
+}
+
+jni::Object<java::util::List> MultiPoint::getCoordinates(jni::JNIEnv &env, jni::Object<MultiPoint> jMultiPoint) {
+ static auto method = MultiPoint::javaClass.GetMethod<jni::Object<java::util::List> ()>(env, "getCoordinates");
+ return jMultiPoint.Call(env, method);
+}
+
+void MultiPoint::registerNative(jni::JNIEnv &env) {
+ // Lookup the class
+ javaClass = *jni::Class<MultiPoint>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<MultiPoint> MultiPoint::javaClass;
+
+} // namespace geojson
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geojson/multi_point.hpp b/platform/android/src/geojson/multi_point.hpp
new file mode 100644
index 0000000000..7a698287eb
--- /dev/null
+++ b/platform/android/src/geojson/multi_point.hpp
@@ -0,0 +1,31 @@
+#pragma once
+
+#include <mbgl/util/geojson.hpp>
+#include <mbgl/util/noncopyable.hpp>
+
+#include <jni/jni.hpp>
+
+#include "../java/util.hpp"
+
+namespace mbgl {
+namespace android {
+namespace geojson {
+
+class MultiPoint : private mbgl::util::noncopyable {
+public:
+ static constexpr auto Name() { return "com/mapbox/services/commons/geojson/MultiPoint"; };
+
+ static constexpr auto Type() { return "MultiPoint"; };
+
+ static mapbox::geojson::multi_point convert(jni::JNIEnv&, jni::Object<MultiPoint>);
+
+ static jni::Object<java::util::List> getCoordinates(jni::JNIEnv&, jni::Object<MultiPoint>);
+
+ static jni::Class<MultiPoint> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+};
+
+} // namespace geojson
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geojson/multi_polygon.cpp b/platform/android/src/geojson/multi_polygon.cpp
new file mode 100644
index 0000000000..a55884a110
--- /dev/null
+++ b/platform/android/src/geojson/multi_polygon.cpp
@@ -0,0 +1,46 @@
+#include "multi_polygon.hpp"
+
+#include "polygon.hpp"
+
+namespace mbgl {
+namespace android {
+namespace geojson {
+
+mapbox::geojson::multi_polygon MultiPolygon::convert(jni::JNIEnv &env, jni::Object<MultiPolygon> jMultiPolygon) {
+ mapbox::geojson::multi_polygon multiPolygon;
+
+ if (jMultiPolygon) {
+ auto jPositionListsListList = MultiPolygon::getCoordinates(env, jMultiPolygon);
+ auto jPositionListsListArray = java::util::List::toArray<java::util::List>(env, jPositionListsListList);
+
+ auto size = jPositionListsListArray.Length(env);
+ multiPolygon.reserve(size);
+
+ for (size_t i = 0; i < size; i++) {
+ auto jPositionListsList = jPositionListsListArray.Get(env, i);
+ multiPolygon.push_back(Polygon::convert(env, jPositionListsList));
+ jni::DeleteLocalRef(env, jPositionListsList);
+ }
+
+ jni::DeleteLocalRef(env, jPositionListsListList);
+ jni::DeleteLocalRef(env, jPositionListsListArray);
+ }
+
+ return multiPolygon;
+}
+
+jni::Object<java::util::List> MultiPolygon::getCoordinates(jni::JNIEnv &env, jni::Object<MultiPolygon> jPolygon) {
+ static auto method = MultiPolygon::javaClass.GetMethod<jni::Object<java::util::List> ()>(env, "getCoordinates");
+ return jPolygon.Call(env, method);
+}
+
+void MultiPolygon::registerNative(jni::JNIEnv &env) {
+ // Lookup the class
+ javaClass = *jni::Class<MultiPolygon>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<MultiPolygon> MultiPolygon::javaClass;
+
+} // namespace geojson
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geojson/multi_polygon.hpp b/platform/android/src/geojson/multi_polygon.hpp
new file mode 100644
index 0000000000..1f144cffd2
--- /dev/null
+++ b/platform/android/src/geojson/multi_polygon.hpp
@@ -0,0 +1,31 @@
+#pragma once
+
+#include <mbgl/util/geojson.hpp>
+#include <mbgl/util/noncopyable.hpp>
+
+#include <jni/jni.hpp>
+
+#include "../java/util.hpp"
+
+namespace mbgl {
+namespace android {
+namespace geojson {
+
+class MultiPolygon : private mbgl::util::noncopyable {
+public:
+ static constexpr auto Name() { return "com/mapbox/services/commons/geojson/MultiPolygon"; };
+
+ static constexpr auto Type() { return "MultiPolygon"; };
+
+ static mapbox::geojson::multi_polygon convert(jni::JNIEnv&, jni::Object<MultiPolygon>);
+
+ static jni::Object<java::util::List> getCoordinates(jni::JNIEnv&, jni::Object<MultiPolygon>);
+
+ static jni::Class<MultiPolygon> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+};
+
+} // namespace geojson
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geojson/point.cpp b/platform/android/src/geojson/point.cpp
new file mode 100644
index 0000000000..3d19a119d7
--- /dev/null
+++ b/platform/android/src/geojson/point.cpp
@@ -0,0 +1,28 @@
+#include "point.hpp"
+
+namespace mbgl {
+namespace android {
+namespace geojson {
+
+mapbox::geojson::point Point::convert(jni::JNIEnv &env, jni::Object<Point> jPoint) {
+ auto jPosition = Point::getPosition(env, jPoint);
+ auto point = Position::convert(env, jPosition);
+ jni::DeleteLocalRef(env, jPosition);
+ return point;
+}
+
+jni::Object<Position> Point::getPosition(JNIEnv& env, jni::Object<Point> jPoint) {
+ static auto method = Point::javaClass.GetMethod<jni::Object<Position> ()>(env, "getCoordinates");
+ return jPoint.Call(env, method);
+}
+
+void Point::registerNative(jni::JNIEnv &env) {
+ // Lookup the class
+ javaClass = *jni::Class<Point>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<Point> Point::javaClass;
+
+} // namespace geojson
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geojson/point.hpp b/platform/android/src/geojson/point.hpp
new file mode 100644
index 0000000000..64ac0af9cc
--- /dev/null
+++ b/platform/android/src/geojson/point.hpp
@@ -0,0 +1,31 @@
+#pragma once
+
+#include <mbgl/util/geojson.hpp>
+#include <mbgl/util/noncopyable.hpp>
+
+#include "position.hpp"
+
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+namespace geojson {
+
+class Point : private mbgl::util::noncopyable {
+public:
+ static constexpr auto Name() { return "com/mapbox/services/commons/geojson/Point"; };
+
+ static constexpr auto Type() { return "Point"; };
+
+ static mapbox::geojson::point convert(jni::JNIEnv&, jni::Object<Point>);
+
+ static jni::Object<Position> getPosition(JNIEnv&, jni::Object<Point>);
+
+ static jni::Class<Point> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+};
+
+} // namespace geojson
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geojson/polygon.cpp b/platform/android/src/geojson/polygon.cpp
new file mode 100644
index 0000000000..ef00f9df3f
--- /dev/null
+++ b/platform/android/src/geojson/polygon.cpp
@@ -0,0 +1,52 @@
+#include "polygon.hpp"
+
+#include "multi_line_string.hpp"
+
+#include "util.hpp"
+
+namespace mbgl {
+namespace android {
+namespace geojson {
+
+mapbox::geojson::polygon Polygon::convert(jni::JNIEnv &env, jni::Object<Polygon> jPolygon) {
+ mapbox::geojson::polygon polygon;
+
+ if (jPolygon) {
+ auto jPositionListsList = Polygon::getCoordinates(env, jPolygon);
+ polygon = Polygon::convert(env, jPositionListsList);
+ jni::DeleteLocalRef(env, jPositionListsList);
+ }
+
+ return polygon;
+}
+
+mapbox::geojson::polygon Polygon::convert(jni::JNIEnv &env, jni::Object<java::util::List/*<java::util::List<Position>>*/> jPositionListsList) {
+ mapbox::geojson::polygon polygon;
+
+ if (jPositionListsList) {
+ auto multiLine = MultiLineString::convert(env, jPositionListsList);
+ polygon.reserve(multiLine.size());
+ for (auto&& line : multiLine) {
+ polygon.emplace_back(convertExplicit<mapbox::geojson::linear_ring>(std::move(line)));
+ }
+ }
+
+ return polygon;
+}
+
+
+jni::Object<java::util::List> Polygon::getCoordinates(jni::JNIEnv &env, jni::Object<Polygon> jPolygon) {
+ static auto method = Polygon::javaClass.GetMethod<jni::Object<java::util::List> ()>(env, "getCoordinates");
+ return jPolygon.Call(env, method);
+}
+
+void Polygon::registerNative(jni::JNIEnv &env) {
+ // Lookup the class
+ javaClass = *jni::Class<Polygon>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<Polygon> Polygon::javaClass;
+
+} // namespace geojson
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geojson/polygon.hpp b/platform/android/src/geojson/polygon.hpp
new file mode 100644
index 0000000000..e5362cedf1
--- /dev/null
+++ b/platform/android/src/geojson/polygon.hpp
@@ -0,0 +1,33 @@
+#pragma once
+
+#include <mbgl/util/geojson.hpp>
+#include <mbgl/util/noncopyable.hpp>
+
+#include <jni/jni.hpp>
+
+#include "../java/util.hpp"
+
+namespace mbgl {
+namespace android {
+namespace geojson {
+
+class Polygon : private mbgl::util::noncopyable {
+public:
+ static constexpr auto Name() { return "com/mapbox/services/commons/geojson/Polygon"; };
+
+ static constexpr auto Type() { return "Polygon"; };
+
+ static mapbox::geojson::polygon convert(jni::JNIEnv &, jni::Object<Polygon>);
+
+ static mapbox::geojson::polygon convert(jni::JNIEnv&, jni::Object<java::util::List/*<java::util::List<Position>>*/>);
+
+ static jni::Object<java::util::List> getCoordinates(jni::JNIEnv&, jni::Object<Polygon>);
+
+ static jni::Class<Polygon> javaClass;
+
+ static void registerNative(jni::JNIEnv &);
+};
+
+} // namespace geojson
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geojson/position.cpp b/platform/android/src/geojson/position.cpp
new file mode 100644
index 0000000000..c0e6da3887
--- /dev/null
+++ b/platform/android/src/geojson/position.cpp
@@ -0,0 +1,27 @@
+#include "position.hpp"
+
+namespace mbgl {
+namespace android {
+namespace geojson {
+
+mapbox::geojson::point Position::convert(jni::JNIEnv &env, jni::Object<Position> jPosition) {
+ static auto method = Position::javaClass.GetMethod<jni::Array<jdouble> ()>(env, "getCoordinates");
+ // Array with 0: longitude, 1: latitude (and optionally 2: altitude)
+ auto coordinates = jPosition.Call(env, method);
+ jdouble lngLat[2];
+ coordinates.GetRegion(env, 0, lngLat);
+ mapbox::geojson::point point(lngLat[0], lngLat[1]);
+ jni::DeleteLocalRef(env, coordinates);
+ return point;
+}
+
+void Position::registerNative(jni::JNIEnv &env) {
+ // Lookup the class
+ javaClass = *jni::Class<Position>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<Position> Position::javaClass;
+
+} // namespace geojson
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geojson/position.hpp b/platform/android/src/geojson/position.hpp
new file mode 100644
index 0000000000..7017a8172a
--- /dev/null
+++ b/platform/android/src/geojson/position.hpp
@@ -0,0 +1,27 @@
+#pragma once
+
+#include <mbgl/util/geojson.hpp>
+#include <mbgl/util/noncopyable.hpp>
+
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+namespace geojson {
+
+class Position : private mbgl::util::noncopyable {
+public:
+ static constexpr auto Name() { return "com/mapbox/services/commons/models/Position"; };
+
+ static constexpr auto Type() { return "Position"; };
+
+ static mapbox::geojson::point convert(jni::JNIEnv&, jni::Object<Position>);
+
+ static jni::Class<Position> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+};
+
+} // namespace geojson
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geojson/util.hpp b/platform/android/src/geojson/util.hpp
new file mode 100644
index 0000000000..ece8e52433
--- /dev/null
+++ b/platform/android/src/geojson/util.hpp
@@ -0,0 +1,22 @@
+#pragma once
+
+#include <type_traits>
+
+namespace mbgl {
+namespace android {
+namespace geojson {
+
+// Clang 3.8 fails to implicitly convert matching types, so we'll have to do it explicitly.
+template <typename To, typename From>
+To convertExplicit(From&& src) {
+ static_assert(std::is_same<typename std::decay_t<From>::container_type,
+ typename To::container_type>::value,
+ "container types do not match");
+ static_assert(std::is_rvalue_reference<From&&>::value,
+ "argument must be rvalue reference");
+ return *reinterpret_cast<std::add_pointer_t<To>>(&src);
+}
+
+} // namespace geojson
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/geometry/feature.cpp b/platform/android/src/geometry/feature.cpp
deleted file mode 100644
index 5355d50ab7..0000000000
--- a/platform/android/src/geometry/feature.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-#include "feature.hpp"
-
-namespace mbgl {
-namespace android {
-
-jni::Object<Feature> Feature::fromGeometry(jni::JNIEnv& env, jni::Object<Geometry> geometry, jni::Object<JsonObject> properties, jni::String id) {
- static auto method = Feature::javaClass.GetStaticMethod<jni::Object<Feature> (jni::Object<Geometry>, jni::Object<JsonObject>, jni::String)>(env, "fromGeometry");
- return Feature::javaClass.Call(env, method, geometry, properties, id);
-}
-
-void Feature::registerNative(jni::JNIEnv& env) {
- // Lookup the class
- Feature::javaClass = *jni::Class<Feature>::Find(env).NewGlobalRef(env).release();
-}
-
-jni::Class<Feature> Feature::javaClass;
-
-
-} // namespace android
-} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geometry/geometry.hpp b/platform/android/src/geometry/geometry.hpp
deleted file mode 100644
index 5c8ae39181..0000000000
--- a/platform/android/src/geometry/geometry.hpp
+++ /dev/null
@@ -1,16 +0,0 @@
-#pragma once
-
-#include <mbgl/util/noncopyable.hpp>
-
-namespace mbgl {
-namespace android {
-
-class Geometry : private mbgl::util::noncopyable {
-public:
- static constexpr auto Name() { return "com/mapbox/services/commons/geojson/Geometry"; };
-
-};
-
-
-} // namespace android
-} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geometry/lat_lng.cpp b/platform/android/src/geometry/lat_lng.cpp
index 9cf3630107..0bf6ea7add 100644
--- a/platform/android/src/geometry/lat_lng.cpp
+++ b/platform/android/src/geometry/lat_lng.cpp
@@ -3,9 +3,9 @@
namespace mbgl {
namespace android {
-jni::Object<LatLng> LatLng::New(jni::JNIEnv& env, double latitude, double longitude) {
+jni::Object<LatLng> LatLng::New(jni::JNIEnv& env, const mbgl::LatLng& latLng) {
static auto constructor = LatLng::javaClass.GetConstructor<double, double>(env);
- return LatLng::javaClass.New(env, constructor, latitude, longitude);
+ return LatLng::javaClass.New(env, constructor, latLng.latitude(), latLng.longitude());
}
mbgl::Point<double> LatLng::getGeometry(jni::JNIEnv& env, jni::Object<LatLng> latLng) {
diff --git a/platform/android/src/geometry/lat_lng.hpp b/platform/android/src/geometry/lat_lng.hpp
index 1ac32ae32e..b2f12c8dcd 100644
--- a/platform/android/src/geometry/lat_lng.hpp
+++ b/platform/android/src/geometry/lat_lng.hpp
@@ -14,7 +14,7 @@ public:
static constexpr auto Name() { return "com/mapbox/mapboxsdk/geometry/LatLng"; };
- static jni::Object<LatLng> New(jni::JNIEnv&, double, double);
+ static jni::Object<LatLng> New(jni::JNIEnv&, const mbgl::LatLng&);
static mbgl::Point<double> getGeometry(jni::JNIEnv&, jni::Object<LatLng>);
diff --git a/platform/android/src/gson/json_array.cpp b/platform/android/src/gson/json_array.cpp
new file mode 100644
index 0000000000..d91e323ac9
--- /dev/null
+++ b/platform/android/src/gson/json_array.cpp
@@ -0,0 +1,40 @@
+#include "json_array.hpp"
+
+#include "json_element.hpp"
+
+namespace mbgl {
+namespace android {
+namespace gson {
+
+std::vector<mapbox::geometry::value> JsonArray::convert(jni::JNIEnv &env, jni::Object<JsonArray> jsonArray) {
+ std::vector<mapbox::geometry::value> values;
+
+ if (jsonArray) {
+ static auto getMethod = JsonArray::javaClass.GetMethod<jni::Object<JsonElement> (jni::jint)>(env, "get");
+ static auto sizeMethod = JsonArray::javaClass.GetMethod<jni::jint ()>(env, "size");
+
+ int size = jsonArray.Call(env, sizeMethod);
+ values.reserve(uint(size));
+
+ for (int i = 0; i < size; i++) {
+ auto entry = jsonArray.Call(env, getMethod, i);
+ if (entry) {
+ values.push_back(JsonElement::convert(env, entry));
+ }
+ jni::DeleteLocalRef(env, entry);
+ }
+ }
+
+ return values;
+}
+
+void JsonArray::registerNative(jni::JNIEnv &env) {
+ // Lookup the class
+ javaClass = *jni::Class<JsonArray>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<JsonArray> JsonArray::javaClass;
+
+} // namespace gson
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/gson/json_array.hpp b/platform/android/src/gson/json_array.hpp
new file mode 100644
index 0000000000..8571ad5dba
--- /dev/null
+++ b/platform/android/src/gson/json_array.hpp
@@ -0,0 +1,25 @@
+#pragma once
+
+#include <mapbox/geometry.hpp>
+#include <mbgl/util/noncopyable.hpp>
+
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+namespace gson {
+
+class JsonArray : private mbgl::util::noncopyable {
+public:
+ static constexpr auto Name() { return "com/google/gson/JsonArray"; };
+
+ static std::vector<mapbox::geometry::value> convert(JNIEnv&, jni::Object<JsonArray>);
+
+ static jni::Class<JsonArray> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+};
+
+} // namespace gson
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/gson/json_element.cpp b/platform/android/src/gson/json_element.cpp
new file mode 100644
index 0000000000..060b1e0fe2
--- /dev/null
+++ b/platform/android/src/gson/json_element.cpp
@@ -0,0 +1,62 @@
+#include "json_element.hpp"
+
+#include "json_array.hpp"
+#include "json_object.hpp"
+#include "json_primitive.hpp"
+
+#include <mapbox/geometry/feature.hpp>
+#include <mapbox/variant.hpp>
+
+namespace mbgl {
+namespace android {
+namespace gson {
+
+mapbox::geometry::value JsonElement::convert(jni::JNIEnv &env, jni::Object<JsonElement> jsonElement) {
+ mapbox::geometry::value value;
+
+ if (jsonElement) {
+ if (isJsonPrimitive(env, jsonElement)) {
+ auto primitive = JsonPrimitive::convert(env, jni::Cast(env, jsonElement, JsonPrimitive::javaClass));
+ value = mapbox::util::apply_visitor([](auto t) { return mapbox::geometry::value { t }; }, primitive);
+ } else if (isJsonObject(env, jsonElement)) {
+ mapbox::geometry::property_map map = JsonObject::convert(env, jni::Cast(env, jsonElement, JsonObject::javaClass));
+ value = mapbox::util::recursive_wrapper<std::unordered_map<std::string, mapbox::geometry::value>> { map } ;
+ } else if (isJsonArray(env, jsonElement)) {
+ value = JsonArray::convert(env, jni::Cast(env, jsonElement, JsonArray::javaClass));
+ } else {
+ value = mapbox::geometry::null_value;
+ }
+ }
+ return value;
+}
+
+bool JsonElement::isJsonObject(JNIEnv& env, jni::Object<JsonElement> jsonElement) {
+ static auto method = JsonElement::javaClass.GetMethod<jni::jboolean ()>(env, "isJsonObject");
+ return jsonElement.Call(env, method);
+}
+
+bool JsonElement::isJsonArray(JNIEnv& env, jni::Object<JsonElement> jsonElement) {
+ static auto method = JsonElement::javaClass.GetMethod<jni::jboolean ()>(env, "isJsonArray");
+ return jsonElement.Call(env, method);
+}
+
+bool JsonElement::isJsonPrimitive(JNIEnv& env, jni::Object<JsonElement> jsonElement) {
+ static auto method = JsonElement::javaClass.GetMethod<jni::jboolean ()>(env, "isJsonPrimitive");
+ return jsonElement.Call(env, method);
+}
+
+bool JsonElement::isJsonNull(JNIEnv& env, jni::Object<JsonElement> jsonElement) {
+ static auto method = JsonElement::javaClass.GetMethod<jni::jboolean ()>(env, "isJsonNull");
+ return jsonElement.Call(env, method);
+}
+
+void JsonElement::registerNative(jni::JNIEnv &env) {
+ // Lookup the class
+ javaClass = *jni::Class<JsonElement>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<JsonElement> JsonElement::javaClass;
+
+} // namespace gson
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/gson/json_element.hpp b/platform/android/src/gson/json_element.hpp
new file mode 100644
index 0000000000..7619350617
--- /dev/null
+++ b/platform/android/src/gson/json_element.hpp
@@ -0,0 +1,33 @@
+#pragma once
+
+#include <mapbox/geometry.hpp>
+#include <mbgl/util/noncopyable.hpp>
+
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+namespace gson {
+
+class JsonElement : private mbgl::util::noncopyable {
+public:
+ static constexpr auto Name() { return "com/google/gson/JsonElement"; };
+
+ static mapbox::geometry::value convert(JNIEnv&, jni::Object<JsonElement>);
+
+ static bool isJsonObject(JNIEnv&, jni::Object<JsonElement>);
+
+ static bool isJsonArray(JNIEnv&, jni::Object<JsonElement>);
+
+ static bool isJsonPrimitive(JNIEnv&, jni::Object<JsonElement>);
+
+ static bool isJsonNull(JNIEnv&, jni::Object<JsonElement>);
+
+ static jni::Class<JsonElement> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+};
+
+} // namespace gson
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/gson/json_object.cpp b/platform/android/src/gson/json_object.cpp
new file mode 100644
index 0000000000..a704dae9dd
--- /dev/null
+++ b/platform/android/src/gson/json_object.cpp
@@ -0,0 +1,64 @@
+#include "json_object.hpp"
+
+#include "json_element.hpp"
+
+#include "../java/util.hpp"
+
+namespace mbgl {
+namespace android {
+namespace gson {
+
+
+template <typename F> // void (jni::String, jni::Object<gson::JsonElement>)
+static void iterateEntrySet(jni::JNIEnv& env, jni::Object<JsonObject> jsonObject, F callback) {
+ // Get Set<Map.Entry<String, JsonElement>>
+ static auto method = JsonObject::javaClass.GetMethod<jni::Object<java::util::Set> ()>(env, "entrySet");
+ auto entrySet = jsonObject.Call(env, method);
+ jni::Array<jni::Object<java::util::Map::Entry>> entryArray = java::util::Set::toArray<java::util::Map::Entry>(env, entrySet);
+
+ size_t size = entryArray.Length(env);
+ for (size_t i = 0; i < size; i++) {
+ auto entry = entryArray.Get(env, i);
+ if (entry) {
+ // Convert
+ auto jKey = java::util::Map::Entry::getKey<jni::ObjectTag>(env, entry);
+ auto jKeyString = jni::String(reinterpret_cast<jni::jstring*>(jKey.Get()));
+ auto jValue = java::util::Map::Entry::getValue<gson::JsonElement>(env, entry);
+
+ // Callback
+ callback(jKeyString, jValue);
+
+ // Cleanup
+ // Skip jKey as it points to the same as jKeyString
+ jni::DeleteLocalRef(env, jKeyString);
+ jni::DeleteLocalRef(env, jValue);
+ }
+ jni::DeleteLocalRef(env, entry);
+ }
+
+ jni::DeleteLocalRef(env, entrySet);
+ jni::DeleteLocalRef(env, entryArray);
+}
+
+mapbox::geometry::property_map JsonObject::convert(jni::JNIEnv &env, jni::Object<JsonObject> jsonObject) {
+ mapbox::geometry::property_map map;
+
+ if (jsonObject) {
+ iterateEntrySet(env, jsonObject, [&map, &env](jni::String jId, jni::Object<gson::JsonElement> jsonElement) {
+ map[jni::Make<std::string>(env, jId)] = JsonElement::convert(env, jsonElement);
+ });
+ }
+
+ return map;
+}
+
+void JsonObject::registerNative(jni::JNIEnv &env) {
+ // Lookup the class
+ javaClass = *jni::Class<JsonObject>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<JsonObject> JsonObject::javaClass;
+
+} // namespace gson
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/gson/json_object.hpp b/platform/android/src/gson/json_object.hpp
index a7de0b1978..aba8e40415 100644
--- a/platform/android/src/gson/json_object.hpp
+++ b/platform/android/src/gson/json_object.hpp
@@ -1,16 +1,25 @@
#pragma once
+#include <mapbox/geometry.hpp>
#include <mbgl/util/noncopyable.hpp>
+#include <jni/jni.hpp>
+
namespace mbgl {
namespace android {
+namespace gson {
class JsonObject : private mbgl::util::noncopyable {
public:
static constexpr auto Name() { return "com/google/gson/JsonObject"; };
-};
+ static mapbox::geometry::property_map convert(JNIEnv&, jni::Object<JsonObject>);
+ static jni::Class<JsonObject> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+};
+} // namespace gson
} // namespace android
} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/gson/json_primitive.cpp b/platform/android/src/gson/json_primitive.cpp
new file mode 100644
index 0000000000..58d0b45fe7
--- /dev/null
+++ b/platform/android/src/gson/json_primitive.cpp
@@ -0,0 +1,66 @@
+#include "json_primitive.hpp"
+
+namespace mbgl {
+namespace android {
+namespace gson {
+
+JsonPrimitive::value JsonPrimitive::convert(jni::JNIEnv &env, jni::Object<JsonPrimitive> jsonPrimitive) {
+ value value;
+ if (jsonPrimitive) {
+ if (isBoolean(env, jsonPrimitive)) {
+ value = getAsBoolean(env, jsonPrimitive);
+ } else if (isNumber(env, jsonPrimitive)) {
+ //TODO: how to differentiate types here?
+ value = getAsDouble(env, jsonPrimitive);
+ } else if (isString(env, jsonPrimitive)) {
+ value = getAsString(env, jsonPrimitive);
+ } else {
+ value = mapbox::geometry::null_value;
+ }
+ }
+ return value;
+}
+
+bool JsonPrimitive::isBoolean(JNIEnv& env, jni::Object<JsonPrimitive> jsonPrimitive) {
+ static auto method = JsonPrimitive::javaClass.GetMethod<jni::jboolean ()>(env, "isBoolean");
+ return jsonPrimitive.Call(env, method);
+}
+
+bool JsonPrimitive::isString(JNIEnv& env, jni::Object<JsonPrimitive> jsonPrimitive) {
+ static auto method = JsonPrimitive::javaClass.GetMethod<jni::jboolean ()>(env, "isString");
+ return jsonPrimitive.Call(env, method);
+}
+
+bool JsonPrimitive::isNumber(JNIEnv& env, jni::Object<JsonPrimitive> jsonPrimitive) {
+ static auto method = JsonPrimitive::javaClass.GetMethod<jni::jboolean ()>(env, "isNumber");
+ return jsonPrimitive.Call(env, method);
+}
+
+bool JsonPrimitive::getAsBoolean(JNIEnv& env, jni::Object<JsonPrimitive> jsonPrimitive) {
+ static auto method = JsonPrimitive::javaClass.GetMethod<jni::jboolean ()>(env, "getAsBoolean");
+ return jsonPrimitive.Call(env, method);
+}
+
+std::string JsonPrimitive::getAsString(JNIEnv& env, jni::Object<JsonPrimitive> jsonPrimitive) {
+ static auto method = JsonPrimitive::javaClass.GetMethod<jni::String ()>(env, "getAsString");
+ auto jString = jsonPrimitive.Call(env, method);
+ auto string = jni::Make<std::string>(env, jString);
+ jni::DeleteLocalRef(env, jString);
+ return string;
+}
+
+double JsonPrimitive::getAsDouble(JNIEnv& env, jni::Object<JsonPrimitive> jsonPrimitive) {
+ static auto method = JsonPrimitive::javaClass.GetMethod<jni::jdouble ()>(env, "getAsDouble");
+ return jsonPrimitive.Call(env, method);
+}
+
+void JsonPrimitive::registerNative(jni::JNIEnv &env) {
+ // Lookup the class
+ javaClass = *jni::Class<JsonPrimitive>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<JsonPrimitive> JsonPrimitive::javaClass;
+
+} // namespace gson
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/gson/json_primitive.hpp b/platform/android/src/gson/json_primitive.hpp
new file mode 100644
index 0000000000..5fc8a2b485
--- /dev/null
+++ b/platform/android/src/gson/json_primitive.hpp
@@ -0,0 +1,39 @@
+#pragma once
+
+#include <mapbox/geometry.hpp>
+#include <mbgl/util/noncopyable.hpp>
+
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+namespace gson {
+
+class JsonPrimitive : private mbgl::util::noncopyable {
+public:
+ using value = mapbox::util::variant<mapbox::geometry::null_value_t, bool, uint64_t, int64_t, double, std::string>;
+
+ static constexpr auto Name() { return "com/google/gson/JsonPrimitive"; };
+
+ static value convert(JNIEnv&, jni::Object<JsonPrimitive>);
+
+ static bool isBoolean(JNIEnv&, jni::Object<JsonPrimitive>);
+
+ static bool isString(JNIEnv&, jni::Object<JsonPrimitive>);
+
+ static bool isNumber(JNIEnv&, jni::Object<JsonPrimitive>);
+
+ static bool getAsBoolean(JNIEnv&, jni::Object<JsonPrimitive>);
+
+ static std::string getAsString(JNIEnv&, jni::Object<JsonPrimitive>);
+
+ static double getAsDouble(JNIEnv&, jni::Object<JsonPrimitive>);
+
+ static jni::Class<JsonPrimitive> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+};
+
+} // namespace gson
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/java/util.cpp b/platform/android/src/java/util.cpp
index c630e403d9..effd2ae0d0 100644
--- a/platform/android/src/java/util.cpp
+++ b/platform/android/src/java/util.cpp
@@ -6,9 +6,15 @@ namespace java {
namespace util {
jni::Class<List> List::javaClass;
+jni::Class<Set> Set::javaClass;
+jni::Class<Map> Map::javaClass;
+jni::Class<Map::Entry> Map::Entry::javaClass;
void registerNative(jni::JNIEnv& env) {
List::javaClass = *jni::Class<List>::Find(env).NewGlobalRef(env).release();
+ Set::javaClass = *jni::Class<Set>::Find(env).NewGlobalRef(env).release();
+ Map::javaClass = *jni::Class<Map>::Find(env).NewGlobalRef(env).release();
+ Map::Entry::javaClass = *jni::Class<Map::Entry>::Find(env).NewGlobalRef(env).release();
}
diff --git a/platform/android/src/java/util.hpp b/platform/android/src/java/util.hpp
index 1a552c7124..dedb8ac348 100644
--- a/platform/android/src/java/util.hpp
+++ b/platform/android/src/java/util.hpp
@@ -24,6 +24,48 @@ public:
};
+class Set : private mbgl::util::noncopyable {
+public:
+
+ static constexpr auto Name() { return "java/util/Set"; };
+
+ template<class T>
+ static jni::Array<jni::Object<T>> toArray(jni::JNIEnv& env, jni::Object<Set> list) {
+ static auto toArray = Set::javaClass.GetMethod<jni::Array<jni::Object<>> ()>(env, "toArray");
+ return (jni::Array<jni::Object<T>>) list.Call(env, toArray);
+ };
+
+ static jni::Class<Set> javaClass;
+
+};
+
+class Map : private mbgl::util::noncopyable {
+public:
+
+ class Entry : private mbgl::util::noncopyable {
+ public:
+ static constexpr auto Name() { return "java/util/Map$Entry"; };
+
+ template <class T>
+ static jni::Object<T> getKey(jni::JNIEnv& env, jni::Object<Entry> entry) {
+ static auto method = Entry::javaClass.GetMethod<jni::Object<> ()>(env, "getKey");
+ return (jni::Object<T>) entry.Call(env, method);
+ }
+
+ template <class T>
+ static jni::Object<T> getValue(jni::JNIEnv& env, jni::Object<Entry> entry) {
+ static auto method = Entry::javaClass.GetMethod<jni::Object<> ()>(env, "getValue");
+ return (jni::Object<T>) entry.Call(env, method).Get();
+ }
+
+ static jni::Class<Entry> javaClass;
+ };
+
+ static constexpr auto Name() { return "java/util/Map"; };
+
+ static jni::Class<Map> javaClass;
+};
+
void registerNative(jni::JNIEnv&);
diff --git a/platform/android/src/java_types.cpp b/platform/android/src/java_types.cpp
index 6383426387..dd165470cf 100644
--- a/platform/android/src/java_types.cpp
+++ b/platform/android/src/java_types.cpp
@@ -13,6 +13,8 @@ namespace java {
jni::jclass* Number::jclass;
jni::jmethodID* Number::floatValueMethodId;
+ jni::jmethodID* Number::doubleValueMethodId;
+ jni::jmethodID* Number::longValueMethodId;
jni::jclass* Map::jclass;
jni::jmethodID* Map::getMethodId;
@@ -27,6 +29,8 @@ namespace java {
Number::jclass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/Number")).release();
Number::floatValueMethodId = &jni::GetMethodID(env, *Number::jclass, "floatValue", "()F");
+ Number::doubleValueMethodId = &jni::GetMethodID(env, *Number::jclass, "doubleValue", "()D");
+ Number::longValueMethodId = &jni::GetMethodID(env, *Number::jclass, "longValue", "()J");
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
index b416a75b91..edec5cb550 100644
--- a/platform/android/src/java_types.hpp
+++ b/platform/android/src/java_types.hpp
@@ -22,6 +22,8 @@ namespace java {
struct Number {
static jni::jclass* jclass;
static jni::jmethodID* floatValueMethodId;
+ static jni::jmethodID* doubleValueMethodId;
+ static jni::jmethodID* longValueMethodId;
};
struct Map {
diff --git a/platform/android/src/jni.cpp b/platform/android/src/jni.cpp
index a86ae4a695..53691acb39 100755
--- a/platform/android/src/jni.cpp
+++ b/platform/android/src/jni.cpp
@@ -11,12 +11,25 @@
#include "conversion/conversion.hpp"
#include "conversion/collection.hpp"
#include "file_source.hpp"
-#include "geometry/feature.hpp"
+#include "geojson/feature.hpp"
+#include "geojson/feature_collection.hpp"
+#include "geojson/geometry.hpp"
+#include "geojson/line_string.hpp"
+#include "geojson/multi_line_string.hpp"
+#include "geojson/multi_point.hpp"
+#include "geojson/multi_polygon.hpp"
+#include "geojson/point.hpp"
+#include "geojson/polygon.hpp"
+#include "geojson/position.hpp"
#include "geometry/lat_lng.hpp"
#include "geometry/lat_lng_bounds.hpp"
#include "geometry/projected_meters.hpp"
#include "graphics/pointf.hpp"
#include "graphics/rectf.hpp"
+#include "gson/json_array.hpp"
+#include "gson/json_element.hpp"
+#include "gson/json_object.hpp"
+#include "gson/json_primitive.hpp"
#include "java_types.hpp"
#include "native_map_view.hpp"
#include "offline/offline_manager.hpp"
@@ -24,6 +37,7 @@
#include "offline/offline_region_definition.hpp"
#include "offline/offline_region_error.hpp"
#include "offline/offline_region_status.hpp"
+#include "style/transition_options.hpp"
#include "style/functions/categorical_stops.hpp"
#include "style/functions/exponential_stops.hpp"
#include "style/functions/identity_stops.hpp"
@@ -97,12 +111,29 @@ void registerNatives(JavaVM *vm) {
PointF::registerNative(env);
RectF::registerNative(env);
+ // GeoJSON
+ geojson::Feature::registerNative(env);
+ geojson::FeatureCollection::registerNative(env);
+ geojson::Geometry::registerNative(env);
+ geojson::LineString::registerNative(env);
+ geojson::MultiLineString::registerNative(env);
+ geojson::MultiPoint::registerNative(env);
+ geojson::MultiPolygon::registerNative(env);
+ geojson::Point::registerNative(env);
+ geojson::Polygon::registerNative(env);
+ geojson::Position::registerNative(env);
+
// Geometry
- Feature::registerNative(env);
LatLng::registerNative(env);
LatLngBounds::registerNative(env);
ProjectedMeters::registerNative(env);
+ // GSon
+ gson::JsonArray::registerNative(env);
+ gson::JsonElement::registerNative(env);
+ gson::JsonObject::registerNative(env);
+ gson::JsonPrimitive::registerNative(env);
+
//Annotation
Marker::registerNative(env);
Polygon::registerNative(env);
@@ -119,6 +150,7 @@ void registerNatives(JavaVM *vm) {
BitmapFactory::registerNative(env);
// Style
+ TransitionOptions::registerNative(env);
registerNativeLayers(env);
registerNativeSources(env);
Stop::registerNative(env);
diff --git a/platform/android/src/jni.hpp b/platform/android/src/jni.hpp
index f0c113f754..e5df92e701 100644
--- a/platform/android/src/jni.hpp
+++ b/platform/android/src/jni.hpp
@@ -13,7 +13,6 @@ extern JavaVM* theJVM;
extern std::string cachePath;
extern std::string dataPath;
-extern std::string apkPath;
bool attach_jni_thread(JavaVM* vm, JNIEnv** env, std::string threadName);
void detach_jni_thread(JavaVM* vm, JNIEnv** env, bool detach);
diff --git a/platform/android/src/map/camera_position.cpp b/platform/android/src/map/camera_position.cpp
index 8d69967014..aa5873b273 100644
--- a/platform/android/src/map/camera_position.cpp
+++ b/platform/android/src/map/camera_position.cpp
@@ -23,7 +23,7 @@ jni::Object<CameraPosition> CameraPosition::New(jni::JNIEnv &env, mbgl::CameraOp
// convert tilt, core ranges from [0 rad, 1,0472 rad], android ranges from 0 to 60
double tilt_degrees = options.pitch.value_or(0) * 180 / M_PI;
- return CameraPosition::javaClass.New(env, constructor, LatLng::New(env, center.latitude, center.longitude), options.zoom.value_or(0), tilt_degrees, bearing_degrees);
+ return CameraPosition::javaClass.New(env, constructor, LatLng::New(env, center), options.zoom.value_or(0), tilt_degrees, bearing_degrees);
}
void CameraPosition::registerNative(jni::JNIEnv &env) {
@@ -35,4 +35,5 @@ jni::Class<CameraPosition> CameraPosition::javaClass;
} // namespace android
-} // namespace mb \ No newline at end of file
+} // namespace mb
+
diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp
index ddd7ba45f8..51ce9c031d 100755
--- a/platform/android/src/native_map_view.cpp
+++ b/platform/android/src/native_map_view.cpp
@@ -14,9 +14,8 @@
#include <jni/jni.hpp>
-#include <mbgl/gl/context.hpp>
-#include <mbgl/gl/extension.hpp>
#include <mbgl/map/backend_scope.hpp>
+#include <mbgl/math/minmax.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/event.hpp>
#include <mbgl/util/exception.hpp>
@@ -25,7 +24,8 @@
#include <mbgl/util/shared_thread_pool.hpp>
#include <mbgl/util/logging.hpp>
#include <mbgl/util/platform.hpp>
-#include <mbgl/sprite/sprite_image.hpp>
+#include <mbgl/util/projection.hpp>
+#include <mbgl/style/image.hpp>
#include <mbgl/style/filter.hpp>
// Java -> C++ conversion
@@ -37,7 +37,7 @@
#include "conversion/conversion.hpp"
#include "conversion/collection.hpp"
#include "style/conversion/filter.hpp"
-#include "geometry/conversion/feature.hpp"
+#include "geojson/conversion/feature.hpp"
#include "jni.hpp"
#include "attach_env.hpp"
@@ -76,6 +76,10 @@ NativeMapView::NativeMapView(jni::JNIEnv& _env,
MapMode::Continuous, GLContextMode::Unique, ConstrainMode::HeightOnly,
ViewportMode::Default, jni::Make<std::string>(_env, _programCacheDir));
+ recalculateSourceTileCacheSize();
+}
+
+void NativeMapView::recalculateSourceTileCacheSize() {
//Calculate a fitting cache size based on device parameters
float zoomFactor = map->getMaxZoom() - map->getMinZoom() + 1;
float cpuFactor = availableProcessors;
@@ -103,13 +107,17 @@ NativeMapView::~NativeMapView() {
* From mbgl::View
*/
void NativeMapView::bind() {
- getContext().bindFramebuffer = 0;
- getContext().viewport = { 0, 0, getFramebufferSize() };
+ setFramebufferBinding(0);
+ setViewportSize(getFramebufferSize());
}
/**
* From mbgl::Backend.
*/
+gl::ProcAddress NativeMapView::initializeExtension(const char* name) {
+ return eglGetProcAddress(name);
+}
+
void NativeMapView::activate() {
if (active++) {
return;
@@ -189,6 +197,70 @@ void NativeMapView::notifyMapChange(mbgl::MapChange change) {
javaPeer->Call(*_env, onMapChanged, (int) change);
}
+void NativeMapView::onCameraWillChange(MapObserver::CameraChangeMode mode) {
+ if (mode == MapObserver::CameraChangeMode::Immediate) {
+ notifyMapChange(MapChange::MapChangeRegionWillChange);
+ } else {
+ notifyMapChange(MapChange::MapChangeRegionWillChangeAnimated);
+ }
+}
+
+void NativeMapView::onCameraIsChanging() {
+ notifyMapChange(MapChange::MapChangeRegionIsChanging);
+}
+
+void NativeMapView::onCameraDidChange(MapObserver::CameraChangeMode mode) {
+ if (mode == MapObserver::CameraChangeMode::Immediate) {
+ notifyMapChange(MapChange::MapChangeRegionDidChange);
+ } else {
+ notifyMapChange(MapChange::MapChangeRegionDidChangeAnimated);
+ }
+}
+
+void NativeMapView::onWillStartLoadingMap() {
+ notifyMapChange(MapChange::MapChangeWillStartLoadingMap);
+}
+
+void NativeMapView::onDidFinishLoadingMap() {
+ notifyMapChange(MapChange::MapChangeDidFinishLoadingMap);
+}
+
+void NativeMapView::onDidFailLoadingMap(std::exception_ptr) {
+ notifyMapChange(MapChange::MapChangeDidFailLoadingMap);
+}
+
+void NativeMapView::onWillStartRenderingFrame() {
+ notifyMapChange(MapChange::MapChangeWillStartRenderingFrame);
+}
+
+void NativeMapView::onDidFinishRenderingFrame(MapObserver::RenderMode mode) {
+ if (mode == MapObserver::RenderMode::Partial) {
+ notifyMapChange(MapChange::MapChangeDidFinishRenderingFrame);
+ } else {
+ notifyMapChange(MapChange::MapChangeDidFinishRenderingFrameFullyRendered);
+ }
+}
+
+void NativeMapView::onWillStartRenderingMap() {
+ notifyMapChange(MapChange::MapChangeWillStartRenderingMap);
+}
+
+void NativeMapView::onDidFinishRenderingMap(MapObserver::RenderMode mode) {
+ if (mode == MapObserver::RenderMode::Partial) {
+ notifyMapChange(MapChange::MapChangeDidFinishRenderingMap);
+ } else {
+ notifyMapChange(MapChange::MapChangeDidFinishRenderingMapFullyRendered);
+ }
+}
+
+void NativeMapView::onDidFinishLoadingStyle() {
+ notifyMapChange(MapChange::MapChangeDidFinishLoadingStyle);
+}
+
+void NativeMapView::onSourceChanged(mbgl::style::Source&) {
+ notifyMapChange(MapChange::MapChangeSourceDidChange);
+}
+
// JNI Methods //
void NativeMapView::initializeDisplay(jni::JNIEnv&) {
@@ -219,18 +291,17 @@ void NativeMapView::render(jni::JNIEnv& env) {
BackendScope guard(*this);
if (framebufferSizeChanged) {
- getContext().viewport = { 0, 0, getFramebufferSize() };
+ setViewportSize(getFramebufferSize());
framebufferSizeChanged = false;
}
- updateViewBinding();
map->render(*this);
if(snapshot){
snapshot = false;
// take snapshot
- auto image = getContext().readFramebuffer<mbgl::PremultipliedImage>(getFramebufferSize());
+ auto image = readFramebuffer(getFramebufferSize());
auto bitmap = Bitmap::CreateBitmap(env, std::move(image));
// invoke Mapview#OnSnapshotReady
@@ -257,9 +328,10 @@ void NativeMapView::update(jni::JNIEnv&) {
}
void NativeMapView::resizeView(jni::JNIEnv&, int w, int h) {
- width = w;
- height = h;
+ width = util::max(64, w);
+ height = util::max(64, h);
map->setSize({ static_cast<uint32_t>(width), static_cast<uint32_t>(height) });
+ recalculateSourceTileCacheSize();
}
void NativeMapView::resizeFramebuffer(jni::JNIEnv&, int w, int h) {
@@ -285,6 +357,14 @@ void NativeMapView::setStyleJson(jni::JNIEnv& env, jni::String json) {
map->setStyleJSON(jni::Make<std::string>(env, json));
}
+void NativeMapView::setLatLngBounds(jni::JNIEnv& env, jni::Object<mbgl::android::LatLngBounds> jBounds) {
+ if (jBounds) {
+ map->setLatLngBounds(mbgl::android::LatLngBounds::getLatLngBounds(env, jBounds));
+ } else {
+ map->setLatLngBounds(mbgl::LatLngBounds::world());
+ }
+}
+
void NativeMapView::cancelTransitions(jni::JNIEnv&) {
map->cancelTransitions();
}
@@ -334,7 +414,7 @@ void NativeMapView::easeTo(jni::JNIEnv&, jni::jdouble angle, jni::jdouble latitu
}
mbgl::AnimationOptions animationOptions;
- animationOptions.duration.emplace(mbgl::Duration(duration));
+ animationOptions.duration.emplace(mbgl::Milliseconds(duration));
if (!easing) {
// add a linear interpolator instead of easing
animationOptions.easing.emplace(mbgl::util::UnitBezier { 0, 0, 1, 1 });
@@ -358,13 +438,12 @@ void NativeMapView::flyTo(jni::JNIEnv&, jni::jdouble angle, jni::jdouble latitud
}
mbgl::AnimationOptions animationOptions;
- animationOptions.duration.emplace(mbgl::Duration(duration));
+ animationOptions.duration.emplace(mbgl::Milliseconds(duration));
map->flyTo(cameraOptions, animationOptions);
}
jni::Object<LatLng> NativeMapView::getLatLng(JNIEnv& env) {
- mbgl::LatLng latLng = map->getLatLng(insets);
- return LatLng::New(env, latLng.latitude, latLng.longitude);
+ return LatLng::New(env, map->getLatLng(insets));
}
void NativeMapView::setLatLng(jni::JNIEnv&, jni::jdouble latitude, jni::jdouble longitude, jni::jlong duration) {
@@ -393,20 +472,6 @@ void NativeMapView::setPitch(jni::JNIEnv&, jni::jdouble pitch, jni::jlong durati
map->setPitch(pitch, mbgl::AnimationOptions{mbgl::Milliseconds(duration)});
}
-void NativeMapView::scaleBy(jni::JNIEnv&, jni::jdouble ds, jni::jdouble cx, jni::jdouble cy, jni::jlong duration) {
- mbgl::ScreenCoordinate center(cx, cy);
- map->scaleBy(ds, center, mbgl::AnimationOptions{mbgl::Milliseconds(duration)});
-}
-
-void NativeMapView::setScale(jni::JNIEnv&, jni::jdouble scale, jni::jdouble cx, jni::jdouble cy, jni::jlong duration) {
- mbgl::ScreenCoordinate center(cx, cy);
- map->setScale(scale, center, mbgl::AnimationOptions{mbgl::Milliseconds(duration)});
-}
-
-jni::jdouble NativeMapView::getScale(jni::JNIEnv&) {
- return map->getScale();
-}
-
void NativeMapView::setZoom(jni::JNIEnv&, jni::jdouble zoom, jni::jdouble x, jni::jdouble y, jni::jlong duration) {
map->setZoom(zoom, mbgl::ScreenCoordinate{x,y}, mbgl::AnimationOptions{mbgl::Milliseconds(duration)});
}
@@ -421,6 +486,7 @@ void NativeMapView::resetZoom(jni::JNIEnv&) {
void NativeMapView::setMinZoom(jni::JNIEnv&, jni::jdouble zoom) {
map->setMinZoom(zoom);
+ recalculateSourceTileCacheSize();
}
jni::jdouble NativeMapView::getMinZoom(jni::JNIEnv&) {
@@ -429,6 +495,7 @@ jni::jdouble NativeMapView::getMinZoom(jni::JNIEnv&) {
void NativeMapView::setMaxZoom(jni::JNIEnv&, jni::jdouble zoom) {
map->setMaxZoom(zoom);
+ recalculateSourceTileCacheSize();
}
jni::jdouble NativeMapView::getMaxZoom(jni::JNIEnv&) {
@@ -564,12 +631,16 @@ jni::jboolean NativeMapView::isFullyLoaded(JNIEnv&) {
}
jni::jdouble NativeMapView::getMetersPerPixelAtLatitude(JNIEnv&, jni::jdouble lat, jni::jdouble zoom) {
- return map->getMetersPerPixelAtLatitude(lat, zoom);
+ return mbgl::Projection::getMetersPerPixelAtLatitude(lat, zoom);
}
jni::Object<ProjectedMeters> NativeMapView::projectedMetersForLatLng(JNIEnv& env, jni::jdouble latitude, jni::jdouble longitude) {
- mbgl::ProjectedMeters projectedMeters = map->projectedMetersForLatLng(mbgl::LatLng(latitude, longitude));
- return ProjectedMeters::New(env, projectedMeters.northing, projectedMeters.easting);
+ mbgl::ProjectedMeters projectedMeters = mbgl::Projection::projectedMetersForLatLng(mbgl::LatLng(latitude, longitude));
+ return ProjectedMeters::New(env, projectedMeters.northing(), projectedMeters.easting());
+}
+
+jni::Object<LatLng> NativeMapView::latLngForProjectedMeters(JNIEnv& env, jdouble northing, jdouble easting) {
+ return LatLng::New(env, mbgl::Projection::latLngForProjectedMeters(mbgl::ProjectedMeters(northing, easting)));
}
jni::Object<PointF> NativeMapView::pixelForLatLng(JNIEnv& env, jdouble latitude, jdouble longitude) {
@@ -577,14 +648,8 @@ jni::Object<PointF> NativeMapView::pixelForLatLng(JNIEnv& env, jdouble latitude,
return PointF::New(env, static_cast<float>(pixel.x), static_cast<float>(pixel.y));
}
-jni::Object<LatLng> NativeMapView::latLngForProjectedMeters(JNIEnv& env, jdouble northing, jdouble easting) {
- mbgl::LatLng latLng = map->latLngForProjectedMeters(mbgl::ProjectedMeters(northing, easting));
- return LatLng::New(env, latLng.latitude, latLng.longitude);
-}
-
jni::Object<LatLng> NativeMapView::latLngForPixel(JNIEnv& env, jfloat x, jfloat y) {
- mbgl::LatLng latLng = map->latLngForPixel(mbgl::ScreenCoordinate(x, y));
- return LatLng::New(env, latLng.latitude, latLng.longitude);
+ return LatLng::New(env, map->latLngForPixel(mbgl::ScreenCoordinate(x, y)));
}
jni::Array<jlong> NativeMapView::addPolylines(JNIEnv& env, jni::Array<jni::Object<Polyline>> polylines) {
@@ -670,33 +735,33 @@ void NativeMapView::addAnnotationIcon(JNIEnv& env, jni::String symbol, jint w, j
}
jni::GetArrayRegion(env, *jpixels, 0, size, reinterpret_cast<jbyte*>(premultipliedImage.data.get()));
- auto iconImage = std::make_shared<mbgl::SpriteImage>(std::move(premultipliedImage), float(scale));
- map->addAnnotationIcon(symbolName, iconImage);
+ map->addAnnotationImage(std::make_unique<mbgl::style::Image>(
+ symbolName, std::move(premultipliedImage), float(scale)));
}
jdouble NativeMapView::getTopOffsetPixelsForAnnotationSymbol(JNIEnv& env, jni::String symbolName) {
- return map->getTopOffsetPixelsForAnnotationIcon(jni::Make<std::string>(env, symbolName));
+ return map->getTopOffsetPixelsForAnnotationImage(jni::Make<std::string>(env, symbolName));
}
jlong NativeMapView::getTransitionDuration(JNIEnv&) {
const auto transitionOptions = map->getTransitionOptions();
- return transitionOptions.duration.value_or(mbgl::Duration::zero()).count();
+ return std::chrono::duration_cast<std::chrono::milliseconds>(transitionOptions.duration.value_or(mbgl::Duration::zero())).count();
}
void NativeMapView::setTransitionDuration(JNIEnv&, jlong duration) {
auto transitionOptions = map->getTransitionOptions();
- transitionOptions.duration = std::chrono::duration_cast<mbgl::Duration>(std::chrono::duration<jlong>(duration));
+ transitionOptions.duration.emplace(mbgl::Milliseconds(duration));
map->setTransitionOptions(transitionOptions);
}
jlong NativeMapView::getTransitionDelay(JNIEnv&) {
const auto transitionOptions = map->getTransitionOptions();
- return transitionOptions.delay.value_or(mbgl::Duration::zero()).count();
+ return std::chrono::duration_cast<std::chrono::milliseconds>(transitionOptions.delay.value_or(mbgl::Duration::zero())).count();
}
void NativeMapView::setTransitionDelay(JNIEnv&, jlong delay) {
auto transitionOptions = map->getTransitionOptions();
- transitionOptions.delay = std::chrono::duration_cast<mbgl::Duration>(std::chrono::duration<jlong>(delay));
+ transitionOptions.delay.emplace(mbgl::Milliseconds(delay));
map->setTransitionOptions(transitionOptions);
}
@@ -721,32 +786,35 @@ jni::Array<jlong> NativeMapView::queryPointAnnotations(JNIEnv& env, jni::Object<
return result;
}
-jni::Array<jni::Object<Feature>> NativeMapView::queryRenderedFeaturesForPoint(JNIEnv& env, jni::jfloat x, jni::jfloat y,
+jni::Array<jni::Object<geojson::Feature>> NativeMapView::queryRenderedFeaturesForPoint(JNIEnv& env, jni::jfloat x, jni::jfloat y,
jni::Array<jni::String> layerIds,
jni::Array<jni::Object<>> jfilter) {
using namespace mbgl::android::conversion;
- using namespace mapbox::geometry;
+ using namespace mbgl::android::geojson;
mbgl::optional<std::vector<std::string>> layers;
if (layerIds != nullptr && layerIds.Length(env) > 0) {
layers = android::conversion::toVector(env, layerIds);
}
- point<double> point = {x, y};
+ mapbox::geometry::point<double> point = {x, y};
return *convert<jni::Array<jni::Object<Feature>>, std::vector<mbgl::Feature>>(env, map->queryRenderedFeatures(point, { layers, toFilter(env, jfilter) }));
}
-jni::Array<jni::Object<Feature>> NativeMapView::queryRenderedFeaturesForBox(JNIEnv& env, jni::jfloat left, jni::jfloat top,
+jni::Array<jni::Object<geojson::Feature>> NativeMapView::queryRenderedFeaturesForBox(JNIEnv& env, jni::jfloat left, jni::jfloat top,
jni::jfloat right, jni::jfloat bottom, jni::Array<jni::String> layerIds,
jni::Array<jni::Object<>> jfilter) {
using namespace mbgl::android::conversion;
- using namespace mapbox::geometry;
+ using namespace mbgl::android::geojson;
mbgl::optional<std::vector<std::string>> layers;
if (layerIds != nullptr && layerIds.Length(env) > 0) {
layers = toVector(env, layerIds);
}
- box<double> box = { point<double>{ left, top}, point<double>{ right, bottom } };
+ mapbox::geometry::box<double> box = {
+ mapbox::geometry::point<double>{ left, top},
+ mapbox::geometry::point<double>{ right, bottom }
+ };
return *convert<jni::Array<jni::Object<Feature>>, std::vector<mbgl::Feature>>(env, map->queryRenderedFeatures(box, { layers, toFilter(env, jfilter) }));
}
@@ -968,9 +1036,11 @@ void NativeMapView::addImage(JNIEnv& env, jni::String name, jni::jint w, jni::ji
}
jni::GetArrayRegion(env, *pixels, 0, size, reinterpret_cast<jbyte*>(premultipliedImage.data.get()));
- auto spriteImage = std::make_unique<mbgl::SpriteImage>(std::move(premultipliedImage), float(scale));
- map->addImage(jni::Make<std::string>(env, name), std::move(spriteImage));
+ map->addImage(std::make_unique<mbgl::style::Image>(
+ jni::Make<std::string>(env, name),
+ std::move(premultipliedImage),
+ float(scale)));
}
void NativeMapView::removeImage(JNIEnv& env, jni::String name) {
@@ -1323,10 +1393,6 @@ void NativeMapView::_createSurface(ANativeWindow *window_) {
eglGetError());
throw std::runtime_error("eglMakeCurrent() failed");
}
-
- mbgl::gl::InitializeExtensions([] (const char * name) {
- return reinterpret_cast<mbgl::gl::glProc>(eglGetProcAddress(name));
- });
}
}
@@ -1340,6 +1406,7 @@ void NativeMapView::_destroySurface() {
}
surface = EGL_NO_SURFACE;
+ firstRender = true;
if (window != nullptr) {
ANativeWindow_release(window);
@@ -1351,11 +1418,9 @@ mbgl::Size NativeMapView::getFramebufferSize() const {
return { static_cast<uint32_t>(fbWidth), static_cast<uint32_t>(fbHeight) };
}
-void NativeMapView::updateViewBinding() {
- getContext().bindFramebuffer.setCurrentValue(0);
- assert(mbgl::gl::value::BindFramebuffer::Get() == getContext().bindFramebuffer.getCurrentValue());
- getContext().viewport.setCurrentValue({ 0, 0, getFramebufferSize() });
- assert(mbgl::gl::value::Viewport::Get() == getContext().viewport.getCurrentValue());
+void NativeMapView::updateAssumedState() {
+ assumeFramebufferBinding(0);
+ assumeViewportSize(getFramebufferSize());
}
void NativeMapView::updateFps() {
@@ -1427,9 +1492,6 @@ void NativeMapView::registerNative(jni::JNIEnv& env) {
METHOD(&NativeMapView::resetPosition, "nativeResetPosition"),
METHOD(&NativeMapView::getPitch, "nativeGetPitch"),
METHOD(&NativeMapView::setPitch, "nativeSetPitch"),
- METHOD(&NativeMapView::scaleBy, "nativeScaleBy"),
- METHOD(&NativeMapView::getScale, "nativeGetScale"),
- METHOD(&NativeMapView::setScale, "nativeSetScale"),
METHOD(&NativeMapView::getZoom, "nativeGetZoom"),
METHOD(&NativeMapView::setZoom, "nativeSetZoom"),
METHOD(&NativeMapView::resetZoom, "nativeResetZoom"),
@@ -1487,7 +1549,8 @@ void NativeMapView::registerNative(jni::JNIEnv& env) {
METHOD(&NativeMapView::removeSourceById, "nativeRemoveSourceById"),
METHOD(&NativeMapView::removeSource, "nativeRemoveSource"),
METHOD(&NativeMapView::addImage, "nativeAddImage"),
- METHOD(&NativeMapView::removeImage, "nativeRemoveImage")
+ METHOD(&NativeMapView::removeImage, "nativeRemoveImage"),
+ METHOD(&NativeMapView::setLatLngBounds, "nativeSetLatLngBounds")
);
}
diff --git a/platform/android/src/native_map_view.hpp b/platform/android/src/native_map_view.hpp
index 0e2bb3eef6..e5fcb9badd 100755
--- a/platform/android/src/native_map_view.hpp
+++ b/platform/android/src/native_map_view.hpp
@@ -1,6 +1,7 @@
#pragma once
#include <mbgl/map/backend.hpp>
+#include <mbgl/map/change.hpp>
#include <mbgl/map/camera.hpp>
#include <mbgl/map/map.hpp>
#include <mbgl/map/view.hpp>
@@ -16,7 +17,7 @@
#include "annotation/polyline.hpp"
#include "graphics/pointf.hpp"
#include "graphics/rectf.hpp"
-#include "geometry/feature.hpp"
+#include "geojson/feature.hpp"
#include "geometry/lat_lng.hpp"
#include "geometry/projected_meters.hpp"
#include "style/layers/layers.hpp"
@@ -24,6 +25,7 @@
#include "geometry/lat_lng_bounds.hpp"
#include "map/camera_position.hpp"
+#include <exception>
#include <string>
#include <jni.h>
#include <android/native_window.h>
@@ -58,8 +60,25 @@ public:
// mbgl::Backend //
+ void updateAssumedState() override;
void invalidate() override;
- void notifyMapChange(mbgl::MapChange) override;
+
+ // Deprecated //
+ void notifyMapChange(mbgl::MapChange);
+
+ // mbgl::Backend (mbgl::MapObserver) //
+ void onCameraWillChange(MapObserver::CameraChangeMode) override;
+ void onCameraIsChanging() override;
+ void onCameraDidChange(MapObserver::CameraChangeMode) override;
+ void onWillStartLoadingMap() override;
+ void onDidFinishLoadingMap() override;
+ void onDidFailLoadingMap(std::exception_ptr) override;
+ void onWillStartRenderingFrame() override;
+ void onDidFinishRenderingFrame(MapObserver::RenderMode) override;
+ void onWillStartRenderingMap() override;
+ void onDidFinishRenderingMap(MapObserver::RenderMode) override;
+ void onDidFinishLoadingStyle() override;
+ void onSourceChanged(mbgl::style::Source&) override;
// JNI //
@@ -93,6 +112,8 @@ public:
void setStyleJson(jni::JNIEnv&, jni::String);
+ void setLatLngBounds(jni::JNIEnv&, jni::Object<mbgl::android::LatLngBounds>);
+
void cancelTransitions(jni::JNIEnv&);
void setGestureInProgress(jni::JNIEnv&, jni::jboolean);
@@ -119,12 +140,6 @@ public:
void setPitch(jni::JNIEnv&, jni::jdouble, jni::jlong);
- void scaleBy(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong);
-
- void setScale(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong);
-
- jni::jdouble getScale(jni::JNIEnv&);
-
void setZoom(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong);
jni::jdouble getZoom(jni::JNIEnv&);
@@ -207,11 +222,11 @@ public:
jni::Array<jlong> queryPointAnnotations(JNIEnv&, jni::Object<RectF>);
- jni::Array<jni::Object<Feature>> queryRenderedFeaturesForPoint(JNIEnv&, jni::jfloat, jni::jfloat,
+ jni::Array<jni::Object<geojson::Feature>> queryRenderedFeaturesForPoint(JNIEnv&, jni::jfloat, jni::jfloat,
jni::Array<jni::String>,
jni::Array<jni::Object<>> jfilter);
- jni::Array<jni::Object<Feature>> queryRenderedFeaturesForBox(JNIEnv&, jni::jfloat, jni::jfloat, jni::jfloat,
+ jni::Array<jni::Object<geojson::Feature>> queryRenderedFeaturesForBox(JNIEnv&, jni::jfloat, jni::jfloat, jni::jfloat,
jni::jfloat, jni::Array<jni::String>,
jni::Array<jni::Object<>> jfilter);
@@ -248,6 +263,7 @@ public:
protected:
// mbgl::Backend //
+ gl::ProcAddress initializeExtension(const char*) override;
void activate() override;
void deactivate() override;
@@ -266,12 +282,12 @@ private:
EGLConfig chooseConfig(const EGLConfig configs[], EGLint numConfigs);
- void updateViewBinding();
mbgl::Size getFramebufferSize() const;
void updateFps();
private:
+ void recalculateSourceTileCacheSize();
JavaVM *vm = nullptr;
jni::UniqueWeakObject<NativeMapView> javaPeer;
@@ -300,10 +316,12 @@ private:
bool firstRender = true;
double fps = 0.0;
- int width = 0;
- int height = 0;
- int fbWidth = 0;
- int fbHeight = 0;
+ // Minimum texture size according to OpenGL ES 2.0 specification.
+ int width = 64;
+ int height = 64;
+ int fbWidth = 64;
+ int fbHeight = 64;
+
bool framebufferSizeChanged = true;
int availableProcessors = 0;
diff --git a/platform/android/src/run_loop.cpp b/platform/android/src/run_loop.cpp
index 170b05c23c..49d28f2ebb 100644
--- a/platform/android/src/run_loop.cpp
+++ b/platform/android/src/run_loop.cpp
@@ -1,6 +1,7 @@
#include "run_loop_impl.hpp"
#include <mbgl/util/platform.hpp>
+#include <mbgl/util/thread.hpp>
#include <mbgl/util/thread_context.hpp>
#include <mbgl/util/thread_local.hpp>
#include <mbgl/util/timer.hpp>
diff --git a/platform/android/src/run_loop_impl.hpp b/platform/android/src/run_loop_impl.hpp
index a3efa92a83..15cbfa14ae 100644
--- a/platform/android/src/run_loop_impl.hpp
+++ b/platform/android/src/run_loop_impl.hpp
@@ -4,7 +4,6 @@
#include <mbgl/util/chrono.hpp>
#include <mbgl/util/run_loop.hpp>
-#include <mbgl/util/thread.hpp>
#include <atomic>
#include <list>
@@ -16,6 +15,7 @@ struct ALooper;
namespace mbgl {
namespace util {
+template <typename T> class Thread;
class Alarm;
class RunLoop::Impl {
diff --git a/platform/android/src/style/android_conversion.hpp b/platform/android/src/style/android_conversion.hpp
index d9b88ab52b..e2b2685928 100644
--- a/platform/android/src/style/android_conversion.hpp
+++ b/platform/android/src/style/android_conversion.hpp
@@ -59,7 +59,8 @@ inline optional<bool> toBool(const mbgl::android::Value& value) {
inline optional<float> toNumber(const mbgl::android::Value& value) {
if (value.isNumber()) {
- return value.toNumber();
+ auto num = value.toFloat();
+ return num;
} else {
return {};
}
@@ -81,8 +82,8 @@ inline optional<Value> toValue(const mbgl::android::Value& value) {
} else if (value.isString()) {
return { value.toString() };
} else if (value.isNumber()) {
- // Need to cast to a double here as the float is otherwise considered a bool...
- return { (double) value.toNumber() };
+ auto doubleVal = value.toDouble();
+ return { doubleVal - (int) doubleVal > 0.0 ? doubleVal : value.toLong() };
} else {
return {};
}
diff --git a/platform/android/src/style/conversion/filter.hpp b/platform/android/src/style/conversion/filter.hpp
index fc36d3a044..1f0abcf3a4 100644
--- a/platform/android/src/style/conversion/filter.hpp
+++ b/platform/android/src/style/conversion/filter.hpp
@@ -17,9 +17,10 @@ inline optional<mbgl::style::Filter> toFilter(jni::JNIEnv& env, jni::Array<jni::
mbgl::optional<mbgl::style::Filter> filter;
if (jfilter) {
Value filterValue(env, jfilter);
- auto converted = mbgl::style::conversion::convert<mbgl::style::Filter>(filterValue);
+ mbgl::style::conversion::Error error;
+ auto converted = mbgl::style::conversion::convert<mbgl::style::Filter>(filterValue, error);
if (!converted) {
- mbgl::Log::Error(mbgl::Event::JNI, "Error converting filter: " + converted.error().message);
+ mbgl::Log::Error(mbgl::Event::JNI, "Error converting filter: " + error.message);
}
filter = std::move(*converted);
}
diff --git a/platform/android/src/style/conversion/geojson.hpp b/platform/android/src/style/conversion/geojson.hpp
index 415d96f467..748fe7361e 100644
--- a/platform/android/src/style/conversion/geojson.hpp
+++ b/platform/android/src/style/conversion/geojson.hpp
@@ -1,57 +1,24 @@
#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/util/logging.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" };
+optional<GeoJSON> Converter<GeoJSON>::operator()(const mbgl::android::Value& value, Error& error) const {
+ if(value.isNull() || !value.isString()) {
+ error = { "no json data found" };
+ return {};
}
- 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;
+ return convert<GeoJSON>(value.toString(), error);
}
-template <>
-struct Converter<GeoJSON> {
-
- Result<GeoJSON> operator()(const mbgl::android::Value& value) const {
- return convertGeoJSON(value);
- }
-
-};
-
} // namespace conversion
} // namespace style
} // namespace mbgl
diff --git a/platform/android/src/style/conversion/transition_options.hpp b/platform/android/src/style/conversion/transition_options.hpp
new file mode 100644
index 0000000000..3614878f43
--- /dev/null
+++ b/platform/android/src/style/conversion/transition_options.hpp
@@ -0,0 +1,29 @@
+#pragma once
+
+#include "../../conversion/conversion.hpp"
+
+#include <jni/jni.hpp>
+#include "../../jni/local_object.hpp"
+#include "../transition_options.hpp"
+
+namespace mbgl {
+namespace android {
+namespace conversion {
+
+template<>
+struct Converter<jni::Object<TransitionOptions>, mbgl::style::TransitionOptions> {
+ Result<jni::Object<TransitionOptions>> operator()(jni::JNIEnv &env, const mbgl::style::TransitionOptions &value) const {
+
+ // Convert duration
+ jlong duration = std::chrono::duration_cast<std::chrono::milliseconds>(value.duration.value_or(mbgl::Duration::zero())).count();
+ // Convert delay
+ jlong delay = std::chrono::duration_cast<std::chrono::milliseconds>(value.delay.value_or(mbgl::Duration::zero())).count();
+
+ // Create transition options
+ return TransitionOptions::fromTransitionOptions(env, duration, delay);
+ }
+};
+
+}
+}
+} \ No newline at end of file
diff --git a/platform/android/src/style/conversion/url_or_tileset.hpp b/platform/android/src/style/conversion/url_or_tileset.hpp
index 4e502324d0..00ef913d41 100644
--- a/platform/android/src/style/conversion/url_or_tileset.hpp
+++ b/platform/android/src/style/conversion/url_or_tileset.hpp
@@ -12,27 +12,25 @@
#include <string>
namespace mbgl {
-namespace style {
-namespace conversion {
-
-template <>
-struct Converter<variant<std::string, Tileset>> {
-
- template <class V>
- Result<variant<std::string, Tileset>> operator()(const V& value) const {
- if (isObject(value)) {
- Result<Tileset> tileset = convert<Tileset>(value);
- if (!tileset) {
- return tileset.error();
- }
- return *tileset;
- } else {
- return *toString(value);
+namespace android {
+
+// This conversion is expected not to fail because it's used only in contexts where
+// the value was originally a String or TileSet object on the Java side. If it fails
+// to convert, it's a bug in our serialization or Java-side static typing.
+inline variant<std::string, Tileset> convertURLOrTileset(const Value& value) {
+ using namespace mbgl::style::conversion;
+
+ if (isObject(value)) {
+ Error error;
+ optional<Tileset> tileset = convert<Tileset>(value, error);
+ if (!tileset) {
+ throw std::logic_error(error.message);
}
+ return { *tileset };
+ } else {
+ return { *toString(value) };
}
-
-};
-
}
+
}
}
diff --git a/platform/android/src/style/layers/background_layer.cpp b/platform/android/src/style/layers/background_layer.cpp
index 9915f3894e..a8f013b230 100644
--- a/platform/android/src/style/layers/background_layer.cpp
+++ b/platform/android/src/style/layers/background_layer.cpp
@@ -5,6 +5,7 @@
#include <string>
#include "../conversion/property_value.hpp"
+#include "../conversion/transition_options.hpp"
namespace mbgl {
namespace android {
@@ -40,18 +41,58 @@ namespace android {
return jni::Object<jni::ObjectTag>(*converted);
}
+ jni::Object<TransitionOptions> BackgroundLayer::getBackgroundColorTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::BackgroundLayer>()->BackgroundLayer::getBackgroundColorTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void BackgroundLayer::setBackgroundColorTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::BackgroundLayer>()->BackgroundLayer::setBackgroundColorTransition(options);
+ }
+
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<TransitionOptions> BackgroundLayer::getBackgroundPatternTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::BackgroundLayer>()->BackgroundLayer::getBackgroundPatternTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void BackgroundLayer::setBackgroundPatternTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::BackgroundLayer>()->BackgroundLayer::setBackgroundPatternTransition(options);
+ }
+
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::Object<TransitionOptions> BackgroundLayer::getBackgroundOpacityTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::BackgroundLayer>()->BackgroundLayer::getBackgroundOpacityTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void BackgroundLayer::setBackgroundOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::BackgroundLayer>()->BackgroundLayer::setBackgroundOpacityTransition(options);
+ }
+
+
jni::Class<BackgroundLayer> BackgroundLayer::javaClass;
jni::jobject* BackgroundLayer::createJavaPeer(jni::JNIEnv& env) {
@@ -71,8 +112,14 @@ namespace android {
std::make_unique<BackgroundLayer, JNIEnv&, jni::String>,
"initialize",
"finalize",
+ METHOD(&BackgroundLayer::getBackgroundColorTransition, "nativeGetBackgroundColorTransition"),
+ METHOD(&BackgroundLayer::setBackgroundColorTransition, "nativeSetBackgroundColorTransition"),
METHOD(&BackgroundLayer::getBackgroundColor, "nativeGetBackgroundColor"),
+ METHOD(&BackgroundLayer::getBackgroundPatternTransition, "nativeGetBackgroundPatternTransition"),
+ METHOD(&BackgroundLayer::setBackgroundPatternTransition, "nativeSetBackgroundPatternTransition"),
METHOD(&BackgroundLayer::getBackgroundPattern, "nativeGetBackgroundPattern"),
+ METHOD(&BackgroundLayer::getBackgroundOpacityTransition, "nativeGetBackgroundOpacityTransition"),
+ METHOD(&BackgroundLayer::setBackgroundOpacityTransition, "nativeSetBackgroundOpacityTransition"),
METHOD(&BackgroundLayer::getBackgroundOpacity, "nativeGetBackgroundOpacity"));
}
diff --git a/platform/android/src/style/layers/background_layer.hpp b/platform/android/src/style/layers/background_layer.hpp
index 2fdc948892..95555a2d78 100644
--- a/platform/android/src/style/layers/background_layer.hpp
+++ b/platform/android/src/style/layers/background_layer.hpp
@@ -3,6 +3,7 @@
#pragma once
#include "layer.hpp"
+#include "../transition_options.hpp"
#include <mbgl/style/layers/background_layer.hpp>
#include <jni/jni.hpp>
@@ -26,13 +27,19 @@ public:
~BackgroundLayer();
- // Property getters
+ // Properties
+
jni::Object<jni::ObjectTag> getBackgroundColor(jni::JNIEnv&);
+ void setBackgroundColorTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getBackgroundColorTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getBackgroundPattern(jni::JNIEnv&);
+ void setBackgroundPatternTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getBackgroundPatternTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getBackgroundOpacity(jni::JNIEnv&);
-
+ void setBackgroundOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getBackgroundOpacityTransition(jni::JNIEnv&);
jni::jobject* createJavaPeer(jni::JNIEnv&);
}; // class BackgroundLayer
diff --git a/platform/android/src/style/layers/circle_layer.cpp b/platform/android/src/style/layers/circle_layer.cpp
index 948c397829..96a9356679 100644
--- a/platform/android/src/style/layers/circle_layer.cpp
+++ b/platform/android/src/style/layers/circle_layer.cpp
@@ -5,6 +5,7 @@
#include <string>
#include "../conversion/property_value.hpp"
+#include "../conversion/transition_options.hpp"
namespace mbgl {
namespace android {
@@ -40,30 +41,95 @@ namespace android {
return jni::Object<jni::ObjectTag>(*converted);
}
+ jni::Object<TransitionOptions> CircleLayer::getCircleRadiusTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::CircleLayer>()->CircleLayer::getCircleRadiusTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void CircleLayer::setCircleRadiusTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::CircleLayer>()->CircleLayer::setCircleRadiusTransition(options);
+ }
+
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<TransitionOptions> CircleLayer::getCircleColorTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::CircleLayer>()->CircleLayer::getCircleColorTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void CircleLayer::setCircleColorTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::CircleLayer>()->CircleLayer::setCircleColorTransition(options);
+ }
+
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<TransitionOptions> CircleLayer::getCircleBlurTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::CircleLayer>()->CircleLayer::getCircleBlurTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void CircleLayer::setCircleBlurTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::CircleLayer>()->CircleLayer::setCircleBlurTransition(options);
+ }
+
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<TransitionOptions> CircleLayer::getCircleOpacityTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::CircleLayer>()->CircleLayer::getCircleOpacityTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void CircleLayer::setCircleOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::CircleLayer>()->CircleLayer::setCircleOpacityTransition(options);
+ }
+
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<TransitionOptions> CircleLayer::getCircleTranslateTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::CircleLayer>()->CircleLayer::getCircleTranslateTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void CircleLayer::setCircleTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::CircleLayer>()->CircleLayer::setCircleTranslateTransition(options);
+ }
+
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());
@@ -82,18 +148,58 @@ namespace android {
return jni::Object<jni::ObjectTag>(*converted);
}
+ jni::Object<TransitionOptions> CircleLayer::getCircleStrokeWidthTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::CircleLayer>()->CircleLayer::getCircleStrokeWidthTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void CircleLayer::setCircleStrokeWidthTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::CircleLayer>()->CircleLayer::setCircleStrokeWidthTransition(options);
+ }
+
jni::Object<jni::ObjectTag> CircleLayer::getCircleStrokeColor(jni::JNIEnv& env) {
using namespace mbgl::android::conversion;
Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::CircleLayer>()->CircleLayer::getCircleStrokeColor());
return jni::Object<jni::ObjectTag>(*converted);
}
+ jni::Object<TransitionOptions> CircleLayer::getCircleStrokeColorTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::CircleLayer>()->CircleLayer::getCircleStrokeColorTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void CircleLayer::setCircleStrokeColorTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::CircleLayer>()->CircleLayer::setCircleStrokeColorTransition(options);
+ }
+
jni::Object<jni::ObjectTag> CircleLayer::getCircleStrokeOpacity(jni::JNIEnv& env) {
using namespace mbgl::android::conversion;
Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::CircleLayer>()->CircleLayer::getCircleStrokeOpacity());
return jni::Object<jni::ObjectTag>(*converted);
}
+ jni::Object<TransitionOptions> CircleLayer::getCircleStrokeOpacityTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::CircleLayer>()->CircleLayer::getCircleStrokeOpacityTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void CircleLayer::setCircleStrokeOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::CircleLayer>()->CircleLayer::setCircleStrokeOpacityTransition(options);
+ }
+
+
jni::Class<CircleLayer> CircleLayer::javaClass;
jni::jobject* CircleLayer::createJavaPeer(jni::JNIEnv& env) {
@@ -113,15 +219,31 @@ namespace android {
std::make_unique<CircleLayer, JNIEnv&, jni::String, jni::String>,
"initialize",
"finalize",
+ METHOD(&CircleLayer::getCircleRadiusTransition, "nativeGetCircleRadiusTransition"),
+ METHOD(&CircleLayer::setCircleRadiusTransition, "nativeSetCircleRadiusTransition"),
METHOD(&CircleLayer::getCircleRadius, "nativeGetCircleRadius"),
+ METHOD(&CircleLayer::getCircleColorTransition, "nativeGetCircleColorTransition"),
+ METHOD(&CircleLayer::setCircleColorTransition, "nativeSetCircleColorTransition"),
METHOD(&CircleLayer::getCircleColor, "nativeGetCircleColor"),
+ METHOD(&CircleLayer::getCircleBlurTransition, "nativeGetCircleBlurTransition"),
+ METHOD(&CircleLayer::setCircleBlurTransition, "nativeSetCircleBlurTransition"),
METHOD(&CircleLayer::getCircleBlur, "nativeGetCircleBlur"),
+ METHOD(&CircleLayer::getCircleOpacityTransition, "nativeGetCircleOpacityTransition"),
+ METHOD(&CircleLayer::setCircleOpacityTransition, "nativeSetCircleOpacityTransition"),
METHOD(&CircleLayer::getCircleOpacity, "nativeGetCircleOpacity"),
+ METHOD(&CircleLayer::getCircleTranslateTransition, "nativeGetCircleTranslateTransition"),
+ METHOD(&CircleLayer::setCircleTranslateTransition, "nativeSetCircleTranslateTransition"),
METHOD(&CircleLayer::getCircleTranslate, "nativeGetCircleTranslate"),
METHOD(&CircleLayer::getCircleTranslateAnchor, "nativeGetCircleTranslateAnchor"),
METHOD(&CircleLayer::getCirclePitchScale, "nativeGetCirclePitchScale"),
+ METHOD(&CircleLayer::getCircleStrokeWidthTransition, "nativeGetCircleStrokeWidthTransition"),
+ METHOD(&CircleLayer::setCircleStrokeWidthTransition, "nativeSetCircleStrokeWidthTransition"),
METHOD(&CircleLayer::getCircleStrokeWidth, "nativeGetCircleStrokeWidth"),
+ METHOD(&CircleLayer::getCircleStrokeColorTransition, "nativeGetCircleStrokeColorTransition"),
+ METHOD(&CircleLayer::setCircleStrokeColorTransition, "nativeSetCircleStrokeColorTransition"),
METHOD(&CircleLayer::getCircleStrokeColor, "nativeGetCircleStrokeColor"),
+ METHOD(&CircleLayer::getCircleStrokeOpacityTransition, "nativeGetCircleStrokeOpacityTransition"),
+ METHOD(&CircleLayer::setCircleStrokeOpacityTransition, "nativeSetCircleStrokeOpacityTransition"),
METHOD(&CircleLayer::getCircleStrokeOpacity, "nativeGetCircleStrokeOpacity"));
}
diff --git a/platform/android/src/style/layers/circle_layer.hpp b/platform/android/src/style/layers/circle_layer.hpp
index ee988d7c57..81737e8996 100644
--- a/platform/android/src/style/layers/circle_layer.hpp
+++ b/platform/android/src/style/layers/circle_layer.hpp
@@ -3,6 +3,7 @@
#pragma once
#include "layer.hpp"
+#include "../transition_options.hpp"
#include <mbgl/style/layers/circle_layer.hpp>
#include <jni/jni.hpp>
@@ -26,27 +27,43 @@ public:
~CircleLayer();
- // Property getters
+ // Properties
+
jni::Object<jni::ObjectTag> getCircleRadius(jni::JNIEnv&);
+ void setCircleRadiusTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getCircleRadiusTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getCircleColor(jni::JNIEnv&);
+ void setCircleColorTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getCircleColorTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getCircleBlur(jni::JNIEnv&);
+ void setCircleBlurTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getCircleBlurTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getCircleOpacity(jni::JNIEnv&);
+ void setCircleOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getCircleOpacityTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getCircleTranslate(jni::JNIEnv&);
+ void setCircleTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getCircleTranslateTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getCircleTranslateAnchor(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getCirclePitchScale(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getCircleStrokeWidth(jni::JNIEnv&);
+ void setCircleStrokeWidthTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getCircleStrokeWidthTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getCircleStrokeColor(jni::JNIEnv&);
+ void setCircleStrokeColorTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getCircleStrokeColorTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getCircleStrokeOpacity(jni::JNIEnv&);
-
+ void setCircleStrokeOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getCircleStrokeOpacityTransition(jni::JNIEnv&);
jni::jobject* createJavaPeer(jni::JNIEnv&);
}; // class CircleLayer
diff --git a/platform/android/src/style/layers/fill_extrusion_layer.cpp b/platform/android/src/style/layers/fill_extrusion_layer.cpp
new file mode 100644
index 0000000000..492e1729b9
--- /dev/null
+++ b/platform/android/src/style/layers/fill_extrusion_layer.cpp
@@ -0,0 +1,200 @@
+// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
+
+#include "fill_extrusion_layer.hpp"
+
+#include <string>
+
+#include "../conversion/property_value.hpp"
+#include "../conversion/transition_options.hpp"
+
+namespace mbgl {
+namespace android {
+
+ /**
+ * Creates an owning peer object (for layers not attached to the map) from the JVM side
+ */
+ FillExtrusionLayer::FillExtrusionLayer(jni::JNIEnv& env, jni::String layerId, jni::String sourceId)
+ : Layer(env, std::make_unique<mbgl::style::FillExtrusionLayer>(jni::Make<std::string>(env, layerId), jni::Make<std::string>(env, sourceId))) {
+ }
+
+ /**
+ * Creates a non-owning peer object (for layers currently attached to the map)
+ */
+ FillExtrusionLayer::FillExtrusionLayer(mbgl::Map& map, mbgl::style::FillExtrusionLayer& coreLayer)
+ : Layer(map, coreLayer) {
+ }
+
+ /**
+ * Creates an owning peer object (for layers not attached to the map)
+ */
+ FillExtrusionLayer::FillExtrusionLayer(mbgl::Map& map, std::unique_ptr<mbgl::style::FillExtrusionLayer> coreLayer)
+ : Layer(map, std::move(coreLayer)) {
+ }
+
+ FillExtrusionLayer::~FillExtrusionLayer() = default;
+
+ // Property getters
+
+ jni::Object<jni::ObjectTag> FillExtrusionLayer::getFillExtrusionOpacity(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::FillExtrusionLayer>()->FillExtrusionLayer::getFillExtrusionOpacity());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<TransitionOptions> FillExtrusionLayer::getFillExtrusionOpacityTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::FillExtrusionLayer>()->FillExtrusionLayer::getFillExtrusionOpacityTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void FillExtrusionLayer::setFillExtrusionOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::FillExtrusionLayer>()->FillExtrusionLayer::setFillExtrusionOpacityTransition(options);
+ }
+
+ jni::Object<jni::ObjectTag> FillExtrusionLayer::getFillExtrusionColor(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::FillExtrusionLayer>()->FillExtrusionLayer::getFillExtrusionColor());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<TransitionOptions> FillExtrusionLayer::getFillExtrusionColorTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::FillExtrusionLayer>()->FillExtrusionLayer::getFillExtrusionColorTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void FillExtrusionLayer::setFillExtrusionColorTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::FillExtrusionLayer>()->FillExtrusionLayer::setFillExtrusionColorTransition(options);
+ }
+
+ jni::Object<jni::ObjectTag> FillExtrusionLayer::getFillExtrusionTranslate(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::FillExtrusionLayer>()->FillExtrusionLayer::getFillExtrusionTranslate());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<TransitionOptions> FillExtrusionLayer::getFillExtrusionTranslateTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::FillExtrusionLayer>()->FillExtrusionLayer::getFillExtrusionTranslateTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void FillExtrusionLayer::setFillExtrusionTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::FillExtrusionLayer>()->FillExtrusionLayer::setFillExtrusionTranslateTransition(options);
+ }
+
+ jni::Object<jni::ObjectTag> FillExtrusionLayer::getFillExtrusionTranslateAnchor(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::FillExtrusionLayer>()->FillExtrusionLayer::getFillExtrusionTranslateAnchor());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<jni::ObjectTag> FillExtrusionLayer::getFillExtrusionPattern(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::FillExtrusionLayer>()->FillExtrusionLayer::getFillExtrusionPattern());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<TransitionOptions> FillExtrusionLayer::getFillExtrusionPatternTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::FillExtrusionLayer>()->FillExtrusionLayer::getFillExtrusionPatternTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void FillExtrusionLayer::setFillExtrusionPatternTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::FillExtrusionLayer>()->FillExtrusionLayer::setFillExtrusionPatternTransition(options);
+ }
+
+ jni::Object<jni::ObjectTag> FillExtrusionLayer::getFillExtrusionHeight(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::FillExtrusionLayer>()->FillExtrusionLayer::getFillExtrusionHeight());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<TransitionOptions> FillExtrusionLayer::getFillExtrusionHeightTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::FillExtrusionLayer>()->FillExtrusionLayer::getFillExtrusionHeightTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void FillExtrusionLayer::setFillExtrusionHeightTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::FillExtrusionLayer>()->FillExtrusionLayer::setFillExtrusionHeightTransition(options);
+ }
+
+ jni::Object<jni::ObjectTag> FillExtrusionLayer::getFillExtrusionBase(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ Result<jni::jobject*> converted = convert<jni::jobject*>(env, layer.as<mbgl::style::FillExtrusionLayer>()->FillExtrusionLayer::getFillExtrusionBase());
+ return jni::Object<jni::ObjectTag>(*converted);
+ }
+
+ jni::Object<TransitionOptions> FillExtrusionLayer::getFillExtrusionBaseTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::FillExtrusionLayer>()->FillExtrusionLayer::getFillExtrusionBaseTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void FillExtrusionLayer::setFillExtrusionBaseTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::FillExtrusionLayer>()->FillExtrusionLayer::setFillExtrusionBaseTransition(options);
+ }
+
+
+ jni::Class<FillExtrusionLayer> FillExtrusionLayer::javaClass;
+
+ jni::jobject* FillExtrusionLayer::createJavaPeer(jni::JNIEnv& env) {
+ static auto constructor = FillExtrusionLayer::javaClass.template GetConstructor<jni::jlong>(env);
+ return FillExtrusionLayer::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this));
+ }
+
+ void FillExtrusionLayer::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ FillExtrusionLayer::javaClass = *jni::Class<FillExtrusionLayer>::Find(env).NewGlobalRef(env).release();
+
+ #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
+
+ // Register the peer
+ jni::RegisterNativePeer<FillExtrusionLayer>(
+ env, FillExtrusionLayer::javaClass, "nativePtr",
+ std::make_unique<FillExtrusionLayer, JNIEnv&, jni::String, jni::String>,
+ "initialize",
+ "finalize",
+ METHOD(&FillExtrusionLayer::getFillExtrusionOpacityTransition, "nativeGetFillExtrusionOpacityTransition"),
+ METHOD(&FillExtrusionLayer::setFillExtrusionOpacityTransition, "nativeSetFillExtrusionOpacityTransition"),
+ METHOD(&FillExtrusionLayer::getFillExtrusionOpacity, "nativeGetFillExtrusionOpacity"),
+ METHOD(&FillExtrusionLayer::getFillExtrusionColorTransition, "nativeGetFillExtrusionColorTransition"),
+ METHOD(&FillExtrusionLayer::setFillExtrusionColorTransition, "nativeSetFillExtrusionColorTransition"),
+ METHOD(&FillExtrusionLayer::getFillExtrusionColor, "nativeGetFillExtrusionColor"),
+ METHOD(&FillExtrusionLayer::getFillExtrusionTranslateTransition, "nativeGetFillExtrusionTranslateTransition"),
+ METHOD(&FillExtrusionLayer::setFillExtrusionTranslateTransition, "nativeSetFillExtrusionTranslateTransition"),
+ METHOD(&FillExtrusionLayer::getFillExtrusionTranslate, "nativeGetFillExtrusionTranslate"),
+ METHOD(&FillExtrusionLayer::getFillExtrusionTranslateAnchor, "nativeGetFillExtrusionTranslateAnchor"),
+ METHOD(&FillExtrusionLayer::getFillExtrusionPatternTransition, "nativeGetFillExtrusionPatternTransition"),
+ METHOD(&FillExtrusionLayer::setFillExtrusionPatternTransition, "nativeSetFillExtrusionPatternTransition"),
+ METHOD(&FillExtrusionLayer::getFillExtrusionPattern, "nativeGetFillExtrusionPattern"),
+ METHOD(&FillExtrusionLayer::getFillExtrusionHeightTransition, "nativeGetFillExtrusionHeightTransition"),
+ METHOD(&FillExtrusionLayer::setFillExtrusionHeightTransition, "nativeSetFillExtrusionHeightTransition"),
+ METHOD(&FillExtrusionLayer::getFillExtrusionHeight, "nativeGetFillExtrusionHeight"),
+ METHOD(&FillExtrusionLayer::getFillExtrusionBaseTransition, "nativeGetFillExtrusionBaseTransition"),
+ METHOD(&FillExtrusionLayer::setFillExtrusionBaseTransition, "nativeSetFillExtrusionBaseTransition"),
+ METHOD(&FillExtrusionLayer::getFillExtrusionBase, "nativeGetFillExtrusionBase"));
+ }
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/layers/fill_extrusion_layer.hpp b/platform/android/src/style/layers/fill_extrusion_layer.hpp
new file mode 100644
index 0000000000..11a74bc8ef
--- /dev/null
+++ b/platform/android/src/style/layers/fill_extrusion_layer.hpp
@@ -0,0 +1,62 @@
+// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
+
+#pragma once
+
+#include "layer.hpp"
+#include "../transition_options.hpp"
+#include <mbgl/style/layers/fill_extrusion_layer.hpp>
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class FillExtrusionLayer : public Layer {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/FillExtrusionLayer"; };
+
+ static jni::Class<FillExtrusionLayer> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+ FillExtrusionLayer(jni::JNIEnv&, jni::String, jni::String);
+
+ FillExtrusionLayer(mbgl::Map&, mbgl::style::FillExtrusionLayer&);
+
+ FillExtrusionLayer(mbgl::Map&, std::unique_ptr<mbgl::style::FillExtrusionLayer>);
+
+ ~FillExtrusionLayer();
+
+ // Properties
+
+ jni::Object<jni::ObjectTag> getFillExtrusionOpacity(jni::JNIEnv&);
+ void setFillExtrusionOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getFillExtrusionOpacityTransition(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getFillExtrusionColor(jni::JNIEnv&);
+ void setFillExtrusionColorTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getFillExtrusionColorTransition(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getFillExtrusionTranslate(jni::JNIEnv&);
+ void setFillExtrusionTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getFillExtrusionTranslateTransition(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getFillExtrusionTranslateAnchor(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getFillExtrusionPattern(jni::JNIEnv&);
+ void setFillExtrusionPatternTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getFillExtrusionPatternTransition(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getFillExtrusionHeight(jni::JNIEnv&);
+ void setFillExtrusionHeightTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getFillExtrusionHeightTransition(jni::JNIEnv&);
+
+ jni::Object<jni::ObjectTag> getFillExtrusionBase(jni::JNIEnv&);
+ void setFillExtrusionBaseTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getFillExtrusionBaseTransition(jni::JNIEnv&);
+ jni::jobject* createJavaPeer(jni::JNIEnv&);
+
+}; // class FillExtrusionLayer
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/layers/fill_layer.cpp b/platform/android/src/style/layers/fill_layer.cpp
index fc1dfccfcc..f4cddc8858 100644
--- a/platform/android/src/style/layers/fill_layer.cpp
+++ b/platform/android/src/style/layers/fill_layer.cpp
@@ -5,6 +5,7 @@
#include <string>
#include "../conversion/property_value.hpp"
+#include "../conversion/transition_options.hpp"
namespace mbgl {
namespace android {
@@ -46,24 +47,76 @@ namespace android {
return jni::Object<jni::ObjectTag>(*converted);
}
+ jni::Object<TransitionOptions> FillLayer::getFillOpacityTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::FillLayer>()->FillLayer::getFillOpacityTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void FillLayer::setFillOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::FillLayer>()->FillLayer::setFillOpacityTransition(options);
+ }
+
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<TransitionOptions> FillLayer::getFillColorTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::FillLayer>()->FillLayer::getFillColorTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void FillLayer::setFillColorTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::FillLayer>()->FillLayer::setFillColorTransition(options);
+ }
+
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<TransitionOptions> FillLayer::getFillOutlineColorTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::FillLayer>()->FillLayer::getFillOutlineColorTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void FillLayer::setFillOutlineColorTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::FillLayer>()->FillLayer::setFillOutlineColorTransition(options);
+ }
+
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<TransitionOptions> FillLayer::getFillTranslateTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::FillLayer>()->FillLayer::getFillTranslateTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void FillLayer::setFillTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::FillLayer>()->FillLayer::setFillTranslateTransition(options);
+ }
+
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());
@@ -76,6 +129,20 @@ namespace android {
return jni::Object<jni::ObjectTag>(*converted);
}
+ jni::Object<TransitionOptions> FillLayer::getFillPatternTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::FillLayer>()->FillLayer::getFillPatternTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void FillLayer::setFillPatternTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::FillLayer>()->FillLayer::setFillPatternTransition(options);
+ }
+
+
jni::Class<FillLayer> FillLayer::javaClass;
jni::jobject* FillLayer::createJavaPeer(jni::JNIEnv& env) {
@@ -96,11 +163,21 @@ namespace android {
"initialize",
"finalize",
METHOD(&FillLayer::getFillAntialias, "nativeGetFillAntialias"),
+ METHOD(&FillLayer::getFillOpacityTransition, "nativeGetFillOpacityTransition"),
+ METHOD(&FillLayer::setFillOpacityTransition, "nativeSetFillOpacityTransition"),
METHOD(&FillLayer::getFillOpacity, "nativeGetFillOpacity"),
+ METHOD(&FillLayer::getFillColorTransition, "nativeGetFillColorTransition"),
+ METHOD(&FillLayer::setFillColorTransition, "nativeSetFillColorTransition"),
METHOD(&FillLayer::getFillColor, "nativeGetFillColor"),
+ METHOD(&FillLayer::getFillOutlineColorTransition, "nativeGetFillOutlineColorTransition"),
+ METHOD(&FillLayer::setFillOutlineColorTransition, "nativeSetFillOutlineColorTransition"),
METHOD(&FillLayer::getFillOutlineColor, "nativeGetFillOutlineColor"),
+ METHOD(&FillLayer::getFillTranslateTransition, "nativeGetFillTranslateTransition"),
+ METHOD(&FillLayer::setFillTranslateTransition, "nativeSetFillTranslateTransition"),
METHOD(&FillLayer::getFillTranslate, "nativeGetFillTranslate"),
METHOD(&FillLayer::getFillTranslateAnchor, "nativeGetFillTranslateAnchor"),
+ METHOD(&FillLayer::getFillPatternTransition, "nativeGetFillPatternTransition"),
+ METHOD(&FillLayer::setFillPatternTransition, "nativeSetFillPatternTransition"),
METHOD(&FillLayer::getFillPattern, "nativeGetFillPattern"));
}
diff --git a/platform/android/src/style/layers/fill_layer.hpp b/platform/android/src/style/layers/fill_layer.hpp
index f43c263ab8..a773cf785b 100644
--- a/platform/android/src/style/layers/fill_layer.hpp
+++ b/platform/android/src/style/layers/fill_layer.hpp
@@ -3,6 +3,7 @@
#pragma once
#include "layer.hpp"
+#include "../transition_options.hpp"
#include <mbgl/style/layers/fill_layer.hpp>
#include <jni/jni.hpp>
@@ -26,21 +27,31 @@ public:
~FillLayer();
- // Property getters
+ // Properties
+
jni::Object<jni::ObjectTag> getFillAntialias(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getFillOpacity(jni::JNIEnv&);
+ void setFillOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getFillOpacityTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getFillColor(jni::JNIEnv&);
+ void setFillColorTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getFillColorTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getFillOutlineColor(jni::JNIEnv&);
+ void setFillOutlineColorTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getFillOutlineColorTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getFillTranslate(jni::JNIEnv&);
+ void setFillTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getFillTranslateTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getFillTranslateAnchor(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getFillPattern(jni::JNIEnv&);
-
+ void setFillPatternTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getFillPatternTransition(jni::JNIEnv&);
jni::jobject* createJavaPeer(jni::JNIEnv&);
}; // class FillLayer
diff --git a/platform/android/src/style/layers/layer.cpp b/platform/android/src/style/layers/layer.cpp
index dbf71fd2af..5352f9e548 100644
--- a/platform/android/src/style/layers/layer.cpp
+++ b/platform/android/src/style/layers/layer.cpp
@@ -3,6 +3,7 @@
#include <jni/jni.hpp>
+#include <mbgl/style/transition_options.hpp>
#include <mbgl/util/logging.hpp>
// Java -> C++ conversion
@@ -90,7 +91,7 @@ namespace android {
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>());
+ optional<mbgl::style::conversion::Error> error = mbgl::style::conversion::setPaintProperty(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;
@@ -104,9 +105,10 @@ namespace android {
Value wrapped(env, jfilter);
Filter filter;
- Result<Filter> converted = convert<Filter>(wrapped);
+ Error error;
+ optional<Filter> converted = convert<Filter>(wrapped, error);
if (!converted) {
- mbgl::Log::Error(mbgl::Event::JNI, "Error setting filter: " + converted.error().message);
+ mbgl::Log::Error(mbgl::Event::JNI, "Error setting filter: " + error.message);
return;
}
filter = std::move(*converted);
@@ -119,6 +121,8 @@ namespace android {
layer.as<SymbolLayer>()->setFilter(filter);
} else if (layer.is<CircleLayer>()) {
layer.as<CircleLayer>()->setFilter(filter);
+ } else if (layer.is<FillExtrusionLayer>()){
+ layer.as<FillExtrusionLayer>()->setFilter(filter);
} else {
mbgl::Log::Warning(mbgl::Event::JNI, "Layer doesn't support filters");
}
@@ -137,11 +141,34 @@ namespace android {
layer.as<SymbolLayer>()->setSourceLayer(layerId);
} else if (layer.is<CircleLayer>()) {
layer.as<CircleLayer>()->setSourceLayer(layerId);
+ } else if(layer.is<FillExtrusionLayer>()) {
+ layer.as<FillExtrusionLayer>()->setSourceLayer(layerId);
} else {
mbgl::Log::Warning(mbgl::Event::JNI, "Layer doesn't support source layer");
}
}
+ jni::String Layer::getSourceLayer(jni::JNIEnv& env) {
+ using namespace mbgl::style;
+
+ std::string sourceLayerId;
+ if (layer.is<FillLayer>()) {
+ sourceLayerId = layer.as<FillLayer>()->getSourceLayer();
+ } else if (layer.is<LineLayer>()) {
+ sourceLayerId = layer.as<LineLayer>()->getSourceLayer();
+ } else if (layer.is<SymbolLayer>()) {
+ sourceLayerId = layer.as<SymbolLayer>()->getSourceLayer();
+ } else if (layer.is<CircleLayer>()) {
+ sourceLayerId = layer.as<CircleLayer>()->getSourceLayer();
+ } else if (layer.is<FillExtrusionLayer>()) {
+ sourceLayerId = layer.as<FillExtrusionLayer>()->getSourceLayer();
+ } else {
+ mbgl::Log::Warning(mbgl::Event::JNI, "Layer doesn't support source layer");
+ }
+
+ return jni::Make<jni::String>(env, sourceLayerId);
+ }
+
jni::jfloat Layer::getMinZoom(jni::JNIEnv&){
return layer.getMinZoom();
}
@@ -178,6 +205,7 @@ namespace android {
METHOD(&Layer::setPaintProperty, "nativeSetPaintProperty"),
METHOD(&Layer::setFilter, "nativeSetFilter"),
METHOD(&Layer::setSourceLayer, "nativeSetSourceLayer"),
+ METHOD(&Layer::getSourceLayer, "nativeGetSourceLayer"),
METHOD(&Layer::getMinZoom, "nativeGetMinZoom"),
METHOD(&Layer::getMaxZoom, "nativeGetMaxZoom"),
METHOD(&Layer::setMinZoom, "nativeSetMinZoom"),
diff --git a/platform/android/src/style/layers/layer.cpp.ejs b/platform/android/src/style/layers/layer.cpp.ejs
index 5da397d77d..1debb096a3 100644
--- a/platform/android/src/style/layers/layer.cpp.ejs
+++ b/platform/android/src/style/layers/layer.cpp.ejs
@@ -9,6 +9,7 @@
#include <string>
#include "../conversion/property_value.hpp"
+#include "../conversion/transition_options.hpp"
namespace mbgl {
namespace android {
@@ -53,7 +54,23 @@ namespace android {
return jni::Object<jni::ObjectTag>(*converted);
}
+<% if (property.transition) { -%>
+ jni::Object<TransitionOptions> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>Transition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::<%- camelize(type) %>Layer>()-><%- camelize(type) %>Layer::get<%- camelize(property.name) %>Transition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>Transition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::<%- camelize(type) %>Layer>()-><%- camelize(type) %>Layer::set<%- camelize(property.name) %>Transition(options);
+ }
+
+<% } -%>
<% } -%>
+
jni::Class<<%- camelize(type) %>Layer> <%- camelize(type) %>Layer::javaClass;
jni::jobject* <%- camelize(type) %>Layer::createJavaPeer(jni::JNIEnv& env) {
@@ -77,8 +94,11 @@ namespace android {
<% } -%>
"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)) {-%>,<% } -%>
-<% } -%>);
+<% if (properties[i].transition) { -%>
+ METHOD(&<%- camelize(type) %>Layer::get<%- camelize(properties[i].name) %>Transition, "nativeGet<%- camelize(properties[i].name) %>Transition"),
+ METHOD(&<%- camelize(type) %>Layer::set<%- camelize(properties[i].name) %>Transition, "nativeSet<%- camelize(properties[i].name) %>Transition"),
+<% } -%>
+ METHOD(&<%- camelize(type) %>Layer::get<%- camelize(properties[i].name) %>, "nativeGet<%- camelize(properties[i].name) %>")<% if(i != (properties.length -1)) {-%>,<% } -%><% } -%>);
}
} // namespace android
diff --git a/platform/android/src/style/layers/layer.hpp b/platform/android/src/style/layers/layer.hpp
index deea7a6613..78c3f80b48 100644
--- a/platform/android/src/style/layers/layer.hpp
+++ b/platform/android/src/style/layers/layer.hpp
@@ -66,9 +66,11 @@ public:
/* common properties, but not shared by all */
- void setFilter(jni::JNIEnv& env, jni::Array<jni::Object<>> jfilter);
+ void setFilter(jni::JNIEnv&, jni::Array<jni::Object<>>);
- void setSourceLayer(jni::JNIEnv& env, jni::String sourceLayer);
+ void setSourceLayer(jni::JNIEnv&, jni::String);
+
+ jni::String getSourceLayer(jni::JNIEnv&);
// Property getters
diff --git a/platform/android/src/style/layers/layer.hpp.ejs b/platform/android/src/style/layers/layer.hpp.ejs
index 102efd2d4d..837049b4c3 100644
--- a/platform/android/src/style/layers/layer.hpp.ejs
+++ b/platform/android/src/style/layers/layer.hpp.ejs
@@ -7,6 +7,7 @@
#pragma once
#include "layer.hpp"
+#include "../transition_options.hpp"
#include <mbgl/style/layers/<%- type.replace('-', '_') %>_layer.hpp>
#include <jni/jni.hpp>
@@ -34,10 +35,14 @@ public:
~<%- camelize(type) %>Layer();
- // Property getters
+ // Properties
<% for (const property of properties) { -%>
- jni::Object<jni::ObjectTag> get<%- camelize(property.name) %>(jni::JNIEnv&);
+ jni::Object<jni::ObjectTag> get<%- camelize(property.name) %>(jni::JNIEnv&);
+<% if (property.transition) { -%>
+ void set<%- camelize(property.name) %>Transition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> get<%- camelize(property.name) %>Transition(jni::JNIEnv&);
+<% } -%>
<% } -%>
jni::jobject* createJavaPeer(jni::JNIEnv&);
diff --git a/platform/android/src/style/layers/layers.cpp b/platform/android/src/style/layers/layers.cpp
index 5c6ee1ae8f..5c49f875ee 100644
--- a/platform/android/src/style/layers/layers.cpp
+++ b/platform/android/src/style/layers/layers.cpp
@@ -3,6 +3,7 @@
#include <mbgl/style/layer.hpp>
#include <mbgl/style/layers/background_layer.hpp>
#include <mbgl/style/layers/circle_layer.hpp>
+#include <mbgl/style/layers/fill_extrusion_layer.hpp>
#include <mbgl/style/layers/fill_layer.hpp>
#include <mbgl/style/layers/line_layer.hpp>
#include <mbgl/style/layers/raster_layer.hpp>
@@ -12,11 +13,13 @@
#include "background_layer.hpp"
#include "circle_layer.hpp"
#include "custom_layer.hpp"
+#include "fill_extrusion_layer.hpp"
#include "fill_layer.hpp"
#include "line_layer.hpp"
#include "raster_layer.hpp"
#include "symbol_layer.hpp"
#include "unknown_layer.hpp"
+#include "fill_extrusion_layer.hpp"
namespace mbgl {
namespace android {
@@ -26,6 +29,8 @@ static Layer* initializeLayerPeer(mbgl::Map& map, mbgl::style::Layer& coreLayer)
return new BackgroundLayer(map, *coreLayer.as<mbgl::style::BackgroundLayer>());
} else if (coreLayer.is<mbgl::style::CircleLayer>()) {
return new CircleLayer(map, *coreLayer.as<mbgl::style::CircleLayer>());
+ } else if (coreLayer.is<mbgl::style::FillExtrusionLayer>()) {
+ return new FillExtrusionLayer(map, *coreLayer.as<mbgl::style::FillExtrusionLayer>());
} else if (coreLayer.is<mbgl::style::FillLayer>()) {
return new FillLayer(map, *coreLayer.as<mbgl::style::FillLayer>());
} else if (coreLayer.is<mbgl::style::LineLayer>()) {
@@ -51,6 +56,8 @@ static Layer* initializeLayerPeer(Map& map, std::unique_ptr<mbgl::style::Layer>
return createPeer<style::BackgroundLayer, BackgroundLayer>(map, std::move(coreLayer));
} else if (coreLayer->is<style::CircleLayer>()) {
return createPeer<style::CircleLayer, CircleLayer>(map, std::move(coreLayer));
+ } else if (coreLayer->is<style::FillExtrusionLayer>()) {
+ return createPeer<style::FillExtrusionLayer, FillExtrusionLayer>(map, std::move(coreLayer));
} else if (coreLayer->is<style::FillLayer>()) {
return createPeer<style::FillLayer, FillLayer>(map, std::move(coreLayer));
} else if (coreLayer->is<style::LineLayer>()) {
@@ -85,6 +92,7 @@ void registerNativeLayers(jni::JNIEnv& env) {
BackgroundLayer::registerNative(env);
CircleLayer::registerNative(env);
CustomLayer::registerNative(env);
+ FillExtrusionLayer::registerNative(env);
FillLayer::registerNative(env);
LineLayer::registerNative(env);
RasterLayer::registerNative(env);
diff --git a/platform/android/src/style/layers/line_layer.cpp b/platform/android/src/style/layers/line_layer.cpp
index 1a3a666a7b..af4e24523e 100644
--- a/platform/android/src/style/layers/line_layer.cpp
+++ b/platform/android/src/style/layers/line_layer.cpp
@@ -5,6 +5,7 @@
#include <string>
#include "../conversion/property_value.hpp"
+#include "../conversion/transition_options.hpp"
namespace mbgl {
namespace android {
@@ -64,18 +65,57 @@ namespace android {
return jni::Object<jni::ObjectTag>(*converted);
}
+ jni::Object<TransitionOptions> LineLayer::getLineOpacityTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::LineLayer>()->LineLayer::getLineOpacityTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void LineLayer::setLineOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::LineLayer>()->LineLayer::setLineOpacityTransition(options);
+ }
+
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<TransitionOptions> LineLayer::getLineColorTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::LineLayer>()->LineLayer::getLineColorTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void LineLayer::setLineColorTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::LineLayer>()->LineLayer::setLineColorTransition(options);
+ }
+
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<TransitionOptions> LineLayer::getLineTranslateTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::LineLayer>()->LineLayer::getLineTranslateTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void LineLayer::setLineTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::LineLayer>()->LineLayer::setLineTranslateTransition(options);
+ }
+
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());
@@ -88,36 +128,115 @@ namespace android {
return jni::Object<jni::ObjectTag>(*converted);
}
+ jni::Object<TransitionOptions> LineLayer::getLineWidthTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::LineLayer>()->LineLayer::getLineWidthTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void LineLayer::setLineWidthTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::LineLayer>()->LineLayer::setLineWidthTransition(options);
+ }
+
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<TransitionOptions> LineLayer::getLineGapWidthTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::LineLayer>()->LineLayer::getLineGapWidthTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void LineLayer::setLineGapWidthTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::LineLayer>()->LineLayer::setLineGapWidthTransition(options);
+ }
+
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<TransitionOptions> LineLayer::getLineOffsetTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::LineLayer>()->LineLayer::getLineOffsetTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void LineLayer::setLineOffsetTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::LineLayer>()->LineLayer::setLineOffsetTransition(options);
+ }
+
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<TransitionOptions> LineLayer::getLineBlurTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::LineLayer>()->LineLayer::getLineBlurTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void LineLayer::setLineBlurTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::LineLayer>()->LineLayer::setLineBlurTransition(options);
+ }
+
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<TransitionOptions> LineLayer::getLineDasharrayTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::LineLayer>()->LineLayer::getLineDasharrayTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void LineLayer::setLineDasharrayTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::LineLayer>()->LineLayer::setLineDasharrayTransition(options);
+ }
+
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::Object<TransitionOptions> LineLayer::getLinePatternTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::LineLayer>()->LineLayer::getLinePatternTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void LineLayer::setLinePatternTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::LineLayer>()->LineLayer::setLinePatternTransition(options);
+ }
+
+
jni::Class<LineLayer> LineLayer::javaClass;
jni::jobject* LineLayer::createJavaPeer(jni::JNIEnv& env) {
@@ -141,15 +260,33 @@ namespace android {
METHOD(&LineLayer::getLineJoin, "nativeGetLineJoin"),
METHOD(&LineLayer::getLineMiterLimit, "nativeGetLineMiterLimit"),
METHOD(&LineLayer::getLineRoundLimit, "nativeGetLineRoundLimit"),
+ METHOD(&LineLayer::getLineOpacityTransition, "nativeGetLineOpacityTransition"),
+ METHOD(&LineLayer::setLineOpacityTransition, "nativeSetLineOpacityTransition"),
METHOD(&LineLayer::getLineOpacity, "nativeGetLineOpacity"),
+ METHOD(&LineLayer::getLineColorTransition, "nativeGetLineColorTransition"),
+ METHOD(&LineLayer::setLineColorTransition, "nativeSetLineColorTransition"),
METHOD(&LineLayer::getLineColor, "nativeGetLineColor"),
+ METHOD(&LineLayer::getLineTranslateTransition, "nativeGetLineTranslateTransition"),
+ METHOD(&LineLayer::setLineTranslateTransition, "nativeSetLineTranslateTransition"),
METHOD(&LineLayer::getLineTranslate, "nativeGetLineTranslate"),
METHOD(&LineLayer::getLineTranslateAnchor, "nativeGetLineTranslateAnchor"),
+ METHOD(&LineLayer::getLineWidthTransition, "nativeGetLineWidthTransition"),
+ METHOD(&LineLayer::setLineWidthTransition, "nativeSetLineWidthTransition"),
METHOD(&LineLayer::getLineWidth, "nativeGetLineWidth"),
+ METHOD(&LineLayer::getLineGapWidthTransition, "nativeGetLineGapWidthTransition"),
+ METHOD(&LineLayer::setLineGapWidthTransition, "nativeSetLineGapWidthTransition"),
METHOD(&LineLayer::getLineGapWidth, "nativeGetLineGapWidth"),
+ METHOD(&LineLayer::getLineOffsetTransition, "nativeGetLineOffsetTransition"),
+ METHOD(&LineLayer::setLineOffsetTransition, "nativeSetLineOffsetTransition"),
METHOD(&LineLayer::getLineOffset, "nativeGetLineOffset"),
+ METHOD(&LineLayer::getLineBlurTransition, "nativeGetLineBlurTransition"),
+ METHOD(&LineLayer::setLineBlurTransition, "nativeSetLineBlurTransition"),
METHOD(&LineLayer::getLineBlur, "nativeGetLineBlur"),
+ METHOD(&LineLayer::getLineDasharrayTransition, "nativeGetLineDasharrayTransition"),
+ METHOD(&LineLayer::setLineDasharrayTransition, "nativeSetLineDasharrayTransition"),
METHOD(&LineLayer::getLineDasharray, "nativeGetLineDasharray"),
+ METHOD(&LineLayer::getLinePatternTransition, "nativeGetLinePatternTransition"),
+ METHOD(&LineLayer::setLinePatternTransition, "nativeSetLinePatternTransition"),
METHOD(&LineLayer::getLinePattern, "nativeGetLinePattern"));
}
diff --git a/platform/android/src/style/layers/line_layer.hpp b/platform/android/src/style/layers/line_layer.hpp
index a79c8b9021..84ecc77139 100644
--- a/platform/android/src/style/layers/line_layer.hpp
+++ b/platform/android/src/style/layers/line_layer.hpp
@@ -3,6 +3,7 @@
#pragma once
#include "layer.hpp"
+#include "../transition_options.hpp"
#include <mbgl/style/layers/line_layer.hpp>
#include <jni/jni.hpp>
@@ -26,7 +27,8 @@ public:
~LineLayer();
- // Property getters
+ // Properties
+
jni::Object<jni::ObjectTag> getLineCap(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getLineJoin(jni::JNIEnv&);
@@ -36,25 +38,42 @@ public:
jni::Object<jni::ObjectTag> getLineRoundLimit(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getLineOpacity(jni::JNIEnv&);
+ void setLineOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getLineOpacityTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getLineColor(jni::JNIEnv&);
+ void setLineColorTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getLineColorTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getLineTranslate(jni::JNIEnv&);
+ void setLineTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getLineTranslateTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getLineTranslateAnchor(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getLineWidth(jni::JNIEnv&);
+ void setLineWidthTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getLineWidthTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getLineGapWidth(jni::JNIEnv&);
+ void setLineGapWidthTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getLineGapWidthTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getLineOffset(jni::JNIEnv&);
+ void setLineOffsetTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getLineOffsetTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getLineBlur(jni::JNIEnv&);
+ void setLineBlurTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getLineBlurTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getLineDasharray(jni::JNIEnv&);
+ void setLineDasharrayTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getLineDasharrayTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getLinePattern(jni::JNIEnv&);
-
+ void setLinePatternTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getLinePatternTransition(jni::JNIEnv&);
jni::jobject* createJavaPeer(jni::JNIEnv&);
}; // class LineLayer
diff --git a/platform/android/src/style/layers/raster_layer.cpp b/platform/android/src/style/layers/raster_layer.cpp
index 8a324b88f2..98923d5129 100644
--- a/platform/android/src/style/layers/raster_layer.cpp
+++ b/platform/android/src/style/layers/raster_layer.cpp
@@ -5,6 +5,7 @@
#include <string>
#include "../conversion/property_value.hpp"
+#include "../conversion/transition_options.hpp"
namespace mbgl {
namespace android {
@@ -40,42 +41,134 @@ namespace android {
return jni::Object<jni::ObjectTag>(*converted);
}
+ jni::Object<TransitionOptions> RasterLayer::getRasterOpacityTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::RasterLayer>()->RasterLayer::getRasterOpacityTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void RasterLayer::setRasterOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::RasterLayer>()->RasterLayer::setRasterOpacityTransition(options);
+ }
+
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<TransitionOptions> RasterLayer::getRasterHueRotateTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::RasterLayer>()->RasterLayer::getRasterHueRotateTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void RasterLayer::setRasterHueRotateTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::RasterLayer>()->RasterLayer::setRasterHueRotateTransition(options);
+ }
+
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<TransitionOptions> RasterLayer::getRasterBrightnessMinTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::RasterLayer>()->RasterLayer::getRasterBrightnessMinTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void RasterLayer::setRasterBrightnessMinTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::RasterLayer>()->RasterLayer::setRasterBrightnessMinTransition(options);
+ }
+
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<TransitionOptions> RasterLayer::getRasterBrightnessMaxTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::RasterLayer>()->RasterLayer::getRasterBrightnessMaxTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void RasterLayer::setRasterBrightnessMaxTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::RasterLayer>()->RasterLayer::setRasterBrightnessMaxTransition(options);
+ }
+
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<TransitionOptions> RasterLayer::getRasterSaturationTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::RasterLayer>()->RasterLayer::getRasterSaturationTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void RasterLayer::setRasterSaturationTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::RasterLayer>()->RasterLayer::setRasterSaturationTransition(options);
+ }
+
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<TransitionOptions> RasterLayer::getRasterContrastTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::RasterLayer>()->RasterLayer::getRasterContrastTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void RasterLayer::setRasterContrastTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::RasterLayer>()->RasterLayer::setRasterContrastTransition(options);
+ }
+
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::Object<TransitionOptions> RasterLayer::getRasterFadeDurationTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::RasterLayer>()->RasterLayer::getRasterFadeDurationTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void RasterLayer::setRasterFadeDurationTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::RasterLayer>()->RasterLayer::setRasterFadeDurationTransition(options);
+ }
+
+
jni::Class<RasterLayer> RasterLayer::javaClass;
jni::jobject* RasterLayer::createJavaPeer(jni::JNIEnv& env) {
@@ -95,12 +188,26 @@ namespace android {
std::make_unique<RasterLayer, JNIEnv&, jni::String, jni::String>,
"initialize",
"finalize",
+ METHOD(&RasterLayer::getRasterOpacityTransition, "nativeGetRasterOpacityTransition"),
+ METHOD(&RasterLayer::setRasterOpacityTransition, "nativeSetRasterOpacityTransition"),
METHOD(&RasterLayer::getRasterOpacity, "nativeGetRasterOpacity"),
+ METHOD(&RasterLayer::getRasterHueRotateTransition, "nativeGetRasterHueRotateTransition"),
+ METHOD(&RasterLayer::setRasterHueRotateTransition, "nativeSetRasterHueRotateTransition"),
METHOD(&RasterLayer::getRasterHueRotate, "nativeGetRasterHueRotate"),
+ METHOD(&RasterLayer::getRasterBrightnessMinTransition, "nativeGetRasterBrightnessMinTransition"),
+ METHOD(&RasterLayer::setRasterBrightnessMinTransition, "nativeSetRasterBrightnessMinTransition"),
METHOD(&RasterLayer::getRasterBrightnessMin, "nativeGetRasterBrightnessMin"),
+ METHOD(&RasterLayer::getRasterBrightnessMaxTransition, "nativeGetRasterBrightnessMaxTransition"),
+ METHOD(&RasterLayer::setRasterBrightnessMaxTransition, "nativeSetRasterBrightnessMaxTransition"),
METHOD(&RasterLayer::getRasterBrightnessMax, "nativeGetRasterBrightnessMax"),
+ METHOD(&RasterLayer::getRasterSaturationTransition, "nativeGetRasterSaturationTransition"),
+ METHOD(&RasterLayer::setRasterSaturationTransition, "nativeSetRasterSaturationTransition"),
METHOD(&RasterLayer::getRasterSaturation, "nativeGetRasterSaturation"),
+ METHOD(&RasterLayer::getRasterContrastTransition, "nativeGetRasterContrastTransition"),
+ METHOD(&RasterLayer::setRasterContrastTransition, "nativeSetRasterContrastTransition"),
METHOD(&RasterLayer::getRasterContrast, "nativeGetRasterContrast"),
+ METHOD(&RasterLayer::getRasterFadeDurationTransition, "nativeGetRasterFadeDurationTransition"),
+ METHOD(&RasterLayer::setRasterFadeDurationTransition, "nativeSetRasterFadeDurationTransition"),
METHOD(&RasterLayer::getRasterFadeDuration, "nativeGetRasterFadeDuration"));
}
diff --git a/platform/android/src/style/layers/raster_layer.hpp b/platform/android/src/style/layers/raster_layer.hpp
index 2f5d4f6fcd..3b119ee0d2 100644
--- a/platform/android/src/style/layers/raster_layer.hpp
+++ b/platform/android/src/style/layers/raster_layer.hpp
@@ -3,6 +3,7 @@
#pragma once
#include "layer.hpp"
+#include "../transition_options.hpp"
#include <mbgl/style/layers/raster_layer.hpp>
#include <jni/jni.hpp>
@@ -26,21 +27,35 @@ public:
~RasterLayer();
- // Property getters
+ // Properties
+
jni::Object<jni::ObjectTag> getRasterOpacity(jni::JNIEnv&);
+ void setRasterOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getRasterOpacityTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getRasterHueRotate(jni::JNIEnv&);
+ void setRasterHueRotateTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getRasterHueRotateTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getRasterBrightnessMin(jni::JNIEnv&);
+ void setRasterBrightnessMinTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getRasterBrightnessMinTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getRasterBrightnessMax(jni::JNIEnv&);
+ void setRasterBrightnessMaxTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getRasterBrightnessMaxTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getRasterSaturation(jni::JNIEnv&);
+ void setRasterSaturationTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getRasterSaturationTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getRasterContrast(jni::JNIEnv&);
+ void setRasterContrastTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getRasterContrastTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getRasterFadeDuration(jni::JNIEnv&);
-
+ void setRasterFadeDurationTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getRasterFadeDurationTransition(jni::JNIEnv&);
jni::jobject* createJavaPeer(jni::JNIEnv&);
}; // class RasterLayer
diff --git a/platform/android/src/style/layers/symbol_layer.cpp b/platform/android/src/style/layers/symbol_layer.cpp
index e42eeb4c77..3a560a5deb 100644
--- a/platform/android/src/style/layers/symbol_layer.cpp
+++ b/platform/android/src/style/layers/symbol_layer.cpp
@@ -5,6 +5,7 @@
#include <string>
#include "../conversion/property_value.hpp"
+#include "../conversion/transition_options.hpp"
namespace mbgl {
namespace android {
@@ -244,36 +245,114 @@ namespace android {
return jni::Object<jni::ObjectTag>(*converted);
}
+ jni::Object<TransitionOptions> SymbolLayer::getIconOpacityTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getIconOpacityTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void SymbolLayer::setIconOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::setIconOpacityTransition(options);
+ }
+
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<TransitionOptions> SymbolLayer::getIconColorTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getIconColorTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void SymbolLayer::setIconColorTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::setIconColorTransition(options);
+ }
+
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<TransitionOptions> SymbolLayer::getIconHaloColorTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getIconHaloColorTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void SymbolLayer::setIconHaloColorTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::setIconHaloColorTransition(options);
+ }
+
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<TransitionOptions> SymbolLayer::getIconHaloWidthTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getIconHaloWidthTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void SymbolLayer::setIconHaloWidthTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::setIconHaloWidthTransition(options);
+ }
+
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<TransitionOptions> SymbolLayer::getIconHaloBlurTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getIconHaloBlurTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void SymbolLayer::setIconHaloBlurTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::setIconHaloBlurTransition(options);
+ }
+
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<TransitionOptions> SymbolLayer::getIconTranslateTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getIconTranslateTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void SymbolLayer::setIconTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::setIconTranslateTransition(options);
+ }
+
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());
@@ -286,42 +365,121 @@ namespace android {
return jni::Object<jni::ObjectTag>(*converted);
}
+ jni::Object<TransitionOptions> SymbolLayer::getTextOpacityTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getTextOpacityTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void SymbolLayer::setTextOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::setTextOpacityTransition(options);
+ }
+
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<TransitionOptions> SymbolLayer::getTextColorTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getTextColorTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void SymbolLayer::setTextColorTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::setTextColorTransition(options);
+ }
+
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<TransitionOptions> SymbolLayer::getTextHaloColorTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getTextHaloColorTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void SymbolLayer::setTextHaloColorTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::setTextHaloColorTransition(options);
+ }
+
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<TransitionOptions> SymbolLayer::getTextHaloWidthTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getTextHaloWidthTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void SymbolLayer::setTextHaloWidthTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::setTextHaloWidthTransition(options);
+ }
+
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<TransitionOptions> SymbolLayer::getTextHaloBlurTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getTextHaloBlurTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void SymbolLayer::setTextHaloBlurTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::setTextHaloBlurTransition(options);
+ }
+
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<TransitionOptions> SymbolLayer::getTextTranslateTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::getTextTranslateTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+ }
+
+ void SymbolLayer::setTextTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ layer.as<mbgl::style::SymbolLayer>()->SymbolLayer::setTextTranslateTransition(options);
+ }
+
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) {
@@ -375,18 +533,42 @@ namespace android {
METHOD(&SymbolLayer::getTextAllowOverlap, "nativeGetTextAllowOverlap"),
METHOD(&SymbolLayer::getTextIgnorePlacement, "nativeGetTextIgnorePlacement"),
METHOD(&SymbolLayer::getTextOptional, "nativeGetTextOptional"),
+ METHOD(&SymbolLayer::getIconOpacityTransition, "nativeGetIconOpacityTransition"),
+ METHOD(&SymbolLayer::setIconOpacityTransition, "nativeSetIconOpacityTransition"),
METHOD(&SymbolLayer::getIconOpacity, "nativeGetIconOpacity"),
+ METHOD(&SymbolLayer::getIconColorTransition, "nativeGetIconColorTransition"),
+ METHOD(&SymbolLayer::setIconColorTransition, "nativeSetIconColorTransition"),
METHOD(&SymbolLayer::getIconColor, "nativeGetIconColor"),
+ METHOD(&SymbolLayer::getIconHaloColorTransition, "nativeGetIconHaloColorTransition"),
+ METHOD(&SymbolLayer::setIconHaloColorTransition, "nativeSetIconHaloColorTransition"),
METHOD(&SymbolLayer::getIconHaloColor, "nativeGetIconHaloColor"),
+ METHOD(&SymbolLayer::getIconHaloWidthTransition, "nativeGetIconHaloWidthTransition"),
+ METHOD(&SymbolLayer::setIconHaloWidthTransition, "nativeSetIconHaloWidthTransition"),
METHOD(&SymbolLayer::getIconHaloWidth, "nativeGetIconHaloWidth"),
+ METHOD(&SymbolLayer::getIconHaloBlurTransition, "nativeGetIconHaloBlurTransition"),
+ METHOD(&SymbolLayer::setIconHaloBlurTransition, "nativeSetIconHaloBlurTransition"),
METHOD(&SymbolLayer::getIconHaloBlur, "nativeGetIconHaloBlur"),
+ METHOD(&SymbolLayer::getIconTranslateTransition, "nativeGetIconTranslateTransition"),
+ METHOD(&SymbolLayer::setIconTranslateTransition, "nativeSetIconTranslateTransition"),
METHOD(&SymbolLayer::getIconTranslate, "nativeGetIconTranslate"),
METHOD(&SymbolLayer::getIconTranslateAnchor, "nativeGetIconTranslateAnchor"),
+ METHOD(&SymbolLayer::getTextOpacityTransition, "nativeGetTextOpacityTransition"),
+ METHOD(&SymbolLayer::setTextOpacityTransition, "nativeSetTextOpacityTransition"),
METHOD(&SymbolLayer::getTextOpacity, "nativeGetTextOpacity"),
+ METHOD(&SymbolLayer::getTextColorTransition, "nativeGetTextColorTransition"),
+ METHOD(&SymbolLayer::setTextColorTransition, "nativeSetTextColorTransition"),
METHOD(&SymbolLayer::getTextColor, "nativeGetTextColor"),
+ METHOD(&SymbolLayer::getTextHaloColorTransition, "nativeGetTextHaloColorTransition"),
+ METHOD(&SymbolLayer::setTextHaloColorTransition, "nativeSetTextHaloColorTransition"),
METHOD(&SymbolLayer::getTextHaloColor, "nativeGetTextHaloColor"),
+ METHOD(&SymbolLayer::getTextHaloWidthTransition, "nativeGetTextHaloWidthTransition"),
+ METHOD(&SymbolLayer::setTextHaloWidthTransition, "nativeSetTextHaloWidthTransition"),
METHOD(&SymbolLayer::getTextHaloWidth, "nativeGetTextHaloWidth"),
+ METHOD(&SymbolLayer::getTextHaloBlurTransition, "nativeGetTextHaloBlurTransition"),
+ METHOD(&SymbolLayer::setTextHaloBlurTransition, "nativeSetTextHaloBlurTransition"),
METHOD(&SymbolLayer::getTextHaloBlur, "nativeGetTextHaloBlur"),
+ METHOD(&SymbolLayer::getTextTranslateTransition, "nativeGetTextTranslateTransition"),
+ METHOD(&SymbolLayer::setTextTranslateTransition, "nativeSetTextTranslateTransition"),
METHOD(&SymbolLayer::getTextTranslate, "nativeGetTextTranslate"),
METHOD(&SymbolLayer::getTextTranslateAnchor, "nativeGetTextTranslateAnchor"));
}
diff --git a/platform/android/src/style/layers/symbol_layer.hpp b/platform/android/src/style/layers/symbol_layer.hpp
index 98ce5572e9..8366051c6e 100644
--- a/platform/android/src/style/layers/symbol_layer.hpp
+++ b/platform/android/src/style/layers/symbol_layer.hpp
@@ -3,6 +3,7 @@
#pragma once
#include "layer.hpp"
+#include "../transition_options.hpp"
#include <mbgl/style/layers/symbol_layer.hpp>
#include <jni/jni.hpp>
@@ -26,7 +27,8 @@ public:
~SymbolLayer();
- // Property getters
+ // Properties
+
jni::Object<jni::ObjectTag> getSymbolPlacement(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getSymbolSpacing(jni::JNIEnv&);
@@ -96,33 +98,56 @@ public:
jni::Object<jni::ObjectTag> getTextOptional(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getIconOpacity(jni::JNIEnv&);
+ void setIconOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getIconOpacityTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getIconColor(jni::JNIEnv&);
+ void setIconColorTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getIconColorTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getIconHaloColor(jni::JNIEnv&);
+ void setIconHaloColorTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getIconHaloColorTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getIconHaloWidth(jni::JNIEnv&);
+ void setIconHaloWidthTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getIconHaloWidthTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getIconHaloBlur(jni::JNIEnv&);
+ void setIconHaloBlurTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getIconHaloBlurTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getIconTranslate(jni::JNIEnv&);
+ void setIconTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getIconTranslateTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getIconTranslateAnchor(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getTextOpacity(jni::JNIEnv&);
+ void setTextOpacityTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getTextOpacityTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getTextColor(jni::JNIEnv&);
+ void setTextColorTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getTextColorTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getTextHaloColor(jni::JNIEnv&);
+ void setTextHaloColorTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getTextHaloColorTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getTextHaloWidth(jni::JNIEnv&);
+ void setTextHaloWidthTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getTextHaloWidthTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getTextHaloBlur(jni::JNIEnv&);
+ void setTextHaloBlurTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getTextHaloBlurTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getTextTranslate(jni::JNIEnv&);
+ void setTextTranslateTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getTextTranslateTransition(jni::JNIEnv&);
jni::Object<jni::ObjectTag> getTextTranslateAnchor(jni::JNIEnv&);
-
jni::jobject* createJavaPeer(jni::JNIEnv&);
}; // class SymbolLayer
diff --git a/platform/android/src/style/layers/unknown_layer.cpp b/platform/android/src/style/layers/unknown_layer.cpp
index 9ec963a41b..8ffda82bfc 100644
--- a/platform/android/src/style/layers/unknown_layer.cpp
+++ b/platform/android/src/style/layers/unknown_layer.cpp
@@ -6,7 +6,7 @@ namespace {
// Dummy initializer (We don't support initializing this from the JVM)
std::unique_ptr<mbgl::android::UnknownLayer> init(jni::JNIEnv&) {
- throw new std::runtime_error("UnknownLayer should not be initialized from the JVM");
+ throw std::runtime_error("UnknownLayer should not be initialized from the JVM");
}
} // namespace
diff --git a/platform/android/src/style/sources/geojson_source.cpp b/platform/android/src/style/sources/geojson_source.cpp
index 7ab98e47c0..780cc4b6f6 100644
--- a/platform/android/src/style/sources/geojson_source.cpp
+++ b/platform/android/src/style/sources/geojson_source.cpp
@@ -8,7 +8,7 @@
// C++ -> Java conversion
#include "../../conversion/conversion.hpp"
#include "../../conversion/collection.hpp"
-#include "../../geometry/conversion/feature.hpp"
+#include "../../geojson/conversion/feature.hpp"
#include "../conversion/url_or_tileset.hpp"
#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/geojson_options.hpp>
@@ -18,11 +18,26 @@
namespace mbgl {
namespace android {
+ // This conversion is expected not to fail because it's used only in contexts where
+ // the value was originally a GeoJsonOptions object on the Java side. If it fails
+ // to convert, it's a bug in our serialization or Java-side static typing.
+ static style::GeoJSONOptions convertGeoJSONOptions(jni::JNIEnv& env, jni::Object<> options) {
+ using namespace mbgl::style::conversion;
+ if (!options) {
+ return style::GeoJSONOptions();
+ }
+ Error error;
+ optional<style::GeoJSONOptions> result = convert<style::GeoJSONOptions>(Value(env, options), error);
+ if (!result) {
+ throw std::logic_error(error.message);
+ }
+ return *result;
+ }
+
GeoJSONSource::GeoJSONSource(jni::JNIEnv& env, jni::String sourceId, jni::Object<> options)
: Source(env, std::make_unique<mbgl::style::GeoJSONSource>(
jni::Make<std::string>(env, sourceId),
- options ? *style::conversion::convert<style::GeoJSONOptions>(Value(env, options)) : style::GeoJSONOptions()
- )
+ convertGeoJSONOptions(env, options))
) {
}
@@ -32,13 +47,14 @@ namespace android {
GeoJSONSource::~GeoJSONSource() = default;
- void GeoJSONSource::setGeoJSON(jni::JNIEnv& env, jni::Object<> json) {
+ void GeoJSONSource::setGeoJSONString(jni::JNIEnv& env, jni::String json) {
using namespace mbgl::style::conversion;
// Convert the jni object
- Result<GeoJSON> converted = convert<GeoJSON>(Value(env, json));
+ Error error;
+ optional<GeoJSON> converted = convert<GeoJSON>(Value(env, json), error);
if(!converted) {
- mbgl::Log::Error(mbgl::Event::JNI, "Error setting geo json: " + converted.error().message);
+ mbgl::Log::Error(mbgl::Event::JNI, "Error setting geo json: " + error.message);
return;
}
@@ -46,18 +62,55 @@ namespace android {
source.as<mbgl::style::GeoJSONSource>()->GeoJSONSource::setGeoJSON(*converted);
}
+ void GeoJSONSource::setFeatureCollection(jni::JNIEnv& env, jni::Object<geojson::FeatureCollection> jFeatures) {
+ using namespace mbgl::android::geojson;
+
+ // Convert the jni object
+ auto features = FeatureCollection::convert(env, jFeatures);
+
+ // Update the core source
+ source.as<mbgl::style::GeoJSONSource>()->GeoJSONSource::setGeoJSON(GeoJSON(features));
+ }
+
+ void GeoJSONSource::setFeature(jni::JNIEnv& env, jni::Object<geojson::Feature> jFeature) {
+ using namespace mbgl::android::geojson;
+
+ // Convert the jni object
+ auto feature = Feature::convert(env, jFeature);
+
+ // Update the core source
+ source.as<mbgl::style::GeoJSONSource>()->GeoJSONSource::setGeoJSON(GeoJSON(feature));
+ }
+
+ void GeoJSONSource::setGeometry(jni::JNIEnv& env, jni::Object<geojson::Geometry> jGeometry) {
+ using namespace mbgl::android::geojson;
+
+ // Convert the jni object
+ auto geometry = Geometry::convert(env, jGeometry);
+
+ // Update the core source
+ source.as<mbgl::style::GeoJSONSource>()->GeoJSONSource::setGeoJSON(GeoJSON(geometry));
+ }
+
void GeoJSONSource::setURL(jni::JNIEnv& env, jni::String url) {
// Update the core source
source.as<mbgl::style::GeoJSONSource>()->GeoJSONSource::setURL(jni::Make<std::string>(env, url));
}
- jni::Array<jni::Object<Feature>> GeoJSONSource::querySourceFeatures(jni::JNIEnv& env,
+ jni::String GeoJSONSource::getURL(jni::JNIEnv& env) {
+ optional<std::string> url = source.as<mbgl::style::GeoJSONSource>()->GeoJSONSource::getURL();
+ return url ? jni::Make<jni::String>(env, *url) : jni::String();
+ }
+
+ jni::Array<jni::Object<geojson::Feature>> GeoJSONSource::querySourceFeatures(jni::JNIEnv& env,
jni::Array<jni::Object<>> jfilter) {
using namespace mbgl::android::conversion;
- using namespace mapbox::geometry;
+ using namespace mbgl::android::geojson;
- auto filter = toFilter(env, jfilter);
- auto features = source.querySourceFeatures({ {}, filter });
+ std::vector<mbgl::Feature> features;
+ if (map) {
+ features = map->querySourceFeatures(source.getID(), { {}, toFilter(env, jfilter) });
+ }
return *convert<jni::Array<jni::Object<Feature>>, std::vector<mbgl::Feature>>(env, features);
}
@@ -80,8 +133,12 @@ namespace android {
std::make_unique<GeoJSONSource, JNIEnv&, jni::String, jni::Object<>>,
"initialize",
"finalize",
- METHOD(&GeoJSONSource::setGeoJSON, "nativeSetGeoJson"),
+ METHOD(&GeoJSONSource::setGeoJSONString, "nativeSetGeoJsonString"),
+ METHOD(&GeoJSONSource::setFeatureCollection, "nativeSetFeatureCollection"),
+ METHOD(&GeoJSONSource::setFeature, "nativeSetFeature"),
+ METHOD(&GeoJSONSource::setGeometry, "nativeSetGeometry"),
METHOD(&GeoJSONSource::setURL, "nativeSetUrl"),
+ METHOD(&GeoJSONSource::getURL, "nativeGetUrl"),
METHOD(&GeoJSONSource::querySourceFeatures, "querySourceFeatures")
);
}
diff --git a/platform/android/src/style/sources/geojson_source.hpp b/platform/android/src/style/sources/geojson_source.hpp
index 5b529fc52a..938a20612c 100644
--- a/platform/android/src/style/sources/geojson_source.hpp
+++ b/platform/android/src/style/sources/geojson_source.hpp
@@ -2,7 +2,9 @@
#include "source.hpp"
#include <mbgl/style/sources/geojson_source.hpp>
-#include "../../geometry/feature.hpp"
+#include "../../geojson/geometry.hpp"
+#include "../../geojson/feature.hpp"
+#include "../../geojson/feature_collection.hpp"
#include <jni/jni.hpp>
namespace mbgl {
@@ -23,11 +25,20 @@ public:
~GeoJSONSource();
- void setGeoJSON(jni::JNIEnv&, jni::Object<>);
+ void setGeoJSONString(jni::JNIEnv&, jni::String);
+
+ void setFeatureCollection(jni::JNIEnv&, jni::Object<geojson::FeatureCollection>);
+
+ void setFeature(jni::JNIEnv&, jni::Object<geojson::Feature>);
+
+ void setGeometry(jni::JNIEnv&, jni::Object<geojson::Geometry>);
void setURL(jni::JNIEnv&, jni::String);
- jni::Array<jni::Object<Feature>> querySourceFeatures(jni::JNIEnv&, jni::Array<jni::Object<>> jfilter);
+ jni::Array<jni::Object<geojson::Feature>> querySourceFeatures(jni::JNIEnv&,
+ jni::Array<jni::Object<>> jfilter);
+
+ jni::String getURL(jni::JNIEnv&);
jni::jobject* createJavaPeer(jni::JNIEnv&);
diff --git a/platform/android/src/style/sources/raster_source.cpp b/platform/android/src/style/sources/raster_source.cpp
index 42ac4cda99..32fdb163b0 100644
--- a/platform/android/src/style/sources/raster_source.cpp
+++ b/platform/android/src/style/sources/raster_source.cpp
@@ -16,7 +16,7 @@ namespace android {
env,
std::make_unique<mbgl::style::RasterSource>(
jni::Make<std::string>(env, sourceId),
- *style::conversion::convert<variant<std::string, Tileset>>(Value(env, urlOrTileSet)),
+ convertURLOrTileset(Value(env, urlOrTileSet)),
tileSize
)
) {
@@ -28,6 +28,11 @@ namespace android {
RasterSource::~RasterSource() = default;
+ jni::String RasterSource::getURL(jni::JNIEnv& env) {
+ optional<std::string> url = source.as<mbgl::style::RasterSource>()->RasterSource::getURL();
+ return url ? jni::Make<jni::String>(env, *url) : jni::String();
+ }
+
jni::Class<RasterSource> RasterSource::javaClass;
jni::jobject* RasterSource::createJavaPeer(jni::JNIEnv& env) {
@@ -46,7 +51,8 @@ namespace android {
env, RasterSource::javaClass, "nativePtr",
std::make_unique<RasterSource, JNIEnv&, jni::String, jni::Object<>, jni::jint>,
"initialize",
- "finalize"
+ "finalize",
+ METHOD(&RasterSource::getURL, "nativeGetUrl")
);
}
diff --git a/platform/android/src/style/sources/raster_source.hpp b/platform/android/src/style/sources/raster_source.hpp
index 6600096f6d..a79ccc10a4 100644
--- a/platform/android/src/style/sources/raster_source.hpp
+++ b/platform/android/src/style/sources/raster_source.hpp
@@ -22,6 +22,8 @@ public:
~RasterSource();
+ jni::String getURL(jni::JNIEnv&);
+
jni::jobject* createJavaPeer(jni::JNIEnv&);
}; // class RasterSource
diff --git a/platform/android/src/style/sources/source.cpp b/platform/android/src/style/sources/source.cpp
index b780de5627..e0e9bb9870 100644
--- a/platform/android/src/style/sources/source.cpp
+++ b/platform/android/src/style/sources/source.cpp
@@ -43,6 +43,11 @@ namespace android {
return jni::Make<jni::String>(env, source.getID());
}
+ jni::String Source::getAttribution(jni::JNIEnv& env) {
+ auto attribution = source.getAttribution();
+ return attribution ? jni::Make<jni::String>(env, attribution.value()) : jni::Make<jni::String>(env,"");
+ }
+
void Source::addToMap(mbgl::Map& _map) {
// Check to see if we own the source first
if (!ownedSource) {
@@ -71,7 +76,8 @@ namespace android {
// Register the peer
jni::RegisterNativePeer<Source>(env, Source::javaClass, "nativePtr",
- METHOD(&Source::getId, "nativeGetId")
+ METHOD(&Source::getId, "nativeGetId"),
+ METHOD(&Source::getAttribution, "nativeGetAttribution")
);
}
diff --git a/platform/android/src/style/sources/source.hpp b/platform/android/src/style/sources/source.hpp
index 9a9d504d68..49fc50d754 100644
--- a/platform/android/src/style/sources/source.hpp
+++ b/platform/android/src/style/sources/source.hpp
@@ -45,6 +45,8 @@ public:
jni::String getId(jni::JNIEnv&);
+ jni::String getAttribution(jni::JNIEnv&);
+
protected:
// Release the owned view and return it
std::unique_ptr<mbgl::style::Source> releaseCoreSource();
diff --git a/platform/android/src/style/sources/unknown_source.cpp b/platform/android/src/style/sources/unknown_source.cpp
index c1b1cc8c02..86736597c3 100644
--- a/platform/android/src/style/sources/unknown_source.cpp
+++ b/platform/android/src/style/sources/unknown_source.cpp
@@ -4,7 +4,7 @@ namespace {
// Dummy initializer (We don't support initializing this from the JVM)
std::unique_ptr<mbgl::android::UnknownSource> init(jni::JNIEnv&) {
- throw new std::runtime_error("UnknownSource should not be initialized from the JVM");
+ throw std::runtime_error("UnknownSource should not be initialized from the JVM");
}
} // namespace
diff --git a/platform/android/src/style/sources/vector_source.cpp b/platform/android/src/style/sources/vector_source.cpp
index 67777f50d4..e2d9f60dec 100644
--- a/platform/android/src/style/sources/vector_source.cpp
+++ b/platform/android/src/style/sources/vector_source.cpp
@@ -7,7 +7,7 @@
// C++ -> Java conversion
#include "../../conversion/conversion.hpp"
#include "../../conversion/collection.hpp"
-#include "../../geometry/conversion/feature.hpp"
+#include "../../geojson/conversion/feature.hpp"
#include "../conversion/url_or_tileset.hpp"
#include <mbgl/util/variant.hpp>
@@ -23,7 +23,7 @@ namespace android {
env,
std::make_unique<mbgl::style::VectorSource>(
jni::Make<std::string>(env, sourceId),
- *style::conversion::convert<variant<std::string, Tileset>>(Value(env, urlOrTileSet))
+ convertURLOrTileset(Value(env, urlOrTileSet))
)
) {
}
@@ -34,15 +34,21 @@ namespace android {
VectorSource::~VectorSource() = default;
- jni::Array<jni::Object<Feature>> VectorSource::querySourceFeatures(jni::JNIEnv& env,
+ jni::String VectorSource::getURL(jni::JNIEnv& env) {
+ optional<std::string> url = source.as<mbgl::style::VectorSource>()->VectorSource::getURL();
+ return url ? jni::Make<jni::String>(env, *url) : jni::String();
+ }
+
+ jni::Array<jni::Object<geojson::Feature>> VectorSource::querySourceFeatures(jni::JNIEnv& env,
jni::Array<jni::String> jSourceLayerIds,
jni::Array<jni::Object<>> jfilter) {
using namespace mbgl::android::conversion;
- using namespace mapbox::geometry;
+ using namespace mbgl::android::geojson;
- mbgl::optional<std::vector<std::string>> sourceLayerIds = { toVector(env, jSourceLayerIds) };
- auto filter = toFilter(env, jfilter);
- auto features = source.querySourceFeatures({ sourceLayerIds, filter });
+ std::vector<mbgl::Feature> features;
+ if (map) {
+ features = map->querySourceFeatures(source.getID(), { toVector(env, jSourceLayerIds), toFilter(env, jfilter) });
+ }
return *convert<jni::Array<jni::Object<Feature>>, std::vector<mbgl::Feature>>(env, features);
}
@@ -65,7 +71,8 @@ namespace android {
std::make_unique<VectorSource, JNIEnv&, jni::String, jni::Object<>>,
"initialize",
"finalize",
- METHOD(&VectorSource::querySourceFeatures, "querySourceFeatures")
+ METHOD(&VectorSource::querySourceFeatures, "querySourceFeatures"),
+ METHOD(&VectorSource::getURL, "nativeGetUrl")
);
}
diff --git a/platform/android/src/style/sources/vector_source.hpp b/platform/android/src/style/sources/vector_source.hpp
index f7e7645c5b..643b468338 100644
--- a/platform/android/src/style/sources/vector_source.hpp
+++ b/platform/android/src/style/sources/vector_source.hpp
@@ -2,7 +2,7 @@
#include "source.hpp"
#include <mbgl/style/sources/vector_source.hpp>
-#include "../../geometry/feature.hpp"
+#include "../../geojson/feature.hpp"
#include <jni/jni.hpp>
namespace mbgl {
@@ -23,8 +23,10 @@ public:
~VectorSource();
- jni::Array<jni::Object<Feature>> querySourceFeatures(jni::JNIEnv&, jni::Array<jni::String>,
- jni::Array<jni::Object<>> jfilter);
+ jni::Array<jni::Object<geojson::Feature>> querySourceFeatures(jni::JNIEnv&, jni::Array<jni::String>,
+ jni::Array<jni::Object<>> jfilter);
+
+ jni::String getURL(jni::JNIEnv&);
jni::jobject* createJavaPeer(jni::JNIEnv&);
diff --git a/platform/android/src/style/transition_options.cpp b/platform/android/src/style/transition_options.cpp
new file mode 100644
index 0000000000..c70aa5fe2e
--- /dev/null
+++ b/platform/android/src/style/transition_options.cpp
@@ -0,0 +1,20 @@
+#include "transition_options.hpp"
+
+namespace mbgl {
+namespace android {
+
+jni::Object<TransitionOptions> TransitionOptions::fromTransitionOptions(jni::JNIEnv& env, jlong duration, jlong delay) {
+ static auto method = TransitionOptions::javaClass.GetStaticMethod<jni::Object<TransitionOptions> (jlong, jlong)>(env, "fromTransitionOptions");
+ return TransitionOptions::javaClass.Call(env, method, duration, delay);
+}
+
+void TransitionOptions::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ TransitionOptions::javaClass = *jni::Class<TransitionOptions>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<TransitionOptions> TransitionOptions::javaClass;
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/style/transition_options.hpp b/platform/android/src/style/transition_options.hpp
new file mode 100644
index 0000000000..3e6b0bc488
--- /dev/null
+++ b/platform/android/src/style/transition_options.hpp
@@ -0,0 +1,25 @@
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class TransitionOptions : private mbgl::util::noncopyable {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/TransitionOptions"; };
+
+ static jni::Object<TransitionOptions> fromTransitionOptions(jni::JNIEnv&, jlong duration, jlong offset);
+
+ static jni::Class<TransitionOptions> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+};
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/style/value.cpp b/platform/android/src/style/value.cpp
index 0b5d81feb1..e1cd81d7fd 100644
--- a/platform/android/src/style/value.cpp
+++ b/platform/android/src/style/value.cpp
@@ -22,7 +22,7 @@ namespace android {
// Instance
- Value::Value(jni::JNIEnv& env, jni::jobject* _value) : jenv(env), value(_value, ObjectDeleter(env)) {}
+ Value::Value(jni::JNIEnv& _env, jni::jobject* _value) : env(_env), value(_value, ObjectDeleter(env)) {}
Value::~Value() = default;
@@ -31,51 +31,59 @@ namespace android {
}
bool Value::isArray() const {
- return jni::IsInstanceOf(jenv, value.get(), *java::ObjectArray::jclass);
+ return jni::IsInstanceOf(env, value.get(), *java::ObjectArray::jclass);
}
bool Value::isObject() const {
- return jni::IsInstanceOf(jenv, value.get(), *java::Map::jclass);;
+ return jni::IsInstanceOf(env, value.get(), *java::Map::jclass);;
}
bool Value::isString() const {
- return jni::IsInstanceOf(jenv, value.get(), *java::String::jclass);
+ return jni::IsInstanceOf(env, value.get(), *java::String::jclass);
}
bool Value::isBool() const {
- return jni::IsInstanceOf(jenv, value.get(), *java::Boolean::jclass);
+ return jni::IsInstanceOf(env, value.get(), *java::Boolean::jclass);
}
bool Value::isNumber() const {
- return jni::IsInstanceOf(jenv, value.get(), *java::Number::jclass);
+ return jni::IsInstanceOf(env, value.get(), *java::Number::jclass);
}
std::string Value::toString() const {
jni::jstring* string = reinterpret_cast<jni::jstring*>(value.get());
- return jni::Make<std::string>(jenv, jni::String(string));
+ return jni::Make<std::string>(env, jni::String(string));
}
- float Value::toNumber() const {
- return jni::CallMethod<jni::jfloat>(jenv, value.get(), *java::Number::floatValueMethodId);
+ float Value::toFloat() const {
+ return jni::CallMethod<jni::jfloat>(env, value.get(), *java::Number::floatValueMethodId);
+ }
+
+ double Value::toDouble() const {
+ return jni::CallMethod<jni::jdouble>(env, value.get(), *java::Number::doubleValueMethodId);
+ }
+
+ long Value::toLong() const {
+ return jni::CallMethod<jni::jlong>(env, value.get(), *java::Number::longValueMethodId);
}
bool Value::toBool() const {
- return jni::CallMethod<jni::jboolean>(jenv, value.get(), *java::Boolean::booleanValueMethodId);
+ return jni::CallMethod<jni::jboolean>(env, value.get(), *java::Boolean::booleanValueMethodId);
}
Value Value::get(const char* key) const {
- jni::jobject* member = jni::CallMethod<jni::jobject*>(jenv, value.get(), *java::Map::getMethodId, jni::Make<jni::String>(jenv, std::string(key)).Get());
- return Value(jenv, member);
+ jni::jobject* member = jni::CallMethod<jni::jobject*>(env, value.get(), *java::Map::getMethodId, jni::Make<jni::String>(env, std::string(key)).Get());
+ return Value(env, member);
}
int Value::getLength() const {
auto array = (jni::jarray<jni::jobject>*) value.get();
- return jni::GetArrayLength(jenv, *array);
+ return jni::GetArrayLength(env, *array);
}
- Value Value::get(const int index ) const {
+ Value Value::get(const int index) const {
auto array = (jni::jarray<jni::jobject>*) value.get();
- return Value(jenv, jni::GetObjectArrayElement(jenv, *array, index));
+ return Value(env, jni::GetObjectArrayElement(env, *array, index));
}
}
}
diff --git a/platform/android/src/style/value.hpp b/platform/android/src/style/value.hpp
index 461fc1a033..7464bae832 100644
--- a/platform/android/src/style/value.hpp
+++ b/platform/android/src/style/value.hpp
@@ -21,15 +21,15 @@ public:
bool isNumber() const;
std::string toString() const;
- float toNumber() const;
+ float toFloat() const;
+ double toDouble() const;
+ long toLong() const;
bool toBool() const;
Value get(const char* key) const;
int getLength() const;
Value get(const int index ) const;
-private:
-
- jni::JNIEnv& jenv;
+ jni::JNIEnv& env;
std::shared_ptr<jni::jobject> value;
};
diff --git a/platform/android/tests/docs/UI_TESTS.md b/platform/android/tests/docs/UI_TESTS.md
index 9341cf1e1e..6d8541a406 100644
--- a/platform/android/tests/docs/UI_TESTS.md
+++ b/platform/android/tests/docs/UI_TESTS.md
@@ -25,7 +25,7 @@ On a terminal, within `mapbox-gl-native/android/java`,
run the tests (`cC` stands for `connectedCheck`):
```
-$ ./gradlew cC -p MapboxGLAndroidSDKTestApp
+$ ./gradlew -Pmapbox.abis=all cC -p MapboxGLAndroidSDKTestApp
```
Then:
@@ -59,7 +59,7 @@ You can generate JaCoCo reports from espresso tests by
- running the gradle task `createMockDebugCoverageReport` when executing tests.
## Running Espresso test automatically on AWS Device Farm
-To run tests on AWS device farm you need to execute `./gradlew devicefarmUpload`.
+To run tests on AWS device farm you need to execute `./gradlew -Pmapbox.abis=none devicefarmUpload`.
You can configure the different steps in the testapp `build.gradle`.
AWS credentials are found in bitrise.
diff --git a/platform/android/tests/docs/UNIT_TESTS.md b/platform/android/tests/docs/UNIT_TESTS.md
index e32a36ef78..fefb435684 100644
--- a/platform/android/tests/docs/UNIT_TESTS.md
+++ b/platform/android/tests/docs/UNIT_TESTS.md
@@ -69,7 +69,7 @@ If you like, you can also run with test coverage enabled. This will show you the
You can also run the tests from the command line with:
```
-$ ./gradlew test --continue -p MapboxGLAndroidSDKTestApp
+$ ./gradlew -Pmapbox.abis=none test -p MapboxGLAndroidSDKTestApp
```
## Running Unit tests on CI
@@ -80,7 +80,7 @@ fails, this will fail and stop the build.
You can find this gradle command in our [buildscript](https://github.com/mapbox/mapbox-gl-native/blob/master/platform/android/bitrise.yml#L48):
```
-$ ./gradlew testReleaseUnitTest --continue
+$ ./gradlew -Pmapbox.abis=none testReleaseUnitTest
```
diff --git a/platform/darwin/docs/guides/For Style Authors.md.ejs b/platform/darwin/docs/guides/For Style Authors.md.ejs
index 86f8c46f53..34c1b5dddc 100644
--- a/platform/darwin/docs/guides/For Style Authors.md.ejs
+++ b/platform/darwin/docs/guides/For Style Authors.md.ejs
@@ -158,7 +158,6 @@ the following terms for concepts defined in the style specification:
In the style specification | In the SDK
---------------------------|---------
-class | style class
filter | predicate
function type | interpolation mode
id | identifier
@@ -240,7 +239,7 @@ whose names differ from the style specification are listed below:
<% for (const type in renamedProperties) { -%>
<% if (renamedProperties.hasOwnProperty(type)) { -%>
-### <%- camelize(type) %> style layers
+### <%- camelize(unhyphenate(type)) %> style layers
In style JSON | In Objective-C | In Swift
--------------|----------------|---------
diff --git a/platform/darwin/docs/guides/Using Style Functions at Runtime.md.ejs b/platform/darwin/docs/guides/Using Style Functions at Runtime.md.ejs
index bd477042c7..e41ac1c832 100644
--- a/platform/darwin/docs/guides/Using Style Functions at Runtime.md.ejs
+++ b/platform/darwin/docs/guides/Using Style Functions at Runtime.md.ejs
@@ -1,9 +1,9 @@
-
<%
const os = locals.os;
const iOS = os === 'iOS';
const macOS = os === 'macOS';
const cocoaPrefix = iOS ? 'UI' : 'NS';
+ const guide = 'UsingStyleFunctionsAtRuntime';
-%>
<!--
This file is generated.
@@ -36,13 +36,7 @@ The documentation for each individual style layer property notes which style fun
Stops are key-value pairs that that determine a style value. With a `MGLCameraSourceFunction` stop, you can use a dictionary with a zoom level for a key and a `MGLStyleValue` for the value. For example, you can use a stops dictionary with zoom levels 0, 10, and 20 as keys, and yellow, orange, and red as the values. A `MGLSourceStyleFunction` uses the relevant attribute value as the key.
-```swift
-let stops = [0: MGLStyleValue<<%- cocoaPrefix %>Color>(rawValue: .yellow),
- 2.5: MGLStyleValue(rawValue: .orange),
- 5: MGLStyleValue(rawValue: .red),
- 7.5: MGLStyleValue(rawValue: .blue),
- 10: MGLStyleValue(rawValue: .white)]
-```
+<%- guideExample(guide, 'Stops', os) %>
## Interpolation mode
@@ -54,28 +48,7 @@ The effect a key has on the style value is determined by the interpolation mode.
The stops dictionary below, for example, shows colors that continuously shift from yellow to orange to red to blue to white based on the attribute value.
-``` swift
-let url = URL(string: "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_week.geojson")
-let symbolSource = MGLSource(identifier: "source")
-let symbolLayer = MGLSymbolStyleLayer(identifier: "place-city-sm", source: symbolSource)
-
-let source = MGLShapeSource(identifier: "earthquakes", url: url, options: nil)
-style.addSource(source)
-
-let stops = [0: MGLStyleValue<<%- cocoaPrefix %>Color>(rawValue: .yellow),
- 2.5: MGLStyleValue(rawValue: .orange),
- 5: MGLStyleValue(rawValue: .red),
- 7.5: MGLStyleValue(rawValue: .blue),
- 10: MGLStyleValue(rawValue: .white)]
-
-let layer = MGLCircleStyleLayer(identifier: "circles", source: source)
-layer.circleColor = MGLStyleValue(interpolationMode: .exponential,
- sourceStops: stops,
- attributeName: "mag",
- options: [.defaultValue: MGLStyleValue<<%- cocoaPrefix %>Color>(rawValue: .green)])
-layer.circleRadius = MGLStyleValue(rawValue: 10)
-style.insertLayer(layer, below: symbolLayer)
-```
+<%- guideExample(guide, 'Linear', os) %>
![exponential mode](img/data-driven-styling/exponential.png)
@@ -90,15 +63,7 @@ Here’s a visualization from Mapbox Studio (see [Working with Mapbox Studio](wo
The example below increases a layer’s `circleRadius` exponentially based on a map’s zoom level. The `MGLStyleFunctionOptionInterpolationBase` is `1.5`.
-```swift
-let stops = [12: MGLStyleValue(rawValue: 0.5),
- 14: MGLStyleValue(rawValue: 2),
- 18: MGLStyleValue(rawValue: 18)]
-
-layer.circleRadius = MGLStyleValue(interpolationMode: .exponential,
- cameraStops: stops,
- options: [.interpolationBase: 1.5])
-```
+<%- guideExample(guide, 'Exponential', os) %>
### Interval
@@ -106,18 +71,7 @@ layer.circleRadius = MGLStyleValue(interpolationMode: .exponential,
When we use the stops dictionary given above with an interval interpolation mode, we create ranges where earthquakes with a magnitude of 0 to just less than 2.5 would be yellow, 2.5 to just less than 5 would be orange, and so on.
-``` swift
-let stops = [0: MGLStyleValue<<%- cocoaPrefix %>Color>(rawValue: .yellow),
- 2.5: MGLStyleValue(rawValue: .orange),
- 5: MGLStyleValue(rawValue: .red),
- 7.5: MGLStyleValue(rawValue: .blue),
- 10: MGLStyleValue(rawValue: .white)]
-
-layer.circleColor = MGLStyleValue(interpolationMode: .interval,
- sourceStops: stops,
- attributeName: "mag",
- options: [.defaultValue: MGLStyleValue<<%- cocoaPrefix %>Color>(rawValue: .green)])
-```
+<%- guideExample(guide, 'Interval', os) %>
![interval mode](img/data-driven-styling/interval.png)
@@ -127,17 +81,7 @@ At each stop, `MGLInterpolationModeCategorical` produces an output value equal t
There are three main types of events in the dataset: earthquakes, explosions, and quarry blasts. In this case, the color of the circle layer will be determined by the type of event, with a default value of blue to catch any events that do not fall into any of those categories.
-``` swift
-let categoricalStops = ["earthquake": MGLStyleValue<<%- cocoaPrefix %>Color>(rawValue: .orange),
- "explosion": MGLStyleValue(rawValue: .red),
- "quarry blast": MGLStyleValue(rawValue: .yellow)]
-
-layer.circleColor = MGLStyleValue(interpolationMode: .categorical,
- sourceStops: categoricalStops,
- attributeName: "type",
- options: [.defaultValue: MGLStyleValue<<%- cocoaPrefix %>Color>(rawValue: .blue)])
-
-```
+<%- guideExample(guide, 'Categorical', os) %>
![categorical mode](img/data-driven-styling/categorical1.png) ![categorical mode](img/data-driven-styling/categorical2.png)
@@ -145,13 +89,7 @@ layer.circleColor = MGLStyleValue(interpolationMode: .categorical,
`MGLInterpolationModeIdentity` uses the attribute’s value as the style value. For example, you can set the `circleRadius` to the earthquake’s magnitude. Since the attribute value itself will be used as the style value, `sourceStops` should be set to `nil`.
-``` swift
-layer.circleRadius = MGLStyleValue(interpolationMode: .identity,
- sourceStops: nil,
- attributeName: "mag",
- options: [.defaultValue: MGLStyleValue<NSNumber>(rawValue: 0)])
-
-```
+<%- guideExample(guide, 'Identity', os) %>
![identity mode](img/data-driven-styling/identity.png)
diff --git a/platform/darwin/docs/theme/assets/img/mapbox.svg b/platform/darwin/docs/theme/assets/img/mapbox.svg
index a0c1ee44a4..8d62aef0ec 100644
--- a/platform/darwin/docs/theme/assets/img/mapbox.svg
+++ b/platform/darwin/docs/theme/assets/img/mapbox.svg
@@ -1,21 +1,42 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<svg width="580px" height="156px" viewBox="0 0 580 156" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
- <!-- Generator: Sketch 3.8.3 (29802) - http://www.bohemiancoding.com/sketch -->
- <title>layer1</title>
- <desc>Created with Sketch.</desc>
- <defs></defs>
- <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
- <g id="mapbox" transform="translate(-1.000000, -1.000000)" fill="#FFFFFF">
- <g id="layer1" transform="translate(0.428470, 0.781010)">
- <g id="g3024" transform="translate(0.542850, 0.401720)">
- <path d="M0.028592,0.417258 L0.028592,122.817276 L18.028592,122.817276 L18.028592,22.017258 L54.028592,83.217258 L90.028592,22.017258 L90.028592,122.817276 L108.028592,122.817276 L108.028592,0.417258 L93.628592,0.417258 C86.428592,0.394218 80.77382,2.217258 77.597342,7.617258 L54.028592,47.667258 L30.459842,7.617258 C27.283364,2.217258 21.628592,0.394218 14.428592,0.417258 L0.028592,0.417258 L0.028592,0.417258 Z" id="path4479"></path>
- <path d="M315.028592,0.417258 L315.028592,124.617276 L349.228592,124.617276 C374.428592,124.617276 394.228592,104.81724 394.228592,77.817258 C394.228592,50.81724 374.428592,31.01724 349.228592,31.017258 C343.529972,31.041018 338.884892,30.824568 333.028592,30.848598 L333.028592,0.417348 L315.028592,0.417348 L315.028592,0.417258 Z M333.028592,49.017258 L349.228592,49.017258 C364.381892,49.017258 376.228592,62.677008 376.228592,77.817258 C376.228592,92.95632 365.621732,106.617258 349.228592,106.617258 L333.028592,106.617258 L333.028592,49.017258 L333.028592,49.017258 Z" id="path4477"></path>
- <path d="M165.628592,31.017258 C140.428592,31.017258 122.428592,50.817258 122.428592,77.817258 C122.428592,104.817258 140.428574,124.617276 165.628592,124.617276 L208.828592,124.617276 L208.828592,77.817258 C208.828592,50.817258 190.82861,31.017258 165.628592,31.017258 L165.628592,31.017258 Z M165.628592,49.017258 C180.028592,49.017258 190.828592,61.424226 190.828592,77.817258 L190.828592,106.617258 L165.628592,106.617258 C151.228574,106.617258 140.428628,93.994254 140.428592,77.817258 C140.428574,61.617258 151.228592,49.017258 165.628592,49.017258 L165.628592,49.017258 Z" id="path4475"></path>
- <path d="M223.228592,31.017258 L223.228592,155.217276 L241.228592,155.217276 L241.228592,124.729776 C247.084856,124.753536 251.729954,124.593516 257.428592,124.617276 C282.628592,124.617276 302.428592,104.817258 302.428592,77.817258 C302.428592,50.817258 282.628592,31.017258 257.428592,31.017258 L223.228592,31.017258 L223.228592,31.017258 Z M241.228592,49.017258 L257.428592,49.017258 C273.821552,49.017258 284.428592,62.678196 284.428592,77.817258 C284.428592,92.957508 272.581892,106.617258 257.428592,106.617258 L241.228592,106.617258 L241.228592,49.017258 L241.228592,49.017258 Z" id="path4473"></path>
- <path d="M450.028592,31.017258 C425.175812,31.017258 405.028592,51.970374 405.028592,77.817258 C405.028592,103.664142 425.175812,124.617276 450.028592,124.617276 C474.881372,124.617276 495.028592,103.664142 495.028592,77.817258 C495.028592,51.970374 474.881372,31.017258 450.028592,31.017258 L450.028592,31.017258 Z M450.028592,49.017258 C464.940332,49.017258 477.028592,61.911522 477.028592,77.817258 C477.028592,93.722994 464.940332,106.617258 450.028592,106.617258 C435.116852,106.617258 423.028592,93.722994 423.028592,77.817258 C423.028592,61.911522 435.116852,49.017258 450.028592,49.017258 L450.028592,49.017258 Z" id="path4471"></path>
- <polygon id="path4469" points="493.116092 32.794182 524.447342 76.444182 491.428592 122.7942 513.478592 122.7942 535.472342 91.856682 557.578592 122.7942 579.628592 122.7942 546.553592 76.444182 577.828592 32.794182 555.666092 32.794182 535.472342 60.975432 515.278592 32.794218"></polygon>
- </g>
- </g>
- </g>
- </g>
-</svg> \ No newline at end of file
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 21.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="new" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 800 180" style="enable-background:new 0 0 800 180;" xml:space="preserve">
+<style type="text/css">
+ .st0{fill:#FFFFFF;}
+</style>
+<title>Mapbox_Logo_08</title>
+<g>
+ <g>
+ <path class="st0" d="M594.6,49.8c-9.9,0-19.4,4.1-26.3,11.3V23c0-1.2-1-2.2-2.2-2.2l0,0h-13.4c-1.2,0-2.2,1-2.2,2.2v103
+ c0,1.2,1,2.2,2.2,2.2h13.4c1.2,0,2.2-1,2.2-2.2v0v-7.1c6.9,7.2,16.3,11.3,26.3,11.3c20.9,0,37.8-18,37.8-40.2
+ S615.5,49.8,594.6,49.8z M591.5,114.1c-12.7,0-23-10.6-23.1-23.8v-0.6c0.2-13.2,10.4-23.8,23.1-23.8c12.8,0,23.1,10.8,23.1,24.1
+ S604.2,114.1,591.5,114.1L591.5,114.1z"/>
+ <path class="st0" d="M681.7,49.8c-22.6,0-40.9,18-40.9,40.2s18.3,40.2,40.9,40.2c22.6,0,40.9-18,40.9-40.2S704.3,49.8,681.7,49.8z
+ M681.6,114.1c-12.8,0-23.1-10.8-23.1-24.1s10.4-24.1,23.1-24.1s23.1,10.8,23.1,24.1S694.3,114.1,681.6,114.1L681.6,114.1z"/>
+ <path class="st0" d="M431.6,51.8h-13.4c-1.2,0-2.2,1-2.2,2.2c0,0,0,0,0,0v7.1c-6.9-7.2-16.3-11.3-26.3-11.3
+ c-20.9,0-37.8,18-37.8,40.2s16.9,40.2,37.8,40.2c9.9,0,19.4-4.1,26.3-11.3v7.1c0,1.2,1,2.2,2.2,2.2l0,0h13.4c1.2,0,2.2-1,2.2-2.2
+ v0V54C433.8,52.8,432.8,51.8,431.6,51.8z M392.8,114.1c-12.8,0-23.1-10.8-23.1-24.1s10.4-24.1,23.1-24.1c12.7,0,23,10.6,23.1,23.8
+ v0.6C415.8,103.5,405.5,114.1,392.8,114.1L392.8,114.1z"/>
+ <path class="st0" d="M498.5,49.8c-9.9,0-19.4,4.1-26.3,11.3V54c0-1.2-1-2.2-2.2-2.2l0,0h-13.4c-1.2,0-2.2,1-2.2,2.2c0,0,0,0,0,0
+ v103c0,1.2,1,2.2,2.2,2.2l0,0h13.4c1.2,0,2.2-1,2.2-2.2v0v-38.1c6.9,7.2,16.3,11.3,26.3,11.3c20.9,0,37.8-18,37.8-40.2
+ S519.4,49.8,498.5,49.8z M495.4,114.1c-12.7,0-23-10.6-23.1-23.8v-0.6c0.2-13.2,10.4-23.8,23.1-23.8c12.8,0,23.1,10.8,23.1,24.1
+ S508.2,114.1,495.4,114.1L495.4,114.1z"/>
+ <path class="st0" d="M311.8,49.8c-10,0.1-19.1,5.9-23.4,15c-4.9-9.3-14.7-15.1-25.2-15c-8.2,0-15.9,4-20.7,10.6V54
+ c0-1.2-1-2.2-2.2-2.2l0,0h-13.4c-1.2,0-2.2,1-2.2,2.2c0,0,0,0,0,0v72c0,1.2,1,2.2,2.2,2.2h0h13.4c1.2,0,2.2-1,2.2-2.2v0V82.9
+ c0.5-9.6,7.2-17.3,15.4-17.3c8.5,0,15.6,7.1,15.6,16.4v44c0,1.2,1,2.2,2.2,2.2l13.5,0c1.2,0,2.2-1,2.2-2.2c0,0,0,0,0,0l-0.1-44.8
+ c1.2-8.8,7.5-15.6,15.2-15.6c8.5,0,15.6,7.1,15.6,16.4v44c0,1.2,1,2.2,2.2,2.2l13.5,0c1.2,0,2.2-1,2.2-2.2c0,0,0,0,0,0l-0.1-49.5
+ C339.9,61.7,327.3,49.8,311.8,49.8z"/>
+ <path class="st0" d="M794.7,125.1l-23.2-35.3l23-35c0.6-0.9,0.3-2.2-0.6-2.8c-0.3-0.2-0.7-0.3-1.1-0.3h-15.5
+ c-1.2,0-2.3,0.6-2.9,1.6L760.9,76l-13.5-22.6c-0.6-1-1.7-1.6-2.9-1.6h-15.5c-1.1,0-2,0.9-2,2c0,0.4,0.1,0.8,0.3,1.1l23,35
+ l-23.2,35.3c-0.6,0.9-0.3,2.2,0.6,2.8c0.3,0.2,0.7,0.3,1.1,0.3h15.5c1.2,0,2.3-0.6,2.9-1.6l13.8-23l13.8,23c0.6,1,1.7,1.6,2.9,1.6
+ H793c1.1,0,2-0.9,2-2C795,125.9,794.9,125.5,794.7,125.1z"/>
+ </g>
+ <g>
+ <path class="st0" d="M93.9,1.1C44.8,1.1,5,40.9,5,90s39.8,88.9,88.9,88.9s88.9-39.8,88.9-88.9C182.8,40.9,143,1.1,93.9,1.1z
+ M136.1,111.8c-30.4,30.4-84.7,20.7-84.7,20.7s-9.8-54.2,20.7-84.7C89,30.9,117,31.6,134.7,49.2S153,94.9,136.1,111.8L136.1,111.8
+ z"/>
+ <polygon class="st0" points="104.1,53.2 95.4,71.1 77.5,79.8 95.4,88.5 104.1,106.4 112.8,88.5 130.7,79.8 112.8,71.1 "/>
+ </g>
+</g>
+</svg>
diff --git a/platform/darwin/resources/es.lproj/Foundation.strings b/platform/darwin/resources/es.lproj/Foundation.strings
new file mode 100644
index 0000000000..fb76820eb4
--- /dev/null
+++ b/platform/darwin/resources/es.lproj/Foundation.strings
@@ -0,0 +1,291 @@
+/* Clock position format, long: {hours} o’clock */
+"CLOCK_FMT_LONG" = "%@ en punto";
+
+/* Clock position format, medium: {hours} o’clock */
+"CLOCK_FMT_MEDIUM" = "%@ en punto";
+
+/* Clock position format, short: {hours}:00 */
+"CLOCK_FMT_SHORT" = "%@:00";
+
+/* East, long */
+"COMPASS_E_LONG" = "este";
+
+/* East, short */
+"COMPASS_E_SHORT" = "E";
+
+/* East by north, long */
+"COMPASS_EbN_LONG" = "este por el norte";
+
+/* East by north, short */
+"COMPASS_EbN_SHORT" = "EpN";
+
+/* East by south, long */
+"COMPASS_EbS_LONG" = "este por el sur";
+
+/* East by south, short */
+"COMPASS_EbS_SHORT" = "EpS";
+
+/* East-northeast, long */
+"COMPASS_ENE_LONG" = "estenordeste";
+
+/* East-northeast, short */
+"COMPASS_ENE_SHORT" = "ENE";
+
+/* East-southeast, long */
+"COMPASS_ESE_LONG" = "estesudeste";
+
+/* East-southeast, short */
+"COMPASS_ESE_SHORT" = "ESE";
+
+/* North, long */
+"COMPASS_N_LONG" = "norte";
+
+/* North, short */
+"COMPASS_N_SHORT" = "N";
+
+/* North by east, long */
+"COMPASS_NbE_LONG" = "norte por el este";
+
+/* North by east, short */
+"COMPASS_NbE_SHORT" = "NpE";
+
+/* North by west, long */
+"COMPASS_NbW_LONG" = "norte por el oeste";
+
+/* North by west, short */
+"COMPASS_NbW_SHORT" = "NpO";
+
+/* Northeast, long */
+"COMPASS_NE_LONG" = "nordeste";
+
+/* Northeast, short */
+"COMPASS_NE_SHORT" = "NE";
+
+/* Northeast by east, long */
+"COMPASS_NEbE_LONG" = "nordeste por el este";
+
+/* Northeast by east, short */
+"COMPASS_NEbE_SHORT" = "NEpE";
+
+/* Northeast by north, long */
+"COMPASS_NEbN_LONG" = "nordeste por el norte";
+
+/* Northeast by north, short */
+"COMPASS_NEbN_SHORT" = "NEpN";
+
+/* North-northeast, long */
+"COMPASS_NNE_LONG" = "nornordeste";
+
+/* North-northeast, short */
+"COMPASS_NNE_SHORT" = "NNE";
+
+/* North-northwest, long */
+"COMPASS_NNW_LONG" = "nornoroeste";
+
+/* North-northwest, short */
+"COMPASS_NNW_SHORT" = "NNO";
+
+/* Northwest, long */
+"COMPASS_NW_LONG" = "noroeste";
+
+/* Northwest, short */
+"COMPASS_NW_SHORT" = "NO";
+
+/* Northwest by north, long */
+"COMPASS_NWbN_LONG" = "noroeste por el norte";
+
+/* Northwest by north, short */
+"COMPASS_NWbN_SHORT" = "NOpN";
+
+/* Northwest by west, long */
+"COMPASS_NWbW_LONG" = "noroeste por el oeste";
+
+/* Northwest by west, short */
+"COMPASS_NWbW_SHORT" = "NOpO";
+
+/* South, long */
+"COMPASS_S_LONG" = "sur";
+
+/* South, short */
+"COMPASS_S_SHORT" = "S";
+
+/* South by east, long */
+"COMPASS_SbE_LONG" = "sur por el este";
+
+/* South by east, short */
+"COMPASS_SbE_SHORT" = "SpE";
+
+/* South by west, long */
+"COMPASS_SbW_LONG" = "sur por el oeste";
+
+/* South by west, short */
+"COMPASS_SbW_SHORT" = "SpO";
+
+/* Southeast, long */
+"COMPASS_SE_LONG" = "sudeste";
+
+/* Southeast, short */
+"COMPASS_SE_SHORT" = "SE";
+
+/* Southeast by east, long */
+"COMPASS_SEbE_LONG" = "sudeste por el este";
+
+/* Southeast by east, short */
+"COMPASS_SEbE_SHORT" = "SEpE";
+
+/* Southeast by south, long */
+"COMPASS_SEbS_LONG" = "sudeste por el sur";
+
+/* Southeast by south, short */
+"COMPASS_SEbS_SHORT" = "SEpS";
+
+/* South-southeast, long */
+"COMPASS_SSE_LONG" = "sudsudeste";
+
+/* South-southeast, short */
+"COMPASS_SSE_SHORT" = "SSE";
+
+/* South-southwest, long */
+"COMPASS_SSW_LONG" = "sudsudoeste";
+
+/* South-southwest, short */
+"COMPASS_SSW_SHORT" = "SSO";
+
+/* Southwest, long */
+"COMPASS_SW_LONG" = "sudoeste";
+
+/* Southwest, short */
+"COMPASS_SW_SHORT" = "SO";
+
+/* Southwest by south, long */
+"COMPASS_SWbS_LONG" = "sudoeste por el sur";
+
+/* Southwest by south, short */
+"COMPASS_SWbS_SHORT" = "SOpS";
+
+/* Southwest by west, long */
+"COMPASS_SWbW_LONG" = "sudoeste por el oeste";
+
+/* Southwest by west, short */
+"COMPASS_SWbW_SHORT" = "SOpO";
+
+/* West, long */
+"COMPASS_W_LONG" = "oeste";
+
+/* West, short */
+"COMPASS_W_SHORT" = "O";
+
+/* West by north, long */
+"COMPASS_WbN_LONG" = "oeste por el norte";
+
+/* West by north, short */
+"COMPASS_WbN_SHORT" = "OpN";
+
+/* West by south, long */
+"COMPASS_WbS_LONG" = "oeste por el sur";
+
+/* West by south, short */
+"COMPASS_WbS_SHORT" = "OpS";
+
+/* West-northwest, long */
+"COMPASS_WNW_LONG" = "oesnoroeste";
+
+/* West-northwest, short */
+"COMPASS_WNW_SHORT" = "ONO";
+
+/* West-southwest, long */
+"COMPASS_WSW_LONG" = "oesudoeste";
+
+/* West-southwest, short */
+"COMPASS_WSW_SHORT" = "OSO";
+
+/* Degrees format, long */
+"COORD_DEG_LONG" = "%d grado(s)";
+
+/* Degrees format, medium: {degrees} */
+"COORD_DEG_MEDIUM" = "%d°";
+
+/* Degrees format, short: {degrees} */
+"COORD_DEG_SHORT" = "%d°";
+
+/* Coordinate format, long: {degrees}{minutes} */
+"COORD_DM_LONG" = "%1$@ y %2$@";
+
+/* Coordinate format, medium: {degrees}{minutes} */
+"COORD_DM_MEDIUM" = "%1$@%2$@";
+
+/* Coordinate format, short: {degrees}{minutes} */
+"COORD_DM_SHORT" = "%1$@%2$@";
+
+/* Coordinate format, long: {degrees}{minutes}{seconds} */
+"COORD_DMS_LONG" = "%1$@, %2$@ y %3$@";
+
+/* Coordinate format, medium: {degrees}{minutes}{seconds} */
+"COORD_DMS_MEDIUM" = "%1$@%2$@%3$@";
+
+/* Coordinate format, short: {degrees}{minutes}{seconds} */
+"COORD_DMS_SHORT" = "%1$@%2$@%3$@";
+
+/* East longitude format, long: {longitude} */
+"COORD_E_LONG" = "%@ este";
+
+/* East longitude format, medium: {longitude} */
+"COORD_E_MEDIUM" = "%@ este";
+
+/* East longitude format, short: {longitude} */
+"COORD_E_SHORT" = "%@E";
+
+/* Coordinate pair format, long: {latitude}, {longitude} */
+"COORD_FMT_LONG" = "%1$@ por %2$@";
+
+/* Coordinate pair format, medium: {latitude}, {longitude} */
+"COORD_FMT_MEDIUM" = "%1$@, %2$@";
+
+/* Coordinate pair format, short: {latitude}, {longitude} */
+"COORD_FMT_SHORT" = "%1$@, %2$@";
+
+/* Minutes format, long */
+"COORD_MIN_LONG" = "%d minuto(s)";
+
+/* Minutes format, medium: {minutes} */
+"COORD_MIN_MEDIUM" = "%d′";
+
+/* Minutes format, short: {minutes} */
+"COORD_MIN_SHORT" = "%d′";
+
+/* North latitude format, long: {latitude} */
+"COORD_N_LONG" = "%@ norte";
+
+/* North latitude format, medium: {latitude} */
+"COORD_N_MEDIUM" = "%@ norte";
+
+/* North latitude format, short: {latitude} */
+"COORD_N_SHORT" = "%@N";
+
+/* South latitude format, long: {latitude} */
+"COORD_S_LONG" = "%@ sur";
+
+/* South latitude format, medium: {latitude} */
+"COORD_S_MEDIUM" = "%@ sur";
+
+/* South latitude format, short: {latitude} */
+"COORD_S_SHORT" = "%@S";
+
+/* Seconds format, long */
+"COORD_SEC_LONG" = "%d segundo(s)";
+
+/* Seconds format, medium: {seconds} */
+"COORD_SEC_MEDIUM" = "%d″";
+
+/* Seconds format, short: {seconds} */
+"COORD_SEC_SHORT" = "%d″";
+
+/* West longitude format, long: {longitude} */
+"COORD_W_LONG" = "%@ oeste";
+
+/* West longitude format, medium: {longitude} */
+"COORD_W_MEDIUM" = "%@ oeste";
+
+/* West longitude format, short: {longitude} */
+"COORD_W_SHORT" = "%@O";
+
diff --git a/platform/darwin/scripts/generate-style-code.js b/platform/darwin/scripts/generate-style-code.js
index 7e798154e4..330a8f1d03 100644
--- a/platform/darwin/scripts/generate-style-code.js
+++ b/platform/darwin/scripts/generate-style-code.js
@@ -13,11 +13,6 @@ const suffix = 'StyleLayer';
let spec = _.merge(require('../../../mapbox-gl-js/src/style-spec/reference/v8'), require('./style-spec-overrides-v8.json'));
-///
-// Temporarily IGNORE layers that are in the spec yet still not supported in mbgl core
-///
-delete spec.layer.type.values['fill-extrusion'];
-
// Rename properties and keep `original` for use with setters and getters
_.forOwn(cocoaConventions, function (properties, kind) {
_.forOwn(properties, function (newName, oldName) {
@@ -605,6 +600,41 @@ for (var layer of layers) {
fs.writeFileSync(`platform/darwin/test/${prefix}${camelize(layer.type)}${suffix}Tests.mm`, testLayers(layer));
}
+// Extract examples for guides from unit tests.
+let examplesSrc = fs.readFileSync('platform/darwin/test/MGLDocumentationGuideTests.swift', 'utf8');
+const exampleRegex = /func test([\w$]+)\s*\(\)\s*\{[^]*?\n([ \t]+)\/\/#-example-code\n([^]+?)\n\2\/\/#-end-example-code\n/gm;
+
+let examples = {};
+let match;
+while ((match = exampleRegex.exec(examplesSrc)) !== null) {
+ let testMethodName = match[1],
+ indentation = match[2],
+ exampleCode = match[3];
+
+ // Trim leading whitespace from the example code.
+ exampleCode = exampleCode.replace(new RegExp('^' + indentation, 'gm'), '');
+
+ examples[testMethodName] = exampleCode;
+}
+
+global.guideExample = function (guide, exampleId, os) {
+ // Get the contents of the test method whose name matches the symbol path.
+ let testMethodName = `${guide}$${exampleId}`;
+ let example = examples[testMethodName];
+ if (!example) {
+ console.error(`MGLDocumentationExampleTests.test${testMethodName}() not found.`);
+ process.exit(1);
+ }
+
+ // Resolve conditional compilation blocks.
+ example = example.replace(/^(\s*)#if\s+os\((iOS|macOS)\)\n([^]*?)(?:^\1#else\n([^]*?))?^\1#endif\b\n?/gm,
+ function (m, indentation, ifOs, ifCase, elseCase) {
+ return (os === ifOs ? ifCase : elseCase).replace(new RegExp('^ ', 'gm'), '');
+ }).replace(/\n$/, '');
+
+ return '```swift\n' + example + '\n```';
+};
+
fs.writeFileSync(`platform/ios/docs/guides/For Style Authors.md`, guideMD({
os: 'iOS',
renamedProperties: renamedPropertiesByLayerType,
diff --git a/platform/darwin/scripts/style-spec-cocoa-conventions-v8.json b/platform/darwin/scripts/style-spec-cocoa-conventions-v8.json
index 9d80ff3896..830b6d69f9 100644
--- a/platform/darwin/scripts/style-spec-cocoa-conventions-v8.json
+++ b/platform/darwin/scripts/style-spec-cocoa-conventions-v8.json
@@ -30,6 +30,10 @@
"fill-translate": "fill-translation",
"fill-translate-anchor": "fill-translation-anchor"
},
+ "paint_fill-extrusion": {
+ "fill-extrusion-translate": "fill-extrusion-translation",
+ "fill-extrusion-translate-anchor": "fill-extrusion-translation-anchor"
+ },
"paint_raster": {
"raster-brightness-min": "minimum-raster-brightness",
"raster-brightness-max": "maximum-raster-brightness",
diff --git a/platform/darwin/scripts/style-spec-overrides-v8.json b/platform/darwin/scripts/style-spec-overrides-v8.json
index 28740d458b..a594ef2957 100644
--- a/platform/darwin/scripts/style-spec-overrides-v8.json
+++ b/platform/darwin/scripts/style-spec-overrides-v8.json
@@ -5,6 +5,9 @@
"fill": {
"doc": "An `MGLFillStyleLayer` is a style layer that renders one or more filled (and optionally stroked) polygons on the map.\n\nUse a fill style layer to configure the visual appearance of polygon or multipolygon features in vector tiles loaded by an `MGLVectorSource` object or `MGLPolygon`, `MGLPolygonFeature`, `MGLMultiPolygon`, or `MGLMultiPolygonFeature` instances in an `MGLShapeSource` object."
},
+ "fill-extrusion": {
+ "doc": "An `MGLFillExtrusionStyleLayer` is a style layer that renders one or more 3D extruded polygons on the map.\n\nUse a fill-extrusion style layer to configure the visual appearance of polygon or multipolygon features in vector tiles loaded by an `MGLVectorSource` object or `MGLPolygon`, `MGLPolygonFeature`, `MGLMultiPolygon`, or `MGLMultiPolygonFeature` instances in an `MGLShapeSource` object."
+ },
"line": {
"doc": "An `MGLLineStyleLayer` is a style layer that renders one or more stroked polylines on the map.\n\nUse a line style layer to configure the visual appearance of polyline or multipolyline features in vector tiles loaded by an `MGLVectorSource` object or `MGLPolyline`, `MGLPolylineFeature`, `MGLMultiPolyline`, or `MGLMultiPolylineFeature` instances in an `MGLShapeSource` object."
},
@@ -50,6 +53,17 @@
"doc": "Name of image in style images to use for drawing image fills. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512)."
}
},
+ "paint_fill-extrusion": {
+ "fill-extrusion-pattern": {
+ "doc": "Name of image in style images to use for drawing image fill-extrusions. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512)."
+ },
+ "fill-extrusion-translate": {
+ "doc": "The geometry's offset."
+ },
+ "fill-extrusion-color": {
+ "doc": "The base color of this layer. The extrusion's surfaces will be shaded differently based on this color in combination with the `light` settings. If this color is specified with an alpha component, the alpha component will be ignored; use `fill-extrusion-opacity` to set layer opacityco."
+ }
+ },
"paint_line": {
"line-pattern": {
"doc": "Name of image in style images to use for drawing image lines. For seamless patterns, image width must be a factor of two (2, 4, 8, ..., 512)."
diff --git a/platform/darwin/scripts/update-examples.js b/platform/darwin/scripts/update-examples.js
index 404cda102a..d453c0e4ba 100644
--- a/platform/darwin/scripts/update-examples.js
+++ b/platform/darwin/scripts/update-examples.js
@@ -103,7 +103,7 @@ function completeExamples(os) {
let testMethodName = symbolPath.join('$').replace(/\$[+-]/, '$').replace(/:/g, '_');
let example = examples[testMethodName];
if (!example) {
- console.error(`MGLDocumentationExampleTests.${testMethodName}() not found.`);
+ console.error(`MGLDocumentationExampleTests.test${testMethodName}() not found.`);
process.exit(1);
}
diff --git a/platform/darwin/src/MGLAttributionInfo.mm b/platform/darwin/src/MGLAttributionInfo.mm
index fa2ae787a5..7583244491 100644
--- a/platform/darwin/src/MGLAttributionInfo.mm
+++ b/platform/darwin/src/MGLAttributionInfo.mm
@@ -93,7 +93,12 @@
return;
}
- MGLAttributionInfo *info = [[MGLAttributionInfo alloc] initWithTitle:title URL:value];
+ // Remove the link, because it forces the text to be blue on macOS 10.12
+ // and above.
+ NSMutableAttributedString *unlinkedTitle = [title mutableCopy];
+ [unlinkedTitle removeAttribute:NSLinkAttributeName range:unlinkedTitle.mgl_wholeRange];
+
+ MGLAttributionInfo *info = [[MGLAttributionInfo alloc] initWithTitle:unlinkedTitle URL:value];
info.feedbackLink = isFeedbackLink;
[infos addObject:info];
}];
diff --git a/platform/darwin/src/MGLBackgroundStyleLayer.h b/platform/darwin/src/MGLBackgroundStyleLayer.h
index cd218d9fb4..659903914c 100644
--- a/platform/darwin/src/MGLBackgroundStyleLayer.h
+++ b/platform/darwin/src/MGLBackgroundStyleLayer.h
@@ -24,7 +24,17 @@ NS_ASSUME_NONNULL_BEGIN
MGL_EXPORT
@interface MGLBackgroundStyleLayer : MGLStyleLayer
-- (instancetype)initWithIdentifier:(NSString *)identifier NS_DESIGNATED_INITIALIZER;
+/**
+Returns a background style layer initialized with an identifier.
+
+After initializing and configuring the style layer, add it to a map view’s
+style using the `-[MGLStyle addLayer:]` or
+`-[MGLStyle insertLayer:belowLayer:]` method.
+
+@param identifier A string that uniquely identifies the source in the style to
+which it is added.
+*/
+- (instancetype)initWithIdentifier:(NSString *)identifier;
#pragma mark - Accessing the Paint Attributes
diff --git a/platform/darwin/src/MGLBackgroundStyleLayer.mm b/platform/darwin/src/MGLBackgroundStyleLayer.mm
index 8f416a0ea2..47b491fc65 100644
--- a/platform/darwin/src/MGLBackgroundStyleLayer.mm
+++ b/platform/darwin/src/MGLBackgroundStyleLayer.mm
@@ -2,35 +2,27 @@
// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLSource.h"
-#import "MGLMapView_Private.h"
#import "NSPredicate+MGLAdditions.h"
#import "NSDate+MGLAdditions.h"
#import "MGLStyleLayer_Private.h"
#import "MGLStyleValue_Private.h"
#import "MGLBackgroundStyleLayer.h"
-#include <mbgl/map/map.hpp>
+#include <mbgl/style/transition_options.hpp>
#include <mbgl/style/layers/background_layer.hpp>
@interface MGLBackgroundStyleLayer ()
-@property (nonatomic) mbgl::style::BackgroundLayer *rawLayer;
+@property (nonatomic, readonly) mbgl::style::BackgroundLayer *rawLayer;
@end
@implementation MGLBackgroundStyleLayer
-{
- std::unique_ptr<mbgl::style::BackgroundLayer> _pendingLayer;
-}
- (instancetype)initWithIdentifier:(NSString *)identifier
{
- if (self = [super initWithIdentifier:identifier]) {
- auto layer = std::make_unique<mbgl::style::BackgroundLayer>(identifier.UTF8String);
- _pendingLayer = std::move(layer);
- self.rawLayer = _pendingLayer.get();
- }
- return self;
+ auto layer = std::make_unique<mbgl::style::BackgroundLayer>(identifier.UTF8String);
+ return self = [super initWithPendingLayer:std::move(layer)];
}
- (mbgl::style::BackgroundLayer *)rawLayer
@@ -38,51 +30,6 @@
return (mbgl::style::BackgroundLayer *)super.rawLayer;
}
-- (void)setRawLayer:(mbgl::style::BackgroundLayer *)rawLayer
-{
- super.rawLayer = rawLayer;
-}
-
-#pragma mark - Adding to and removing from a map view
-
-- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer
-{
- if (_pendingLayer == nullptr) {
- [NSException raise:@"MGLRedundantLayerException"
- format:@"This instance %@ was already added to %@. Adding the same layer instance " \
- "to the style more than once is invalid.", self, mapView.style];
- }
-
- if (otherLayer) {
- const mbgl::optional<std::string> belowLayerId{otherLayer.identifier.UTF8String};
- mapView.mbglMap->addLayer(std::move(_pendingLayer), belowLayerId);
- } else {
- mapView.mbglMap->addLayer(std::move(_pendingLayer));
- }
-}
-
-- (void)removeFromMapView:(MGLMapView *)mapView
-{
- if (self.rawLayer != mapView.mbglMap->getLayer(self.identifier.UTF8String)) {
- return;
- }
-
- auto removedLayer = mapView.mbglMap->removeLayer(self.identifier.UTF8String);
- if (!removedLayer) {
- return;
- }
-
- mbgl::style::BackgroundLayer *layer = dynamic_cast<mbgl::style::BackgroundLayer *>(removedLayer.get());
- if (!layer) {
- return;
- }
-
- removedLayer.release();
-
- _pendingLayer = std::unique_ptr<mbgl::style::BackgroundLayer>(layer);
- self.rawLayer = _pendingLayer.get();
-}
-
#pragma mark - Accessing the Paint Attributes
- (void)setBackgroundColor:(MGLStyleValue<MGLColor *> *)backgroundColor {
diff --git a/platform/darwin/src/MGLCircleStyleLayer.h b/platform/darwin/src/MGLCircleStyleLayer.h
index 69c823a868..789ff7a258 100644
--- a/platform/darwin/src/MGLCircleStyleLayer.h
+++ b/platform/darwin/src/MGLCircleStyleLayer.h
@@ -79,6 +79,21 @@ typedef NS_ENUM(NSUInteger, MGLCircleTranslationAnchor) {
MGL_EXPORT
@interface MGLCircleStyleLayer : MGLVectorStyleLayer
+/**
+ Returns a circle style layer initialized with an identifier and source.
+
+ After initializing and configuring the style layer, add it to a map view’s
+ style using the `-[MGLStyle addLayer:]` or
+ `-[MGLStyle insertLayer:belowLayer:]` method.
+
+ @param identifier A string that uniquely identifies the source in the style to
+ which it is added.
+ @param source The source from which to obtain the data to style. If the source
+ has not yet been added to the current style, the behavior is undefined.
+ @return An initialized foreground style layer.
+ */
+- (instancetype)initWithIdentifier:(NSString *)identifier source:(MGLSource *)source;
+
#pragma mark - Accessing the Paint Attributes
/**
diff --git a/platform/darwin/src/MGLCircleStyleLayer.mm b/platform/darwin/src/MGLCircleStyleLayer.mm
index 330b9cdac0..42961f2e12 100644
--- a/platform/darwin/src/MGLCircleStyleLayer.mm
+++ b/platform/darwin/src/MGLCircleStyleLayer.mm
@@ -2,14 +2,13 @@
// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLSource.h"
-#import "MGLMapView_Private.h"
#import "NSPredicate+MGLAdditions.h"
#import "NSDate+MGLAdditions.h"
#import "MGLStyleLayer_Private.h"
#import "MGLStyleValue_Private.h"
#import "MGLCircleStyleLayer.h"
-#include <mbgl/map/map.hpp>
+#include <mbgl/style/transition_options.hpp>
#include <mbgl/style/layers/circle_layer.hpp>
namespace mbgl {
@@ -28,23 +27,16 @@ namespace mbgl {
@interface MGLCircleStyleLayer ()
-@property (nonatomic) mbgl::style::CircleLayer *rawLayer;
+@property (nonatomic, readonly) mbgl::style::CircleLayer *rawLayer;
@end
@implementation MGLCircleStyleLayer
-{
- std::unique_ptr<mbgl::style::CircleLayer> _pendingLayer;
-}
- (instancetype)initWithIdentifier:(NSString *)identifier source:(MGLSource *)source
{
- if (self = [super initWithIdentifier:identifier source:source]) {
- auto layer = std::make_unique<mbgl::style::CircleLayer>(identifier.UTF8String, source.identifier.UTF8String);
- _pendingLayer = std::move(layer);
- self.rawLayer = _pendingLayer.get();
- }
- return self;
+ auto layer = std::make_unique<mbgl::style::CircleLayer>(identifier.UTF8String, source.identifier.UTF8String);
+ return self = [super initWithPendingLayer:std::move(layer)];
}
- (mbgl::style::CircleLayer *)rawLayer
@@ -52,11 +44,6 @@ namespace mbgl {
return (mbgl::style::CircleLayer *)super.rawLayer;
}
-- (void)setRawLayer:(mbgl::style::CircleLayer *)rawLayer
-{
- super.rawLayer = rawLayer;
-}
-
- (NSString *)sourceIdentifier
{
MGLAssertStyleLayerIsValid();
@@ -93,46 +80,6 @@ namespace mbgl {
return [NSPredicate mgl_predicateWithFilter:self.rawLayer->getFilter()];
}
-#pragma mark - Adding to and removing from a map view
-
-- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer
-{
- if (_pendingLayer == nullptr) {
- [NSException raise:@"MGLRedundantLayerException"
- format:@"This instance %@ was already added to %@. Adding the same layer instance " \
- "to the style more than once is invalid.", self, mapView.style];
- }
-
- if (otherLayer) {
- const mbgl::optional<std::string> belowLayerId{otherLayer.identifier.UTF8String};
- mapView.mbglMap->addLayer(std::move(_pendingLayer), belowLayerId);
- } else {
- mapView.mbglMap->addLayer(std::move(_pendingLayer));
- }
-}
-
-- (void)removeFromMapView:(MGLMapView *)mapView
-{
- if (self.rawLayer != mapView.mbglMap->getLayer(self.identifier.UTF8String)) {
- return;
- }
-
- auto removedLayer = mapView.mbglMap->removeLayer(self.identifier.UTF8String);
- if (!removedLayer) {
- return;
- }
-
- mbgl::style::CircleLayer *layer = dynamic_cast<mbgl::style::CircleLayer *>(removedLayer.get());
- if (!layer) {
- return;
- }
-
- removedLayer.release();
-
- _pendingLayer = std::unique_ptr<mbgl::style::CircleLayer>(layer);
- self.rawLayer = _pendingLayer.get();
-}
-
#pragma mark - Accessing the Paint Attributes
- (void)setCircleBlur:(MGLStyleValue<NSNumber *> *)circleBlur {
diff --git a/platform/darwin/src/MGLDistanceFormatter.m b/platform/darwin/src/MGLDistanceFormatter.m
index e77e48b512..a7a2f9c9e1 100644
--- a/platform/darwin/src/MGLDistanceFormatter.m
+++ b/platform/darwin/src/MGLDistanceFormatter.m
@@ -24,7 +24,7 @@ static const double FEET_PER_MILE = YARDS_PER_MILE * 3.0;
return [self stringFromValue:miles unit:unit];
} else {
unit = NSLengthFormatterUnitFoot;
- self.numberFormatter.roundingIncrement = @50;
+ self.numberFormatter.roundingIncrement = @1;
return [self stringFromValue:feet unit:unit];
}
} else {
diff --git a/platform/darwin/src/MGLFillExtrusionStyleLayer.h b/platform/darwin/src/MGLFillExtrusionStyleLayer.h
new file mode 100644
index 0000000000..84f6bedde4
--- /dev/null
+++ b/platform/darwin/src/MGLFillExtrusionStyleLayer.h
@@ -0,0 +1,364 @@
+// This file is generated.
+// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
+
+#import "MGLFoundation.h"
+#import "MGLStyleValue.h"
+#import "MGLVectorStyleLayer.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Controls the translation reference point.
+
+ Values of this type are used in the `MGLFillExtrusionStyleLayer.fillExtrusionTranslationAnchor`
+ property.
+ */
+typedef NS_ENUM(NSUInteger, MGLFillExtrusionTranslationAnchor) {
+ /**
+ The fill extrusion is translated relative to the map.
+ */
+ MGLFillExtrusionTranslationAnchorMap,
+ /**
+ The fill extrusion is translated relative to the viewport.
+ */
+ MGLFillExtrusionTranslationAnchorViewport,
+};
+
+/**
+ An `MGLFillExtrusionStyleLayer` is a style layer that renders one or more 3D
+ extruded polygons on the map.
+
+ Use a fill-extrusion style layer to configure the visual appearance of polygon
+ or multipolygon features in vector tiles loaded by an `MGLVectorSource` object
+ or `MGLPolygon`, `MGLPolygonFeature`, `MGLMultiPolygon`, or
+ `MGLMultiPolygonFeature` instances in an `MGLShapeSource` object.
+
+ You can access an existing fill-extrusion style layer using the
+ `-[MGLStyle layerWithIdentifier:]` method if you know its identifier;
+ otherwise, find it using the `MGLStyle.layers` property. You can also create a
+ new fill-extrusion style layer and add it to the style using a method such as
+ `-[MGLStyle addLayer:]`.
+
+ ### Example
+
+ ```swift
+ let layer = MGLFillExtrusionStyleLayer(identifier: "buildings", source: buildings)
+ layer.sourceLayerIdentifier = "building"
+ layer.fillExtrusionHeight = MGLStyleValue(interpolationMode: .identity, sourceStops: nil, attributeName: "height", options: nil)
+ layer.fillExtrusionBase = MGLStyleValue(interpolationMode: .identity, sourceStops: nil, attributeName: "min_height", options: nil)
+ layer.predicate = NSPredicate(format: "extrude == TRUE")
+ mapView.style?.addLayer(layer)
+ ```
+ */
+MGL_EXPORT
+@interface MGLFillExtrusionStyleLayer : MGLVectorStyleLayer
+
+/**
+ Returns a fill-extrusion style layer initialized with an identifier and source.
+
+ After initializing and configuring the style layer, add it to a map view’s
+ style using the `-[MGLStyle addLayer:]` or
+ `-[MGLStyle insertLayer:belowLayer:]` method.
+
+ @param identifier A string that uniquely identifies the source in the style to
+ which it is added.
+ @param source The source from which to obtain the data to style. If the source
+ has not yet been added to the current style, the behavior is undefined.
+ @return An initialized foreground style layer.
+ */
+- (instancetype)initWithIdentifier:(NSString *)identifier source:(MGLSource *)source;
+
+#pragma mark - Accessing the Paint Attributes
+
+/**
+ The height with which to extrude the base of this layer. Must be less than or
+ equal to `fillExtrusionHeight`.
+
+ This property is measured in meters.
+
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `0`. Set this property to `nil` to reset
+ it to the default value.
+
+ This property is only applied to the style if `fillExtrusionHeight` is
+ non-`nil`. Otherwise, it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLConstantStyleValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ */
+@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *fillExtrusionBase;
+
+/**
+ The transition affecting any changes to this layer’s `fillExtrusionBase` property.
+
+ This property corresponds to the `fill-extrusion-base-transition` property in the style JSON file format.
+*/
+@property (nonatomic) MGLTransition fillExtrusionBaseTransition;
+
+#if TARGET_OS_IPHONE
+/**
+ The base color of this layer. The extrusion's surfaces will be shaded
+ differently based on this color in combination with the `light` settings. If
+ this color is specified with an alpha component, the alpha component will be
+ ignored; use `fillExtrusionOpacity` to set layer opacityco.
+
+ The default value of this property is an `MGLStyleValue` object containing
+ `UIColor.blackColor`. Set this property to `nil` to reset it to the default
+ value.
+
+ This property is only applied to the style if `fillExtrusionPattern` is set to
+ `nil`. Otherwise, it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLConstantStyleValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ */
+@property (nonatomic, null_resettable) MGLStyleValue<UIColor *> *fillExtrusionColor;
+#else
+/**
+ The base color of this layer. The extrusion's surfaces will be shaded
+ differently based on this color in combination with the `light` settings. If
+ this color is specified with an alpha component, the alpha component will be
+ ignored; use `fillExtrusionOpacity` to set layer opacityco.
+
+ The default value of this property is an `MGLStyleValue` object containing
+ `NSColor.blackColor`. Set this property to `nil` to reset it to the default
+ value.
+
+ This property is only applied to the style if `fillExtrusionPattern` is set to
+ `nil`. Otherwise, it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLConstantStyleValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ */
+@property (nonatomic, null_resettable) MGLStyleValue<NSColor *> *fillExtrusionColor;
+#endif
+
+/**
+ The transition affecting any changes to this layer’s `fillExtrusionColor` property.
+
+ This property corresponds to the `fill-extrusion-color-transition` property in the style JSON file format.
+*/
+@property (nonatomic) MGLTransition fillExtrusionColorTransition;
+
+/**
+ The height with which to extrude this layer.
+
+ This property is measured in meters.
+
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `0`. Set this property to `nil` to reset
+ it to the default value.
+
+ You can set this property to an instance of:
+
+ * `MGLConstantStyleValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ */
+@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *fillExtrusionHeight;
+
+/**
+ The transition affecting any changes to this layer’s `fillExtrusionHeight` property.
+
+ This property corresponds to the `fill-extrusion-height-transition` property in the style JSON file format.
+*/
+@property (nonatomic) MGLTransition fillExtrusionHeightTransition;
+
+/**
+ The opacity of the entire fill extrusion layer. This is rendered on a
+ per-layer, not per-feature, basis, and data-driven styling is not available.
+
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSNumber` object containing the float `1`. Set this property to `nil` to reset
+ it to the default value.
+
+ You can set this property to an instance of:
+
+ * `MGLConstantStyleValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ */
+@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *fillExtrusionOpacity;
+
+/**
+ The transition affecting any changes to this layer’s `fillExtrusionOpacity` property.
+
+ This property corresponds to the `fill-extrusion-opacity-transition` property in the style JSON file format.
+*/
+@property (nonatomic) MGLTransition fillExtrusionOpacityTransition;
+
+/**
+ Name of image in style images to use for drawing image fill-extrusions. For
+ seamless patterns, image width and height must be a factor of two (2, 4, 8,
+ ..., 512).
+
+ You can set this property to an instance of:
+
+ * `MGLConstantStyleValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of
+ `MGLInterpolationModeInterval`
+ */
+@property (nonatomic, null_resettable) MGLStyleValue<NSString *> *fillExtrusionPattern;
+
+/**
+ The transition affecting any changes to this layer’s `fillExtrusionPattern` property.
+
+ This property corresponds to the `fill-extrusion-pattern-transition` property in the style JSON file format.
+*/
+@property (nonatomic) MGLTransition fillExtrusionPatternTransition;
+
+#if TARGET_OS_IPHONE
+/**
+ The geometry's offset.
+
+ This property is measured in points.
+
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSValue` object containing a `CGVector` struct set to 0 points rightward and 0
+ points downward. Set this property to `nil` to reset it to the default value.
+
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-fill-extrusion-translate"><code>fill-extrusion-translate</code></a>
+ layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLConstantStyleValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ */
+@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *fillExtrusionTranslation;
+#else
+/**
+ The geometry's offset.
+
+ This property is measured in points.
+
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSValue` object containing a `CGVector` struct set to 0 points rightward and 0
+ points upward. Set this property to `nil` to reset it to the default value.
+
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-fill-extrusion-translate"><code>fill-extrusion-translate</code></a>
+ layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLConstantStyleValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ */
+@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *fillExtrusionTranslation;
+#endif
+
+/**
+ The transition affecting any changes to this layer’s `fillExtrusionTranslation` property.
+
+ This property corresponds to the `fill-extrusion-translate-transition` property in the style JSON file format.
+*/
+@property (nonatomic) MGLTransition fillExtrusionTranslationTransition;
+
+@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *fillExtrusionTranslate __attribute__((unavailable("Use fillExtrusionTranslation instead.")));
+
+/**
+ Controls the translation reference point.
+
+ The default value of this property is an `MGLStyleValue` object containing an
+ `NSValue` object containing `MGLFillExtrusionTranslationAnchorMap`. Set this
+ property to `nil` to reset it to the default value.
+
+ This property is only applied to the style if `fillExtrusionTranslation` is
+ non-`nil`. Otherwise, it is ignored.
+
+ This attribute corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-fill-extrusion-translate-anchor"><code>fill-extrusion-translate-anchor</code></a>
+ layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLConstantStyleValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of
+ `MGLInterpolationModeInterval`
+ */
+@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *fillExtrusionTranslationAnchor;
+
+@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *fillExtrusionTranslateAnchor __attribute__((unavailable("Use fillExtrusionTranslationAnchor instead.")));
+
+@end
+
+/**
+ Methods for wrapping an enumeration value for a style layer attribute in an
+ `MGLFillExtrusionStyleLayer` object and unwrapping its raw value.
+ */
+@interface NSValue (MGLFillExtrusionStyleLayerAdditions)
+
+#pragma mark Working with Fill extrusion Style Layer Attribute Values
+
+/**
+ Creates a new value object containing the given `MGLFillExtrusionTranslationAnchor` enumeration.
+
+ @param fillExtrusionTranslationAnchor The value for the new object.
+ @return A new value object that contains the enumeration value.
+ */
++ (instancetype)valueWithMGLFillExtrusionTranslationAnchor:(MGLFillExtrusionTranslationAnchor)fillExtrusionTranslationAnchor;
+
+/**
+ The `MGLFillExtrusionTranslationAnchor` enumeration representation of the value.
+ */
+@property (readonly) MGLFillExtrusionTranslationAnchor MGLFillExtrusionTranslationAnchorValue;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLFillExtrusionStyleLayer.mm b/platform/darwin/src/MGLFillExtrusionStyleLayer.mm
new file mode 100644
index 0000000000..b00ed8e09f
--- /dev/null
+++ b/platform/darwin/src/MGLFillExtrusionStyleLayer.mm
@@ -0,0 +1,335 @@
+// This file is generated.
+// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
+
+#import "MGLSource.h"
+#import "NSPredicate+MGLAdditions.h"
+#import "NSDate+MGLAdditions.h"
+#import "MGLStyleLayer_Private.h"
+#import "MGLStyleValue_Private.h"
+#import "MGLFillExtrusionStyleLayer.h"
+
+#include <mbgl/style/transition_options.hpp>
+#include <mbgl/style/layers/fill_extrusion_layer.hpp>
+
+namespace mbgl {
+
+ MBGL_DEFINE_ENUM(MGLFillExtrusionTranslationAnchor, {
+ { MGLFillExtrusionTranslationAnchorMap, "map" },
+ { MGLFillExtrusionTranslationAnchorViewport, "viewport" },
+ });
+
+}
+
+@interface MGLFillExtrusionStyleLayer ()
+
+@property (nonatomic, readonly) mbgl::style::FillExtrusionLayer *rawLayer;
+
+@end
+
+@implementation MGLFillExtrusionStyleLayer
+
+- (instancetype)initWithIdentifier:(NSString *)identifier source:(MGLSource *)source
+{
+ auto layer = std::make_unique<mbgl::style::FillExtrusionLayer>(identifier.UTF8String, source.identifier.UTF8String);
+ return self = [super initWithPendingLayer:std::move(layer)];
+}
+
+- (mbgl::style::FillExtrusionLayer *)rawLayer
+{
+ return (mbgl::style::FillExtrusionLayer *)super.rawLayer;
+}
+
+- (NSString *)sourceIdentifier
+{
+ MGLAssertStyleLayerIsValid();
+
+ return @(self.rawLayer->getSourceID().c_str());
+}
+
+- (NSString *)sourceLayerIdentifier
+{
+ MGLAssertStyleLayerIsValid();
+
+ auto layerID = self.rawLayer->getSourceLayer();
+ return layerID.empty() ? nil : @(layerID.c_str());
+}
+
+- (void)setSourceLayerIdentifier:(NSString *)sourceLayerIdentifier
+{
+ MGLAssertStyleLayerIsValid();
+
+ self.rawLayer->setSourceLayer(sourceLayerIdentifier.UTF8String ?: "");
+}
+
+- (void)setPredicate:(NSPredicate *)predicate
+{
+ MGLAssertStyleLayerIsValid();
+
+ self.rawLayer->setFilter(predicate ? predicate.mgl_filter : mbgl::style::NullFilter());
+}
+
+- (NSPredicate *)predicate
+{
+ MGLAssertStyleLayerIsValid();
+
+ return [NSPredicate mgl_predicateWithFilter:self.rawLayer->getFilter()];
+}
+
+#pragma mark - Accessing the Paint Attributes
+
+- (void)setFillExtrusionBase:(MGLStyleValue<NSNumber *> *)fillExtrusionBase {
+ MGLAssertStyleLayerIsValid();
+
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(fillExtrusionBase);
+ self.rawLayer->setFillExtrusionBase(mbglValue);
+}
+
+- (MGLStyleValue<NSNumber *> *)fillExtrusionBase {
+ MGLAssertStyleLayerIsValid();
+
+ auto propertyValue = self.rawLayer->getFillExtrusionBase();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultFillExtrusionBase());
+ }
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
+}
+
+- (void)setFillExtrusionBaseTransition:(MGLTransition )transition {
+ MGLAssertStyleLayerIsValid();
+
+ mbgl::style::TransitionOptions options { { MGLDurationFromTimeInterval(transition.duration) }, { MGLDurationFromTimeInterval(transition.delay) } };
+ self.rawLayer->setFillExtrusionBaseTransition(options);
+}
+
+- (MGLTransition)fillExtrusionBaseTransition {
+ MGLAssertStyleLayerIsValid();
+
+ mbgl::style::TransitionOptions transitionOptions = self.rawLayer->getFillExtrusionBaseTransition();
+ MGLTransition transition;
+ transition.duration = MGLTimeIntervalFromDuration(transitionOptions.duration.value_or(mbgl::Duration::zero()));
+ transition.delay = MGLTimeIntervalFromDuration(transitionOptions.delay.value_or(mbgl::Duration::zero()));
+
+ return transition;
+}
+
+- (void)setFillExtrusionColor:(MGLStyleValue<MGLColor *> *)fillExtrusionColor {
+ MGLAssertStyleLayerIsValid();
+
+ auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenPropertyValue(fillExtrusionColor);
+ self.rawLayer->setFillExtrusionColor(mbglValue);
+}
+
+- (MGLStyleValue<MGLColor *> *)fillExtrusionColor {
+ MGLAssertStyleLayerIsValid();
+
+ auto propertyValue = self.rawLayer->getFillExtrusionColor();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(self.rawLayer->getDefaultFillExtrusionColor());
+ }
+ return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(propertyValue);
+}
+
+- (void)setFillExtrusionColorTransition:(MGLTransition )transition {
+ MGLAssertStyleLayerIsValid();
+
+ mbgl::style::TransitionOptions options { { MGLDurationFromTimeInterval(transition.duration) }, { MGLDurationFromTimeInterval(transition.delay) } };
+ self.rawLayer->setFillExtrusionColorTransition(options);
+}
+
+- (MGLTransition)fillExtrusionColorTransition {
+ MGLAssertStyleLayerIsValid();
+
+ mbgl::style::TransitionOptions transitionOptions = self.rawLayer->getFillExtrusionColorTransition();
+ MGLTransition transition;
+ transition.duration = MGLTimeIntervalFromDuration(transitionOptions.duration.value_or(mbgl::Duration::zero()));
+ transition.delay = MGLTimeIntervalFromDuration(transitionOptions.delay.value_or(mbgl::Duration::zero()));
+
+ return transition;
+}
+
+- (void)setFillExtrusionHeight:(MGLStyleValue<NSNumber *> *)fillExtrusionHeight {
+ MGLAssertStyleLayerIsValid();
+
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(fillExtrusionHeight);
+ self.rawLayer->setFillExtrusionHeight(mbglValue);
+}
+
+- (MGLStyleValue<NSNumber *> *)fillExtrusionHeight {
+ MGLAssertStyleLayerIsValid();
+
+ auto propertyValue = self.rawLayer->getFillExtrusionHeight();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultFillExtrusionHeight());
+ }
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
+}
+
+- (void)setFillExtrusionHeightTransition:(MGLTransition )transition {
+ MGLAssertStyleLayerIsValid();
+
+ mbgl::style::TransitionOptions options { { MGLDurationFromTimeInterval(transition.duration) }, { MGLDurationFromTimeInterval(transition.delay) } };
+ self.rawLayer->setFillExtrusionHeightTransition(options);
+}
+
+- (MGLTransition)fillExtrusionHeightTransition {
+ MGLAssertStyleLayerIsValid();
+
+ mbgl::style::TransitionOptions transitionOptions = self.rawLayer->getFillExtrusionHeightTransition();
+ MGLTransition transition;
+ transition.duration = MGLTimeIntervalFromDuration(transitionOptions.duration.value_or(mbgl::Duration::zero()));
+ transition.delay = MGLTimeIntervalFromDuration(transitionOptions.delay.value_or(mbgl::Duration::zero()));
+
+ return transition;
+}
+
+- (void)setFillExtrusionOpacity:(MGLStyleValue<NSNumber *> *)fillExtrusionOpacity {
+ MGLAssertStyleLayerIsValid();
+
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(fillExtrusionOpacity);
+ self.rawLayer->setFillExtrusionOpacity(mbglValue);
+}
+
+- (MGLStyleValue<NSNumber *> *)fillExtrusionOpacity {
+ MGLAssertStyleLayerIsValid();
+
+ auto propertyValue = self.rawLayer->getFillExtrusionOpacity();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultFillExtrusionOpacity());
+ }
+ return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+}
+
+- (void)setFillExtrusionOpacityTransition:(MGLTransition )transition {
+ MGLAssertStyleLayerIsValid();
+
+ mbgl::style::TransitionOptions options { { MGLDurationFromTimeInterval(transition.duration) }, { MGLDurationFromTimeInterval(transition.delay) } };
+ self.rawLayer->setFillExtrusionOpacityTransition(options);
+}
+
+- (MGLTransition)fillExtrusionOpacityTransition {
+ MGLAssertStyleLayerIsValid();
+
+ mbgl::style::TransitionOptions transitionOptions = self.rawLayer->getFillExtrusionOpacityTransition();
+ MGLTransition transition;
+ transition.duration = MGLTimeIntervalFromDuration(transitionOptions.duration.value_or(mbgl::Duration::zero()));
+ transition.delay = MGLTimeIntervalFromDuration(transitionOptions.delay.value_or(mbgl::Duration::zero()));
+
+ return transition;
+}
+
+- (void)setFillExtrusionPattern:(MGLStyleValue<NSString *> *)fillExtrusionPattern {
+ MGLAssertStyleLayerIsValid();
+
+ auto mbglValue = MGLStyleValueTransformer<std::string, NSString *>().toPropertyValue(fillExtrusionPattern);
+ self.rawLayer->setFillExtrusionPattern(mbglValue);
+}
+
+- (MGLStyleValue<NSString *> *)fillExtrusionPattern {
+ MGLAssertStyleLayerIsValid();
+
+ auto propertyValue = self.rawLayer->getFillExtrusionPattern();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(self.rawLayer->getDefaultFillExtrusionPattern());
+ }
+ return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(propertyValue);
+}
+
+- (void)setFillExtrusionPatternTransition:(MGLTransition )transition {
+ MGLAssertStyleLayerIsValid();
+
+ mbgl::style::TransitionOptions options { { MGLDurationFromTimeInterval(transition.duration) }, { MGLDurationFromTimeInterval(transition.delay) } };
+ self.rawLayer->setFillExtrusionPatternTransition(options);
+}
+
+- (MGLTransition)fillExtrusionPatternTransition {
+ MGLAssertStyleLayerIsValid();
+
+ mbgl::style::TransitionOptions transitionOptions = self.rawLayer->getFillExtrusionPatternTransition();
+ MGLTransition transition;
+ transition.duration = MGLTimeIntervalFromDuration(transitionOptions.duration.value_or(mbgl::Duration::zero()));
+ transition.delay = MGLTimeIntervalFromDuration(transitionOptions.delay.value_or(mbgl::Duration::zero()));
+
+ return transition;
+}
+
+- (void)setFillExtrusionTranslation:(MGLStyleValue<NSValue *> *)fillExtrusionTranslation {
+ MGLAssertStyleLayerIsValid();
+
+ auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toInterpolatablePropertyValue(fillExtrusionTranslation);
+ self.rawLayer->setFillExtrusionTranslate(mbglValue);
+}
+
+- (MGLStyleValue<NSValue *> *)fillExtrusionTranslation {
+ MGLAssertStyleLayerIsValid();
+
+ auto propertyValue = self.rawLayer->getFillExtrusionTranslate();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(self.rawLayer->getDefaultFillExtrusionTranslate());
+ }
+ return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(propertyValue);
+}
+
+- (void)setFillExtrusionTranslationTransition:(MGLTransition )transition {
+ MGLAssertStyleLayerIsValid();
+
+ mbgl::style::TransitionOptions options { { MGLDurationFromTimeInterval(transition.duration) }, { MGLDurationFromTimeInterval(transition.delay) } };
+ self.rawLayer->setFillExtrusionTranslateTransition(options);
+}
+
+- (MGLTransition)fillExtrusionTranslationTransition {
+ MGLAssertStyleLayerIsValid();
+
+ mbgl::style::TransitionOptions transitionOptions = self.rawLayer->getFillExtrusionTranslateTransition();
+ MGLTransition transition;
+ transition.duration = MGLTimeIntervalFromDuration(transitionOptions.duration.value_or(mbgl::Duration::zero()));
+ transition.delay = MGLTimeIntervalFromDuration(transitionOptions.delay.value_or(mbgl::Duration::zero()));
+
+ return transition;
+}
+
+- (void)setFillExtrusionTranslate:(MGLStyleValue<NSValue *> *)fillExtrusionTranslate {
+}
+
+- (MGLStyleValue<NSValue *> *)fillExtrusionTranslate {
+ return self.fillExtrusionTranslation;
+}
+
+- (void)setFillExtrusionTranslationAnchor:(MGLStyleValue<NSValue *> *)fillExtrusionTranslationAnchor {
+ MGLAssertStyleLayerIsValid();
+
+ auto mbglValue = MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLFillExtrusionTranslationAnchor>().toEnumPropertyValue(fillExtrusionTranslationAnchor);
+ self.rawLayer->setFillExtrusionTranslateAnchor(mbglValue);
+}
+
+- (MGLStyleValue<NSValue *> *)fillExtrusionTranslationAnchor {
+ MGLAssertStyleLayerIsValid();
+
+ auto propertyValue = self.rawLayer->getFillExtrusionTranslateAnchor();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLFillExtrusionTranslationAnchor>().toEnumStyleValue(self.rawLayer->getDefaultFillExtrusionTranslateAnchor());
+ }
+ return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLFillExtrusionTranslationAnchor>().toEnumStyleValue(propertyValue);
+}
+
+- (void)setFillExtrusionTranslateAnchor:(MGLStyleValue<NSValue *> *)fillExtrusionTranslateAnchor {
+}
+
+- (MGLStyleValue<NSValue *> *)fillExtrusionTranslateAnchor {
+ return self.fillExtrusionTranslationAnchor;
+}
+
+@end
+
+@implementation NSValue (MGLFillExtrusionStyleLayerAdditions)
+
++ (NSValue *)valueWithMGLFillExtrusionTranslationAnchor:(MGLFillExtrusionTranslationAnchor)fillExtrusionTranslationAnchor {
+ return [NSValue value:&fillExtrusionTranslationAnchor withObjCType:@encode(MGLFillExtrusionTranslationAnchor)];
+}
+
+- (MGLFillExtrusionTranslationAnchor)MGLFillExtrusionTranslationAnchorValue {
+ MGLFillExtrusionTranslationAnchor fillExtrusionTranslationAnchor;
+ [self getValue:&fillExtrusionTranslationAnchor];
+ return fillExtrusionTranslationAnchor;
+}
+
+@end
diff --git a/platform/darwin/src/MGLFillStyleLayer.h b/platform/darwin/src/MGLFillStyleLayer.h
index 1f3cfc8af5..6e3297bdec 100644
--- a/platform/darwin/src/MGLFillStyleLayer.h
+++ b/platform/darwin/src/MGLFillStyleLayer.h
@@ -52,6 +52,21 @@ typedef NS_ENUM(NSUInteger, MGLFillTranslationAnchor) {
MGL_EXPORT
@interface MGLFillStyleLayer : MGLVectorStyleLayer
+/**
+ Returns a fill style layer initialized with an identifier and source.
+
+ After initializing and configuring the style layer, add it to a map view’s
+ style using the `-[MGLStyle addLayer:]` or
+ `-[MGLStyle insertLayer:belowLayer:]` method.
+
+ @param identifier A string that uniquely identifies the source in the style to
+ which it is added.
+ @param source The source from which to obtain the data to style. If the source
+ has not yet been added to the current style, the behavior is undefined.
+ @return An initialized foreground style layer.
+ */
+- (instancetype)initWithIdentifier:(NSString *)identifier source:(MGLSource *)source;
+
#pragma mark - Accessing the Paint Attributes
/**
diff --git a/platform/darwin/src/MGLFillStyleLayer.mm b/platform/darwin/src/MGLFillStyleLayer.mm
index 1322a7a0b6..71b01a6661 100644
--- a/platform/darwin/src/MGLFillStyleLayer.mm
+++ b/platform/darwin/src/MGLFillStyleLayer.mm
@@ -2,14 +2,13 @@
// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLSource.h"
-#import "MGLMapView_Private.h"
#import "NSPredicate+MGLAdditions.h"
#import "NSDate+MGLAdditions.h"
#import "MGLStyleLayer_Private.h"
#import "MGLStyleValue_Private.h"
#import "MGLFillStyleLayer.h"
-#include <mbgl/map/map.hpp>
+#include <mbgl/style/transition_options.hpp>
#include <mbgl/style/layers/fill_layer.hpp>
namespace mbgl {
@@ -23,23 +22,16 @@ namespace mbgl {
@interface MGLFillStyleLayer ()
-@property (nonatomic) mbgl::style::FillLayer *rawLayer;
+@property (nonatomic, readonly) mbgl::style::FillLayer *rawLayer;
@end
@implementation MGLFillStyleLayer
-{
- std::unique_ptr<mbgl::style::FillLayer> _pendingLayer;
-}
- (instancetype)initWithIdentifier:(NSString *)identifier source:(MGLSource *)source
{
- if (self = [super initWithIdentifier:identifier source:source]) {
- auto layer = std::make_unique<mbgl::style::FillLayer>(identifier.UTF8String, source.identifier.UTF8String);
- _pendingLayer = std::move(layer);
- self.rawLayer = _pendingLayer.get();
- }
- return self;
+ auto layer = std::make_unique<mbgl::style::FillLayer>(identifier.UTF8String, source.identifier.UTF8String);
+ return self = [super initWithPendingLayer:std::move(layer)];
}
- (mbgl::style::FillLayer *)rawLayer
@@ -47,11 +39,6 @@ namespace mbgl {
return (mbgl::style::FillLayer *)super.rawLayer;
}
-- (void)setRawLayer:(mbgl::style::FillLayer *)rawLayer
-{
- super.rawLayer = rawLayer;
-}
-
- (NSString *)sourceIdentifier
{
MGLAssertStyleLayerIsValid();
@@ -88,46 +75,6 @@ namespace mbgl {
return [NSPredicate mgl_predicateWithFilter:self.rawLayer->getFilter()];
}
-#pragma mark - Adding to and removing from a map view
-
-- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer
-{
- if (_pendingLayer == nullptr) {
- [NSException raise:@"MGLRedundantLayerException"
- format:@"This instance %@ was already added to %@. Adding the same layer instance " \
- "to the style more than once is invalid.", self, mapView.style];
- }
-
- if (otherLayer) {
- const mbgl::optional<std::string> belowLayerId{otherLayer.identifier.UTF8String};
- mapView.mbglMap->addLayer(std::move(_pendingLayer), belowLayerId);
- } else {
- mapView.mbglMap->addLayer(std::move(_pendingLayer));
- }
-}
-
-- (void)removeFromMapView:(MGLMapView *)mapView
-{
- if (self.rawLayer != mapView.mbglMap->getLayer(self.identifier.UTF8String)) {
- return;
- }
-
- auto removedLayer = mapView.mbglMap->removeLayer(self.identifier.UTF8String);
- if (!removedLayer) {
- return;
- }
-
- mbgl::style::FillLayer *layer = dynamic_cast<mbgl::style::FillLayer *>(removedLayer.get());
- if (!layer) {
- return;
- }
-
- removedLayer.release();
-
- _pendingLayer = std::unique_ptr<mbgl::style::FillLayer>(layer);
- self.rawLayer = _pendingLayer.get();
-}
-
#pragma mark - Accessing the Paint Attributes
- (void)setFillAntialiased:(MGLStyleValue<NSNumber *> *)fillAntialiased {
diff --git a/platform/darwin/src/MGLForegroundStyleLayer.h b/platform/darwin/src/MGLForegroundStyleLayer.h
index 87763f4634..16a973630e 100644
--- a/platform/darwin/src/MGLForegroundStyleLayer.h
+++ b/platform/darwin/src/MGLForegroundStyleLayer.h
@@ -20,23 +20,7 @@ MGL_EXPORT
#pragma mark Initializing a Style Layer
-- (instancetype)init __attribute__((unavailable("Use -initWithIdentifier:source: instead.")));
-- (instancetype)initWithIdentifier:(NSString *)identifier __attribute__((unavailable("Use -initWithIdentifier:source: instead.")));
-
-/**
- Returns a foreground style layer initialized with an identifier and source.
-
- After initializing and configuring the style layer, add it to a map view’s
- style using the `-[MGLStyle addLayer:]` or
- `-[MGLStyle insertLayer:belowLayer:]` method.
-
- @param identifier A string that uniquely identifies the source in the style to
- which it is added.
- @param source The source from which to obtain the data to style. If the source
- has not yet been added to the current style, the behavior is undefined.
- @return An initialized foreground style layer.
- */
-- (instancetype)initWithIdentifier:(NSString *)identifier source:(MGLSource *)source NS_DESIGNATED_INITIALIZER;
+- (instancetype)init __attribute__((unavailable("Use -init methods of concrete subclasses instead.")));
#pragma mark Specifying a Style Layer’s Content
diff --git a/platform/darwin/src/MGLForegroundStyleLayer.m b/platform/darwin/src/MGLForegroundStyleLayer.mm
index b7a0379af2..6888f89b92 100644
--- a/platform/darwin/src/MGLForegroundStyleLayer.m
+++ b/platform/darwin/src/MGLForegroundStyleLayer.mm
@@ -1,13 +1,11 @@
#import "MGLForegroundStyleLayer.h"
-#import "MGLSource.h"
@implementation MGLForegroundStyleLayer
-- (instancetype)initWithIdentifier:(NSString *)identifier source:(MGLSource *)source {
- if (self = [super initWithIdentifier:identifier]) {
- _sourceIdentifier = source.identifier;
- }
- return self;
+- (NSString *)sourceIdentifier {
+ [NSException raise:@"MGLAbstractClassException"
+ format:@"MGLForegroundStyleLayer is an abstract class"];
+ return nil;
}
- (NSString *)description {
diff --git a/platform/darwin/src/MGLGeometry.mm b/platform/darwin/src/MGLGeometry.mm
index 8c0c5f9cb7..1540a3a741 100644
--- a/platform/darwin/src/MGLGeometry.mm
+++ b/platform/darwin/src/MGLGeometry.mm
@@ -32,6 +32,15 @@ CGRect MGLExtendRect(CGRect rect, CGPoint point) {
return rect;
}
+mbgl::LatLng MGLLatLngFromLocationCoordinate2D(CLLocationCoordinate2D coordinate) {
+ try {
+ return mbgl::LatLng(coordinate.latitude, coordinate.longitude);
+ } catch (std::domain_error &error) {
+ [NSException raise:NSInvalidArgumentException format:@"%s", error.what()];
+ return {};
+ }
+}
+
MGL_EXPORT
CLLocationDistance MGLAltitudeForZoomLevel(double zoomLevel, CGFloat pitch, CLLocationDegrees latitude, CGSize size) {
CLLocationDistance metersPerPixel = mbgl::Projection::getMetersPerPixelAtLatitude(latitude, zoomLevel);
diff --git a/platform/darwin/src/MGLGeometry_Private.h b/platform/darwin/src/MGLGeometry_Private.h
index e6b37b3530..3e029e8ee0 100644
--- a/platform/darwin/src/MGLGeometry_Private.h
+++ b/platform/darwin/src/MGLGeometry_Private.h
@@ -12,16 +12,14 @@
/// the given point.
CGRect MGLExtendRect(CGRect rect, CGPoint point);
-NS_INLINE mbgl::LatLng MGLLatLngFromLocationCoordinate2D(CLLocationCoordinate2D coordinate) {
- return mbgl::LatLng(coordinate.latitude, coordinate.longitude);
-}
+mbgl::LatLng MGLLatLngFromLocationCoordinate2D(CLLocationCoordinate2D coordinate);
NS_INLINE mbgl::Point<double> MGLPointFromLocationCoordinate2D(CLLocationCoordinate2D coordinate) {
return mbgl::Point<double>(coordinate.longitude, coordinate.latitude);
}
NS_INLINE CLLocationCoordinate2D MGLLocationCoordinate2DFromLatLng(mbgl::LatLng latLng) {
- return CLLocationCoordinate2DMake(latLng.latitude, latLng.longitude);
+ return CLLocationCoordinate2DMake(latLng.latitude(), latLng.longitude());
}
NS_INLINE MGLCoordinateBounds MGLCoordinateBoundsFromLatLngBounds(mbgl::LatLngBounds latLngBounds) {
diff --git a/platform/darwin/src/MGLLineStyleLayer.h b/platform/darwin/src/MGLLineStyleLayer.h
index e03f3e347e..38513652c5 100644
--- a/platform/darwin/src/MGLLineStyleLayer.h
+++ b/platform/darwin/src/MGLLineStyleLayer.h
@@ -107,6 +107,21 @@ typedef NS_ENUM(NSUInteger, MGLLineTranslationAnchor) {
MGL_EXPORT
@interface MGLLineStyleLayer : MGLVectorStyleLayer
+/**
+ Returns a line style layer initialized with an identifier and source.
+
+ After initializing and configuring the style layer, add it to a map view’s
+ style using the `-[MGLStyle addLayer:]` or
+ `-[MGLStyle insertLayer:belowLayer:]` method.
+
+ @param identifier A string that uniquely identifies the source in the style to
+ which it is added.
+ @param source The source from which to obtain the data to style. If the source
+ has not yet been added to the current style, the behavior is undefined.
+ @return An initialized foreground style layer.
+ */
+- (instancetype)initWithIdentifier:(NSString *)identifier source:(MGLSource *)source;
+
#pragma mark - Accessing the Layout Attributes
/**
diff --git a/platform/darwin/src/MGLLineStyleLayer.mm b/platform/darwin/src/MGLLineStyleLayer.mm
index e37489cf0b..8b90efd0c4 100644
--- a/platform/darwin/src/MGLLineStyleLayer.mm
+++ b/platform/darwin/src/MGLLineStyleLayer.mm
@@ -2,14 +2,13 @@
// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLSource.h"
-#import "MGLMapView_Private.h"
#import "NSPredicate+MGLAdditions.h"
#import "NSDate+MGLAdditions.h"
#import "MGLStyleLayer_Private.h"
#import "MGLStyleValue_Private.h"
#import "MGLLineStyleLayer.h"
-#include <mbgl/map/map.hpp>
+#include <mbgl/style/transition_options.hpp>
#include <mbgl/style/layers/line_layer.hpp>
namespace mbgl {
@@ -35,23 +34,16 @@ namespace mbgl {
@interface MGLLineStyleLayer ()
-@property (nonatomic) mbgl::style::LineLayer *rawLayer;
+@property (nonatomic, readonly) mbgl::style::LineLayer *rawLayer;
@end
@implementation MGLLineStyleLayer
-{
- std::unique_ptr<mbgl::style::LineLayer> _pendingLayer;
-}
- (instancetype)initWithIdentifier:(NSString *)identifier source:(MGLSource *)source
{
- if (self = [super initWithIdentifier:identifier source:source]) {
- auto layer = std::make_unique<mbgl::style::LineLayer>(identifier.UTF8String, source.identifier.UTF8String);
- _pendingLayer = std::move(layer);
- self.rawLayer = _pendingLayer.get();
- }
- return self;
+ auto layer = std::make_unique<mbgl::style::LineLayer>(identifier.UTF8String, source.identifier.UTF8String);
+ return self = [super initWithPendingLayer:std::move(layer)];
}
- (mbgl::style::LineLayer *)rawLayer
@@ -59,11 +51,6 @@ namespace mbgl {
return (mbgl::style::LineLayer *)super.rawLayer;
}
-- (void)setRawLayer:(mbgl::style::LineLayer *)rawLayer
-{
- super.rawLayer = rawLayer;
-}
-
- (NSString *)sourceIdentifier
{
MGLAssertStyleLayerIsValid();
@@ -100,46 +87,6 @@ namespace mbgl {
return [NSPredicate mgl_predicateWithFilter:self.rawLayer->getFilter()];
}
-#pragma mark - Adding to and removing from a map view
-
-- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer
-{
- if (_pendingLayer == nullptr) {
- [NSException raise:@"MGLRedundantLayerException"
- format:@"This instance %@ was already added to %@. Adding the same layer instance " \
- "to the style more than once is invalid.", self, mapView.style];
- }
-
- if (otherLayer) {
- const mbgl::optional<std::string> belowLayerId{otherLayer.identifier.UTF8String};
- mapView.mbglMap->addLayer(std::move(_pendingLayer), belowLayerId);
- } else {
- mapView.mbglMap->addLayer(std::move(_pendingLayer));
- }
-}
-
-- (void)removeFromMapView:(MGLMapView *)mapView
-{
- if (self.rawLayer != mapView.mbglMap->getLayer(self.identifier.UTF8String)) {
- return;
- }
-
- auto removedLayer = mapView.mbglMap->removeLayer(self.identifier.UTF8String);
- if (!removedLayer) {
- return;
- }
-
- mbgl::style::LineLayer *layer = dynamic_cast<mbgl::style::LineLayer *>(removedLayer.get());
- if (!layer) {
- return;
- }
-
- removedLayer.release();
-
- _pendingLayer = std::unique_ptr<mbgl::style::LineLayer>(layer);
- self.rawLayer = _pendingLayer.get();
-}
-
#pragma mark - Accessing the Layout Attributes
- (void)setLineCap:(MGLStyleValue<NSValue *> *)lineCap {
diff --git a/platform/darwin/src/MGLMapCamera.mm b/platform/darwin/src/MGLMapCamera.mm
index 613124da66..1611dbf4a3 100644
--- a/platform/darwin/src/MGLMapCamera.mm
+++ b/platform/darwin/src/MGLMapCamera.mm
@@ -1,4 +1,5 @@
#import "MGLMapCamera.h"
+#import "MGLGeometry_Private.h"
#include <mbgl/util/projection.hpp>
@@ -23,17 +24,21 @@ BOOL MGLEqualFloatWithAccuracy(CGFloat left, CGFloat right, CGFloat accuracy)
fromEyeCoordinate:(CLLocationCoordinate2D)eyeCoordinate
eyeAltitude:(CLLocationDistance)eyeAltitude
{
- mbgl::LatLng centerLatLng = mbgl::LatLng(centerCoordinate.latitude, centerCoordinate.longitude);
- mbgl::LatLng eyeLatLng = mbgl::LatLng(eyeCoordinate.latitude, eyeCoordinate.longitude);
-
- mbgl::ProjectedMeters centerMeters = mbgl::Projection::projectedMetersForLatLng(centerLatLng);
- mbgl::ProjectedMeters eyeMeters = mbgl::Projection::projectedMetersForLatLng(eyeLatLng);
- CLLocationDirection heading = std::atan((centerMeters.northing - eyeMeters.northing) /
- (centerMeters.easting - eyeMeters.easting));
-
- double groundDistance = std::hypot(centerMeters.northing - eyeMeters.northing,
- centerMeters.easting - eyeMeters.easting);
- CGFloat pitch = std::atan(eyeAltitude / groundDistance);
+ CLLocationDirection heading = -1;
+ CGFloat pitch = -1;
+ if (CLLocationCoordinate2DIsValid(centerCoordinate) && CLLocationCoordinate2DIsValid(eyeCoordinate)) {
+ mbgl::LatLng centerLatLng = MGLLatLngFromLocationCoordinate2D(centerCoordinate);
+ mbgl::LatLng eyeLatLng = MGLLatLngFromLocationCoordinate2D(eyeCoordinate);
+
+ mbgl::ProjectedMeters centerMeters = mbgl::Projection::projectedMetersForLatLng(centerLatLng);
+ mbgl::ProjectedMeters eyeMeters = mbgl::Projection::projectedMetersForLatLng(eyeLatLng);
+ heading = std::atan((centerMeters.northing() - eyeMeters.northing()) /
+ (centerMeters.easting() - eyeMeters.easting()));
+
+ double groundDistance = std::hypot(centerMeters.northing() - eyeMeters.northing(),
+ centerMeters.easting() - eyeMeters.easting());
+ pitch = std::atan(eyeAltitude / groundDistance);
+ }
return [[self alloc] initWithCenterCoordinate:centerCoordinate
altitude:eyeAltitude
diff --git a/platform/darwin/src/MGLMultiPoint.h b/platform/darwin/src/MGLMultiPoint.h
index ca08e5405a..429bbdb22d 100644
--- a/platform/darwin/src/MGLMultiPoint.h
+++ b/platform/darwin/src/MGLMultiPoint.h
@@ -58,8 +58,12 @@ MGL_EXPORT
- (void)setCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count;
/**
- Inserts the given vertices into the shape. If the shape is currently visible on
- the map, it is redrawn immediately.
+ Inserts the given vertices into the shape.
+
+ If the shape is currently visible on the map as an annotation, it is redrawn
+ immediately. If the shape is part of an `MGLShapeSource` object, you must
+ explicitly set the `MGLShapeSource.shape` property in order for any style
+ layers that use the source to be redrawn.
@param coords The array of coordinates to insert into the shape. The data in
this array is copied to the shape’s `coordinates` property.
@@ -70,8 +74,12 @@ MGL_EXPORT
- (void)insertCoordinates:(const CLLocationCoordinate2D *)coords count:(NSUInteger)count atIndex:(NSUInteger)index;
/**
- Appends the given vertices to the shape. If the shape is currently visible on
- the map, it is redrawn immediately.
+ Appends the given vertices to the shape.
+
+ If the shape is currently visible on the map as an annotation, it is redrawn
+ immediately. If the shape is part of an `MGLShapeSource` object, you must
+ explicitly set the `MGLShapeSource.shape` property in order for any style
+ layers that use the source to be redrawn.
@param coords The array of coordinates to add to the shape. The data in this
array is copied to the shape’s `coordinates` property.
@@ -81,8 +89,12 @@ MGL_EXPORT
/**
Replaces the vertices at the given range in the shape with the same number of
- vertices from a given C array. If the shape is currently visible on the map, it
- is redrawn immediately.
+ vertices from a given C array.
+
+ If the shape is currently visible on the map as an annotation, it is redrawn
+ immediately. If the shape is part of an `MGLShapeSource` object, you must
+ explicitly set the `MGLShapeSource.shape` property in order for any style
+ layers that use the source to be redrawn.
The number of coordinates in `coords` must be equal to the length of `range`.
If you want to insert or delete one or more vertices, use the
@@ -103,8 +115,12 @@ MGL_EXPORT
/**
Replaces the vertices at the given range in the shape with the specified number
- of vertices from a given C array. If the shape is currently visible on the map,
- it is redrawn immediately.
+ of vertices from a given C array.
+
+ If the shape is currently visible on the map as an annotation, it is redrawn
+ immediately. If the shape is part of an `MGLShapeSource` object, you must
+ explicitly set the `MGLShapeSource.shape` property in order for any style
+ layers that use the source to be redrawn.
If `count` is greater than the `length` field of `range`, some vertices will
effectively be inserted into the shape. On the other hand, if `count` is less
@@ -128,8 +144,12 @@ MGL_EXPORT
- (void)replaceCoordinatesInRange:(NSRange)range withCoordinates:(const CLLocationCoordinate2D *)coords count:(NSUInteger)count;
/**
- Removes the vertices at the given range from the shape. If the shape is
- currently visible on the map, it is redrawn immediately.
+ Removes the vertices at the given range from the shape.
+
+ If the shape is currently visible on the map as an annotation, it is redrawn
+ immediately. If the shape is part of an `MGLShapeSource` object, you must
+ explicitly set the `MGLShapeSource.shape` property in order for any style
+ layers that use the source to be redrawn.
If `range` extends beyond the shape’s `coordinates` property, an
`NSRangeException` is raised.
diff --git a/platform/darwin/src/MGLMultiPoint.mm b/platform/darwin/src/MGLMultiPoint.mm
index 8e8c5be304..ef46bbb0fe 100644
--- a/platform/darwin/src/MGLMultiPoint.mm
+++ b/platform/darwin/src/MGLMultiPoint.mm
@@ -163,7 +163,11 @@
if (!_bounds) {
mbgl::LatLngBounds bounds = mbgl::LatLngBounds::empty();
for (auto coordinate : _coordinates) {
- bounds.extend(mbgl::LatLng(coordinate.latitude, coordinate.longitude));
+ if (!CLLocationCoordinate2DIsValid(coordinate)) {
+ bounds = mbgl::LatLngBounds::empty();
+ break;
+ }
+ bounds.extend(MGLLatLngFromLocationCoordinate2D(coordinate));
}
_bounds = bounds;
}
diff --git a/platform/darwin/src/MGLOpenGLStyleLayer.h b/platform/darwin/src/MGLOpenGLStyleLayer.h
index de4fc92b17..bdad5f9d07 100644
--- a/platform/darwin/src/MGLOpenGLStyleLayer.h
+++ b/platform/darwin/src/MGLOpenGLStyleLayer.h
@@ -23,6 +23,8 @@ MGL_EXPORT
@property (nonatomic, weak, readonly) MGLMapView *mapView;
+- (instancetype)initWithIdentifier:(NSString *)identifier;
+
- (void)didMoveToMapView:(MGLMapView *)mapView;
- (void)willMoveFromMapView:(MGLMapView *)mapView;
diff --git a/platform/darwin/src/MGLOpenGLStyleLayer.mm b/platform/darwin/src/MGLOpenGLStyleLayer.mm
index da131b6de8..39eda758eb 100644
--- a/platform/darwin/src/MGLOpenGLStyleLayer.mm
+++ b/platform/darwin/src/MGLOpenGLStyleLayer.mm
@@ -72,7 +72,7 @@ void MGLFinishCustomStyleLayer(void *context) {
*/
@interface MGLOpenGLStyleLayer ()
-@property (nonatomic) mbgl::style::CustomLayer *rawLayer;
+@property (nonatomic, readonly) mbgl::style::CustomLayer *rawLayer;
/**
The map view whose style currently contains the layer.
@@ -84,9 +84,7 @@ void MGLFinishCustomStyleLayer(void *context) {
@end
-@implementation MGLOpenGLStyleLayer {
- std::unique_ptr<mbgl::style::CustomLayer> _pendingLayer;
-}
+@implementation MGLOpenGLStyleLayer
/**
Returns an OpenGL style layer object initialized with the given identifier.
@@ -100,26 +98,18 @@ void MGLFinishCustomStyleLayer(void *context) {
@return An initialized OpenGL style layer.
*/
- (instancetype)initWithIdentifier:(NSString *)identifier {
- if (self = [super initWithIdentifier:identifier]) {
- auto layer = std::make_unique<mbgl::style::CustomLayer>(identifier.UTF8String,
- MGLPrepareCustomStyleLayer,
- MGLDrawCustomStyleLayer,
- MGLFinishCustomStyleLayer,
- (__bridge void *)self);
- _pendingLayer = std::move(layer);
- self.rawLayer = _pendingLayer.get();
- }
- return self;
+ auto layer = std::make_unique<mbgl::style::CustomLayer>(identifier.UTF8String,
+ MGLPrepareCustomStyleLayer,
+ MGLDrawCustomStyleLayer,
+ MGLFinishCustomStyleLayer,
+ (__bridge void *)self);
+ return self = [super initWithPendingLayer:std::move(layer)];
}
- (mbgl::style::CustomLayer *)rawLayer {
return (mbgl::style::CustomLayer *)super.rawLayer;
}
-- (void)setRawLayer:(mbgl::style::CustomLayer *)rawLayer {
- super.rawLayer = rawLayer;
-}
-
#pragma mark - Adding to and removing from a map view
- (void)setMapView:(MGLMapView *)mapView {
@@ -134,22 +124,12 @@ void MGLFinishCustomStyleLayer(void *context) {
- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer {
self.mapView = mapView;
- if (otherLayer) {
- const mbgl::optional<std::string> belowLayerId{ otherLayer.identifier.UTF8String };
- mapView.mbglMap->addLayer(std::move(_pendingLayer), belowLayerId);
- } else {
- mapView.mbglMap->addLayer(std::move(_pendingLayer));
- }
+ [super addToMapView:mapView belowLayer:otherLayer];
}
- (void)removeFromMapView:(MGLMapView *)mapView {
- auto removedLayer = mapView.mbglMap->removeLayer(self.identifier.UTF8String);
+ [super removeFromMapView:mapView];
self.mapView = nil;
- if (!removedLayer) {
- return;
- }
- _pendingLayer = std::move(reinterpret_cast<std::unique_ptr<mbgl::style::CustomLayer> &>(removedLayer));
- self.rawLayer = _pendingLayer.get();
}
/**
diff --git a/platform/darwin/src/MGLPointCollection.mm b/platform/darwin/src/MGLPointCollection.mm
index ac4aaed60c..8f20d91a42 100644
--- a/platform/darwin/src/MGLPointCollection.mm
+++ b/platform/darwin/src/MGLPointCollection.mm
@@ -54,7 +54,11 @@ NS_ASSUME_NONNULL_BEGIN
if (!_bounds) {
mbgl::LatLngBounds bounds = mbgl::LatLngBounds::empty();
for (auto coordinate : _coordinates) {
- bounds.extend(mbgl::LatLng(coordinate.latitude, coordinate.longitude));
+ if (!CLLocationCoordinate2DIsValid(coordinate)) {
+ bounds = mbgl::LatLngBounds::empty();
+ break;
+ }
+ bounds.extend(MGLLatLngFromLocationCoordinate2D(coordinate));
}
_bounds = bounds;
}
@@ -119,8 +123,9 @@ NS_ASSUME_NONNULL_BEGIN
- (NSString *)description
{
- return [NSString stringWithFormat:@"<%@: %p; count = %lu>",
- NSStringFromClass([self class]), (void *)self, (unsigned long)[self pointCount]];
+ return [NSString stringWithFormat:@"<%@: %p; count = %lu; bounds = %@>",
+ NSStringFromClass([self class]), (void *)self, (unsigned long)[self pointCount],
+ MGLStringFromCoordinateBounds(self.overlayBounds)];
}
@end
diff --git a/platform/darwin/src/MGLRasterSource.h b/platform/darwin/src/MGLRasterSource.h
index 694a818246..519784f4f1 100644
--- a/platform/darwin/src/MGLRasterSource.h
+++ b/platform/darwin/src/MGLRasterSource.h
@@ -104,6 +104,109 @@ MGL_EXPORT
*/
- (instancetype)initWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL tileSize:(CGFloat)tileSize NS_DESIGNATED_INITIALIZER;
+/**
+ Returns a raster source initialized an identifier, tile URL templates, and
+ options.
+
+ After initializing and configuring the source, add it to a map view’s style
+ using the `-[MGLStyle addSource:]` method.
+
+ #### Tile URL templates
+
+ Tile URL templates are strings that specify the URLs of the tile images to
+ load. Each template resembles an absolute URL, but with any number of
+ placeholder strings that the source evaluates based on the tile it needs to
+ load. For example:
+
+ <ul>
+ <li><code>http://www.example.com/tiles/{z}/{x}/{y}.pbf</code> could be
+ evaluated as <code>http://www.example.com/tiles/14/6/9.pbf</code>.</li>
+ <li><code>http://www.example.com/tiles/{z}/{x}/{y}{ratio}.png</code> could be
+ evaluated as <code>http://www.example.com/tiles/14/6/9@2x.png</code>.</li>
+ </ul>
+
+ Tile sources support the following placeholder strings in tile URL templates,
+ all of which are optional:
+
+ <table>
+ <thead>
+ <tr><th>Placeholder string</th><th>Description</th></tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><code>{x}</code></td>
+ <td>The index of the tile along the map’s x axis according to Spherical
+ Mercator projection. If the value is 0, the tile’s left edge corresponds
+ to the 180th meridian west. If the value is 2<sup><var>z</var></sup>−1,
+ the tile’s right edge corresponds to the 180th meridian east.</td>
+ </tr>
+ <tr>
+ <td><code>{y}</code></td>
+ <td>The index of the tile along the map’s y axis according to Spherical
+ Mercator projection. If the value is 0, the tile’s tile edge corresponds
+ to arctan(sinh(π)), or approximately 85.0511 degrees north. If the value
+ is 2<sup><var>z</var></sup>−1, the tile’s bottom edge corresponds to
+ −arctan(sinh(π)), or approximately 85.0511 degrees south. The y axis is
+ inverted if the <code>options</code> parameter contains
+ <code>MGLTileSourceOptionTileCoordinateSystem</code> with a value of
+ <code>MGLTileCoordinateSystemTMS</code>.</td>
+ </tr>
+ <tr>
+ <td><code>{z}</code></td>
+ <td>The tile’s zoom level. At zoom level 0, each tile covers the entire
+ world map; at zoom level 1, it covers ¼ of the world; at zoom level 2,
+ <sup>1</sup>⁄<sub>16</sub> of the world, and so on. For tiles loaded by
+ a <code>MGLRasterSource</code> object, whether the tile zoom level
+ matches the map’s current zoom level depends on the value of the
+ source’s tile size as specified in the
+ <code>MGLTileSourceOptionTileSize</code> key of the
+ <code>options</code> parameter.</td>
+ </tr>
+ <tr>
+ <td><code>{bbox-epsg-3857}</code></td>
+ <td>The tile’s bounding box, expressed as a comma-separated list of the
+ tile’s western, southern, eastern, and northern extents according to
+ Spherical Mercator (EPSG:3857) projection. The bounding box is typically
+ used with map services conforming to the
+ <a href="http://www.opengeospatial.org/standards/wms">Web Map Service</a>
+ protocol.</td>
+ </tr>
+ <tr>
+ <td><code>{quadkey}</code></td>
+ <td>A quadkey indicating both the tile’s location and its zoom level. The
+ quadkey is typically used with
+ <a href="https://msdn.microsoft.com/en-us/library/bb259689.aspx">Bing Maps</a>.
+ </td>
+ </tr>
+ <tr>
+ <td><code>{ratio}</code></td>
+ <td>A suffix indicating the resolution of the tile image. The suffix is the
+ empty string for standard resolution displays and <code>@2x</code> for
+ Retina displays, including displays for which
+ <code>NSScreen.backingScaleFactor</code> or <code>UIScreen.scale</code>
+ is 3.</td>
+ </tr>
+ <tr>
+ <td><code>{prefix}</code></td>
+ <td>Two hexadecimal digits chosen such that each visible tile has a
+ different prefix. The prefix is typically used for domain sharding.</td>
+ </tr>
+ </tbody>
+ </table>
+
+ For more information about the `{x}`, `{y}`, and `{z}` placeholder strings,
+ consult the
+ <a href="https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames">OpenStreetMap Wiki</a>.
+
+ @param identifier A string that uniquely identifies the source in the style to
+ which it is added.
+ @param tileURLTemplates An array of tile URL template strings. Only the first
+ string is used; any additional strings are ignored.
+ @param options A dictionary containing configuration options. See
+ `MGLTileSourceOption` for available keys and values. Pass in `nil` to use
+ the default values.
+ @return An initialized tile source.
+ */
- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates options:(nullable NS_DICTIONARY_OF(MGLTileSourceOption, id) *)options NS_DESIGNATED_INITIALIZER;
@end
diff --git a/platform/darwin/src/MGLRasterSource.mm b/platform/darwin/src/MGLRasterSource.mm
index c73a824ea8..8fc18ba69d 100644
--- a/platform/darwin/src/MGLRasterSource.mm
+++ b/platform/darwin/src/MGLRasterSource.mm
@@ -15,15 +15,11 @@ static const CGFloat MGLRasterSourceRetinaTileSize = 512;
@interface MGLRasterSource ()
-- (instancetype)initWithRawSource:(mbgl::style::RasterSource *)rawSource NS_DESIGNATED_INITIALIZER;
-
-@property (nonatomic) mbgl::style::RasterSource *rawSource;
+@property (nonatomic, readonly) mbgl::style::RasterSource *rawSource;
@end
-@implementation MGLRasterSource {
- std::unique_ptr<mbgl::style::RasterSource> _pendingSource;
-}
+@implementation MGLRasterSource
- (instancetype)initWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL {
// The style specification default is 512, but 256 is the expected value for
@@ -37,76 +33,32 @@ static const CGFloat MGLRasterSourceRetinaTileSize = 512;
}
- (instancetype)initWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL tileSize:(CGFloat)tileSize {
- if (self = [super initWithIdentifier:identifier configurationURL:configurationURL]) {
- auto source = std::make_unique<mbgl::style::RasterSource>(identifier.UTF8String,
- configurationURL.mgl_URLByStandardizingScheme.absoluteString.UTF8String,
- uint16_t(round(tileSize)));
- _pendingSource = std::move(source);
- self.rawSource = _pendingSource.get();
- }
- return self;
+ auto source = std::make_unique<mbgl::style::RasterSource>(identifier.UTF8String,
+ configurationURL.mgl_URLByStandardizingScheme.absoluteString.UTF8String,
+ uint16_t(round(tileSize)));
+ return self = [super initWithPendingSource:std::move(source)];
}
- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates options:(nullable NS_DICTIONARY_OF(MGLTileSourceOption, id) *)options {
- if (self = [super initWithIdentifier:identifier tileURLTemplates:tileURLTemplates options:options]) {
- mbgl::Tileset tileSet = MGLTileSetFromTileURLTemplates(tileURLTemplates, options);
-
- uint16_t tileSize = MGLRasterSourceRetinaTileSize;
- if (NSNumber *tileSizeNumber = options[MGLTileSourceOptionTileSize]) {
- if (![tileSizeNumber isKindOfClass:[NSNumber class]]) {
- [NSException raise:NSInvalidArgumentException
- format:@"MGLTileSourceOptionTileSize must be set to an NSNumber."];
- }
- tileSize = static_cast<uint16_t>(round(tileSizeNumber.doubleValue));
- }
-
- auto source = std::make_unique<mbgl::style::RasterSource>(identifier.UTF8String, tileSet, tileSize);
- _pendingSource = std::move(source);
- self.rawSource = _pendingSource.get();
- }
- return self;
-}
-
-- (instancetype)initWithRawSource:(mbgl::style::RasterSource *)rawSource {
- return [super initWithRawSource:rawSource];
-}
-
-- (void)addToMapView:(MGLMapView *)mapView {
- if (_pendingSource == nullptr) {
- [NSException raise:@"MGLRedundantSourceException"
- format:@"This instance %@ was already added to %@. Adding the same source instance " \
- @"to the style more than once is invalid.", self, mapView.style];
- }
-
- mapView.mbglMap->addSource(std::move(_pendingSource));
-}
-
-- (void)removeFromMapView:(MGLMapView *)mapView {
- if (self.rawSource != mapView.mbglMap->getSource(self.identifier.UTF8String)) {
- return;
- }
+ mbgl::Tileset tileSet = MGLTileSetFromTileURLTemplates(tileURLTemplates, options);
- auto removedSource = mapView.mbglMap->removeSource(self.identifier.UTF8String);
-
- mbgl::style::RasterSource *source = dynamic_cast<mbgl::style::RasterSource *>(removedSource.get());
- if (!source) {
- return;
+ uint16_t tileSize = MGLRasterSourceRetinaTileSize;
+ if (NSNumber *tileSizeNumber = options[MGLTileSourceOptionTileSize]) {
+ if (![tileSizeNumber isKindOfClass:[NSNumber class]]) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"MGLTileSourceOptionTileSize must be set to an NSNumber."];
+ }
+ tileSize = static_cast<uint16_t>(round(tileSizeNumber.doubleValue));
}
- removedSource.release();
-
- _pendingSource = std::unique_ptr<mbgl::style::RasterSource>(source);
- self.rawSource = _pendingSource.get();
+ auto source = std::make_unique<mbgl::style::RasterSource>(identifier.UTF8String, tileSet, tileSize);
+ return self = [super initWithPendingSource:std::move(source)];
}
- (mbgl::style::RasterSource *)rawSource {
return (mbgl::style::RasterSource *)super.rawSource;
}
-- (void)setRawSource:(mbgl::style::RasterSource *)rawSource {
- super.rawSource = rawSource;
-}
-
- (NSURL *)configurationURL {
auto url = self.rawSource->getURL();
return url ? [NSURL URLWithString:@(url->c_str())] : nil;
diff --git a/platform/darwin/src/MGLRasterSource_Private.h b/platform/darwin/src/MGLRasterSource_Private.h
index 47b1c13517..76790bd053 100644
--- a/platform/darwin/src/MGLRasterSource_Private.h
+++ b/platform/darwin/src/MGLRasterSource_Private.h
@@ -2,16 +2,7 @@
NS_ASSUME_NONNULL_BEGIN
-namespace mbgl {
- namespace style {
- class RasterSource;
- }
-}
-
@interface MGLRasterSource (Private)
-
-- (instancetype)initWithRawSource:(mbgl::style::RasterSource *)rawSource;
-
@end
NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLRasterStyleLayer.h b/platform/darwin/src/MGLRasterStyleLayer.h
index 377b7f45cd..53a6a98b8a 100644
--- a/platform/darwin/src/MGLRasterStyleLayer.h
+++ b/platform/darwin/src/MGLRasterStyleLayer.h
@@ -36,6 +36,21 @@ NS_ASSUME_NONNULL_BEGIN
MGL_EXPORT
@interface MGLRasterStyleLayer : MGLForegroundStyleLayer
+/**
+ Returns a raster style layer initialized with an identifier and source.
+
+ After initializing and configuring the style layer, add it to a map view’s
+ style using the `-[MGLStyle addLayer:]` or
+ `-[MGLStyle insertLayer:belowLayer:]` method.
+
+ @param identifier A string that uniquely identifies the source in the style to
+ which it is added.
+ @param source The source from which to obtain the data to style. If the source
+ has not yet been added to the current style, the behavior is undefined.
+ @return An initialized foreground style layer.
+ */
+- (instancetype)initWithIdentifier:(NSString *)identifier source:(MGLSource *)source;
+
#pragma mark - Accessing the Paint Attributes
/**
diff --git a/platform/darwin/src/MGLRasterStyleLayer.mm b/platform/darwin/src/MGLRasterStyleLayer.mm
index 80508e4e70..c63fd23529 100644
--- a/platform/darwin/src/MGLRasterStyleLayer.mm
+++ b/platform/darwin/src/MGLRasterStyleLayer.mm
@@ -2,35 +2,27 @@
// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLSource.h"
-#import "MGLMapView_Private.h"
#import "NSPredicate+MGLAdditions.h"
#import "NSDate+MGLAdditions.h"
#import "MGLStyleLayer_Private.h"
#import "MGLStyleValue_Private.h"
#import "MGLRasterStyleLayer.h"
-#include <mbgl/map/map.hpp>
+#include <mbgl/style/transition_options.hpp>
#include <mbgl/style/layers/raster_layer.hpp>
@interface MGLRasterStyleLayer ()
-@property (nonatomic) mbgl::style::RasterLayer *rawLayer;
+@property (nonatomic, readonly) mbgl::style::RasterLayer *rawLayer;
@end
@implementation MGLRasterStyleLayer
-{
- std::unique_ptr<mbgl::style::RasterLayer> _pendingLayer;
-}
- (instancetype)initWithIdentifier:(NSString *)identifier source:(MGLSource *)source
{
- if (self = [super initWithIdentifier:identifier source:source]) {
- auto layer = std::make_unique<mbgl::style::RasterLayer>(identifier.UTF8String, source.identifier.UTF8String);
- _pendingLayer = std::move(layer);
- self.rawLayer = _pendingLayer.get();
- }
- return self;
+ auto layer = std::make_unique<mbgl::style::RasterLayer>(identifier.UTF8String, source.identifier.UTF8String);
+ return self = [super initWithPendingLayer:std::move(layer)];
}
- (mbgl::style::RasterLayer *)rawLayer
@@ -38,11 +30,6 @@
return (mbgl::style::RasterLayer *)super.rawLayer;
}
-- (void)setRawLayer:(mbgl::style::RasterLayer *)rawLayer
-{
- super.rawLayer = rawLayer;
-}
-
- (NSString *)sourceIdentifier
{
MGLAssertStyleLayerIsValid();
@@ -50,46 +37,6 @@
return @(self.rawLayer->getSourceID().c_str());
}
-#pragma mark - Adding to and removing from a map view
-
-- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer
-{
- if (_pendingLayer == nullptr) {
- [NSException raise:@"MGLRedundantLayerException"
- format:@"This instance %@ was already added to %@. Adding the same layer instance " \
- "to the style more than once is invalid.", self, mapView.style];
- }
-
- if (otherLayer) {
- const mbgl::optional<std::string> belowLayerId{otherLayer.identifier.UTF8String};
- mapView.mbglMap->addLayer(std::move(_pendingLayer), belowLayerId);
- } else {
- mapView.mbglMap->addLayer(std::move(_pendingLayer));
- }
-}
-
-- (void)removeFromMapView:(MGLMapView *)mapView
-{
- if (self.rawLayer != mapView.mbglMap->getLayer(self.identifier.UTF8String)) {
- return;
- }
-
- auto removedLayer = mapView.mbglMap->removeLayer(self.identifier.UTF8String);
- if (!removedLayer) {
- return;
- }
-
- mbgl::style::RasterLayer *layer = dynamic_cast<mbgl::style::RasterLayer *>(removedLayer.get());
- if (!layer) {
- return;
- }
-
- removedLayer.release();
-
- _pendingLayer = std::unique_ptr<mbgl::style::RasterLayer>(layer);
- self.rawLayer = _pendingLayer.get();
-}
-
#pragma mark - Accessing the Paint Attributes
- (void)setMaximumRasterBrightness:(MGLStyleValue<NSNumber *> *)maximumRasterBrightness {
diff --git a/platform/darwin/src/MGLShapeSource.mm b/platform/darwin/src/MGLShapeSource.mm
index 7de2d69af3..023a81bba8 100644
--- a/platform/darwin/src/MGLShapeSource.mm
+++ b/platform/darwin/src/MGLShapeSource.mm
@@ -20,38 +20,26 @@ const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance = @"MGLSh
@interface MGLShapeSource ()
-- (instancetype)initWithRawSource:(mbgl::style::GeoJSONSource *)rawSource NS_DESIGNATED_INITIALIZER;
-
@property (nonatomic, readwrite) NSDictionary *options;
-@property (nonatomic) mbgl::style::GeoJSONSource *rawSource;
+@property (nonatomic, readonly) mbgl::style::GeoJSONSource *rawSource;
@end
-@implementation MGLShapeSource {
- std::unique_ptr<mbgl::style::GeoJSONSource> _pendingSource;
-}
+@implementation MGLShapeSource
- (instancetype)initWithIdentifier:(NSString *)identifier URL:(NSURL *)url options:(NS_DICTIONARY_OF(NSString *, id) *)options {
- if (self = [super initWithIdentifier:identifier]) {
- auto geoJSONOptions = MGLGeoJSONOptionsFromDictionary(options);
- auto source = std::make_unique<mbgl::style::GeoJSONSource>(identifier.UTF8String, geoJSONOptions);
-
- _pendingSource = std::move(source);
- self.rawSource = _pendingSource.get();
-
+ auto geoJSONOptions = MGLGeoJSONOptionsFromDictionary(options);
+ auto source = std::make_unique<mbgl::style::GeoJSONSource>(identifier.UTF8String, geoJSONOptions);
+ if (self = [super initWithPendingSource:std::move(source)]) {
self.URL = url;
}
return self;
}
- (instancetype)initWithIdentifier:(NSString *)identifier shape:(nullable MGLShape *)shape options:(NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options {
- if (self = [super initWithIdentifier:identifier]) {
- auto geoJSONOptions = MGLGeoJSONOptionsFromDictionary(options);
- auto source = std::make_unique<mbgl::style::GeoJSONSource>(identifier.UTF8String, geoJSONOptions);
-
- _pendingSource = std::move(source);
- self.rawSource = _pendingSource.get();
-
+ auto geoJSONOptions = MGLGeoJSONOptionsFromDictionary(options);
+ auto source = std::make_unique<mbgl::style::GeoJSONSource>(identifier.UTF8String, geoJSONOptions);
+ if (self = [super initWithPendingSource:std::move(source)]) {
self.shape = shape;
}
return self;
@@ -72,46 +60,10 @@ const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance = @"MGLSh
return [self initWithIdentifier:identifier shape:shapeCollection options:options];
}
-- (instancetype)initWithRawSource:(mbgl::style::GeoJSONSource *)rawSource {
- return [super initWithRawSource:rawSource];
-}
-
-- (void)addToMapView:(MGLMapView *)mapView {
- if (_pendingSource == nullptr) {
- [NSException raise:@"MGLRedundantSourceException"
- format:@"This instance %@ was already added to %@. Adding the same source instance " \
- "to the style more than once is invalid.", self, mapView.style];
- }
-
- mapView.mbglMap->addSource(std::move(_pendingSource));
-}
-
-- (void)removeFromMapView:(MGLMapView *)mapView {
- if (self.rawSource != mapView.mbglMap->getSource(self.identifier.UTF8String)) {
- return;
- }
-
- auto removedSource = mapView.mbglMap->removeSource(self.identifier.UTF8String);
-
- mbgl::style::GeoJSONSource *source = dynamic_cast<mbgl::style::GeoJSONSource *>(removedSource.get());
- if (!source) {
- return;
- }
-
- removedSource.release();
-
- _pendingSource = std::unique_ptr<mbgl::style::GeoJSONSource>(source);
- self.rawSource = _pendingSource.get();
-}
-
- (mbgl::style::GeoJSONSource *)rawSource {
return (mbgl::style::GeoJSONSource *)super.rawSource;
}
-- (void)setRawSource:(mbgl::style::GeoJSONSource *)rawSource {
- super.rawSource = rawSource;
-}
-
- (NSURL *)URL {
auto url = self.rawSource->getURL();
return url ? [NSURL URLWithString:@(url->c_str())] : nil;
@@ -143,7 +95,10 @@ const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance = @"MGLSh
optionalFilter = predicate.mgl_filter;
}
- std::vector<mbgl::Feature> features = self.rawSource->querySourceFeatures({ {}, optionalFilter });
+ std::vector<mbgl::Feature> features;
+ if (self.mapView) {
+ features = self.mapView.mbglMap->querySourceFeatures(self.rawSource->getID(), { {}, optionalFilter });
+ }
return MGLFeaturesFromMBGLFeatures(features);
}
diff --git a/platform/darwin/src/MGLShapeSource_Private.h b/platform/darwin/src/MGLShapeSource_Private.h
index c14f4fbb59..84eb5deed4 100644
--- a/platform/darwin/src/MGLShapeSource_Private.h
+++ b/platform/darwin/src/MGLShapeSource_Private.h
@@ -6,14 +6,10 @@ NS_ASSUME_NONNULL_BEGIN
namespace mbgl {
namespace style {
class GeoJSONOptions;
- struct GeoJSONSource;
}
}
@interface MGLShapeSource (Private)
-
-- (instancetype)initWithRawSource:(mbgl::style::GeoJSONSource *)rawSource;
-
@end
MGL_EXPORT
diff --git a/platform/darwin/src/MGLSource.mm b/platform/darwin/src/MGLSource.mm
index c96b6c41c6..eb859ba2c0 100644
--- a/platform/darwin/src/MGLSource.mm
+++ b/platform/darwin/src/MGLSource.mm
@@ -1,16 +1,23 @@
#import "MGLSource_Private.h"
+#import "MGLMapView_Private.h"
+#include <mbgl/map/map.hpp>
#include <mbgl/style/source.hpp>
@interface MGLSource ()
// Even though this class is abstract, MGLStyle uses it to represent some
// special internal source types like mbgl::AnnotationSource.
-@property (nonatomic) mbgl::style::Source *rawSource;
+@property (nonatomic, readonly) mbgl::style::Source *rawSource;
+
+@property (nonatomic, readonly, weak) MGLMapView *mapView;
@end
-@implementation MGLSource
+@implementation MGLSource {
+ std::unique_ptr<mbgl::style::Source> _pendingSource;
+}
+
- (instancetype)initWithIdentifier:(NSString *)identifier
{
@@ -24,22 +31,34 @@
NSString *identifier = @(rawSource->getID().c_str());
if (self = [self initWithIdentifier:identifier]) {
_rawSource = rawSource;
+ _rawSource->peer = SourceWrapper { self };
+ }
+ return self;
+}
+
+- (instancetype)initWithPendingSource:(std::unique_ptr<mbgl::style::Source>)pendingSource {
+ if (self = [self initWithRawSource:pendingSource.get()]) {
+ _pendingSource = std::move(pendingSource);
}
return self;
}
- (void)addToMapView:(MGLMapView *)mapView {
- [NSException raise:NSInvalidArgumentException format:
- @"The source %@ cannot be added to the style. "
- @"Make sure the source was created as a member of a concrete subclass of MGLSource.",
- self];
+ if (_pendingSource == nullptr) {
+ [NSException raise:@"MGLRedundantSourceException"
+ format:@"This instance %@ was already added to %@. Adding the same source instance " \
+ "to the style more than once is invalid.", self, mapView.style];
+ }
+
+ _mapView = mapView;
+ mapView.mbglMap->addSource(std::move(_pendingSource));
}
- (void)removeFromMapView:(MGLMapView *)mapView {
- [NSException raise:NSInvalidArgumentException format:
- @"The source %@ cannot be removed from the style. "
- @"Make sure the source was created as a member of a concrete subclass of MGLSource.",
- self];
+ if (self.rawSource == mapView.mbglMap->getSource(self.identifier.UTF8String)) {
+ _pendingSource = mapView.mbglMap->removeSource(self.identifier.UTF8String);
+ _mapView = nil;
+ }
}
- (NSString *)description {
diff --git a/platform/darwin/src/MGLSource_Private.h b/platform/darwin/src/MGLSource_Private.h
index acb325e2f3..91bfac6390 100644
--- a/platform/darwin/src/MGLSource_Private.h
+++ b/platform/darwin/src/MGLSource_Private.h
@@ -1,5 +1,7 @@
#import "MGLSource.h"
+#include <memory>
+
NS_ASSUME_NONNULL_BEGIN
namespace mbgl {
@@ -8,23 +10,46 @@ namespace mbgl {
}
}
+// A struct to be stored in the `peer` member of mbgl::style::Source, in order to implement
+// object identity. We don't store a MGLSource pointer directly because that doesn't
+// interoperate with ARC. The inner pointer is weak in order to avoid a reference cycle for
+// "pending" MGLSources, which have a strong owning pointer to the mbgl::style::Source.
+struct SourceWrapper {
+ __weak MGLSource *source;
+};
+
@class MGLMapView;
@interface MGLSource (Private)
/**
- Initializes and returns a source with a raw pointer to the backing store.
+ Initializes and returns a source with a raw pointer to the backing store,
+ associated with a style.
*/
- (instancetype)initWithRawSource:(mbgl::style::Source *)rawSource;
/**
+ Initializes and returns a source with an owning pointer to the backing store,
+ unassociated from a style.
+ */
+- (instancetype)initWithPendingSource:(std::unique_ptr<mbgl::style::Source>)pendingSource;
+
+/**
A raw pointer to the mbgl object, which is always initialized, either to the
value returned by `mbgl::Map getSource`, or for independently created objects,
to the pointer value held in `pendingSource`. In the latter case, this raw
pointer value stays even after ownership of the object is transferred via
`mbgl::Map addSource`.
*/
-@property (nonatomic) mbgl::style::Source *rawSource;
+@property (nonatomic, readonly) mbgl::style::Source *rawSource;
+
+/**
+ The map view whose style currently contains the source.
+
+ If the source is not currently part of any map view’s style, this property is
+ set to `nil`.
+ */
+@property (nonatomic, readonly, weak) MGLMapView *mapView;
/**
Adds the mbgl source that this object represents to the mbgl map.
diff --git a/platform/darwin/src/MGLStyle.h b/platform/darwin/src/MGLStyle.h
index bd17fdec44..ccec863236 100644
--- a/platform/darwin/src/MGLStyle.h
+++ b/platform/darwin/src/MGLStyle.h
@@ -10,9 +10,9 @@
NS_ASSUME_NONNULL_BEGIN
/**
- A version number identifying the default version of the suite of default styles
- provided by Mapbox. This version number may be passed into one of the
- “StyleURLWithVersion” class methods of MGLStyle.
+ A version number identifying the default version of the Mapbox Streets style
+ obtained through the `-streetsStyleURL` method. This version number may also be
+ passed into the `-streetsStyleURLWithVersion:` method.
The value of this constant generally corresponds to the latest released version
as of the date on which this SDK was published. You can use this constant to
@@ -28,7 +28,7 @@ NS_ASSUME_NONNULL_BEGIN
the constant itself. Such details may change significantly from version to
version.
*/
-static MGL_EXPORT const NSInteger MGLStyleDefaultVersion = 9;
+static MGL_EXPORT const NSInteger MGLStyleDefaultVersion = 10;
/**
The proxy object for the current map style.
@@ -52,15 +52,22 @@ MGL_EXPORT
#pragma mark Accessing Default Styles
/**
- Returns the URL to version 8 of the
- <a href="https://www.mapbox.com/maps/streets/">Mapbox Streets</a> style.
+ Returns the URL to the current version of the
+ <a href="https://www.mapbox.com/maps/streets/">Mapbox Streets</a> style as of
+ publication.
Streets is a general-purpose style with detailed road and transit networks.
`MGLMapView` and `MGLTilePyramidOfflineRegion` use Mapbox Streets when no style
is specified explicitly.
+
+ @warning The return value may change in a future release of the SDK. If you use
+ any feature that depends on a specific aspect of a default style – for
+ instance, the minimum zoom level that includes roads – use the
+ `-streetsStyleURLWithVersion:` method instead. Such details may change
+ significantly from version to version.
*/
-+ (NSURL *)streetsStyleURL __attribute__((deprecated("Use -streetsStyleURLWithVersion:.")));
++ (NSURL *)streetsStyleURL;
/**
Returns the URL to the given version of the
@@ -71,8 +78,7 @@ MGL_EXPORT
`MGLMapView` and `MGLTilePyramidOfflineRegion` use Mapbox Streets when no style
is specified explicitly.
- @param version The style’s latest released version. As of publication, the
- current version is `9`.
+ @param version A specific version of the style.
*/
+ (NSURL *)streetsStyleURLWithVersion:(NSInteger)version;
@@ -85,70 +91,102 @@ MGL_EXPORT
+ (NSURL *)emeraldStyleURL __attribute__((deprecated("Create an NSURL object with the string “mapbox://styles/mapbox/emerald-v8”.")));
/**
+ Returns the URL to the current version of the
+ <a href="https://www.mapbox.com/maps/outdoors/">Mapbox Outdoors</a> style as of
+ publication.
+
+ Outdoors is a general-purpose style tailored to outdoor activities.
+
+ @warning The return value may change in a future release of the SDK. If you use
+ any feature that depends on a specific aspect of a default style – for
+ instance, the minimum zoom level that includes roads – use the
+ `-outdoorsStyleURLWithVersion:` method instead. Such details may change
+ significantly from version to version.
+ */
++ (NSURL *)outdoorsStyleURL;
+
+/**
Returns the URL to the given version of the
<a href="https://www.mapbox.com/maps/outdoors/">Mapbox Outdoors</a> style.
Outdoors is a general-purpose style tailored to outdoor activities.
- @param version The style’s latest released version. As of publication, the
- current version is `9`.
+ @param version A specific version of the style.
*/
+ (NSURL *)outdoorsStyleURLWithVersion:(NSInteger)version;
/**
- Returns the URL to version 8 of the
+ Returns the URL to the current version of the
<a href="https://www.mapbox.com/maps/light-dark/">Mapbox Light</a> style.
Light is a subtle, light-colored backdrop for data visualizations.
+
+ @warning The return value may change in a future release of the SDK. If you use
+ any feature that depends on a specific aspect of a default style – for
+ instance, the minimum zoom level that includes roads – use the
+ `-lightStyleURLWithVersion:` method instead. Such details may change
+ significantly from version to version.
*/
-+ (NSURL *)lightStyleURL __attribute__((deprecated("Use -lightStyleURLWithVersion:.")));
++ (NSURL *)lightStyleURL;
/**
Returns the URL to the given version of the
- <a href="https://www.mapbox.com/maps/light-dark/">Mapbox Light</a> style.
+ <a href="https://www.mapbox.com/maps/light-dark/">Mapbox Light</a> style as of
+ publication.
Light is a subtle, light-colored backdrop for data visualizations.
- @param version The style’s latest released version. As of publication, the
- current version is `9`.
+ @param version A specific version of the style.
*/
+ (NSURL *)lightStyleURLWithVersion:(NSInteger)version;
/**
- Returns the URL to version 8 of the
+ Returns the URL to the current version of the
<a href="https://www.mapbox.com/maps/light-dark/">Mapbox Dark</a> style.
Dark is a subtle, dark-colored backdrop for data visualizations.
+
+ @warning The return value may change in a future release of the SDK. If you use
+ any feature that depends on a specific aspect of a default style – for
+ instance, the minimum zoom level that includes roads – use the
+ `-darkStyleURLWithVersion:` method instead. Such details may change
+ significantly from version to version.
*/
-+ (NSURL *)darkStyleURL __attribute__((deprecated("Use -darkStyleURLWithVersion:.")));
++ (NSURL *)darkStyleURL;
/**
Returns the URL to the given version of the
- <a href="https://www.mapbox.com/maps/light-dark/">Mapbox Dark</a> style.
+ <a href="https://www.mapbox.com/maps/light-dark/">Mapbox Dark</a> style as of
+ publication.
Dark is a subtle, dark-colored backdrop for data visualizations.
- @param version The style’s latest released version. As of publication, the
- current version is `9`.
+ @param version A specific version of the style.
*/
+ (NSURL *)darkStyleURLWithVersion:(NSInteger)version;
/**
- Returns the URL to version 8 of the
+ Returns the URL to the current version of the
<a href="https://www.mapbox.com/maps/satellite/">Mapbox Satellite</a> style.
Satellite is high-resolution satellite and aerial imagery.
+
+ @warning The return value may change in a future release of the SDK. If you use
+ any feature that depends on a specific aspect of a default style – for
+ instance, the raster tile sets included in the style – use the
+ `-satelliteStyleURLWithVersion:` method instead. Such details may change
+ significantly from version to version.
*/
-+ (NSURL *)satelliteStyleURL __attribute__((deprecated("Use -satelliteStyleURLWithVersion:.")));
++ (NSURL *)satelliteStyleURL;
/**
Returns the URL to the given version of the
- <a href="https://www.mapbox.com/maps/satellite/">Mapbox Satellite</a> style.
+ <a href="https://www.mapbox.com/maps/satellite/">Mapbox Satellite</a> style as
+ of publication.
Satellite is high-resolution satellite and aerial imagery.
- @param version The style’s latest released version. As of publication, the
- current version is `9`.
+ @param version A specific version of the style.
*/
+ (NSURL *)satelliteStyleURLWithVersion:(NSInteger)version;
@@ -161,7 +199,24 @@ MGL_EXPORT
Mapbox Satellite with unobtrusive labels and translucent roads from Mapbox
Streets.
*/
-+ (NSURL *)hybridStyleURL __attribute__((deprecated("Use -satelliteStreetsStyleURLWithVersion:.")));
++ (NSURL *)hybridStyleURL __attribute__((deprecated("Use -satelliteStreetsStyleURL.")));
+
+/**
+ Returns the URL to the current version of the
+ <a href="https://www.mapbox.com/maps/satellite/">Mapbox Satellite Streets</a>
+ style as of publication.
+
+ Satellite Streets combines the high-resolution satellite and aerial imagery of
+ Mapbox Satellite with unobtrusive labels and translucent roads from Mapbox
+ Streets.
+
+ @warning The return value may change in a future release of the SDK. If you use
+ any feature that depends on a specific aspect of a default style – for
+ instance, the minimum zoom level that includes roads – use the
+ `-satelliteStreetsStyleURLWithVersion:` method instead. Such details may
+ change significantly from version to version.
+ */
++ (NSURL *)satelliteStreetsStyleURL;
/**
Returns the URL to the given version of the
@@ -172,11 +227,72 @@ MGL_EXPORT
Mapbox Satellite with unobtrusive labels and translucent roads from Mapbox
Streets.
- @param version The style’s latest released version. As of publication, the
- current version is `9`.
+ @param version A specific version of the style.
*/
+ (NSURL *)satelliteStreetsStyleURLWithVersion:(NSInteger)version;
+/**
+ Returns the URL to the current version of the
+ <a href="https://www.mapbox.com/blog/live-traffic-maps/">Mapbox Traffic Day</a>
+ style.
+
+ Traffic Day color-codes roads based on live traffic congestion data. Traffic
+ data is currently available in
+ <a href="https://www.mapbox.com/api-documentation/pages/traffic-countries.html">these select countries</a>.
+
+ @warning The return value may change in a future release of the SDK. If you use
+ any feature that depends on a specific aspect of a default style – for
+ instance, the minimum zoom level that includes roads – use the
+ `-trafficDayStyleURLWithVersion:` method instead. Such details may change
+ significantly from version to version.
+ */
++ (NSURL *)trafficDayStyleURL;
+
+/**
+ Returns the URL to the given version of the
+ <a href="https://www.mapbox.com/blog/live-traffic-maps/">Mapbox Traffic Day</a>
+ style as of publication.
+
+ Traffic Day color-codes roads based on live traffic congestion data. Traffic
+ data is currently available in
+ <a href="https://www.mapbox.com/api-documentation/pages/traffic-countries.html">these select countries</a>.
+
+ @param version A specific version of the style.
+ */
++ (NSURL *)trafficDayStyleURLWithVersion:(NSInteger)version;
+
+/**
+ Returns the URL to the current version of the
+ <a href="https://www.mapbox.com/blog/live-traffic-maps/">Mapbox Traffic Night</a>
+ style.
+
+ Traffic Night color-codes roads based on live traffic congestion data and is
+ designed to maximize legibility in low-light situations. Traffic data is
+ currently available in
+ <a href="https://www.mapbox.com/api-documentation/pages/traffic-countries.html">these select countries</a>.
+
+ @warning The return value may change in a future release of the SDK. If you use
+ any feature that depends on a specific aspect of a default style – for
+ instance, the minimum zoom level that includes roads – use the
+ `-trafficNightStyleURLWithVersion:` method instead. Such details may change
+ significantly from version to version.
+ */
++ (NSURL *)trafficNightStyleURL;
+
+/**
+ Returns the URL to the given version of the
+ <a href="https://www.mapbox.com/blog/live-traffic-maps/">Mapbox Traffic Night</a>
+ style as of publication.
+
+ Traffic Night color-codes roads based on live traffic congestion data and is
+ designed to maximize legibility in low-light situations. Traffic data is
+ currently available in
+ <a href="https://www.mapbox.com/api-documentation/pages/traffic-countries.html">these select countries</a>.
+
+ @param version A specific version of the style.
+ */
++ (NSURL *)trafficNightStyleURLWithVersion:(NSInteger)version;
+
#pragma mark Accessing Metadata About the Style
/**
@@ -367,40 +483,24 @@ MGL_EXPORT
#pragma mark Managing Style Classes
/**
- Currently active style classes, represented as an array of string identifiers.
+ Support for style classes has been removed. This property always returns an empty array.
*/
-@property (nonatomic) NS_ARRAY_OF(NSString *) *styleClasses __attribute__((deprecated("This property will be removed in a future release.")));
+@property (nonatomic) NS_ARRAY_OF(NSString *) *styleClasses __attribute__((deprecated("This property is non-functional.")));
/**
- Returns a Boolean value indicating whether the style class with the given
- identifier is currently active.
-
- @param styleClass The style class to query for.
- @return Whether the style class is currently active.
+ Support for style classes has been removed. This method always returns NO.
*/
-- (BOOL)hasStyleClass:(NSString *)styleClass __attribute__((deprecated("This method will be removed in a future release.")));
+- (BOOL)hasStyleClass:(NSString *)styleClass __attribute__((deprecated("This method is non-functional.")));
/**
- Activates the style class with the given identifier.
-
- @param styleClass The style class to activate.
+ Support for style classes has been removed. This method is a no-op.
*/
-- (void)addStyleClass:(NSString *)styleClass __attribute__((deprecated("This method will be removed in a future release.")));
+- (void)addStyleClass:(NSString *)styleClass __attribute__((deprecated("This method is non-functional.")));
/**
- Deactivates the style class with the given identifier.
-
- @note Style class names are not guaranteed to exist across styles or different
- versions of the same style. Applications that use this API must first set the
- style URL to an explicitly versioned style using a convenience method like
- `+[MGLStyle outdoorsStyleURLWithVersion:]`, `MGLMapView`’s “Style URL”
- inspectable in Interface Builder, or a manually constructed `NSURL`. This
- approach also avoids style class name changes that will occur in the default
- style over time.
-
- @param styleClass The style class to deactivate.
+ Support for style classes has been removed. This method is a no-op.
*/
-- (void)removeStyleClass:(NSString *)styleClass __attribute__((deprecated("This method will be removed in a future release.")));
+- (void)removeStyleClass:(NSString *)styleClass __attribute__((deprecated("This method is non-functional.")));
#pragma mark Managing a Style’s Images
diff --git a/platform/darwin/src/MGLStyle.mm b/platform/darwin/src/MGLStyle.mm
index aa493d9ef7..5f26b4fed2 100644
--- a/platform/darwin/src/MGLStyle.mm
+++ b/platform/darwin/src/MGLStyle.mm
@@ -3,6 +3,7 @@
#import "MGLMapView_Private.h"
#import "MGLStyleLayer.h"
#import "MGLFillStyleLayer.h"
+#import "MGLFillExtrusionStyleLayer.h"
#import "MGLLineStyleLayer.h"
#import "MGLCircleStyleLayer.h"
#import "MGLSymbolStyleLayer.h"
@@ -26,8 +27,9 @@
#include <mbgl/map/map.hpp>
#include <mbgl/util/default_styles.hpp>
-#include <mbgl/sprite/sprite_image.hpp>
+#include <mbgl/style/image.hpp>
#include <mbgl/style/layers/fill_layer.hpp>
+#include <mbgl/style/layers/fill_extrusion_layer.hpp>
#include <mbgl/style/layers/line_layer.hpp>
#include <mbgl/style/layers/symbol_layer.hpp>
#include <mbgl/style/layers/raster_layer.hpp>
@@ -56,8 +58,6 @@
#pragma mark Default style URLs
-static_assert(mbgl::util::default_styles::currentVersion == MGLStyleDefaultVersion, "mbgl::util::default_styles::currentVersion and MGLStyleDefaultVersion disagree.");
-
/// @param name The style’s marketing name, written in lower camelCase.
/// @param fileName The last path component in the style’s URL, excluding the version suffix.
#define MGL_DEFINE_STYLE(name, fileName) \
@@ -65,17 +65,13 @@ static_assert(mbgl::util::default_styles::currentVersion == MGLStyleDefaultVersi
+ (NSURL *)name##StyleURL { \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
- MGLStyleURL_##name = [self name##StyleURLWithVersion:8]; \
+ MGLStyleURL_##name = [self name##StyleURLWithVersion:mbgl::util::default_styles::name.currentVersion]; \
}); \
return MGLStyleURL_##name; \
} \
\
+ (NSURL *)name##StyleURL##WithVersion:(NSInteger)version { \
- if (mbgl::util::default_styles::currentVersion == version) { \
- return [NSURL URLWithString:@(mbgl::util::default_styles::name.url)]; \
- } else { \
- return [NSURL URLWithString:[@"mapbox://styles/mapbox/" #fileName "-v" stringByAppendingFormat:@"%li", (long)version]]; \
- } \
+ return [NSURL URLWithString:[@"mapbox://styles/mapbox/" #fileName "-v" stringByAppendingFormat:@"%li", (long)version]]; \
}
MGL_DEFINE_STYLE(streets, streets)
@@ -84,10 +80,12 @@ MGL_DEFINE_STYLE(light, light)
MGL_DEFINE_STYLE(dark, dark)
MGL_DEFINE_STYLE(satellite, satellite)
MGL_DEFINE_STYLE(satelliteStreets, satellite-streets)
+MGL_DEFINE_STYLE(trafficDay, traffic-day)
+MGL_DEFINE_STYLE(trafficNight, traffic-night)
// Make sure all the styles listed in mbgl::util::default_styles::orderedStyles
// are defined above and also declared in MGLStyle.h.
-static_assert(6 == mbgl::util::default_styles::numOrderedStyles,
+static_assert(8 == mbgl::util::default_styles::numOrderedStyles,
"mbgl::util::default_styles::orderedStyles and MGLStyle have different numbers of styles.");
// Hybrid has been renamed Satellite Streets, so the last Hybrid version is hard-coded here.
@@ -165,17 +163,21 @@ static NSURL *MGLStyleURL_emerald;
return rawSource ? [self sourceFromMBGLSource:rawSource] : nil;
}
-- (MGLSource *)sourceFromMBGLSource:(mbgl::style::Source *)source {
+- (MGLSource *)sourceFromMBGLSource:(mbgl::style::Source *)rawSource {
+ if (MGLSource *source = rawSource->peer.empty() ? nil : mbgl::any_cast<SourceWrapper>(rawSource->peer).source) {
+ return source;
+ }
+
// TODO: Fill in options specific to the respective source classes
// https://github.com/mapbox/mapbox-gl-native/issues/6584
- if (auto vectorSource = source->as<mbgl::style::VectorSource>()) {
+ if (auto vectorSource = rawSource->as<mbgl::style::VectorSource>()) {
return [[MGLVectorSource alloc] initWithRawSource:vectorSource];
- } else if (auto geoJSONSource = source->as<mbgl::style::GeoJSONSource>()) {
+ } else if (auto geoJSONSource = rawSource->as<mbgl::style::GeoJSONSource>()) {
return [[MGLShapeSource alloc] initWithRawSource:geoJSONSource];
- } else if (auto rasterSource = source->as<mbgl::style::RasterSource>()) {
+ } else if (auto rasterSource = rawSource->as<mbgl::style::RasterSource>()) {
return [[MGLRasterSource alloc] initWithRawSource:rasterSource];
} else {
- return [[MGLSource alloc] initWithRawSource:source];
+ return [[MGLSource alloc] initWithRawSource:rawSource];
}
}
@@ -318,44 +320,34 @@ static NSURL *MGLStyleURL_emerald;
[styleLayer removeFromMapView:self.mapView];
}
-- (MGLStyleLayer *)layerFromMBGLLayer:(mbgl::style::Layer *)mbglLayer
+- (MGLStyleLayer *)layerFromMBGLLayer:(mbgl::style::Layer *)rawLayer
{
- NSParameterAssert(mbglLayer);
-
- NSString *identifier = @(mbglLayer->getID().c_str());
- MGLStyleLayer *styleLayer;
- if (auto fillLayer = mbglLayer->as<mbgl::style::FillLayer>()) {
- MGLSource *source = [self sourceWithIdentifier:@(fillLayer->getSourceID().c_str())];
- styleLayer = [[MGLFillStyleLayer alloc] initWithIdentifier:identifier source:source];
- } else if (auto lineLayer = mbglLayer->as<mbgl::style::LineLayer>()) {
- MGLSource *source = [self sourceWithIdentifier:@(lineLayer->getSourceID().c_str())];
- styleLayer = [[MGLLineStyleLayer alloc] initWithIdentifier:identifier source:source];
- } else if (auto symbolLayer = mbglLayer->as<mbgl::style::SymbolLayer>()) {
- MGLSource *source = [self sourceWithIdentifier:@(symbolLayer->getSourceID().c_str())];
- styleLayer = [[MGLSymbolStyleLayer alloc] initWithIdentifier:identifier source:source];
- } else if (auto rasterLayer = mbglLayer->as<mbgl::style::RasterLayer>()) {
- MGLSource *source = [self sourceWithIdentifier:@(rasterLayer->getSourceID().c_str())];
- styleLayer = [[MGLRasterStyleLayer alloc] initWithIdentifier:identifier source:source];
- } else if (auto circleLayer = mbglLayer->as<mbgl::style::CircleLayer>()) {
- MGLSource *source = [self sourceWithIdentifier:@(circleLayer->getSourceID().c_str())];
- styleLayer = [[MGLCircleStyleLayer alloc] initWithIdentifier:identifier source:source];
- } else if (mbglLayer->is<mbgl::style::BackgroundLayer>()) {
- styleLayer = [[MGLBackgroundStyleLayer alloc] initWithIdentifier:identifier];
- } else if (mbglLayer->is<mbgl::style::CustomLayer>()) {
- styleLayer = self.openGLLayers[identifier];
- if (styleLayer) {
- NSAssert(styleLayer.rawLayer == mbglLayer->as<mbgl::style::CustomLayer>(), @"%@ wraps a CustomLayer that differs from the one associated with the underlying style.", styleLayer);
- return styleLayer;
- }
- styleLayer = [[MGLOpenGLStyleLayer alloc] initWithIdentifier:identifier];
+ NSParameterAssert(rawLayer);
+
+ if (MGLStyleLayer *layer = rawLayer->peer.empty() ? nil : mbgl::any_cast<LayerWrapper>(rawLayer->peer).layer) {
+ return layer;
+ }
+
+ if (auto fillLayer = rawLayer->as<mbgl::style::FillLayer>()) {
+ return [[MGLFillStyleLayer alloc] initWithRawLayer:fillLayer];
+ } else if (auto fillExtrusionLayer = rawLayer->as<mbgl::style::FillExtrusionLayer>()) {
+ return [[MGLFillExtrusionStyleLayer alloc] initWithRawLayer:fillExtrusionLayer];
+ } else if (auto lineLayer = rawLayer->as<mbgl::style::LineLayer>()) {
+ return [[MGLLineStyleLayer alloc] initWithRawLayer:lineLayer];
+ } else if (auto symbolLayer = rawLayer->as<mbgl::style::SymbolLayer>()) {
+ return [[MGLSymbolStyleLayer alloc] initWithRawLayer:symbolLayer];
+ } else if (auto rasterLayer = rawLayer->as<mbgl::style::RasterLayer>()) {
+ return [[MGLRasterStyleLayer alloc] initWithRawLayer:rasterLayer];
+ } else if (auto circleLayer = rawLayer->as<mbgl::style::CircleLayer>()) {
+ return [[MGLCircleStyleLayer alloc] initWithRawLayer:circleLayer];
+ } else if (auto backgroundLayer = rawLayer->as<mbgl::style::BackgroundLayer>()) {
+ return [[MGLBackgroundStyleLayer alloc] initWithRawLayer:backgroundLayer];
+ } else if (auto customLayer = rawLayer->as<mbgl::style::CustomLayer>()) {
+ return [[MGLOpenGLStyleLayer alloc] initWithRawLayer:customLayer];
} else {
NSAssert(NO, @"Unrecognized layer type");
return nil;
}
-
- styleLayer.rawLayer = mbglLayer;
-
- return styleLayer;
}
- (MGLStyleLayer *)layerWithIdentifier:(NSString *)identifier
@@ -477,60 +469,32 @@ static NSURL *MGLStyleURL_emerald;
- (NS_ARRAY_OF(NSString *) *)styleClasses
{
- const std::vector<std::string> &appliedClasses = self.mapView.mbglMap->getClasses();
-
- NSMutableArray *returnArray = [NSMutableArray arrayWithCapacity:appliedClasses.size()];
-
- for (auto appliedClass : appliedClasses) {
- [returnArray addObject:@(appliedClass.c_str())];
- }
-
- return returnArray;
+ return @[];
}
- (void)setStyleClasses:(NS_ARRAY_OF(NSString *) *)appliedClasses
{
- [self setStyleClasses:appliedClasses transitionDuration:0];
}
- (void)setStyleClasses:(NS_ARRAY_OF(NSString *) *)appliedClasses transitionDuration:(NSTimeInterval)transitionDuration
{
- std::vector<std::string> newAppliedClasses;
-
- for (NSString *appliedClass in appliedClasses)
- {
- newAppliedClasses.push_back([appliedClass UTF8String]);
- }
-
- mbgl::style::TransitionOptions transition { { MGLDurationFromTimeInterval(transitionDuration) } };
- self.mapView.mbglMap->setTransitionOptions(transition);
- self.mapView.mbglMap->setClasses(newAppliedClasses);
}
- (NSUInteger)countOfStyleClasses {
- const auto &classes = self.mapView.mbglMap->getClasses();
- return classes.size();
+ return 0;
}
- (BOOL)hasStyleClass:(NSString *)styleClass
{
- return styleClass && self.mapView.mbglMap->hasClass([styleClass UTF8String]);
+ return NO;
}
- (void)addStyleClass:(NSString *)styleClass
{
- if (styleClass)
- {
- self.mapView.mbglMap->addClass([styleClass UTF8String]);
- }
}
- (void)removeStyleClass:(NSString *)styleClass
{
- if (styleClass)
- {
- self.mapView.mbglMap->removeClass([styleClass UTF8String]);
- }
}
#pragma mark Style images
@@ -546,7 +510,7 @@ static NSURL *MGLStyleURL_emerald;
format:@"Cannot assign image %@ to a nil name.", image];
}
- self.mapView.mbglMap->addImage([name UTF8String], image.mgl_spriteImage);
+ self.mapView.mbglMap->addImage([image mgl_styleImageWithIdentifier:name]);
}
- (void)removeImageForName:(NSString *)name
@@ -566,8 +530,8 @@ static NSURL *MGLStyleURL_emerald;
format:@"Cannot get image with nil name."];
}
- auto spriteImage = self.mapView.mbglMap->getImage([name UTF8String]);
- return spriteImage ? [[MGLImage alloc] initWithMGLSpriteImage:spriteImage] : nil;
+ auto styleImage = self.mapView.mbglMap->getImage([name UTF8String]);
+ return styleImage ? [[MGLImage alloc] initWithMGLStyleImage:styleImage] : nil;
}
#pragma mark Style transitions
diff --git a/platform/darwin/src/MGLStyleLayer.h b/platform/darwin/src/MGLStyleLayer.h
index ac9b739c74..7d181667d6 100644
--- a/platform/darwin/src/MGLStyleLayer.h
+++ b/platform/darwin/src/MGLStyleLayer.h
@@ -27,25 +27,7 @@ MGL_EXPORT
#pragma mark Initializing a Style Layer
-- (instancetype)init __attribute__((unavailable("Use -initWithIdentifier: instead.")));
-
-/**
- Returns a style layer object initialized with the given identifier.
-
- The default implementation of this initializer in MGLStyleLayer creates an
- invalid style layer. Call this initializer on `MGLBackgroundStyleLayer` or one of
- the concrete subclasses of `MGLForegroundStyleLayer` to create a valid style
- layer.
-
- After initializing and configuring the style layer, add it to a map view’s
- style using the `-[MGLStyle addLayer:]` or
- `-[MGLStyle insertLayer:belowLayer:]` method.
-
- @param identifier A string that uniquely identifies the layer in the style to
- which it is added.
- @return An initialized style layer.
- */
-- (instancetype)initWithIdentifier:(NSString *)identifier;
+- (instancetype)init __attribute__((unavailable("Use -init methods of concrete subclasses instead.")));
#pragma mark Identifying a Style Layer
diff --git a/platform/darwin/src/MGLStyleLayer.h.ejs b/platform/darwin/src/MGLStyleLayer.h.ejs
index e6c60a76db..df42621c6d 100644
--- a/platform/darwin/src/MGLStyleLayer.h.ejs
+++ b/platform/darwin/src/MGLStyleLayer.h.ejs
@@ -84,7 +84,33 @@ MGL_EXPORT
%>StyleLayer
<% if (type === 'background') { -%>
-- (instancetype)initWithIdentifier:(NSString *)identifier NS_DESIGNATED_INITIALIZER;
+/**
+Returns a <%- type %> style layer initialized with an identifier.
+
+After initializing and configuring the style layer, add it to a map view’s
+style using the `-[MGLStyle addLayer:]` or
+`-[MGLStyle insertLayer:belowLayer:]` method.
+
+@param identifier A string that uniquely identifies the source in the style to
+which it is added.
+*/
+- (instancetype)initWithIdentifier:(NSString *)identifier;
+<% } else { -%>
+
+/**
+ Returns a <%- type %> style layer initialized with an identifier and source.
+
+ After initializing and configuring the style layer, add it to a map view’s
+ style using the `-[MGLStyle addLayer:]` or
+ `-[MGLStyle insertLayer:belowLayer:]` method.
+
+ @param identifier A string that uniquely identifies the source in the style to
+ which it is added.
+ @param source The source from which to obtain the data to style. If the source
+ has not yet been added to the current style, the behavior is undefined.
+ @return An initialized foreground style layer.
+ */
+- (instancetype)initWithIdentifier:(NSString *)identifier source:(MGLSource *)source;
<% } -%>
<% if (layoutProperties.length) { -%>
@@ -135,7 +161,7 @@ MGL_EXPORT
*/
@interface NSValue (MGL<%- camelize(type) %>StyleLayerAdditions)
-#pragma mark Working with <%- camelize(type) %> Style Layer Attribute Values
+#pragma mark Working with <%- camelize(unhyphenate(type)) %> Style Layer Attribute Values
<% for (let property of enumProperties) { -%>
/**
diff --git a/platform/darwin/src/MGLStyleLayer.mm b/platform/darwin/src/MGLStyleLayer.mm
index 47f41e0388..4bfaea934b 100644
--- a/platform/darwin/src/MGLStyleLayer.mm
+++ b/platform/darwin/src/MGLStyleLayer.mm
@@ -1,24 +1,58 @@
#import "MGLStyleLayer_Private.h"
#import "MGLMapView_Private.h"
+#include <mbgl/map/map.hpp>
#include <mbgl/style/layer.hpp>
@interface MGLStyleLayer ()
-@property (nonatomic) mbgl::style::Layer *rawLayer;
+@property (nonatomic, readonly) mbgl::style::Layer *rawLayer;
@end
-@implementation MGLStyleLayer
+@implementation MGLStyleLayer {
+ std::unique_ptr<mbgl::style::Layer> _pendingLayer;
+}
-- (instancetype)initWithIdentifier:(NSString *)identifier
-{
+- (instancetype)initWithRawLayer:(mbgl::style::Layer *)rawLayer {
if (self = [super init]) {
- _identifier = identifier;
+ _identifier = @(rawLayer->getID().c_str());
+ _rawLayer = rawLayer;
+ _rawLayer->peer = LayerWrapper { self };
+ }
+ return self;
+}
+
+- (instancetype)initWithPendingLayer:(std::unique_ptr<mbgl::style::Layer>)pendingLayer {
+ if (self = [self initWithRawLayer:pendingLayer.get()]) {
+ _pendingLayer = std::move(pendingLayer);
}
return self;
}
+- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer
+{
+ if (_pendingLayer == nullptr) {
+ [NSException raise:@"MGLRedundantLayerException"
+ format:@"This instance %@ was already added to %@. Adding the same layer instance " \
+ "to the style more than once is invalid.", self, mapView.style];
+ }
+
+ if (otherLayer) {
+ const mbgl::optional<std::string> belowLayerId{otherLayer.identifier.UTF8String};
+ mapView.mbglMap->addLayer(std::move(_pendingLayer), belowLayerId);
+ } else {
+ mapView.mbglMap->addLayer(std::move(_pendingLayer));
+ }
+}
+
+- (void)removeFromMapView:(MGLMapView *)mapView
+{
+ if (self.rawLayer == mapView.mbglMap->getLayer(self.identifier.UTF8String)) {
+ _pendingLayer = mapView.mbglMap->removeLayer(self.identifier.UTF8String);
+ }
+}
+
- (void)setVisible:(BOOL)visible
{
MGLAssertStyleLayerIsValid();
diff --git a/platform/darwin/src/MGLStyleLayer.mm.ejs b/platform/darwin/src/MGLStyleLayer.mm.ejs
index 1e5f3df160..da67cbd633 100644
--- a/platform/darwin/src/MGLStyleLayer.mm.ejs
+++ b/platform/darwin/src/MGLStyleLayer.mm.ejs
@@ -8,14 +8,13 @@
// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLSource.h"
-#import "MGLMapView_Private.h"
#import "NSPredicate+MGLAdditions.h"
#import "NSDate+MGLAdditions.h"
#import "MGLStyleLayer_Private.h"
#import "MGLStyleValue_Private.h"
#import "MGL<%- camelize(type) %>StyleLayer.h"
-#include <mbgl/map/map.hpp>
+#include <mbgl/style/transition_options.hpp>
#include <mbgl/style/layers/<%- type.replace('-', '_') %>_layer.hpp>
<% if (enumProperties) { -%>
@@ -50,35 +49,24 @@ namespace mbgl {
@interface MGL<%- camelize(type) %>StyleLayer ()
-@property (nonatomic) mbgl::style::<%- camelize(type) %>Layer *rawLayer;
+@property (nonatomic, readonly) mbgl::style::<%- camelize(type) %>Layer *rawLayer;
@end
@implementation MGL<%- camelize(type) %>StyleLayer
-{
- std::unique_ptr<mbgl::style::<%- camelize(type) %>Layer> _pendingLayer;
-}
<% if (type == 'background') { -%>
- (instancetype)initWithIdentifier:(NSString *)identifier
{
- if (self = [super initWithIdentifier:identifier]) {
- auto layer = std::make_unique<mbgl::style::<%- camelize(type) %>Layer>(identifier.UTF8String);
- _pendingLayer = std::move(layer);
- self.rawLayer = _pendingLayer.get();
- }
- return self;
+ auto layer = std::make_unique<mbgl::style::<%- camelize(type) %>Layer>(identifier.UTF8String);
+ return self = [super initWithPendingLayer:std::move(layer)];
}
<% } else { -%>
- (instancetype)initWithIdentifier:(NSString *)identifier source:(MGLSource *)source
{
- if (self = [super initWithIdentifier:identifier source:source]) {
- auto layer = std::make_unique<mbgl::style::<%- camelize(type) %>Layer>(identifier.UTF8String, source.identifier.UTF8String);
- _pendingLayer = std::move(layer);
- self.rawLayer = _pendingLayer.get();
- }
- return self;
+ auto layer = std::make_unique<mbgl::style::<%- camelize(type) %>Layer>(identifier.UTF8String, source.identifier.UTF8String);
+ return self = [super initWithPendingLayer:std::move(layer)];
}
<% } -%>
@@ -87,11 +75,6 @@ namespace mbgl {
return (mbgl::style::<%- camelize(type) %>Layer *)super.rawLayer;
}
-- (void)setRawLayer:(mbgl::style::<%- camelize(type) %>Layer *)rawLayer
-{
- super.rawLayer = rawLayer;
-}
-
<% if (type !== 'background') { -%>
- (NSString *)sourceIdentifier
{
@@ -131,46 +114,6 @@ namespace mbgl {
}
<% }} -%>
-#pragma mark - Adding to and removing from a map view
-
-- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer
-{
- if (_pendingLayer == nullptr) {
- [NSException raise:@"MGLRedundantLayerException"
- format:@"This instance %@ was already added to %@. Adding the same layer instance " \
- "to the style more than once is invalid.", self, mapView.style];
- }
-
- if (otherLayer) {
- const mbgl::optional<std::string> belowLayerId{otherLayer.identifier.UTF8String};
- mapView.mbglMap->addLayer(std::move(_pendingLayer), belowLayerId);
- } else {
- mapView.mbglMap->addLayer(std::move(_pendingLayer));
- }
-}
-
-- (void)removeFromMapView:(MGLMapView *)mapView
-{
- if (self.rawLayer != mapView.mbglMap->getLayer(self.identifier.UTF8String)) {
- return;
- }
-
- auto removedLayer = mapView.mbglMap->removeLayer(self.identifier.UTF8String);
- if (!removedLayer) {
- return;
- }
-
- mbgl::style::<%- camelize(type) %>Layer *layer = dynamic_cast<mbgl::style::<%- camelize(type) %>Layer *>(removedLayer.get());
- if (!layer) {
- return;
- }
-
- removedLayer.release();
-
- _pendingLayer = std::unique_ptr<mbgl::style::<%- camelize(type) %>Layer>(layer);
- self.rawLayer = _pendingLayer.get();
-}
-
<% if (layoutProperties.length) { -%>
#pragma mark - Accessing the Layout Attributes
diff --git a/platform/darwin/src/MGLStyleLayer_Private.h b/platform/darwin/src/MGLStyleLayer_Private.h
index b5d709a7af..ed8ec31755 100644
--- a/platform/darwin/src/MGLStyleLayer_Private.h
+++ b/platform/darwin/src/MGLStyleLayer_Private.h
@@ -7,6 +7,14 @@
NS_ASSUME_NONNULL_BEGIN
+// A struct to be stored in the `peer` member of mbgl::style::Layer, in order to implement
+// object identity. We don't store a MGLStyleLayer pointer directly because that doesn't
+// interoperate with ARC. The inner pointer is weak in order to avoid a reference cycle for
+// "pending" MGLStyleLayers, which have a strong owning pointer to the mbgl::style::Layer.
+struct LayerWrapper {
+ __weak MGLStyleLayer *layer;
+};
+
/**
Assert that the style layer is valid.
@@ -30,6 +38,18 @@ NS_ASSUME_NONNULL_BEGIN
@interface MGLStyleLayer (Private)
+/**
+ Initializes and returns a layer with a raw pointer to the backing store,
+ associated with a style.
+ */
+- (instancetype)initWithRawLayer:(mbgl::style::Layer *)rawLayer;
+
+/**
+ Initializes and returns a layer with an owning pointer to the backing store,
+ unassociated from a style.
+ */
+- (instancetype)initWithPendingLayer:(std::unique_ptr<mbgl::style::Layer>)pendingLayer;
+
@property (nonatomic, readwrite, copy) NSString *identifier;
/**
@@ -39,7 +59,7 @@ NS_ASSUME_NONNULL_BEGIN
pointer value stays even after ownership of the object is transferred via
`mbgl::Map addLayer`.
*/
-@property (nonatomic) mbgl::style::Layer *rawLayer;
+@property (nonatomic, readonly) mbgl::style::Layer *rawLayer;
/**
Adds the mbgl style layer that this object represents to the mbgl map below the
diff --git a/platform/darwin/src/MGLStyleValue_Private.h b/platform/darwin/src/MGLStyleValue_Private.h
index 90d6622c93..263b54d7e5 100644
--- a/platform/darwin/src/MGLStyleValue_Private.h
+++ b/platform/darwin/src/MGLStyleValue_Private.h
@@ -123,8 +123,9 @@ public:
return toMBGLConstantValue((MGLConstantStyleValue<ObjCType> *)value);
} else if ([value isKindOfClass:[MGLStyleFunction class]]) {
auto rawValue = toRawStyleSpecValue((MGLStyleFunction<ObjCType> *) value);
- auto result = mbgl::style::conversion::convert<mbgl::style::DataDrivenPropertyValue<MBGLType>>(rawValue);
- NSCAssert(result, @(result.error().message.c_str()));
+ mbgl::style::conversion::Error error;
+ auto result = mbgl::style::conversion::convert<mbgl::style::DataDrivenPropertyValue<MBGLType>>(rawValue, error);
+ NSCAssert(result, @(error.message.c_str()));
return *result;
} else {
return {};
diff --git a/platform/darwin/src/MGLSymbolStyleLayer.h b/platform/darwin/src/MGLSymbolStyleLayer.h
index c76efe2de7..b6c6372324 100644
--- a/platform/darwin/src/MGLSymbolStyleLayer.h
+++ b/platform/darwin/src/MGLSymbolStyleLayer.h
@@ -280,6 +280,21 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslationAnchor) {
MGL_EXPORT
@interface MGLSymbolStyleLayer : MGLVectorStyleLayer
+/**
+ Returns a symbol style layer initialized with an identifier and source.
+
+ After initializing and configuring the style layer, add it to a map view’s
+ style using the `-[MGLStyle addLayer:]` or
+ `-[MGLStyle insertLayer:belowLayer:]` method.
+
+ @param identifier A string that uniquely identifies the source in the style to
+ which it is added.
+ @param source The source from which to obtain the data to style. If the source
+ has not yet been added to the current style, the behavior is undefined.
+ @return An initialized foreground style layer.
+ */
+- (instancetype)initWithIdentifier:(NSString *)identifier source:(MGLSource *)source;
+
#pragma mark - Accessing the Layout Attributes
/**
@@ -344,8 +359,18 @@ MGL_EXPORT
You can set this property to an instance of:
* `MGLConstantStyleValue`
- * `MGLCameraStyleFunction` with an interpolation mode of
- `MGLInterpolationModeInterval`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSString *> *iconImageName;
@@ -527,6 +552,15 @@ MGL_EXPORT
* `MGLCameraStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconScale;
@@ -909,6 +943,15 @@ MGL_EXPORT
* `MGLCameraStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textFontSize;
@@ -1026,6 +1069,15 @@ MGL_EXPORT
* `MGLCameraStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textOffset;
#else
@@ -1047,6 +1099,15 @@ MGL_EXPORT
* `MGLCameraStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textOffset;
#endif
@@ -1132,6 +1193,15 @@ MGL_EXPORT
* `MGLCameraStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textRotation;
diff --git a/platform/darwin/src/MGLSymbolStyleLayer.mm b/platform/darwin/src/MGLSymbolStyleLayer.mm
index 8441931685..5a8f8c6084 100644
--- a/platform/darwin/src/MGLSymbolStyleLayer.mm
+++ b/platform/darwin/src/MGLSymbolStyleLayer.mm
@@ -2,14 +2,13 @@
// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLSource.h"
-#import "MGLMapView_Private.h"
#import "NSPredicate+MGLAdditions.h"
#import "NSDate+MGLAdditions.h"
#import "MGLStyleLayer_Private.h"
#import "MGLStyleValue_Private.h"
#import "MGLSymbolStyleLayer.h"
-#include <mbgl/map/map.hpp>
+#include <mbgl/style/transition_options.hpp>
#include <mbgl/style/layers/symbol_layer.hpp>
namespace mbgl {
@@ -82,23 +81,16 @@ namespace mbgl {
@interface MGLSymbolStyleLayer ()
-@property (nonatomic) mbgl::style::SymbolLayer *rawLayer;
+@property (nonatomic, readonly) mbgl::style::SymbolLayer *rawLayer;
@end
@implementation MGLSymbolStyleLayer
-{
- std::unique_ptr<mbgl::style::SymbolLayer> _pendingLayer;
-}
- (instancetype)initWithIdentifier:(NSString *)identifier source:(MGLSource *)source
{
- if (self = [super initWithIdentifier:identifier source:source]) {
- auto layer = std::make_unique<mbgl::style::SymbolLayer>(identifier.UTF8String, source.identifier.UTF8String);
- _pendingLayer = std::move(layer);
- self.rawLayer = _pendingLayer.get();
- }
- return self;
+ auto layer = std::make_unique<mbgl::style::SymbolLayer>(identifier.UTF8String, source.identifier.UTF8String);
+ return self = [super initWithPendingLayer:std::move(layer)];
}
- (mbgl::style::SymbolLayer *)rawLayer
@@ -106,11 +98,6 @@ namespace mbgl {
return (mbgl::style::SymbolLayer *)super.rawLayer;
}
-- (void)setRawLayer:(mbgl::style::SymbolLayer *)rawLayer
-{
- super.rawLayer = rawLayer;
-}
-
- (NSString *)sourceIdentifier
{
MGLAssertStyleLayerIsValid();
@@ -147,46 +134,6 @@ namespace mbgl {
return [NSPredicate mgl_predicateWithFilter:self.rawLayer->getFilter()];
}
-#pragma mark - Adding to and removing from a map view
-
-- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer
-{
- if (_pendingLayer == nullptr) {
- [NSException raise:@"MGLRedundantLayerException"
- format:@"This instance %@ was already added to %@. Adding the same layer instance " \
- "to the style more than once is invalid.", self, mapView.style];
- }
-
- if (otherLayer) {
- const mbgl::optional<std::string> belowLayerId{otherLayer.identifier.UTF8String};
- mapView.mbglMap->addLayer(std::move(_pendingLayer), belowLayerId);
- } else {
- mapView.mbglMap->addLayer(std::move(_pendingLayer));
- }
-}
-
-- (void)removeFromMapView:(MGLMapView *)mapView
-{
- if (self.rawLayer != mapView.mbglMap->getLayer(self.identifier.UTF8String)) {
- return;
- }
-
- auto removedLayer = mapView.mbglMap->removeLayer(self.identifier.UTF8String);
- if (!removedLayer) {
- return;
- }
-
- mbgl::style::SymbolLayer *layer = dynamic_cast<mbgl::style::SymbolLayer *>(removedLayer.get());
- if (!layer) {
- return;
- }
-
- removedLayer.release();
-
- _pendingLayer = std::unique_ptr<mbgl::style::SymbolLayer>(layer);
- self.rawLayer = _pendingLayer.get();
-}
-
#pragma mark - Accessing the Layout Attributes
- (void)setIconAllowsOverlap:(MGLStyleValue<NSNumber *> *)iconAllowsOverlap {
@@ -240,7 +187,7 @@ namespace mbgl {
- (void)setIconImageName:(MGLStyleValue<NSString *> *)iconImageName {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<std::string, NSString *>().toPropertyValue(iconImageName);
+ auto mbglValue = MGLStyleValueTransformer<std::string, NSString *>().toDataDrivenPropertyValue(iconImageName);
self.rawLayer->setIconImage(mbglValue);
}
@@ -249,9 +196,9 @@ namespace mbgl {
auto propertyValue = self.rawLayer->getIconImage();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(self.rawLayer->getDefaultIconImage());
+ return MGLStyleValueTransformer<std::string, NSString *>().toDataDrivenStyleValue(self.rawLayer->getDefaultIconImage());
}
- return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<std::string, NSString *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setIconImage:(MGLStyleValue<NSString *> *)iconImage {
@@ -356,7 +303,7 @@ namespace mbgl {
- (void)setIconScale:(MGLStyleValue<NSNumber *> *)iconScale {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(iconScale);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(iconScale);
self.rawLayer->setIconSize(mbglValue);
}
@@ -365,9 +312,9 @@ namespace mbgl {
auto propertyValue = self.rawLayer->getIconSize();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultIconSize());
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultIconSize());
}
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setIconSize:(MGLStyleValue<NSNumber *> *)iconSize {
@@ -657,7 +604,7 @@ namespace mbgl {
- (void)setTextFontSize:(MGLStyleValue<NSNumber *> *)textFontSize {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(textFontSize);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(textFontSize);
self.rawLayer->setTextSize(mbglValue);
}
@@ -666,9 +613,9 @@ namespace mbgl {
auto propertyValue = self.rawLayer->getTextSize();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultTextSize());
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultTextSize());
}
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setTextSize:(MGLStyleValue<NSNumber *> *)textSize {
@@ -763,7 +710,7 @@ namespace mbgl {
- (void)setTextOffset:(MGLStyleValue<NSValue *> *)textOffset {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toInterpolatablePropertyValue(textOffset);
+ auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toDataDrivenPropertyValue(textOffset);
self.rawLayer->setTextOffset(mbglValue);
}
@@ -772,9 +719,9 @@ namespace mbgl {
auto propertyValue = self.rawLayer->getTextOffset();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(self.rawLayer->getDefaultTextOffset());
+ return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toDataDrivenStyleValue(self.rawLayer->getDefaultTextOffset());
}
- return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setTextOptional:(MGLStyleValue<NSNumber *> *)textOptional {
@@ -831,7 +778,7 @@ namespace mbgl {
- (void)setTextRotation:(MGLStyleValue<NSNumber *> *)textRotation {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(textRotation);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(textRotation);
self.rawLayer->setTextRotate(mbglValue);
}
@@ -840,9 +787,9 @@ namespace mbgl {
auto propertyValue = self.rawLayer->getTextRotate();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultTextRotate());
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultTextRotate());
}
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setTextRotate:(MGLStyleValue<NSNumber *> *)textRotate {
diff --git a/platform/darwin/src/MGLTileSource.h b/platform/darwin/src/MGLTileSource.h
index 54c756332d..538b94037e 100644
--- a/platform/darwin/src/MGLTileSource.h
+++ b/platform/darwin/src/MGLTileSource.h
@@ -147,135 +147,6 @@ typedef NS_ENUM(NSUInteger, MGLTileCoordinateSystem) {
MGL_EXPORT
@interface MGLTileSource : MGLSource
-#pragma mark Initializing a Source
-
-- (instancetype)init __attribute__((unavailable("Use -initWithIdentifier:configurationURL: or -initWithIdentifier:tileURLTemplates:options: instead.")));
-- (instancetype)initWithIdentifier:(NSString *)identifier __attribute__((unavailable("Use -initWithIdentifier:configurationURL: or -initWithIdentifier:tileURLTemplates:options: instead.")));
-
-/**
- Returns a tile source initialized with an identifier and configuration URL.
-
- After initializing and configuring the source, add it to a map view’s style
- using the `-[MGLStyle addSource:]` method.
-
- The URL may be a full HTTP or HTTPS URL or, for tile sets hosted by Mapbox, a
- Mapbox URL indicating a map identifier (`mapbox://<mapid>`). The URL should
- point to a JSON file that conforms to the
- <a href="https://github.com/mapbox/tilejson-spec/">TileJSON specification</a>.
-
- @param identifier A string that uniquely identifies the source in the style to
- which it is added.
- @param configurationURL A URL to a TileJSON configuration file describing the
- source’s contents and other metadata.
- @return An initialized tile source.
- */
-- (instancetype)initWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL;
-
-/**
- Returns a tile source initialized an identifier, tile URL templates, and
- options.
-
- After initializing and configuring the source, add it to a map view’s style
- using the `-[MGLStyle addSource:]` method.
-
- #### Tile URL templates
-
- Tile URL templates are strings that specify the URLs of the tile images to
- load. Each template resembles an absolute URL, but with any number of
- placeholder strings that the source evaluates based on the tile it needs to
- load. For example:
-
- <ul>
- <li><code>http://www.example.com/tiles/{z}/{x}/{y}.pbf</code> could be
- evaluated as <code>http://www.example.com/tiles/14/6/9.pbf</code>.</li>
- <li><code>http://www.example.com/tiles/{z}/{x}/{y}{ratio}.png</code> could be
- evaluated as <code>http://www.example.com/tiles/14/6/9@2x.png</code>.</li>
- </ul>
-
- Tile sources support the following placeholder strings in tile URL templates,
- all of which are optional:
-
- <table>
- <thead>
- <tr><th>Placeholder string</th><th>Description</th></tr>
- </thead>
- <tbody>
- <tr>
- <td><code>{x}</code></td>
- <td>The index of the tile along the map’s x axis according to Spherical
- Mercator projection. If the value is 0, the tile’s left edge corresponds
- to the 180th meridian west. If the value is 2<sup><var>z</var></sup>−1,
- the tile’s right edge corresponds to the 180th meridian east.</td>
- </tr>
- <tr>
- <td><code>{y}</code></td>
- <td>The index of the tile along the map’s y axis according to Spherical
- Mercator projection. If the value is 0, the tile’s tile edge corresponds
- to arctan(sinh(π)), or approximately 85.0511 degrees north. If the value
- is 2<sup><var>z</var></sup>−1, the tile’s bottom edge corresponds to
- −arctan(sinh(π)), or approximately 85.0511 degrees south. The y axis is
- inverted if the <code>options</code> parameter contains
- <code>MGLTileSourceOptionTileCoordinateSystem</code> with a value of
- <code>MGLTileCoordinateSystemTMS</code>.</td>
- </tr>
- <tr>
- <td><code>{z}</code></td>
- <td>The tile’s zoom level. At zoom level 0, each tile covers the entire
- world map; at zoom level 1, it covers ¼ of the world; at zoom level 2,
- <sup>1</sup>⁄<sub>16</sub> of the world, and so on. For tiles loaded by
- a <code>MGLRasterSource</code> object, whether the tile zoom level
- matches the map’s current zoom level depends on the value of the
- source’s tile size as specified in the
- <code>MGLTileSourceOptionTileSize</code> key of the
- <code>options</code> parameter.</td>
- </tr>
- <tr>
- <td><code>{bbox-epsg-3857}</code></td>
- <td>The tile’s bounding box, expressed as a comma-separated list of the
- tile’s western, southern, eastern, and northern extents according to
- Spherical Mercator (EPSG:3857) projection. The bounding box is typically
- used with map services conforming to the
- <a href="http://www.opengeospatial.org/standards/wms">Web Map Service</a>
- protocol.</td>
- </tr>
- <tr>
- <td><code>{quadkey}</code></td>
- <td>A quadkey indicating both the tile’s location and its zoom level. The
- quadkey is typically used with
- <a href="https://msdn.microsoft.com/en-us/library/bb259689.aspx">Bing Maps</a>.
- </td>
- </tr>
- <tr>
- <td><code>{ratio}</code></td>
- <td>A suffix indicating the resolution of the tile image. The suffix is the
- empty string for standard resolution displays and <code>@2x</code> for
- Retina displays, including displays for which
- <code>NSScreen.backingScaleFactor</code> or <code>UIScreen.scale</code>
- is 3.</td>
- </tr>
- <tr>
- <td><code>{prefix}</code></td>
- <td>Two hexadecimal digits chosen such that each visible tile has a
- different prefix. The prefix is typically used for domain sharding.</td>
- </tr>
- </tbody>
- </table>
-
- For more information about the `{x}`, `{y}`, and `{z}` placeholder strings,
- consult the
- <a href="https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames">OpenStreetMap Wiki</a>.
-
- @param identifier A string that uniquely identifies the source in the style to
- which it is added.
- @param tileURLTemplates An array of tile URL template strings. Only the first
- string is used; any additional strings are ignored.
- @param options A dictionary containing configuration options. See
- `MGLTileSourceOption` for available keys and values. Pass in `nil` to use
- the default values.
- @return An initialized tile source.
- */
-- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates options:(nullable NS_DICTIONARY_OF(MGLTileSourceOption, id) *)options;
-
#pragma mark Accessing a Source’s Content
/**
diff --git a/platform/darwin/src/MGLTileSource.mm b/platform/darwin/src/MGLTileSource.mm
index aa2a299a46..5644ad9a06 100644
--- a/platform/darwin/src/MGLTileSource.mm
+++ b/platform/darwin/src/MGLTileSource.mm
@@ -19,14 +19,6 @@ const MGLTileSourceOption MGLTileSourceOptionTileCoordinateSystem = @"MGLTileSou
@implementation MGLTileSource
-- (instancetype)initWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL {
- return [super initWithIdentifier:identifier];
-}
-
-- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates options:(NS_DICTIONARY_OF(MGLTileSourceOption, id) *)options {
- return [super initWithIdentifier:identifier];
-}
-
- (NSURL *)configurationURL {
[NSException raise:@"MGLAbstractClassException"
format:@"MGLTileSource is an abstract class"];
diff --git a/platform/darwin/src/MGLTypes.h b/platform/darwin/src/MGLTypes.h
index 5216e921f1..c06fd8b0e7 100644
--- a/platform/darwin/src/MGLTypes.h
+++ b/platform/darwin/src/MGLTypes.h
@@ -42,6 +42,10 @@ typedef NS_ENUM(NSInteger, MGLErrorCode) {
MGLErrorCodeBadServerResponse = 2,
/** An attempt to establish a connection failed. */
MGLErrorCodeConnectionFailed = 3,
+ /** A style parse error occurred while attempting to load the map. */
+ MGLErrorCodeParseStyleFailed = 4,
+ /** An attempt to load the style failed. */
+ MGLErrorCodeLoadStyleFailed = 5,
};
/** Options for enabling debugging features in an `MGLMapView` instance. */
diff --git a/platform/darwin/src/MGLVectorSource.h b/platform/darwin/src/MGLVectorSource.h
index 83926fd287..a48434f7a3 100644
--- a/platform/darwin/src/MGLVectorSource.h
+++ b/platform/darwin/src/MGLVectorSource.h
@@ -51,8 +51,128 @@ MGL_EXPORT
#pragma mark Initializing a Source
+/**
+ Returns a vector source initialized with an identifier and configuration URL.
+
+ After initializing and configuring the source, add it to a map view’s style
+ using the `-[MGLStyle addSource:]` method.
+
+ The URL may be a full HTTP or HTTPS URL or, for tile sets hosted by Mapbox, a
+ Mapbox URL indicating a map identifier (`mapbox://<mapid>`). The URL should
+ point to a JSON file that conforms to the
+ <a href="https://github.com/mapbox/tilejson-spec/">TileJSON specification</a>.
+
+ @param identifier A string that uniquely identifies the source in the style to
+ which it is added.
+ @param configurationURL A URL to a TileJSON configuration file describing the
+ source’s contents and other metadata.
+ @return An initialized vector source.
+ */
- (instancetype)initWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL NS_DESIGNATED_INITIALIZER;
+/**
+ Returns a vector source initialized an identifier, tile URL templates, and
+ options.
+
+ After initializing and configuring the source, add it to a map view’s style
+ using the `-[MGLStyle addSource:]` method.
+
+ #### Tile URL templates
+
+ Tile URL templates are strings that specify the URLs of the tile images to
+ load. Each template resembles an absolute URL, but with any number of
+ placeholder strings that the source evaluates based on the tile it needs to
+ load. For example:
+
+ <ul>
+ <li><code>http://www.example.com/tiles/{z}/{x}/{y}.pbf</code> could be
+ evaluated as <code>http://www.example.com/tiles/14/6/9.pbf</code>.</li>
+ <li><code>http://www.example.com/tiles/{z}/{x}/{y}{ratio}.png</code> could be
+ evaluated as <code>http://www.example.com/tiles/14/6/9@2x.png</code>.</li>
+ </ul>
+
+ Tile sources support the following placeholder strings in tile URL templates,
+ all of which are optional:
+
+ <table>
+ <thead>
+ <tr><th>Placeholder string</th><th>Description</th></tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><code>{x}</code></td>
+ <td>The index of the tile along the map’s x axis according to Spherical
+ Mercator projection. If the value is 0, the tile’s left edge corresponds
+ to the 180th meridian west. If the value is 2<sup><var>z</var></sup>−1,
+ the tile’s right edge corresponds to the 180th meridian east.</td>
+ </tr>
+ <tr>
+ <td><code>{y}</code></td>
+ <td>The index of the tile along the map’s y axis according to Spherical
+ Mercator projection. If the value is 0, the tile’s tile edge corresponds
+ to arctan(sinh(π)), or approximately 85.0511 degrees north. If the value
+ is 2<sup><var>z</var></sup>−1, the tile’s bottom edge corresponds to
+ −arctan(sinh(π)), or approximately 85.0511 degrees south. The y axis is
+ inverted if the <code>options</code> parameter contains
+ <code>MGLTileSourceOptionTileCoordinateSystem</code> with a value of
+ <code>MGLTileCoordinateSystemTMS</code>.</td>
+ </tr>
+ <tr>
+ <td><code>{z}</code></td>
+ <td>The tile’s zoom level. At zoom level 0, each tile covers the entire
+ world map; at zoom level 1, it covers ¼ of the world; at zoom level 2,
+ <sup>1</sup>⁄<sub>16</sub> of the world, and so on. For tiles loaded by
+ a <code>MGLRasterSource</code> object, whether the tile zoom level
+ matches the map’s current zoom level depends on the value of the
+ source’s tile size as specified in the
+ <code>MGLTileSourceOptionTileSize</code> key of the
+ <code>options</code> parameter.</td>
+ </tr>
+ <tr>
+ <td><code>{bbox-epsg-3857}</code></td>
+ <td>The tile’s bounding box, expressed as a comma-separated list of the
+ tile’s western, southern, eastern, and northern extents according to
+ Spherical Mercator (EPSG:3857) projection. The bounding box is typically
+ used with map services conforming to the
+ <a href="http://www.opengeospatial.org/standards/wms">Web Map Service</a>
+ protocol.</td>
+ </tr>
+ <tr>
+ <td><code>{quadkey}</code></td>
+ <td>A quadkey indicating both the tile’s location and its zoom level. The
+ quadkey is typically used with
+ <a href="https://msdn.microsoft.com/en-us/library/bb259689.aspx">Bing Maps</a>.
+ </td>
+ </tr>
+ <tr>
+ <td><code>{ratio}</code></td>
+ <td>A suffix indicating the resolution of the tile image. The suffix is the
+ empty string for standard resolution displays and <code>@2x</code> for
+ Retina displays, including displays for which
+ <code>NSScreen.backingScaleFactor</code> or <code>UIScreen.scale</code>
+ is 3.</td>
+ </tr>
+ <tr>
+ <td><code>{prefix}</code></td>
+ <td>Two hexadecimal digits chosen such that each visible tile has a
+ different prefix. The prefix is typically used for domain sharding.</td>
+ </tr>
+ </tbody>
+ </table>
+
+ For more information about the `{x}`, `{y}`, and `{z}` placeholder strings,
+ consult the
+ <a href="https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames">OpenStreetMap Wiki</a>.
+
+ @param identifier A string that uniquely identifies the source in the style to
+ which it is added.
+ @param tileURLTemplates An array of tile URL template strings. Only the first
+ string is used; any additional strings are ignored.
+ @param options A dictionary containing configuration options. See
+ `MGLTileSourceOption` for available keys and values. Pass in `nil` to use
+ the default values.
+ @return An initialized tile source.
+ */
- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates options:(nullable NS_DICTIONARY_OF(MGLTileSourceOption, id) *)options NS_DESIGNATED_INITIALIZER;
#pragma mark Accessing a Source’s Content
diff --git a/platform/darwin/src/MGLVectorSource.mm b/platform/darwin/src/MGLVectorSource.mm
index aeec2e40ac..5e9f4f4a6e 100644
--- a/platform/darwin/src/MGLVectorSource.mm
+++ b/platform/darwin/src/MGLVectorSource.mm
@@ -1,9 +1,9 @@
#import "MGLVectorSource_Private.h"
-#import "MGLMapView_Private.h"
#import "MGLFeature_Private.h"
#import "MGLSource_Private.h"
#import "MGLTileSource_Private.h"
+#import "MGLMapView_Private.h"
#import "NSPredicate+MGLAdditions.h"
#import "NSURL+MGLAdditions.h"
@@ -12,77 +12,28 @@
@interface MGLVectorSource ()
-- (instancetype)initWithRawSource:(mbgl::style::VectorSource *)rawSource NS_DESIGNATED_INITIALIZER;
-
-@property (nonatomic) mbgl::style::VectorSource *rawSource;
+@property (nonatomic, readonly) mbgl::style::VectorSource *rawSource;
@end
-@implementation MGLVectorSource {
- std::unique_ptr<mbgl::style::VectorSource> _pendingSource;
-}
+@implementation MGLVectorSource
- (instancetype)initWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL {
- if (self = [super initWithIdentifier:identifier configurationURL:configurationURL]) {
- auto source = std::make_unique<mbgl::style::VectorSource>(identifier.UTF8String,
- configurationURL.mgl_URLByStandardizingScheme.absoluteString.UTF8String);
- _pendingSource = std::move(source);
- self.rawSource = _pendingSource.get();
- }
- return self;
+ auto source = std::make_unique<mbgl::style::VectorSource>(identifier.UTF8String,
+ configurationURL.mgl_URLByStandardizingScheme.absoluteString.UTF8String);
+ return self = [super initWithPendingSource:std::move(source)];
}
- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates options:(nullable NS_DICTIONARY_OF(MGLTileSourceOption, id) *)options {
- if (self = [super initWithIdentifier:identifier tileURLTemplates:tileURLTemplates options:options]) {
- mbgl::Tileset tileSet = MGLTileSetFromTileURLTemplates(tileURLTemplates, options);
-
- auto source = std::make_unique<mbgl::style::VectorSource>(identifier.UTF8String, tileSet);
- _pendingSource = std::move(source);
- self.rawSource = _pendingSource.get();
- }
- return self;
-}
-
-- (instancetype)initWithRawSource:(mbgl::style::VectorSource *)rawSource {
- return [super initWithRawSource:rawSource];
-}
-
-- (void)addToMapView:(MGLMapView *)mapView {
- if (_pendingSource == nullptr) {
- [NSException raise:@"MGLRedundantSourceException"
- format:@"This instance %@ was already added to %@. Adding the same source instance " \
- "to the style more than once is invalid.", self, mapView.style];
- }
-
- mapView.mbglMap->addSource(std::move(_pendingSource));
-}
-
-- (void)removeFromMapView:(MGLMapView *)mapView {
- if (self.rawSource != mapView.mbglMap->getSource(self.identifier.UTF8String)) {
- return;
- }
-
- auto removedSource = mapView.mbglMap->removeSource(self.identifier.UTF8String);
-
- mbgl::style::VectorSource *source = dynamic_cast<mbgl::style::VectorSource *>(removedSource.get());
- if (!source) {
- return;
- }
-
- removedSource.release();
-
- _pendingSource = std::unique_ptr<mbgl::style::VectorSource>(source);
- self.rawSource = _pendingSource.get();
+ mbgl::Tileset tileSet = MGLTileSetFromTileURLTemplates(tileURLTemplates, options);
+ auto source = std::make_unique<mbgl::style::VectorSource>(identifier.UTF8String, tileSet);
+ return self = [super initWithPendingSource:std::move(source)];
}
- (mbgl::style::VectorSource *)rawSource {
return (mbgl::style::VectorSource *)super.rawSource;
}
-- (void)setRawSource:(mbgl::style::VectorSource *)rawSource {
- super.rawSource = rawSource;
-}
-
- (NSURL *)configurationURL {
auto url = self.rawSource->getURL();
return url ? [NSURL URLWithString:@(url->c_str())] : nil;
@@ -110,7 +61,10 @@
optionalFilter = predicate.mgl_filter;
}
- std::vector<mbgl::Feature> features = self.rawSource->querySourceFeatures({ optionalSourceLayerIDs, optionalFilter });
+ std::vector<mbgl::Feature> features;
+ if (self.mapView) {
+ features = self.mapView.mbglMap->querySourceFeatures(self.rawSource->getID(), { optionalSourceLayerIDs, optionalFilter });
+ }
return MGLFeaturesFromMBGLFeatures(features);
}
diff --git a/platform/darwin/src/MGLVectorSource_Private.h b/platform/darwin/src/MGLVectorSource_Private.h
index 12fcd82012..335743173e 100644
--- a/platform/darwin/src/MGLVectorSource_Private.h
+++ b/platform/darwin/src/MGLVectorSource_Private.h
@@ -2,16 +2,7 @@
NS_ASSUME_NONNULL_BEGIN
-namespace mbgl {
- namespace style {
- class VectorSource;
- }
-}
-
@interface MGLVectorSource (Private)
-
-- (instancetype)initWithRawSource:(mbgl::style::VectorSource *)rawSource;
-
@end
NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/headless_backend_cgl.cpp b/platform/darwin/src/headless_backend_cgl.cpp
index 7069738fb1..6ad98f4326 100644
--- a/platform/darwin/src/headless_backend_cgl.cpp
+++ b/platform/darwin/src/headless_backend_cgl.cpp
@@ -36,7 +36,7 @@ struct CGLImpl : public HeadlessBackend::Impl {
CGLContextObj glContext = nullptr;
};
-gl::glProc HeadlessBackend::initializeExtension(const char* name) {
+gl::ProcAddress HeadlessBackend::initializeExtension(const char* name) {
static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
if (!framework) {
throw std::runtime_error("Failed to load OpenGL framework.");
@@ -46,7 +46,7 @@ gl::glProc HeadlessBackend::initializeExtension(const char* name) {
void* symbol = CFBundleGetFunctionPointerForName(framework, str);
CFRelease(str);
- return reinterpret_cast<gl::glProc>(symbol);
+ return reinterpret_cast<gl::ProcAddress>(symbol);
}
bool HeadlessBackend::hasDisplay() {
diff --git a/platform/darwin/src/headless_backend_eagl.mm b/platform/darwin/src/headless_backend_eagl.mm
index bd4a202ec5..1daaeaf54c 100644
--- a/platform/darwin/src/headless_backend_eagl.mm
+++ b/platform/darwin/src/headless_backend_eagl.mm
@@ -1,7 +1,5 @@
#include <mbgl/gl/headless_backend.hpp>
-#include <mbgl/gl/extension.hpp>
-
#include <OpenGLES/EAGL.h>
#include <stdexcept>
@@ -29,7 +27,7 @@ struct EAGLImpl : public HeadlessBackend::Impl {
EAGLContext* glContext = nullptr;
};
-gl::glProc HeadlessBackend::initializeExtension(const char* name) {
+gl::ProcAddress HeadlessBackend::initializeExtension(const char* name) {
static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengles"));
if (!framework) {
throw std::runtime_error("Failed to load OpenGL framework.");
@@ -39,7 +37,7 @@ gl::glProc HeadlessBackend::initializeExtension(const char* name) {
void* symbol = CFBundleGetFunctionPointerForName(framework, str);
CFRelease(str);
- return reinterpret_cast<gl::glProc>(symbol);
+ return reinterpret_cast<gl::ProcAddress>(symbol);
}
bool HeadlessBackend::hasDisplay() {
diff --git a/platform/darwin/test/MGLAttributionInfoTests.m b/platform/darwin/test/MGLAttributionInfoTests.m
index 74859bda82..e258671c09 100644
--- a/platform/darwin/test/MGLAttributionInfoTests.m
+++ b/platform/darwin/test/MGLAttributionInfoTests.m
@@ -68,7 +68,7 @@
XCTAssertEqual(infos.count, 1);
XCTAssertEqualObjects(infos[0].title.string, @"Mapbox");
- XCTAssertEqualObjects([infos[0].title attribute:NSLinkAttributeName atIndex:0 effectiveRange:nil], [NSURL URLWithString:@"https://www.mapbox.com/"]);
+ XCTAssertNil([infos[0].title attribute:NSLinkAttributeName atIndex:0 effectiveRange:nil]);
XCTAssertEqualObjects([infos[0].title attribute:NSUnderlineStyleAttributeName atIndex:0 effectiveRange:nil], @(NSUnderlineStyleSingle));
#if TARGET_OS_IPHONE
diff --git a/platform/darwin/test/MGLDocumentationExampleTests.swift b/platform/darwin/test/MGLDocumentationExampleTests.swift
index 177d97d523..6d2dc597a9 100644
--- a/platform/darwin/test/MGLDocumentationExampleTests.swift
+++ b/platform/darwin/test/MGLDocumentationExampleTests.swift
@@ -158,6 +158,22 @@ class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate {
XCTAssertNotNil(mapView.style?.layer(withIdentifier: "parks"))
}
+
+ func testMGLFillExtrusionStyleLayer() {
+ let buildings = MGLVectorSource(identifier: "buildings", configurationURL: URL(string: "https://example.com/style.json")!)
+ mapView.style?.addSource(buildings)
+
+ //#-example-code
+ let layer = MGLFillExtrusionStyleLayer(identifier: "buildings", source: buildings)
+ layer.sourceLayerIdentifier = "building"
+ layer.fillExtrusionHeight = MGLStyleValue(interpolationMode: .identity, sourceStops: nil, attributeName: "height", options: nil)
+ layer.fillExtrusionBase = MGLStyleValue(interpolationMode: .identity, sourceStops: nil, attributeName: "min_height", options: nil)
+ layer.predicate = NSPredicate(format: "extrude == TRUE")
+ mapView.style?.addLayer(layer)
+ //#-end-example-code
+
+ XCTAssertNotNil(mapView.style?.layer(withIdentifier: "buildings"))
+ }
func testMGLSymbolStyleLayer() {
let pois = MGLVectorSource(identifier: "pois", configurationURL: URL(string: "https://example.com/style.json")!)
diff --git a/platform/darwin/test/MGLDocumentationGuideTests.swift b/platform/darwin/test/MGLDocumentationGuideTests.swift
new file mode 100644
index 0000000000..c71f1b46c7
--- /dev/null
+++ b/platform/darwin/test/MGLDocumentationGuideTests.swift
@@ -0,0 +1,214 @@
+import Foundation
+import Mapbox
+#if os(iOS)
+ import UIKit
+#else
+ import Cocoa
+#endif
+
+/**
+ Test cases that ensure the inline examples in the jazzy guides compile.
+
+ To add an example:
+ 1. Add a test case named in the form `testGuideName$ExampleName`.
+ 2. Wrap the code you’d like to appear in the documentation within the
+ following comment blocks:
+ ```
+ //#-example-code
+ ...
+ //#-end-example-code
+ ```
+ 3. Insert a call to `guideExample()` where you’d like the example code to be
+ inserted in the guide’s Markdown.
+ ```
+ <%- guideExample('GuideName', 'ExampleName', 'iOS') %>
+ ```
+ 4. Run `make darwin-style-code` to extract example code from the test method
+ below and insert it into the guide.
+ */
+class MGLDocumentationGuideTests: XCTestCase, MGLMapViewDelegate {
+ var mapView: MGLMapView!
+ var styleLoadingExpectation: XCTestExpectation!
+
+ override func setUp() {
+ super.setUp()
+ let styleURL = Bundle(for: MGLDocumentationGuideTests.self).url(forResource: "one-liner", withExtension: "json")
+ mapView = MGLMapView(frame: CGRect(x: 0, y: 0, width: 256, height: 256), styleURL: styleURL)
+ mapView.delegate = self
+ styleLoadingExpectation = expectation(description: "Map view should finish loading style")
+ waitForExpectations(timeout: 1, handler: nil)
+ }
+
+ override func tearDown() {
+ mapView = nil
+ styleLoadingExpectation = nil
+ super.tearDown()
+ }
+
+ func mapView(_ mapView: MGLMapView, didFinishLoading style: MGLStyle) {
+ styleLoadingExpectation.fulfill()
+ }
+
+ func testUsingStyleFunctionsAtRuntime$Stops() {
+ //#-example-code
+ #if os(macOS)
+ let stops = [
+ 0: MGLStyleValue<NSColor>(rawValue: .yellow),
+ 2.5: MGLStyleValue(rawValue: .orange),
+ 5: MGLStyleValue(rawValue: .red),
+ 7.5: MGLStyleValue(rawValue: .blue),
+ 10: MGLStyleValue(rawValue: .white),
+ ]
+ #else
+ let stops = [
+ 0: MGLStyleValue<UIColor>(rawValue: .yellow),
+ 2.5: MGLStyleValue(rawValue: .orange),
+ 5: MGLStyleValue(rawValue: .red),
+ 7.5: MGLStyleValue(rawValue: .blue),
+ 10: MGLStyleValue(rawValue: .white),
+ ]
+ #endif
+ //#-end-example-code
+
+ let _ = MGLStyleValue(interpolationMode: .exponential, cameraStops: stops, options: nil)
+ }
+
+ func testUsingStyleFunctionsAtRuntime$Linear() {
+ //#-example-code
+ let url = URL(string: "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_week.geojson")!
+ let symbolSource = MGLSource(identifier: "source")
+ let symbolLayer = MGLSymbolStyleLayer(identifier: "place-city-sm", source: symbolSource)
+
+ let source = MGLShapeSource(identifier: "earthquakes", url: url, options: nil)
+ mapView.style?.addSource(source)
+
+ #if os(macOS)
+ let stops = [
+ 0: MGLStyleValue<NSColor>(rawValue: .yellow),
+ 2.5: MGLStyleValue(rawValue: .orange),
+ 5: MGLStyleValue(rawValue: .red),
+ 7.5: MGLStyleValue(rawValue: .blue),
+ 10: MGLStyleValue(rawValue: .white),
+ ]
+ #else
+ let stops = [
+ 0: MGLStyleValue<UIColor>(rawValue: .yellow),
+ 2.5: MGLStyleValue(rawValue: .orange),
+ 5: MGLStyleValue(rawValue: .red),
+ 7.5: MGLStyleValue(rawValue: .blue),
+ 10: MGLStyleValue(rawValue: .white),
+ ]
+ #endif
+
+ let layer = MGLCircleStyleLayer(identifier: "circles", source: source)
+ #if os(macOS)
+ layer.circleColor = MGLStyleValue(interpolationMode: .exponential,
+ sourceStops: stops,
+ attributeName: "mag",
+ options: [.defaultValue: MGLStyleValue<NSColor>(rawValue: .green)])
+ #else
+ layer.circleColor = MGLStyleValue(interpolationMode: .exponential,
+ sourceStops: stops,
+ attributeName: "mag",
+ options: [.defaultValue: MGLStyleValue<UIColor>(rawValue: .green)])
+ #endif
+ layer.circleRadius = MGLStyleValue(rawValue: 10)
+ mapView.style?.insertLayer(layer, below: symbolLayer)
+ //#-end-example-code
+ }
+
+ func testUsingStyleFunctionsAtRuntime$Exponential() {
+ let source = MGLShapeSource(identifier: "circles", shape: nil, options: nil)
+ let layer = MGLCircleStyleLayer(identifier: "circles", source: source)
+
+ //#-example-code
+ let stops = [
+ 12: MGLStyleValue<NSNumber>(rawValue: 0.5),
+ 14: MGLStyleValue(rawValue: 2),
+ 18: MGLStyleValue(rawValue: 18),
+ ]
+
+ layer.circleRadius = MGLStyleValue(interpolationMode: .exponential,
+ cameraStops: stops,
+ options: [.interpolationBase: 1.5])
+ //#-end-example-code
+ }
+
+ func testUsingStyleFunctionsAtRuntime$Interval() {
+ let source = MGLShapeSource(identifier: "circles", shape: nil, options: nil)
+ let layer = MGLCircleStyleLayer(identifier: "circles", source: source)
+
+ //#-example-code
+ #if os(macOS)
+ let stops = [
+ 0: MGLStyleValue<NSColor>(rawValue: .yellow),
+ 2.5: MGLStyleValue(rawValue: .orange),
+ 5: MGLStyleValue(rawValue: .red),
+ 7.5: MGLStyleValue(rawValue: .blue),
+ 10: MGLStyleValue(rawValue: .white),
+ ]
+
+ layer.circleColor = MGLStyleValue(interpolationMode: .interval,
+ sourceStops: stops,
+ attributeName: "mag",
+ options: [.defaultValue: MGLStyleValue<NSColor>(rawValue: .green)])
+ #else
+ let stops = [
+ 0: MGLStyleValue<UIColor>(rawValue: .yellow),
+ 2.5: MGLStyleValue(rawValue: .orange),
+ 5: MGLStyleValue(rawValue: .red),
+ 7.5: MGLStyleValue(rawValue: .blue),
+ 10: MGLStyleValue(rawValue: .white),
+ ]
+
+ layer.circleColor = MGLStyleValue(interpolationMode: .interval,
+ sourceStops: stops,
+ attributeName: "mag",
+ options: [.defaultValue: MGLStyleValue<UIColor>(rawValue: .green)])
+ #endif
+ //#-end-example-code
+ }
+
+ func testUsingStyleFunctionsAtRuntime$Categorical() {
+ let source = MGLShapeSource(identifier: "circles", shape: nil, options: nil)
+ let layer = MGLCircleStyleLayer(identifier: "circles", source: source)
+
+ //#-example-code
+ #if os(macOS)
+ let categoricalStops = [
+ "earthquake": MGLStyleValue<NSColor>(rawValue: .orange),
+ "explosion": MGLStyleValue(rawValue: .red),
+ "quarry blast": MGLStyleValue(rawValue: .yellow),
+ ]
+
+ layer.circleColor = MGLStyleValue(interpolationMode: .categorical,
+ sourceStops: categoricalStops,
+ attributeName: "type",
+ options: [.defaultValue: MGLStyleValue<NSColor>(rawValue: .blue)])
+ #else
+ let categoricalStops = [
+ "earthquake": MGLStyleValue<UIColor>(rawValue: .orange),
+ "explosion": MGLStyleValue(rawValue: .red),
+ "quarry blast": MGLStyleValue(rawValue: .yellow),
+ ]
+
+ layer.circleColor = MGLStyleValue(interpolationMode: .categorical,
+ sourceStops: categoricalStops,
+ attributeName: "type",
+ options: [.defaultValue: MGLStyleValue<UIColor>(rawValue: .blue)])
+ #endif
+ //#-end-example-code
+ }
+
+ func testUsingStyleFunctionsAtRuntime$Identity() {
+ let source = MGLShapeSource(identifier: "circles", shape: nil, options: nil)
+ let layer = MGLCircleStyleLayer(identifier: "circles", source: source)
+
+ //#-example-code
+ layer.circleRadius = MGLStyleValue(interpolationMode: .identity,
+ sourceStops: nil,
+ attributeName: "mag",
+ options: [.defaultValue: MGLStyleValue<NSNumber>(rawValue: 0)])
+ //#-end-example-code
+ }
+}
diff --git a/platform/darwin/test/MGLFillExtrusionStyleLayerTests.mm b/platform/darwin/test/MGLFillExtrusionStyleLayerTests.mm
new file mode 100644
index 0000000000..5d99c815ea
--- /dev/null
+++ b/platform/darwin/test/MGLFillExtrusionStyleLayerTests.mm
@@ -0,0 +1,445 @@
+// This file is generated.
+// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
+
+#import "MGLStyleLayerTests.h"
+#import "../../darwin/src/NSDate+MGLAdditions.h"
+
+#import "MGLStyleLayer_Private.h"
+
+#include <mbgl/style/layers/fill_extrusion_layer.hpp>
+#include <mbgl/style/transition_options.hpp>
+
+@interface MGLFillExtrusionLayerTests : MGLStyleLayerTests
+@end
+
+@implementation MGLFillExtrusionLayerTests
+
++ (NSString *)layerType {
+ return @"fill-extrusion";
+}
+
+- (void)testPredicates {
+ MGLPointFeature *feature = [[MGLPointFeature alloc] init];
+ MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
+ MGLFillExtrusionStyleLayer *layer = [[MGLFillExtrusionStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
+
+ XCTAssertNil(layer.sourceLayerIdentifier);
+ layer.sourceLayerIdentifier = @"layerID";
+ XCTAssertEqualObjects(layer.sourceLayerIdentifier, @"layerID");
+ layer.sourceLayerIdentifier = nil;
+ XCTAssertNil(layer.sourceLayerIdentifier);
+
+ XCTAssertNil(layer.predicate);
+ layer.predicate = [NSPredicate predicateWithValue:NO];
+ XCTAssertEqualObjects(layer.predicate, [NSPredicate predicateWithValue:NO]);
+ layer.predicate = nil;
+ XCTAssertNil(layer.predicate);
+}
+
+- (void)testProperties {
+ MGLPointFeature *feature = [[MGLPointFeature alloc] init];
+ MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
+
+ MGLFillExtrusionStyleLayer *layer = [[MGLFillExtrusionStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
+ XCTAssertNotEqual(layer.rawLayer, nullptr);
+ XCTAssertTrue(layer.rawLayer->is<mbgl::style::FillExtrusionLayer>());
+ auto rawLayer = layer.rawLayer->as<mbgl::style::FillExtrusionLayer>();
+
+ MGLTransition transitionTest = MGLTransitionMake(5, 4);
+
+
+ // fill-extrusion-base
+ {
+ XCTAssertTrue(rawLayer->getFillExtrusionBase().isUndefined(),
+ @"fill-extrusion-base should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.fillExtrusionBase;
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.fillExtrusionBase = constantStyleValue;
+ mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getFillExtrusionBase(), propertyValue,
+ @"Setting fillExtrusionBase to a constant value should update fill-extrusion-base.");
+ XCTAssertEqualObjects(layer.fillExtrusionBase, constantStyleValue,
+ @"fillExtrusionBase should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.fillExtrusionBase = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
+
+ XCTAssertEqual(rawLayer->getFillExtrusionBase(), propertyValue,
+ @"Setting fillExtrusionBase to a camera function should update fill-extrusion-base.");
+ XCTAssertEqualObjects(layer.fillExtrusionBase, functionStyleValue,
+ @"fillExtrusionBase should round-trip camera functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.fillExtrusionBase = functionStyleValue;
+
+ mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getFillExtrusionBase(), propertyValue,
+ @"Setting fillExtrusionBase to a source function should update fill-extrusion-base.");
+ XCTAssertEqualObjects(layer.fillExtrusionBase, functionStyleValue,
+ @"fillExtrusionBase should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.fillExtrusionBase = functionStyleValue;
+
+ std::map<float, float> innerStops { {18, 0xff} };
+ mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getFillExtrusionBase(), propertyValue,
+ @"Setting fillExtrusionBase to a composite function should update fill-extrusion-base.");
+ XCTAssertEqualObjects(layer.fillExtrusionBase, functionStyleValue,
+ @"fillExtrusionBase should round-trip composite functions.");
+
+
+ layer.fillExtrusionBase = nil;
+ XCTAssertTrue(rawLayer->getFillExtrusionBase().isUndefined(),
+ @"Unsetting fillExtrusionBase should return fill-extrusion-base to the default value.");
+ XCTAssertEqualObjects(layer.fillExtrusionBase, defaultStyleValue,
+ @"fillExtrusionBase should return the default value after being unset.");
+ // Transition property test
+ layer.fillExtrusionBaseTransition = transitionTest;
+ auto toptions = rawLayer->getFillExtrusionBaseTransition();
+ XCTAssert(toptions.delay && MGLTimeIntervalFromDuration(*toptions.delay) == transitionTest.delay);
+ XCTAssert(toptions.duration && MGLTimeIntervalFromDuration(*toptions.duration) == transitionTest.duration);
+
+ MGLTransition fillExtrusionBaseTransition = layer.fillExtrusionBaseTransition;
+ XCTAssertEqual(fillExtrusionBaseTransition.delay, transitionTest.delay);
+ XCTAssertEqual(fillExtrusionBaseTransition.duration, transitionTest.duration);
+ }
+
+ // fill-extrusion-color
+ {
+ XCTAssertTrue(rawLayer->getFillExtrusionColor().isUndefined(),
+ @"fill-extrusion-color should be unset initially.");
+ MGLStyleValue<MGLColor *> *defaultStyleValue = layer.fillExtrusionColor;
+
+ MGLStyleValue<MGLColor *> *constantStyleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
+ layer.fillExtrusionColor = constantStyleValue;
+ mbgl::style::DataDrivenPropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
+ XCTAssertEqual(rawLayer->getFillExtrusionColor(), propertyValue,
+ @"Setting fillExtrusionColor to a constant value should update fill-extrusion-color.");
+ XCTAssertEqualObjects(layer.fillExtrusionColor, constantStyleValue,
+ @"fillExtrusionColor should round-trip constant values.");
+
+ MGLStyleValue<MGLColor *> * functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.fillExtrusionColor = functionStyleValue;
+
+ mbgl::style::IntervalStops<mbgl::Color> intervalStops = { {{18, { 1, 0, 0, 1 }}} };
+ propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
+
+ XCTAssertEqual(rawLayer->getFillExtrusionColor(), propertyValue,
+ @"Setting fillExtrusionColor to a camera function should update fill-extrusion-color.");
+ XCTAssertEqualObjects(layer.fillExtrusionColor, functionStyleValue,
+ @"fillExtrusionColor should round-trip camera functions.");
+
+ functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.fillExtrusionColor = functionStyleValue;
+
+ mbgl::style::ExponentialStops<mbgl::Color> exponentialStops = { {{18, { 1, 0, 0, 1 }}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<mbgl::Color> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getFillExtrusionColor(), propertyValue,
+ @"Setting fillExtrusionColor to a source function should update fill-extrusion-color.");
+ XCTAssertEqualObjects(layer.fillExtrusionColor, functionStyleValue,
+ @"fillExtrusionColor should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.fillExtrusionColor = functionStyleValue;
+
+ std::map<float, mbgl::Color> innerStops { {18, { 1, 0, 0, 1 }} };
+ mbgl::style::CompositeExponentialStops<mbgl::Color> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<mbgl::Color> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getFillExtrusionColor(), propertyValue,
+ @"Setting fillExtrusionColor to a composite function should update fill-extrusion-color.");
+ XCTAssertEqualObjects(layer.fillExtrusionColor, functionStyleValue,
+ @"fillExtrusionColor should round-trip composite functions.");
+
+
+ layer.fillExtrusionColor = nil;
+ XCTAssertTrue(rawLayer->getFillExtrusionColor().isUndefined(),
+ @"Unsetting fillExtrusionColor should return fill-extrusion-color to the default value.");
+ XCTAssertEqualObjects(layer.fillExtrusionColor, defaultStyleValue,
+ @"fillExtrusionColor should return the default value after being unset.");
+ // Transition property test
+ layer.fillExtrusionColorTransition = transitionTest;
+ auto toptions = rawLayer->getFillExtrusionColorTransition();
+ XCTAssert(toptions.delay && MGLTimeIntervalFromDuration(*toptions.delay) == transitionTest.delay);
+ XCTAssert(toptions.duration && MGLTimeIntervalFromDuration(*toptions.duration) == transitionTest.duration);
+
+ MGLTransition fillExtrusionColorTransition = layer.fillExtrusionColorTransition;
+ XCTAssertEqual(fillExtrusionColorTransition.delay, transitionTest.delay);
+ XCTAssertEqual(fillExtrusionColorTransition.duration, transitionTest.duration);
+ }
+
+ // fill-extrusion-height
+ {
+ XCTAssertTrue(rawLayer->getFillExtrusionHeight().isUndefined(),
+ @"fill-extrusion-height should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.fillExtrusionHeight;
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.fillExtrusionHeight = constantStyleValue;
+ mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getFillExtrusionHeight(), propertyValue,
+ @"Setting fillExtrusionHeight to a constant value should update fill-extrusion-height.");
+ XCTAssertEqualObjects(layer.fillExtrusionHeight, constantStyleValue,
+ @"fillExtrusionHeight should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.fillExtrusionHeight = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
+
+ XCTAssertEqual(rawLayer->getFillExtrusionHeight(), propertyValue,
+ @"Setting fillExtrusionHeight to a camera function should update fill-extrusion-height.");
+ XCTAssertEqualObjects(layer.fillExtrusionHeight, functionStyleValue,
+ @"fillExtrusionHeight should round-trip camera functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.fillExtrusionHeight = functionStyleValue;
+
+ mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getFillExtrusionHeight(), propertyValue,
+ @"Setting fillExtrusionHeight to a source function should update fill-extrusion-height.");
+ XCTAssertEqualObjects(layer.fillExtrusionHeight, functionStyleValue,
+ @"fillExtrusionHeight should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.fillExtrusionHeight = functionStyleValue;
+
+ std::map<float, float> innerStops { {18, 0xff} };
+ mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getFillExtrusionHeight(), propertyValue,
+ @"Setting fillExtrusionHeight to a composite function should update fill-extrusion-height.");
+ XCTAssertEqualObjects(layer.fillExtrusionHeight, functionStyleValue,
+ @"fillExtrusionHeight should round-trip composite functions.");
+
+
+ layer.fillExtrusionHeight = nil;
+ XCTAssertTrue(rawLayer->getFillExtrusionHeight().isUndefined(),
+ @"Unsetting fillExtrusionHeight should return fill-extrusion-height to the default value.");
+ XCTAssertEqualObjects(layer.fillExtrusionHeight, defaultStyleValue,
+ @"fillExtrusionHeight should return the default value after being unset.");
+ // Transition property test
+ layer.fillExtrusionHeightTransition = transitionTest;
+ auto toptions = rawLayer->getFillExtrusionHeightTransition();
+ XCTAssert(toptions.delay && MGLTimeIntervalFromDuration(*toptions.delay) == transitionTest.delay);
+ XCTAssert(toptions.duration && MGLTimeIntervalFromDuration(*toptions.duration) == transitionTest.duration);
+
+ MGLTransition fillExtrusionHeightTransition = layer.fillExtrusionHeightTransition;
+ XCTAssertEqual(fillExtrusionHeightTransition.delay, transitionTest.delay);
+ XCTAssertEqual(fillExtrusionHeightTransition.duration, transitionTest.duration);
+ }
+
+ // fill-extrusion-opacity
+ {
+ XCTAssertTrue(rawLayer->getFillExtrusionOpacity().isUndefined(),
+ @"fill-extrusion-opacity should be unset initially.");
+ MGLStyleValue<NSNumber *> *defaultStyleValue = layer.fillExtrusionOpacity;
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.fillExtrusionOpacity = constantStyleValue;
+ mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ XCTAssertEqual(rawLayer->getFillExtrusionOpacity(), propertyValue,
+ @"Setting fillExtrusionOpacity to a constant value should update fill-extrusion-opacity.");
+ XCTAssertEqualObjects(layer.fillExtrusionOpacity, constantStyleValue,
+ @"fillExtrusionOpacity should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.fillExtrusionOpacity = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
+
+ XCTAssertEqual(rawLayer->getFillExtrusionOpacity(), propertyValue,
+ @"Setting fillExtrusionOpacity to a camera function should update fill-extrusion-opacity.");
+ XCTAssertEqualObjects(layer.fillExtrusionOpacity, functionStyleValue,
+ @"fillExtrusionOpacity should round-trip camera functions.");
+
+
+
+ layer.fillExtrusionOpacity = nil;
+ XCTAssertTrue(rawLayer->getFillExtrusionOpacity().isUndefined(),
+ @"Unsetting fillExtrusionOpacity should return fill-extrusion-opacity to the default value.");
+ XCTAssertEqualObjects(layer.fillExtrusionOpacity, defaultStyleValue,
+ @"fillExtrusionOpacity should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.fillExtrusionOpacity = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.fillExtrusionOpacity = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ // Transition property test
+ layer.fillExtrusionOpacityTransition = transitionTest;
+ auto toptions = rawLayer->getFillExtrusionOpacityTransition();
+ XCTAssert(toptions.delay && MGLTimeIntervalFromDuration(*toptions.delay) == transitionTest.delay);
+ XCTAssert(toptions.duration && MGLTimeIntervalFromDuration(*toptions.duration) == transitionTest.duration);
+
+ MGLTransition fillExtrusionOpacityTransition = layer.fillExtrusionOpacityTransition;
+ XCTAssertEqual(fillExtrusionOpacityTransition.delay, transitionTest.delay);
+ XCTAssertEqual(fillExtrusionOpacityTransition.duration, transitionTest.duration);
+ }
+
+ // fill-extrusion-pattern
+ {
+ XCTAssertTrue(rawLayer->getFillExtrusionPattern().isUndefined(),
+ @"fill-extrusion-pattern should be unset initially.");
+ MGLStyleValue<NSString *> *defaultStyleValue = layer.fillExtrusionPattern;
+
+ MGLStyleValue<NSString *> *constantStyleValue = [MGLStyleValue<NSString *> valueWithRawValue:@"Fill Extrusion Pattern"];
+ layer.fillExtrusionPattern = constantStyleValue;
+ mbgl::style::PropertyValue<std::string> propertyValue = { "Fill Extrusion Pattern" };
+ XCTAssertEqual(rawLayer->getFillExtrusionPattern(), propertyValue,
+ @"Setting fillExtrusionPattern to a constant value should update fill-extrusion-pattern.");
+ XCTAssertEqualObjects(layer.fillExtrusionPattern, constantStyleValue,
+ @"fillExtrusionPattern should round-trip constant values.");
+
+ MGLStyleValue<NSString *> * functionStyleValue = [MGLStyleValue<NSString *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.fillExtrusionPattern = functionStyleValue;
+
+ mbgl::style::IntervalStops<std::string> intervalStops = { {{18, "Fill Extrusion Pattern"}} };
+ propertyValue = mbgl::style::CameraFunction<std::string> { intervalStops };
+
+ XCTAssertEqual(rawLayer->getFillExtrusionPattern(), propertyValue,
+ @"Setting fillExtrusionPattern to a camera function should update fill-extrusion-pattern.");
+ XCTAssertEqualObjects(layer.fillExtrusionPattern, functionStyleValue,
+ @"fillExtrusionPattern should round-trip camera functions.");
+
+
+
+ layer.fillExtrusionPattern = nil;
+ XCTAssertTrue(rawLayer->getFillExtrusionPattern().isUndefined(),
+ @"Unsetting fillExtrusionPattern should return fill-extrusion-pattern to the default value.");
+ XCTAssertEqualObjects(layer.fillExtrusionPattern, defaultStyleValue,
+ @"fillExtrusionPattern should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSString *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.fillExtrusionPattern = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSString *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.fillExtrusionPattern = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ // Transition property test
+ layer.fillExtrusionPatternTransition = transitionTest;
+ auto toptions = rawLayer->getFillExtrusionPatternTransition();
+ XCTAssert(toptions.delay && MGLTimeIntervalFromDuration(*toptions.delay) == transitionTest.delay);
+ XCTAssert(toptions.duration && MGLTimeIntervalFromDuration(*toptions.duration) == transitionTest.duration);
+
+ MGLTransition fillExtrusionPatternTransition = layer.fillExtrusionPatternTransition;
+ XCTAssertEqual(fillExtrusionPatternTransition.delay, transitionTest.delay);
+ XCTAssertEqual(fillExtrusionPatternTransition.duration, transitionTest.duration);
+ }
+
+ // fill-extrusion-translate
+ {
+ XCTAssertTrue(rawLayer->getFillExtrusionTranslate().isUndefined(),
+ @"fill-extrusion-translate should be unset initially.");
+ MGLStyleValue<NSValue *> *defaultStyleValue = layer.fillExtrusionTranslation;
+
+ MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:
+#if TARGET_OS_IPHONE
+ [NSValue valueWithCGVector:CGVectorMake(1, 1)]
+#else
+ [NSValue valueWithMGLVector:CGVectorMake(1, -1)]
+#endif
+ ];
+ layer.fillExtrusionTranslation = constantStyleValue;
+ mbgl::style::PropertyValue<std::array<float, 2>> propertyValue = { { 1, 1 } };
+ XCTAssertEqual(rawLayer->getFillExtrusionTranslate(), propertyValue,
+ @"Setting fillExtrusionTranslation to a constant value should update fill-extrusion-translate.");
+ XCTAssertEqualObjects(layer.fillExtrusionTranslation, constantStyleValue,
+ @"fillExtrusionTranslation should round-trip constant values.");
+
+ MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.fillExtrusionTranslation = functionStyleValue;
+
+ mbgl::style::IntervalStops<std::array<float, 2>> intervalStops = { {{18, { 1, 1 }}} };
+ propertyValue = mbgl::style::CameraFunction<std::array<float, 2>> { intervalStops };
+
+ XCTAssertEqual(rawLayer->getFillExtrusionTranslate(), propertyValue,
+ @"Setting fillExtrusionTranslation to a camera function should update fill-extrusion-translate.");
+ XCTAssertEqualObjects(layer.fillExtrusionTranslation, functionStyleValue,
+ @"fillExtrusionTranslation should round-trip camera functions.");
+
+
+
+ layer.fillExtrusionTranslation = nil;
+ XCTAssertTrue(rawLayer->getFillExtrusionTranslate().isUndefined(),
+ @"Unsetting fillExtrusionTranslation should return fill-extrusion-translate to the default value.");
+ XCTAssertEqualObjects(layer.fillExtrusionTranslation, defaultStyleValue,
+ @"fillExtrusionTranslation should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.fillExtrusionTranslation = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.fillExtrusionTranslation = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ }
+
+ // fill-extrusion-translate-anchor
+ {
+ XCTAssertTrue(rawLayer->getFillExtrusionTranslateAnchor().isUndefined(),
+ @"fill-extrusion-translate-anchor should be unset initially.");
+ MGLStyleValue<NSValue *> *defaultStyleValue = layer.fillExtrusionTranslationAnchor;
+
+ MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLFillExtrusionTranslationAnchor:MGLFillExtrusionTranslationAnchorViewport]];
+ layer.fillExtrusionTranslationAnchor = constantStyleValue;
+ mbgl::style::PropertyValue<mbgl::style::TranslateAnchorType> propertyValue = { mbgl::style::TranslateAnchorType::Viewport };
+ XCTAssertEqual(rawLayer->getFillExtrusionTranslateAnchor(), propertyValue,
+ @"Setting fillExtrusionTranslationAnchor to a constant value should update fill-extrusion-translate-anchor.");
+ XCTAssertEqualObjects(layer.fillExtrusionTranslationAnchor, constantStyleValue,
+ @"fillExtrusionTranslationAnchor should round-trip constant values.");
+
+ MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.fillExtrusionTranslationAnchor = functionStyleValue;
+
+ mbgl::style::IntervalStops<mbgl::style::TranslateAnchorType> intervalStops = { {{18, mbgl::style::TranslateAnchorType::Viewport}} };
+ propertyValue = mbgl::style::CameraFunction<mbgl::style::TranslateAnchorType> { intervalStops };
+
+ XCTAssertEqual(rawLayer->getFillExtrusionTranslateAnchor(), propertyValue,
+ @"Setting fillExtrusionTranslationAnchor to a camera function should update fill-extrusion-translate-anchor.");
+ XCTAssertEqualObjects(layer.fillExtrusionTranslationAnchor, functionStyleValue,
+ @"fillExtrusionTranslationAnchor should round-trip camera functions.");
+
+
+
+ layer.fillExtrusionTranslationAnchor = nil;
+ XCTAssertTrue(rawLayer->getFillExtrusionTranslateAnchor().isUndefined(),
+ @"Unsetting fillExtrusionTranslationAnchor should return fill-extrusion-translate-anchor to the default value.");
+ XCTAssertEqualObjects(layer.fillExtrusionTranslationAnchor, defaultStyleValue,
+ @"fillExtrusionTranslationAnchor should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.fillExtrusionTranslationAnchor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.fillExtrusionTranslationAnchor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ }
+}
+
+- (void)testPropertyNames {
+ [self testPropertyName:@"fill-extrusion-base" isBoolean:NO];
+ [self testPropertyName:@"fill-extrusion-color" isBoolean:NO];
+ [self testPropertyName:@"fill-extrusion-height" isBoolean:NO];
+ [self testPropertyName:@"fill-extrusion-opacity" isBoolean:NO];
+ [self testPropertyName:@"fill-extrusion-pattern" isBoolean:NO];
+ [self testPropertyName:@"fill-extrusion-translation" isBoolean:NO];
+ [self testPropertyName:@"fill-extrusion-translation-anchor" isBoolean:NO];
+}
+
+- (void)testValueAdditions {
+ XCTAssertEqual([NSValue valueWithMGLFillExtrusionTranslationAnchor:MGLFillExtrusionTranslationAnchorMap].MGLFillExtrusionTranslationAnchorValue, MGLFillExtrusionTranslationAnchorMap);
+ XCTAssertEqual([NSValue valueWithMGLFillExtrusionTranslationAnchor:MGLFillExtrusionTranslationAnchorViewport].MGLFillExtrusionTranslationAnchorValue, MGLFillExtrusionTranslationAnchorViewport);
+}
+
+@end
diff --git a/platform/darwin/test/MGLSDKTestHelpers.swift b/platform/darwin/test/MGLSDKTestHelpers.swift
new file mode 100644
index 0000000000..82b5caa273
--- /dev/null
+++ b/platform/darwin/test/MGLSDKTestHelpers.swift
@@ -0,0 +1,47 @@
+import Foundation
+
+class MGLSDKTestHelpers {
+
+ class func checkTestsContainAllMethods(testClass: Swift.AnyClass, in p: Protocol) {
+ let testMethods = self.classMethodDescriptions(testClass)
+ let subjectMethods = self.protocolMethodDescriptions(p)
+
+ for method in subjectMethods {
+ if !testMethods.contains(method) {
+ XCTFail("\(String(describing: testClass)) does not contain \(method) from \(String(describing: p))")
+ }
+ }
+
+ XCTAssert(true)
+ }
+
+}
+
+extension MGLSDKTestHelpers {
+
+ class func protocolMethodDescriptions(_ p: Protocol) -> Set<String> {
+ var methods = Set<String>()
+ var methodCount = UInt32()
+ let methodDescriptionList: UnsafeMutablePointer<objc_method_description>! = protocol_copyMethodDescriptionList(p, false, true, &methodCount)
+ for i in 0..<Int(methodCount) {
+ let description: objc_method_description = methodDescriptionList[i]
+ methods.insert(description.name.description)
+ }
+ free(methodDescriptionList)
+ return methods
+ }
+
+ class func classMethodDescriptions(_ cls: Swift.AnyClass) -> Set<String> {
+ var methods = Set<String>()
+ var methodCount = UInt32()
+ let methodList: UnsafeMutablePointer<Method?>! = class_copyMethodList(cls, &methodCount)
+ for i in 0..<Int(methodCount) {
+ let method = methodList[i]
+ let selector : Selector = method_getName(method)
+ methods.insert(selector.description)
+ }
+ free(methodList)
+ return methods
+ }
+
+}
diff --git a/platform/darwin/test/MGLShapeSourceTests.mm b/platform/darwin/test/MGLShapeSourceTests.mm
index ba85d76020..561af7f3d0 100644
--- a/platform/darwin/test/MGLShapeSourceTests.mm
+++ b/platform/darwin/test/MGLShapeSourceTests.mm
@@ -104,11 +104,11 @@
- (void)testMGLShapeSourceWithPolygonFeatures {
CLLocationCoordinate2D coordinates[] = {
- CLLocationCoordinate2DMake(100.0, 0.0),
- CLLocationCoordinate2DMake(101.0, 0.0),
- CLLocationCoordinate2DMake(101.0, 1.0),
- CLLocationCoordinate2DMake(100.0, 1.0),
- CLLocationCoordinate2DMake(100.0, 0.0)};
+ CLLocationCoordinate2DMake(0.0, 100.0),
+ CLLocationCoordinate2DMake(0.0, 101.0),
+ CLLocationCoordinate2DMake(1.0, 101.0),
+ CLLocationCoordinate2DMake(1.0, 100.0),
+ CLLocationCoordinate2DMake(0.0, 100.0)};
MGLPolygonFeature *polygonFeature = [MGLPolygonFeature polygonWithCoordinates:coordinates count:5];
polygonFeature.identifier = @"feature-id";
@@ -150,18 +150,18 @@
- (void)testMGLShapeSourceWithPolygonFeaturesInculdingInteriorPolygons {
CLLocationCoordinate2D coordinates[] = {
- CLLocationCoordinate2DMake(100.0, 0.0),
- CLLocationCoordinate2DMake(101.0, 0.0),
- CLLocationCoordinate2DMake(101.0, 1.0),
- CLLocationCoordinate2DMake(100.0, 1.0),
- CLLocationCoordinate2DMake(100.0, 0.0)};
+ CLLocationCoordinate2DMake(0.0, 100.0),
+ CLLocationCoordinate2DMake(0.0, 101.0),
+ CLLocationCoordinate2DMake(1.0, 101.0),
+ CLLocationCoordinate2DMake(1.0, 100.0),
+ CLLocationCoordinate2DMake(0.0, 100.0)};
CLLocationCoordinate2D interiorCoordinates[] = {
- CLLocationCoordinate2DMake(100.2, 0.2),
- CLLocationCoordinate2DMake(100.8, 0.2),
- CLLocationCoordinate2DMake(100.8, 0.8),
- CLLocationCoordinate2DMake(100.2, 0.8),
- CLLocationCoordinate2DMake(100.2, 0.2)};
+ CLLocationCoordinate2DMake(0.2, 100.2),
+ CLLocationCoordinate2DMake(0.2, 100.8),
+ CLLocationCoordinate2DMake(0.8, 100.8),
+ CLLocationCoordinate2DMake(0.8, 100.2),
+ CLLocationCoordinate2DMake(0.2, 100.2)};
MGLPolygon *polygon = [MGLPolygon polygonWithCoordinates:interiorCoordinates count:5];
@@ -188,18 +188,18 @@
- (void)testMGLShapeSourceWithMultiPolygonFeatures {
CLLocationCoordinate2D coordinates[] = {
- CLLocationCoordinate2DMake(100.0, 0.0),
- CLLocationCoordinate2DMake(101.0, 0.0),
- CLLocationCoordinate2DMake(101.0, 1.0),
- CLLocationCoordinate2DMake(100.0, 1.0),
- CLLocationCoordinate2DMake(100.0, 0.0)};
+ CLLocationCoordinate2DMake(0.0, 100.0),
+ CLLocationCoordinate2DMake(0.0, 101.0),
+ CLLocationCoordinate2DMake(1.0, 101.0),
+ CLLocationCoordinate2DMake(1.0, 100.0),
+ CLLocationCoordinate2DMake(0.0, 100.0)};
CLLocationCoordinate2D interiorCoordinates[] = {
- CLLocationCoordinate2DMake(100.2, 0.2),
- CLLocationCoordinate2DMake(100.8, 0.2),
- CLLocationCoordinate2DMake(100.8, 0.8),
- CLLocationCoordinate2DMake(100.2, 0.8),
- CLLocationCoordinate2DMake(100.2, 0.2)};
+ CLLocationCoordinate2DMake(0.2, 100.2),
+ CLLocationCoordinate2DMake(0.2, 100.8),
+ CLLocationCoordinate2DMake(0.8, 100.8),
+ CLLocationCoordinate2DMake(0.8, 100.2),
+ CLLocationCoordinate2DMake(0.2, 100.2)};
MGLPolygon *polygon = [MGLPolygon polygonWithCoordinates:interiorCoordinates count:5];
@@ -216,7 +216,7 @@
- (void)testMGLShapeSourceWithPointFeature {
MGLPointFeature *pointFeature = [MGLPointFeature new];
- pointFeature.coordinate = CLLocationCoordinate2DMake(100.2, 0.2);
+ pointFeature.coordinate = CLLocationCoordinate2DMake(0.2, 100.2);
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"souce-id" shape:pointFeature options:nil];
@@ -226,11 +226,11 @@
- (void)testMGLShapeSourceWithPointCollectionFeature {
CLLocationCoordinate2D coordinates[] = {
- CLLocationCoordinate2DMake(100.0, 0.0),
- CLLocationCoordinate2DMake(101.0, 0.0),
- CLLocationCoordinate2DMake(101.0, 1.0),
- CLLocationCoordinate2DMake(100.0, 1.0),
- CLLocationCoordinate2DMake(100.0, 0.0)};
+ CLLocationCoordinate2DMake(0.0, 100.0),
+ CLLocationCoordinate2DMake(0.0, 101.0),
+ CLLocationCoordinate2DMake(1.0, 101.0),
+ CLLocationCoordinate2DMake(1.0, 100.0),
+ CLLocationCoordinate2DMake(0.0, 100.0)};
MGLPointCollectionFeature *pointCollectionFeature = [MGLPointCollectionFeature pointCollectionWithCoordinates:coordinates count:5];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"souce-id" shape:pointCollectionFeature options:nil];
@@ -240,18 +240,18 @@
- (void)testMGLShapeSourceWithShapeCollectionFeatures {
CLLocationCoordinate2D coordinates[] = {
- CLLocationCoordinate2DMake(100.0, 0.0),
- CLLocationCoordinate2DMake(101.0, 0.0),
- CLLocationCoordinate2DMake(101.0, 1.0),
- CLLocationCoordinate2DMake(100.0, 1.0),
- CLLocationCoordinate2DMake(100.0, 0.0)};
+ CLLocationCoordinate2DMake(0.0, 100.0),
+ CLLocationCoordinate2DMake(0.0, 101.0),
+ CLLocationCoordinate2DMake(1.0, 101.0),
+ CLLocationCoordinate2DMake(1.0, 100.0),
+ CLLocationCoordinate2DMake(0.0, 100.0)};
CLLocationCoordinate2D interiorCoordinates[] = {
- CLLocationCoordinate2DMake(100.2, 0.2),
- CLLocationCoordinate2DMake(100.8, 0.2),
- CLLocationCoordinate2DMake(100.8, 0.8),
- CLLocationCoordinate2DMake(100.2, 0.8),
- CLLocationCoordinate2DMake(100.2, 0.2)};
+ CLLocationCoordinate2DMake(0.2, 100.2),
+ CLLocationCoordinate2DMake(0.2, 100.8),
+ CLLocationCoordinate2DMake(0.8, 100.8),
+ CLLocationCoordinate2DMake(0.8, 100.2),
+ CLLocationCoordinate2DMake(0.2, 100.2)};
MGLPolygon *polygon = [MGLPolygon polygonWithCoordinates:interiorCoordinates count:5];
@@ -267,7 +267,7 @@
MGLPointCollectionFeature *pointCollectionFeature = [MGLPointCollectionFeature pointCollectionWithCoordinates:coordinates count:5];
MGLPointFeature *pointFeature = [MGLPointFeature new];
- pointFeature.coordinate = CLLocationCoordinate2DMake(100.2, 0.2);
+ pointFeature.coordinate = CLLocationCoordinate2DMake(0.2, 100.2);
MGLShapeCollectionFeature *shapeCollectionFeature = [MGLShapeCollectionFeature shapeCollectionWithShapes:@[polygonFeature, polylineFeature, multiPolygonFeature, multiPolylineFeature, pointCollectionFeature, pointFeature]];
@@ -280,11 +280,11 @@
- (void)testMGLShapeSourceWithFeaturesConvenienceInitializer {
CLLocationCoordinate2D coordinates[] = {
- CLLocationCoordinate2DMake(100.0, 0.0),
- CLLocationCoordinate2DMake(101.0, 0.0),
- CLLocationCoordinate2DMake(101.0, 1.0),
- CLLocationCoordinate2DMake(100.0, 1.0),
- CLLocationCoordinate2DMake(100.0, 0.0)};
+ CLLocationCoordinate2DMake(0.0, 100.0),
+ CLLocationCoordinate2DMake(0.0, 101.0),
+ CLLocationCoordinate2DMake(1.0, 101.0),
+ CLLocationCoordinate2DMake(1.0, 100.0),
+ CLLocationCoordinate2DMake(0.0, 100.0)};
MGLPolygonFeature *polygonFeature = [MGLPolygonFeature polygonWithCoordinates:coordinates count:sizeof(coordinates)/sizeof(coordinates[0]) interiorPolygons:nil];
@@ -302,11 +302,11 @@
- (void)testMGLShapeSourceWithShapesConvenienceInitializer {
CLLocationCoordinate2D coordinates[] = {
- CLLocationCoordinate2DMake(100.0, 0.0),
- CLLocationCoordinate2DMake(101.0, 0.0),
- CLLocationCoordinate2DMake(101.0, 1.0),
- CLLocationCoordinate2DMake(100.0, 1.0),
- CLLocationCoordinate2DMake(100.0, 0.0)};
+ CLLocationCoordinate2DMake(0.0, 100.0),
+ CLLocationCoordinate2DMake(0.0, 101.0),
+ CLLocationCoordinate2DMake(1.0, 101.0),
+ CLLocationCoordinate2DMake(1.0, 100.0),
+ CLLocationCoordinate2DMake(0.0, 100.0)};
MGLPolygon *polygon = [MGLPolygon polygonWithCoordinates:coordinates count:sizeof(coordinates)/sizeof(coordinates[0]) interiorPolygons:nil];
diff --git a/platform/darwin/test/MGLSourceQueryTests.m b/platform/darwin/test/MGLSourceQueryTests.m
index 28e968146b..d1ef180a52 100644
--- a/platform/darwin/test/MGLSourceQueryTests.m
+++ b/platform/darwin/test/MGLSourceQueryTests.m
@@ -1,73 +1,25 @@
#import <Mapbox/Mapbox.h>
-
-#import "NSBundle+MGLAdditions.h"
-
#import <XCTest/XCTest.h>
-#if TARGET_OS_IPHONE
- #import <UIKit/UIKit.h>
-#else
- #import <Cocoa/Cocoa.h>
-#endif
@interface MGLSourceQueryTests : XCTestCase <MGLMapViewDelegate>
-@property (nonatomic) MGLMapView *mapView;
-@property (nonatomic) MGLStyle *style;
-
@end
-@implementation MGLSourceQueryTests {
- XCTestExpectation *_styleLoadingExpectation;
-}
-
-- (void)setUp {
- [super setUp];
-
- [MGLAccountManager setAccessToken:@"pk.feedcafedeadbeefbadebede"];
- NSURL *styleURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"query-style" withExtension:@"json"];
- self.mapView = [[MGLMapView alloc] initWithFrame:CGRectMake(0, 0, 100, 100) styleURL:styleURL];
- self.mapView.delegate = self;
- if (!self.mapView.style) {
- _styleLoadingExpectation = [self expectationWithDescription:@"Map view should finish loading style."];
- [self waitForExpectationsWithTimeout:1 handler:nil];
- }
-}
-
-- (void)mapView:(MGLMapView *)mapView didFinishLoadingStyle:(MGLStyle *)style {
- XCTAssertNotNil(mapView.style);
- XCTAssertEqual(mapView.style, style);
-
- [_styleLoadingExpectation fulfill];
-}
-
-- (void)tearDown {
- _styleLoadingExpectation = nil;
- self.mapView = nil;
-
- [super tearDown];
-}
-
-- (MGLStyle *)style {
- return self.mapView.style;
-}
+@implementation MGLSourceQueryTests
- (void) testQueryVectorSource {
- MGLVectorSource *source = (MGLVectorSource *)[self.style sourceWithIdentifier:@"source5"];
-
+ MGLVectorSource *source = [[MGLVectorSource alloc] initWithIdentifier:@"vector" tileURLTemplates:@[@"fake"] options:nil];
NSSet *sourceLayers = [NSSet setWithObjects:@"buildings", @"water", nil];
NSArray* features = [source featuresInSourceLayersWithIdentifiers:sourceLayers predicate:nil];
- // Source won't be loaded yet, so features is 0
+ // Source not added yet, so features is 0
XCTAssertEqual([features count], 0);
}
- (void) testQueryShapeSource {
- MGLShapeSource *source = (MGLShapeSource *)[self.style sourceWithIdentifier:@"source4"];
-
- NSPredicate *eqPredicate = [NSPredicate predicateWithFormat:@"key1 == 'value1'"];
- NSArray* features = [source featuresMatchingPredicate:eqPredicate];
- // Source won't be loaded yet, so features is 0
+ MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"shape" shape:[MGLShapeCollection shapeCollectionWithShapes:@[]] options:nil];
+ NSArray* features = [source featuresMatchingPredicate:nil];
+ // Source not added yet, so features is 0
XCTAssertEqual([features count], 0);
-
}
@end
diff --git a/platform/darwin/test/MGLStyleLayerTests.mm.ejs b/platform/darwin/test/MGLStyleLayerTests.mm.ejs
index a405ae58c4..5fdfc3d44e 100644
--- a/platform/darwin/test/MGLStyleLayerTests.mm.ejs
+++ b/platform/darwin/test/MGLStyleLayerTests.mm.ejs
@@ -11,7 +11,7 @@
#import "MGLStyleLayer_Private.h"
-#include <mbgl/style/layers/<%- type %>_layer.hpp>
+#include <mbgl/style/layers/<%- type.replace('-', '_') %>_layer.hpp>
#include <mbgl/style/transition_options.hpp>
@interface MGL<%- camelize(type) %>LayerTests : MGLStyleLayerTests
diff --git a/platform/darwin/test/MGLStyleTests.mm b/platform/darwin/test/MGLStyleTests.mm
index 36772e556d..f80d5776f0 100644
--- a/platform/darwin/test/MGLStyleTests.mm
+++ b/platform/darwin/test/MGLStyleTests.mm
@@ -55,13 +55,19 @@
}
- (void)testUnversionedStyleURLs {
+ XCTAssertEqual(mbgl::util::default_styles::streets.currentVersion, MGLStyleDefaultVersion,
+ "mbgl::util::default_styles::streets.currentVersion and MGLStyleDefaultVersion disagree.");
+
+ XCTAssertEqualObjects([MGLStyle streetsStyleURL].absoluteString, @(mbgl::util::default_styles::streets.url));
+ XCTAssertEqualObjects([MGLStyle outdoorsStyleURL].absoluteString, @(mbgl::util::default_styles::outdoors.url));
+ XCTAssertEqualObjects([MGLStyle lightStyleURL].absoluteString, @(mbgl::util::default_styles::light.url));
+ XCTAssertEqualObjects([MGLStyle darkStyleURL].absoluteString, @(mbgl::util::default_styles::dark.url));
+ XCTAssertEqualObjects([MGLStyle satelliteStyleURL].absoluteString, @(mbgl::util::default_styles::satellite.url));
+ XCTAssertEqualObjects([MGLStyle satelliteStreetsStyleURL].absoluteString, @(mbgl::util::default_styles::satelliteStreets.url));
+
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
- XCTAssertEqualObjects([MGLStyle streetsStyleURL].absoluteString, @"mapbox://styles/mapbox/streets-v8");
XCTAssertEqualObjects([MGLStyle emeraldStyleURL].absoluteString, @"mapbox://styles/mapbox/emerald-v8");
- XCTAssertEqualObjects([MGLStyle lightStyleURL].absoluteString, @"mapbox://styles/mapbox/light-v8");
- XCTAssertEqualObjects([MGLStyle darkStyleURL].absoluteString, @"mapbox://styles/mapbox/dark-v8");
- XCTAssertEqualObjects([MGLStyle satelliteStyleURL].absoluteString, @"mapbox://styles/mapbox/satellite-v8");
XCTAssertEqualObjects([MGLStyle hybridStyleURL].absoluteString, @"mapbox://styles/mapbox/satellite-hybrid-v8");
#pragma clang diagnostic pop
}
@@ -69,20 +75,40 @@
- (void)testVersionedStyleURLs {
// Test that all the default styles have publicly-declared MGLStyle class
// methods and that the URLs all have the right values.
- XCTAssertEqualObjects([MGLStyle streetsStyleURLWithVersion:MGLStyleDefaultVersion].absoluteString, @(mbgl::util::default_styles::streets.url));
- XCTAssertEqualObjects([MGLStyle streetsStyleURLWithVersion:99].absoluteString, @"mapbox://styles/mapbox/streets-v99");
- XCTAssertEqualObjects([MGLStyle outdoorsStyleURLWithVersion:MGLStyleDefaultVersion].absoluteString, @(mbgl::util::default_styles::outdoors.url));
- XCTAssertEqualObjects([MGLStyle outdoorsStyleURLWithVersion:99].absoluteString, @"mapbox://styles/mapbox/outdoors-v99");
- XCTAssertEqualObjects([MGLStyle lightStyleURLWithVersion:MGLStyleDefaultVersion].absoluteString, @(mbgl::util::default_styles::light.url));
- XCTAssertEqualObjects([MGLStyle lightStyleURLWithVersion:99].absoluteString, @"mapbox://styles/mapbox/light-v99");
- XCTAssertEqualObjects([MGLStyle darkStyleURLWithVersion:MGLStyleDefaultVersion].absoluteString, @(mbgl::util::default_styles::dark.url));
- XCTAssertEqualObjects([MGLStyle darkStyleURLWithVersion:99].absoluteString, @"mapbox://styles/mapbox/dark-v99");
- XCTAssertEqualObjects([MGLStyle satelliteStyleURLWithVersion:MGLStyleDefaultVersion].absoluteString, @(mbgl::util::default_styles::satellite.url));
- XCTAssertEqualObjects([MGLStyle satelliteStyleURLWithVersion:99].absoluteString, @"mapbox://styles/mapbox/satellite-v99");
- XCTAssertEqualObjects([MGLStyle satelliteStreetsStyleURLWithVersion:MGLStyleDefaultVersion].absoluteString, @(mbgl::util::default_styles::satelliteStreets.url));
- XCTAssertEqualObjects([MGLStyle satelliteStreetsStyleURLWithVersion:99].absoluteString, @"mapbox://styles/mapbox/satellite-streets-v99");
-
- static_assert(6 == mbgl::util::default_styles::numOrderedStyles,
+ XCTAssertEqualObjects([MGLStyle streetsStyleURLWithVersion:mbgl::util::default_styles::streets.currentVersion].absoluteString,
+ @(mbgl::util::default_styles::streets.url));
+ XCTAssertEqualObjects([MGLStyle streetsStyleURLWithVersion:99].absoluteString,
+ @"mapbox://styles/mapbox/streets-v99");
+ XCTAssertEqualObjects([MGLStyle outdoorsStyleURLWithVersion:mbgl::util::default_styles::outdoors.currentVersion].absoluteString,
+ @(mbgl::util::default_styles::outdoors.url));
+ XCTAssertEqualObjects([MGLStyle outdoorsStyleURLWithVersion:99].absoluteString,
+ @"mapbox://styles/mapbox/outdoors-v99");
+ XCTAssertEqualObjects([MGLStyle lightStyleURLWithVersion:mbgl::util::default_styles::light.currentVersion].absoluteString,
+ @(mbgl::util::default_styles::light.url));
+ XCTAssertEqualObjects([MGLStyle lightStyleURLWithVersion:99].absoluteString,
+ @"mapbox://styles/mapbox/light-v99");
+ XCTAssertEqualObjects([MGLStyle darkStyleURLWithVersion:mbgl::util::default_styles::dark.currentVersion].absoluteString,
+ @(mbgl::util::default_styles::dark.url));
+ XCTAssertEqualObjects([MGLStyle darkStyleURLWithVersion:99].absoluteString,
+ @"mapbox://styles/mapbox/dark-v99");
+ XCTAssertEqualObjects([MGLStyle satelliteStyleURLWithVersion:mbgl::util::default_styles::satellite.currentVersion].absoluteString,
+ @(mbgl::util::default_styles::satellite.url));
+ XCTAssertEqualObjects([MGLStyle satelliteStyleURLWithVersion:99].absoluteString,
+ @"mapbox://styles/mapbox/satellite-v99");
+ XCTAssertEqualObjects([MGLStyle satelliteStreetsStyleURLWithVersion:mbgl::util::default_styles::satelliteStreets.currentVersion].absoluteString,
+ @(mbgl::util::default_styles::satelliteStreets.url));
+ XCTAssertEqualObjects([MGLStyle satelliteStreetsStyleURLWithVersion:99].absoluteString,
+ @"mapbox://styles/mapbox/satellite-streets-v99");
+ XCTAssertEqualObjects([MGLStyle trafficDayStyleURLWithVersion:mbgl::util::default_styles::trafficDay.currentVersion].absoluteString,
+ @(mbgl::util::default_styles::trafficDay.url));
+ XCTAssertEqualObjects([MGLStyle trafficDayStyleURLWithVersion:99].absoluteString,
+ @"mapbox://styles/mapbox/traffic-day-v99");
+ XCTAssertEqualObjects([MGLStyle trafficNightStyleURLWithVersion:mbgl::util::default_styles::trafficNight.currentVersion].absoluteString,
+ @(mbgl::util::default_styles::trafficNight.url));
+ XCTAssertEqualObjects([MGLStyle trafficNightStyleURLWithVersion:99].absoluteString,
+ @"mapbox://styles/mapbox/traffic-night-v99");
+
+ static_assert(8 == mbgl::util::default_styles::numOrderedStyles,
"MGLStyleTests isn’t testing all the styles in mbgl::util::default_styles.");
}
@@ -119,19 +145,6 @@
XCTAssertNil(versionedMethodError, @"Error compiling regular expression to search for versioned methods.");
NSUInteger numVersionedMethodDeclarations = [versionedMethodExpression numberOfMatchesInString:styleHeader options:0 range:NSMakeRange(0, styleHeader.length)];
XCTAssertEqual(numVersionedMethodDeclarations, numVersionedMethods);
-
- // Test that “current version is” statements are present and current for all versioned style methods.
- NSError *versionError;
- NSString *versionExpressionString = @(R"RE(current version is `(\d+)`)RE");
- NSRegularExpression *versionExpression = [NSRegularExpression regularExpressionWithPattern:versionExpressionString options:0 error:&versionError];
- XCTAssertNil(versionError, @"Error compiling regular expression to search for current version statements.");
- NSUInteger numVersionDeclarations = [versionExpression numberOfMatchesInString:styleHeader options:0 range:NSMakeRange(0, styleHeader.length)];
- XCTAssertEqual(numVersionDeclarations, numVersionedMethods);
- [versionExpression enumerateMatchesInString:styleHeader options:0 range:NSMakeRange(0, styleHeader.length) usingBlock:^(NSTextCheckingResult * _Nullable result, NSMatchingFlags flags, BOOL * _Nonnull stop) {
- XCTAssertEqual(result.numberOfRanges, 2, @"Regular expression should have one capture group.");
- NSString *version = [styleHeader substringWithRange:[result rangeAtIndex:1]];
- XCTAssertEqual([version integerValue], MGLStyleDefaultVersion, @"Versioned style URL method should document current version as %ld, not %ld.", MGLStyleDefaultVersion, version.integerValue);
- }];
}
- (void)testName {
@@ -148,6 +161,7 @@
MGLShapeSource *shapeSource = [[MGLShapeSource alloc] initWithIdentifier:@"shapeSource" shape:nil options:nil];
[self.style addSource:shapeSource];
XCTAssertEqual(self.style.sources.count, initialSources.count + 1);
+ XCTAssertEqual(shapeSource, [self.style sourceWithIdentifier:@"shapeSource"]);
[self.style removeSource:shapeSource];
XCTAssertEqual(self.style.sources.count, initialSources.count);
}
@@ -238,6 +252,7 @@
MGLFillStyleLayer *fillLayer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"fillLayer" source:shapeSource];
[self.style addLayer:fillLayer];
XCTAssertEqual(self.style.layers.count, initialLayers.count + 1);
+ XCTAssertEqual(fillLayer, [self.style layerWithIdentifier:@"fillLayer"]);
[self.style removeLayer:fillLayer];
XCTAssertEqual(self.style.layers.count, initialLayers.count);
}
diff --git a/platform/darwin/test/MGLSymbolStyleLayerTests.mm b/platform/darwin/test/MGLSymbolStyleLayerTests.mm
index e3e473ef78..367ebf363c 100644
--- a/platform/darwin/test/MGLSymbolStyleLayerTests.mm
+++ b/platform/darwin/test/MGLSymbolStyleLayerTests.mm
@@ -134,7 +134,7 @@
MGLStyleValue<NSString *> *constantStyleValue = [MGLStyleValue<NSString *> valueWithRawValue:@"Icon Image"];
layer.iconImageName = constantStyleValue;
- mbgl::style::PropertyValue<std::string> propertyValue = { "Icon Image" };
+ mbgl::style::DataDrivenPropertyValue<std::string> propertyValue = { "Icon Image" };
XCTAssertEqual(rawLayer->getIconImage(), propertyValue,
@"Setting iconImageName to a constant value should update icon-image.");
XCTAssertEqualObjects(layer.iconImageName, constantStyleValue,
@@ -158,11 +158,6 @@
@"Unsetting iconImageName should return icon-image to the default value.");
XCTAssertEqualObjects(layer.iconImageName, defaultStyleValue,
@"iconImageName should return the default value after being unset.");
-
- functionStyleValue = [MGLStyleValue<NSString *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.iconImageName = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSString *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.iconImageName = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
// icon-offset
@@ -410,7 +405,7 @@
MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
layer.iconScale = constantStyleValue;
- mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getIconSize(), propertyValue,
@"Setting iconScale to a constant value should update icon-size.");
XCTAssertEqualObjects(layer.iconScale, constantStyleValue,
@@ -427,6 +422,29 @@
XCTAssertEqualObjects(layer.iconScale, functionStyleValue,
@"iconScale should round-trip camera functions.");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.iconScale = functionStyleValue;
+
+ mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getIconSize(), propertyValue,
+ @"Setting iconScale to a source function should update icon-size.");
+ XCTAssertEqualObjects(layer.iconScale, functionStyleValue,
+ @"iconScale should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.iconScale = functionStyleValue;
+
+ std::map<float, float> innerStops { {18, 0xff} };
+ mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getIconSize(), propertyValue,
+ @"Setting iconScale to a composite function should update icon-size.");
+ XCTAssertEqualObjects(layer.iconScale, functionStyleValue,
+ @"iconScale should round-trip composite functions.");
layer.iconScale = nil;
@@ -434,11 +452,6 @@
@"Unsetting iconScale should return icon-size to the default value.");
XCTAssertEqualObjects(layer.iconScale, defaultStyleValue,
@"iconScale should return the default value after being unset.");
-
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.iconScale = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.iconScale = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
// icon-text-fit
@@ -957,7 +970,7 @@
MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
layer.textFontSize = constantStyleValue;
- mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getTextSize(), propertyValue,
@"Setting textFontSize to a constant value should update text-size.");
XCTAssertEqualObjects(layer.textFontSize, constantStyleValue,
@@ -974,6 +987,29 @@
XCTAssertEqualObjects(layer.textFontSize, functionStyleValue,
@"textFontSize should round-trip camera functions.");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.textFontSize = functionStyleValue;
+
+ mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getTextSize(), propertyValue,
+ @"Setting textFontSize to a source function should update text-size.");
+ XCTAssertEqualObjects(layer.textFontSize, functionStyleValue,
+ @"textFontSize should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.textFontSize = functionStyleValue;
+
+ std::map<float, float> innerStops { {18, 0xff} };
+ mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getTextSize(), propertyValue,
+ @"Setting textFontSize to a composite function should update text-size.");
+ XCTAssertEqualObjects(layer.textFontSize, functionStyleValue,
+ @"textFontSize should round-trip composite functions.");
layer.textFontSize = nil;
@@ -981,11 +1017,6 @@
@"Unsetting textFontSize should return text-size to the default value.");
XCTAssertEqualObjects(layer.textFontSize, defaultStyleValue,
@"textFontSize should return the default value after being unset.");
-
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.textFontSize = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.textFontSize = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
// text-ignore-placement
@@ -1158,7 +1189,7 @@
#endif
];
layer.textOffset = constantStyleValue;
- mbgl::style::PropertyValue<std::array<float, 2>> propertyValue = { { 1, 1 } };
+ mbgl::style::DataDrivenPropertyValue<std::array<float, 2>> propertyValue = { { 1, 1 } };
XCTAssertEqual(rawLayer->getTextOffset(), propertyValue,
@"Setting textOffset to a constant value should update text-offset.");
XCTAssertEqualObjects(layer.textOffset, constantStyleValue,
@@ -1175,6 +1206,29 @@
XCTAssertEqualObjects(layer.textOffset, functionStyleValue,
@"textOffset should round-trip camera functions.");
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.textOffset = functionStyleValue;
+
+ mbgl::style::ExponentialStops<std::array<float, 2>> exponentialStops = { {{18, { 1, 1 }}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<std::array<float, 2>> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getTextOffset(), propertyValue,
+ @"Setting textOffset to a source function should update text-offset.");
+ XCTAssertEqualObjects(layer.textOffset, functionStyleValue,
+ @"textOffset should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.textOffset = functionStyleValue;
+
+ std::map<float, std::array<float, 2>> innerStops { {18, { 1, 1 }} };
+ mbgl::style::CompositeExponentialStops<std::array<float, 2>> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<std::array<float, 2>> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getTextOffset(), propertyValue,
+ @"Setting textOffset to a composite function should update text-offset.");
+ XCTAssertEqualObjects(layer.textOffset, functionStyleValue,
+ @"textOffset should round-trip composite functions.");
layer.textOffset = nil;
@@ -1182,11 +1236,6 @@
@"Unsetting textOffset should return text-offset to the default value.");
XCTAssertEqualObjects(layer.textOffset, defaultStyleValue,
@"textOffset should return the default value after being unset.");
-
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.textOffset = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.textOffset = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
// text-optional
@@ -1314,7 +1363,7 @@
MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
layer.textRotation = constantStyleValue;
- mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getTextRotate(), propertyValue,
@"Setting textRotation to a constant value should update text-rotate.");
XCTAssertEqualObjects(layer.textRotation, constantStyleValue,
@@ -1331,6 +1380,29 @@
XCTAssertEqualObjects(layer.textRotation, functionStyleValue,
@"textRotation should round-trip camera functions.");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.textRotation = functionStyleValue;
+
+ mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getTextRotate(), propertyValue,
+ @"Setting textRotation to a source function should update text-rotate.");
+ XCTAssertEqualObjects(layer.textRotation, functionStyleValue,
+ @"textRotation should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.textRotation = functionStyleValue;
+
+ std::map<float, float> innerStops { {18, 0xff} };
+ mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getTextRotate(), propertyValue,
+ @"Setting textRotation to a composite function should update text-rotate.");
+ XCTAssertEqualObjects(layer.textRotation, functionStyleValue,
+ @"textRotation should round-trip composite functions.");
layer.textRotation = nil;
@@ -1338,11 +1410,6 @@
@"Unsetting textRotation should return text-rotate to the default value.");
XCTAssertEqualObjects(layer.textRotation, defaultStyleValue,
@"textRotation should return the default value after being unset.");
-
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.textRotation = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.textRotation = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
// text-rotation-alignment
diff --git a/platform/darwin/test/query-style.json b/platform/darwin/test/query-style.json
deleted file mode 100644
index 97f1d04432..0000000000
--- a/platform/darwin/test/query-style.json
+++ /dev/null
@@ -1,98 +0,0 @@
-{
- "version": 8,
- "sources": {
- "source1": {
- "type": "geojson",
- "data": {
- "type": "Point",
- "coordinates": [
- 0,
- 0
- ]
- }
- },
- "source2": {
- "type": "geojson",
- "data": {
- "type": "Point",
- "coordinates": [
- 0,
- 0
- ]
- }
- },
- "source3": {
- "type": "geojson",
- "data": {
- "type": "Point",
- "coordinates": [
- 0,
- 0
- ]
- }
- },
- "source4": {
- "type": "geojson",
- "data": {
- "type": "Feature",
- "id": "feature1",
- "geometry": {
- "type": "Point",
- "coordinates": [
- 0.0,
- 0.0
- ]
- },
- "properties": {
- "key1": "value1",
- "key2": 1.5,
- "key3": false,
- "key4": 0.5
- }
- }
- },
- "source5": {
- "type": "vector",
- "url": "mapbox://mapbox.mapbox-streets-v6"
- },
- "source6": {
- "type": "raster",
- "url": "mapbox://mapbox.satellite",
- "tileSize": 256
- }
- },
- "layers": [
- {
- "id": "layer1",
- "type": "symbol",
- "source": "source1",
- "layout": {
- "icon-image": "test-icon"
- }
- },
- {
- "id": "layer2",
- "type": "symbol",
- "source": "source2",
- "layout": {
- "icon-image": "test-icon"
- }
- },
- {
- "id": "layer3",
- "type": "symbol",
- "source": "source3",
- "layout": {
- "icon-image": "test-icon"
- }
- },
- {
- "id": "layer4",
- "type": "symbol",
- "source": "source4",
- "layout": {
- "icon-image": "test-icon"
- }
- }
- ]
-}
diff --git a/platform/default/async_task.cpp b/platform/default/async_task.cpp
index 05cf759863..50891056d8 100644
--- a/platform/default/async_task.cpp
+++ b/platform/default/async_task.cpp
@@ -7,12 +7,6 @@
#include <uv.h>
-#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
-#define UV_ASYNC_PARAMS(handle) uv_async_t *handle, int
-#else
-#define UV_ASYNC_PARAMS(handle) uv_async_t *handle
-#endif
-
namespace mbgl {
namespace util {
@@ -22,7 +16,7 @@ public:
: async(new uv_async_t),
task(std::move(fn)) {
- uv_loop_t* loop = reinterpret_cast<uv_loop_t*>(RunLoop::getLoopHandle());
+ auto* loop = reinterpret_cast<uv_loop_t*>(RunLoop::getLoopHandle());
if (uv_async_init(loop, async, asyncCallback) != 0) {
throw std::runtime_error("Failed to initialize async.");
}
@@ -45,7 +39,7 @@ public:
}
private:
- static void asyncCallback(UV_ASYNC_PARAMS(handle)) {
+ static void asyncCallback(uv_async_t* handle) {
reinterpret_cast<Impl*>(handle->data)->task();
}
diff --git a/platform/default/bidi.cpp b/platform/default/bidi.cpp
index d9ed2658ef..d475c387b3 100644
--- a/platform/default/bidi.cpp
+++ b/platform/default/bidi.cpp
@@ -30,7 +30,7 @@ std::u16string applyArabicShaping(const std::u16string& input) {
UErrorCode errorCode = U_ZERO_ERROR;
const int32_t outputLength =
- u_shapeArabic(mbgl::utf16char_cast<const UChar*>(input.c_str()), static_cast<int32_t>(input.size()), NULL, 0,
+ u_shapeArabic(mbgl::utf16char_cast<const UChar*>(input.c_str()), static_cast<int32_t>(input.size()), nullptr, 0,
(U_SHAPE_LETTERS_SHAPE & U_SHAPE_LETTERS_MASK) |
(U_SHAPE_TEXT_DIRECTION_LOGICAL & U_SHAPE_TEXT_DIRECTION_MASK),
&errorCode);
@@ -57,7 +57,7 @@ void BiDi::mergeParagraphLineBreaks(std::set<size_t>& lineBreakPoints) {
for (int32_t i = 0; i < paragraphCount; i++) {
UErrorCode errorCode = U_ZERO_ERROR;
int32_t paragraphEndIndex;
- ubidi_getParagraphByIndex(impl->bidiText, i, NULL, &paragraphEndIndex, NULL, &errorCode);
+ ubidi_getParagraphByIndex(impl->bidiText, i, nullptr, &paragraphEndIndex, nullptr, &errorCode);
if (U_FAILURE(errorCode)) {
throw std::runtime_error(std::string("ProcessedBiDiText::mergeParagraphLineBreaks: ") +
@@ -92,7 +92,7 @@ std::vector<std::u16string> BiDi::processText(const std::u16string& input,
UErrorCode errorCode = U_ZERO_ERROR;
ubidi_setPara(impl->bidiText, mbgl::utf16char_cast<const UChar*>(input.c_str()), static_cast<int32_t>(input.size()),
- UBIDI_DEFAULT_LTR, NULL, &errorCode);
+ UBIDI_DEFAULT_LTR, nullptr, &errorCode);
if (U_FAILURE(errorCode)) {
throw std::runtime_error(std::string("BiDi::processText: ") + u_errorName(errorCode));
@@ -118,7 +118,7 @@ std::u16string BiDi::getLine(std::size_t start, std::size_t end) {
// UBIDI_DO_MIRRORING: Apply unicode mirroring of characters like parentheses
// UBIDI_REMOVE_BIDI_CONTROLS: Now that all the lines are set, remove control characters so that
// they don't show up on screen (some fonts have glyphs representing them)
- ubidi_writeReordered(impl->bidiLine, &outputText[0], outputLength,
+ ubidi_writeReordered(impl->bidiLine, mbgl::utf16char_cast<UChar*>(&outputText[0]), outputLength,
UBIDI_DO_MIRRORING | UBIDI_REMOVE_BIDI_CONTROLS, &errorCode);
if (U_FAILURE(errorCode)) {
diff --git a/platform/default/default_file_source.cpp b/platform/default/default_file_source.cpp
index 20a3eadc8b..7db0b85461 100644
--- a/platform/default/default_file_source.cpp
+++ b/platform/default/default_file_source.cpp
@@ -167,9 +167,15 @@ private:
DefaultFileSource::DefaultFileSource(const std::string& cachePath,
const std::string& assetRoot,
uint64_t maximumCacheSize)
+ : DefaultFileSource(cachePath, std::make_unique<AssetFileSource>(assetRoot), maximumCacheSize) {
+}
+
+DefaultFileSource::DefaultFileSource(const std::string& cachePath,
+ std::unique_ptr<FileSource>&& assetFileSource_,
+ uint64_t maximumCacheSize)
: thread(std::make_unique<util::Thread<Impl>>(util::ThreadContext{"DefaultFileSource", util::ThreadPriority::Low},
cachePath, maximumCacheSize)),
- assetFileSource(std::make_unique<AssetFileSource>(assetRoot)),
+ assetFileSource(std::move(assetFileSource_)),
localFileSource(std::make_unique<LocalFileSource>()) {
}
@@ -194,12 +200,16 @@ std::string DefaultFileSource::getAccessToken() const {
}
void DefaultFileSource::setResourceTransform(std::function<std::string(Resource::Kind, std::string&&)> transform) {
- auto loop = util::RunLoop::Get();
- thread->invoke(&Impl::setResourceTransform, [loop, transform](Resource::Kind kind_, std::string&& url_, auto callback_) {
- return loop->invokeWithCallback([transform](Resource::Kind kind, std::string&& url, auto callback) {
- callback(transform(kind, std::move(url)));
- }, kind_, std::move(url_), callback_);
- });
+ if (transform) {
+ auto loop = util::RunLoop::Get();
+ thread->invoke(&Impl::setResourceTransform, [loop, transform](Resource::Kind kind_, std::string&& url_, auto callback_) {
+ return loop->invokeWithCallback([transform](Resource::Kind kind, std::string&& url, auto callback) {
+ callback(transform(kind, std::move(url)));
+ }, kind_, std::move(url_), callback_);
+ });
+ } else {
+ thread->invoke(&Impl::setResourceTransform, nullptr);
+ }
}
std::unique_ptr<AsyncRequest> DefaultFileSource::request(const Resource& resource, Callback callback) {
diff --git a/platform/default/headless_backend_osmesa.cpp b/platform/default/headless_backend_osmesa.cpp
index 8ec6079bd0..5042f5ed10 100644
--- a/platform/default/headless_backend_osmesa.cpp
+++ b/platform/default/headless_backend_osmesa.cpp
@@ -25,7 +25,7 @@ struct OSMesaImpl : public HeadlessBackend::Impl {
GLubyte fakeBuffer = 0;
};
-gl::glProc HeadlessBackend::initializeExtension(const char* name) {
+gl::ProcAddress HeadlessBackend::initializeExtension(const char* name) {
return OSMesaGetProcAddress(name);
}
diff --git a/platform/default/image.cpp b/platform/default/image.cpp
index ad9d83a08d..447c6bcd66 100644
--- a/platform/default/image.cpp
+++ b/platform/default/image.cpp
@@ -12,7 +12,7 @@ PremultipliedImage decodePNG(const uint8_t*, size_t);
PremultipliedImage decodeJPEG(const uint8_t*, size_t);
PremultipliedImage decodeImage(const std::string& string) {
- const uint8_t* data = reinterpret_cast<const uint8_t*>(string.data());
+ const auto* data = reinterpret_cast<const uint8_t*>(string.data());
const size_t size = string.size();
#if !defined(__ANDROID__) && !defined(__APPLE__)
diff --git a/platform/default/jpeg_reader.cpp b/platform/default/jpeg_reader.cpp
index c5e9d880c0..5f613f9423 100644
--- a/platform/default/jpeg_reader.cpp
+++ b/platform/default/jpeg_reader.cpp
@@ -21,12 +21,12 @@ struct jpeg_stream_wrapper {
};
static void init_source(j_decompress_ptr cinfo) {
- jpeg_stream_wrapper* wrap = reinterpret_cast<jpeg_stream_wrapper*>(cinfo->src);
+ auto* wrap = reinterpret_cast<jpeg_stream_wrapper*>(cinfo->src);
wrap->stream->seekg(0, std::ios_base::beg);
}
static boolean fill_input_buffer(j_decompress_ptr cinfo) {
- jpeg_stream_wrapper* wrap = reinterpret_cast<jpeg_stream_wrapper*>(cinfo->src);
+ auto* wrap = reinterpret_cast<jpeg_stream_wrapper*>(cinfo->src);
wrap->stream->read(reinterpret_cast<char*>(&wrap->buffer[0]), BUF_SIZE);
std::streamsize size = wrap->stream->gcount();
wrap->manager.next_input_byte = wrap->buffer.data();
@@ -36,7 +36,7 @@ static boolean fill_input_buffer(j_decompress_ptr cinfo) {
static void skip(j_decompress_ptr cinfo, long count) {
if (count <= 0) return; // A zero or negative skip count should be treated as a no-op.
- jpeg_stream_wrapper* wrap = reinterpret_cast<jpeg_stream_wrapper*>(cinfo->src);
+ auto* wrap = reinterpret_cast<jpeg_stream_wrapper*>(cinfo->src);
if (wrap->manager.bytes_in_buffer > 0 && count < static_cast<long>(wrap->manager.bytes_in_buffer))
{
@@ -59,7 +59,7 @@ static void attach_stream(j_decompress_ptr cinfo, std::istream* in) {
cinfo->src = (struct jpeg_source_mgr *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(jpeg_stream_wrapper));
}
- jpeg_stream_wrapper * src = reinterpret_cast<jpeg_stream_wrapper*> (cinfo->src);
+ auto * src = reinterpret_cast<jpeg_stream_wrapper*> (cinfo->src);
src->manager.init_source = init_source;
src->manager.fill_input_buffer = fill_input_buffer;
src->manager.skip_input_data = skip;
diff --git a/platform/default/mbgl/gl/headless_backend.cpp b/platform/default/mbgl/gl/headless_backend.cpp
index c105fd6b84..df3a517823 100644
--- a/platform/default/mbgl/gl/headless_backend.cpp
+++ b/platform/default/mbgl/gl/headless_backend.cpp
@@ -9,8 +9,7 @@
namespace mbgl {
-HeadlessBackend::HeadlessBackend() {
-}
+HeadlessBackend::HeadlessBackend() = default;
HeadlessBackend::HeadlessBackend(std::shared_ptr<HeadlessDisplay> display_)
: display(std::move(display_)) {
@@ -33,11 +32,6 @@ void HeadlessBackend::activate() {
assert(hasContext());
impl->activateContext();
-
- if (!extensionsLoaded) {
- gl::InitializeExtensions(initializeExtension);
- extensionsLoaded = true;
- }
}
void HeadlessBackend::deactivate() {
@@ -46,14 +40,12 @@ void HeadlessBackend::deactivate() {
active = false;
}
-void HeadlessBackend::invalidate() {
- assert(false);
+void HeadlessBackend::updateAssumedState() {
+ // no-op
}
-void HeadlessBackend::notifyMapChange(MapChange change) {
- if (mapChangeCallback) {
- mapChangeCallback(change);
- }
+void HeadlessBackend::invalidate() {
+ assert(false);
}
} // namespace mbgl
diff --git a/platform/default/mbgl/gl/headless_backend.hpp b/platform/default/mbgl/gl/headless_backend.hpp
index e632d0feb6..26033acf82 100644
--- a/platform/default/mbgl/gl/headless_backend.hpp
+++ b/platform/default/mbgl/gl/headless_backend.hpp
@@ -1,7 +1,5 @@
#pragma once
-#include <mbgl/gl/extension.hpp>
-
#include <mbgl/map/backend.hpp>
#include <memory>
@@ -17,20 +15,19 @@ public:
HeadlessBackend(std::shared_ptr<HeadlessDisplay>);
~HeadlessBackend() override;
- void invalidate() override;
- void notifyMapChange(MapChange) override;
+ void updateAssumedState() override;
- void setMapChangeCallback(std::function<void(MapChange)>&& cb) { mapChangeCallback = std::move(cb); }
+ void invalidate() override;
struct Impl {
- virtual ~Impl() {}
+ virtual ~Impl() = default;
virtual void activateContext() = 0;
virtual void deactivateContext() {}
};
private:
// Implementation specific functions
- static gl::glProc initializeExtension(const char*);
+ gl::ProcAddress initializeExtension(const char*) override;
void activate() override;
void deactivate() override;
@@ -40,13 +37,10 @@ private:
void createContext();
- std::unique_ptr<Impl> impl;
std::shared_ptr<HeadlessDisplay> display;
+ std::unique_ptr<Impl> impl;
- bool extensionsLoaded = false;
bool active = false;
-
- std::function<void(MapChange)> mapChangeCallback;
};
} // namespace mbgl
diff --git a/platform/default/mbgl/gl/offscreen_view.cpp b/platform/default/mbgl/gl/offscreen_view.cpp
index a517cefad9..5424e03c96 100644
--- a/platform/default/mbgl/gl/offscreen_view.cpp
+++ b/platform/default/mbgl/gl/offscreen_view.cpp
@@ -12,7 +12,7 @@ namespace mbgl {
class OffscreenView::Impl {
public:
Impl(gl::Context& context_, const Size size_) : context(context_), size(std::move(size_)) {
- assert(size);
+ assert(!size.isEmpty());
}
void bind() {
diff --git a/platform/default/mbgl/gl/offscreen_view.hpp b/platform/default/mbgl/gl/offscreen_view.hpp
index bf1a9889cd..eb888272e5 100644
--- a/platform/default/mbgl/gl/offscreen_view.hpp
+++ b/platform/default/mbgl/gl/offscreen_view.hpp
@@ -12,7 +12,7 @@ class Context;
class OffscreenView : public View {
public:
OffscreenView(gl::Context&, Size size = { 256, 256 });
- ~OffscreenView();
+ ~OffscreenView() override;
void bind() override;
diff --git a/platform/default/mbgl/storage/offline_download.cpp b/platform/default/mbgl/storage/offline_download.cpp
index c8aa98d874..235baac12c 100644
--- a/platform/default/mbgl/storage/offline_download.cpp
+++ b/platform/default/mbgl/storage/offline_download.cpp
@@ -5,8 +5,11 @@
#include <mbgl/storage/response.hpp>
#include <mbgl/storage/http_file_source.hpp>
#include <mbgl/style/parser.hpp>
-#include <mbgl/style/sources/geojson_source_impl.hpp>
-#include <mbgl/style/tile_source_impl.hpp>
+#include <mbgl/style/sources/vector_source.hpp>
+#include <mbgl/style/sources/raster_source.hpp>
+#include <mbgl/style/sources/geojson_source.hpp>
+#include <mbgl/style/conversion/json.hpp>
+#include <mbgl/style/conversion/tileset.hpp>
#include <mbgl/text/glyph.hpp>
#include <mbgl/util/mapbox.hpp>
#include <mbgl/util/run_loop.hpp>
@@ -17,6 +20,8 @@
namespace mbgl {
+using namespace style;
+
OfflineDownload::OfflineDownload(int64_t id_,
OfflineRegionDefinition&& definition_,
OfflineDatabase& offlineDatabase_,
@@ -69,38 +74,44 @@ OfflineRegionStatus OfflineDownload::getStatus() const {
result.requiredResourceCountIsPrecise = true;
for (const auto& source : parser.sources) {
- SourceType type = source->baseImpl->type;
-
- switch (type) {
- case SourceType::Vector:
- case SourceType::Raster: {
- style::TileSourceImpl* tileSource =
- static_cast<style::TileSourceImpl*>(source->baseImpl.get());
- const variant<std::string, Tileset>& urlOrTileset = tileSource->getURLOrTileset();
- const uint16_t tileSize = tileSource->getTileSize();
+ SourceType type = source->getType();
+ auto handleTiledSource = [&] (const variant<std::string, Tileset>& urlOrTileset, const uint16_t tileSize) {
if (urlOrTileset.is<Tileset>()) {
result.requiredResourceCount +=
definition.tileCover(type, tileSize, urlOrTileset.get<Tileset>().zoomRange).size();
} else {
result.requiredResourceCount += 1;
- const std::string& url = urlOrTileset.get<std::string>();
+ const auto& url = urlOrTileset.get<std::string>();
optional<Response> sourceResponse = offlineDatabase.get(Resource::source(url));
if (sourceResponse) {
- result.requiredResourceCount +=
- definition.tileCover(type, tileSize, style::TileSourceImpl::parseTileJSON(
- *sourceResponse->data, url, type, tileSize).zoomRange).size();
+ style::conversion::Error error;
+ optional<Tileset> tileset = style::conversion::convertJSON<Tileset>(*sourceResponse->data, error);
+ if (tileset) {
+ result.requiredResourceCount +=
+ definition.tileCover(type, tileSize, (*tileset).zoomRange).size();
+ }
} else {
result.requiredResourceCountIsPrecise = false;
}
}
+ };
+
+ switch (type) {
+ case SourceType::Vector: {
+ const auto& vectorSource = *source->as<VectorSource>();
+ handleTiledSource(vectorSource.getURLOrTileset(), util::tileSize);
break;
}
- case SourceType::GeoJSON: {
- style::GeoJSONSource::Impl* geojsonSource =
- static_cast<style::GeoJSONSource::Impl*>(source->baseImpl.get());
+ case SourceType::Raster: {
+ const auto& rasterSource = *source->as<RasterSource>();
+ handleTiledSource(rasterSource.getURLOrTileset(), rasterSource.getTileSize());
+ break;
+ }
+ case SourceType::GeoJSON: {
+ auto* geojsonSource = source->as<GeoJSONSource>();
if (geojsonSource->getURL()) {
result.requiredResourceCount += 1;
}
@@ -135,40 +146,48 @@ void OfflineDownload::activateDownload() {
parser.parse(*styleResponse.data);
for (const auto& source : parser.sources) {
- SourceType type = source->baseImpl->type;
-
- switch (type) {
- case SourceType::Vector:
- case SourceType::Raster: {
- const style::TileSourceImpl* tileSource =
- static_cast<style::TileSourceImpl*>(source->baseImpl.get());
- const variant<std::string, Tileset>& urlOrTileset = tileSource->getURLOrTileset();
- const uint16_t tileSize = tileSource->getTileSize();
+ SourceType type = source->getType();
+ auto handleTiledSource = [&] (const variant<std::string, Tileset>& urlOrTileset, const uint16_t tileSize) {
if (urlOrTileset.is<Tileset>()) {
queueTiles(type, tileSize, urlOrTileset.get<Tileset>());
} else {
- const std::string& url = urlOrTileset.get<std::string>();
+ const auto& url = urlOrTileset.get<std::string>();
status.requiredResourceCountIsPrecise = false;
status.requiredResourceCount++;
requiredSourceURLs.insert(url);
ensureResource(Resource::source(url), [=](Response sourceResponse) {
- queueTiles(type, tileSize, style::TileSourceImpl::parseTileJSON(
- *sourceResponse.data, url, type, tileSize));
-
- requiredSourceURLs.erase(url);
- if (requiredSourceURLs.empty()) {
- status.requiredResourceCountIsPrecise = true;
+ style::conversion::Error error;
+ optional<Tileset> tileset = style::conversion::convertJSON<Tileset>(*sourceResponse.data, error);
+ if (tileset) {
+ util::mapbox::canonicalizeTileset(*tileset, url, type, tileSize);
+ queueTiles(type, tileSize, *tileset);
+
+ requiredSourceURLs.erase(url);
+ if (requiredSourceURLs.empty()) {
+ status.requiredResourceCountIsPrecise = true;
+ }
}
});
}
+ };
+
+ switch (type) {
+ case SourceType::Vector: {
+ const auto& vectorSource = *source->as<VectorSource>();
+ handleTiledSource(vectorSource.getURLOrTileset(), util::tileSize);
+ break;
+ }
+
+ case SourceType::Raster: {
+ const auto& rasterSource = *source->as<RasterSource>();
+ handleTiledSource(rasterSource.getURLOrTileset(), rasterSource.getTileSize());
break;
}
case SourceType::GeoJSON: {
- style::GeoJSONSource::Impl* geojsonSource =
- static_cast<style::GeoJSONSource::Impl*>(source->baseImpl.get());
+ const auto* geojsonSource = static_cast<const GeoJSONSource*>(source.get());
if (geojsonSource->getURL()) {
queueResource(Resource::source(*geojsonSource->getURL()));
diff --git a/platform/default/mbgl/util/default_styles.cpp b/platform/default/mbgl/util/default_styles.cpp
index 17cc2f5740..5f4ca862fe 100644
--- a/platform/default/mbgl/util/default_styles.cpp
+++ b/platform/default/mbgl/util/default_styles.cpp
@@ -4,12 +4,14 @@ namespace mbgl {
namespace util {
namespace default_styles {
-const DefaultStyle streets = { "mapbox://styles/mapbox/streets-v9", "Streets" };
-const DefaultStyle outdoors = { "mapbox://styles/mapbox/outdoors-v9", "Outdoors" };
-const DefaultStyle light = { "mapbox://styles/mapbox/light-v9", "Light" };
-const DefaultStyle dark = { "mapbox://styles/mapbox/dark-v9", "Dark" };
-const DefaultStyle satellite = { "mapbox://styles/mapbox/satellite-v9", "Satellite" };
-const DefaultStyle satelliteStreets = { "mapbox://styles/mapbox/satellite-streets-v9", "Satellite Streets" };
+const DefaultStyle streets = { "mapbox://styles/mapbox/streets-v10", "Streets", 10 };
+const DefaultStyle outdoors = { "mapbox://styles/mapbox/outdoors-v10", "Outdoors", 10 };
+const DefaultStyle light = { "mapbox://styles/mapbox/light-v9", "Light", 9 };
+const DefaultStyle dark = { "mapbox://styles/mapbox/dark-v9", "Dark", 9 };
+const DefaultStyle satellite = { "mapbox://styles/mapbox/satellite-v9", "Satellite", 9 };
+const DefaultStyle satelliteStreets = { "mapbox://styles/mapbox/satellite-streets-v10", "Satellite Streets", 10 };
+const DefaultStyle trafficDay = { "mapbox://styles/mapbox/traffic-day-v2", "Traffic Day", 2 };
+const DefaultStyle trafficNight = { "mapbox://styles/mapbox/traffic-night-v2", "Traffic Night", 2 };
} // namespace default_styles
} // end namespace util
diff --git a/platform/default/mbgl/util/default_styles.hpp b/platform/default/mbgl/util/default_styles.hpp
index eb7e034722..466102d623 100644
--- a/platform/default/mbgl/util/default_styles.hpp
+++ b/platform/default/mbgl/util/default_styles.hpp
@@ -10,6 +10,7 @@ namespace default_styles {
struct DefaultStyle {
const char* url;
const char* name;
+ const unsigned currentVersion;
};
extern const DefaultStyle streets;
@@ -18,14 +19,15 @@ extern const DefaultStyle light;
extern const DefaultStyle dark;
extern const DefaultStyle satellite;
extern const DefaultStyle satelliteStreets;
+extern const DefaultStyle trafficDay;
+extern const DefaultStyle trafficNight;
const DefaultStyle orderedStyles[] = {
streets, outdoors, light, dark, satellite, satelliteStreets,
+ trafficDay, trafficNight,
};
const size_t numOrderedStyles = sizeof(orderedStyles) / sizeof(DefaultStyle);
-static const unsigned currentVersion = 9;
-
} // end namespace default_styles
} // end namespace util
} // end namespace mbgl
diff --git a/platform/default/png_reader.cpp b/platform/default/png_reader.cpp
index d694f43405..4d4ee29d1f 100644
--- a/platform/default/png_reader.cpp
+++ b/platform/default/png_reader.cpp
@@ -40,7 +40,7 @@ static void user_warning_fn(png_structp, png_const_charp warning_msg) {
}
static void png_read_data(png_structp png_ptr, png_bytep data, png_size_t length) {
- std::istream* fin = reinterpret_cast<std::istream*>(png_get_io_ptr(png_ptr));
+ auto* fin = reinterpret_cast<std::istream*>(png_get_io_ptr(png_ptr));
fin->read(reinterpret_cast<char*>(data), length);
std::streamsize read_count = fin->gcount();
if (read_count < 0 || static_cast<png_size_t>(read_count) != length)
@@ -98,7 +98,7 @@ PremultipliedImage decodePNG(const uint8_t* data, size_t size) {
int color_type = 0;
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, nullptr, nullptr, nullptr);
- UnassociatedImage image({ width, height });
+ UnassociatedImage image({ static_cast<uint32_t>(width), static_cast<uint32_t>(height) });
if (color_type == PNG_COLOR_TYPE_PALETTE)
png_set_expand(png_ptr);
diff --git a/platform/default/resources/attribution-logo.svg b/platform/default/resources/attribution-logo.svg
index f6edd35cd2..d0de0c6904 100644
--- a/platform/default/resources/attribution-logo.svg
+++ b/platform/default/resources/attribution-logo.svg
@@ -1 +1,91 @@
-<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.1" width="65" height="20"><defs/><metadata><rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/><dc:title/></cc:Work></rdf:RDF></metadata><g transform="translate(-261.8483,-98.50395)"><g transform="matrix(0.17441836,0,0,0.17441836,220.52282,29.229342)" style="opacity:0.25;fill:#ffffff;stroke:#000000;stroke-width:17.20002365;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"><path d="M 5.28 1.5 C 4.54 1.56 3.9 2.25 3.91 3 l 0 11.88 c 0.02 0.77 0.72 1.47 1.5 1.47 l 1.75 0 c 0.78 0 1.48 -0.69 1.5 -1.47 l 0 -4.28 0.72 1.19 c 0.53 0.87 2.03 0.87 2.56 0 l 0.72 -1.19 0 4.28 c 0.02 0.76 0.7 1.45 1.47 1.47 l 1.75 0 c 0.78 0 1.48 -0.69 1.5 -1.47 l 0 -0.16 c 1.02 1.12 2.46 1.81 4.09 1.81 l 4.09 0 0 1.47 c -0 0.78 0.69 1.48 1.47 1.5 l 1.75 0 c 0.79 -0 1.5 -0.71 1.5 -1.5 l 0.02 -1.47 c 1.72 0 3.08 -0.64 4.14 -1.69 l 0 0.19 c 0 0.39 0.16 0.79 0.44 1.06 0.28 0.28 0.67 0.44 1.06 0.44 l 3.31 0 c 2.03 0 3.85 -1.06 4.91 -2.69 1.05 1.61 2.84 2.69 4.88 2.69 1.03 0 1.98 -0.27 2.81 -0.75 0.28 0.35 0.73 0.57 1.19 0.56 l 2.12 0 c 0.48 0.01 0.97 -0.23 1.25 -0.62 l 0.91 -1.28 0.91 1.28 c 0.28 0.39 0.74 0.63 1.22 0.62 l 2.16 0 C 62.67 16.33 63.42 14.89 62.81 14 L 60.22 10.38 62.62 7 C 63.26 6.11 62.5 4.62 61.41 4.62 l -2.16 0 C 58.78 4.62 58.31 4.86 58.03 5.25 L 57.31 6.28 56.56 5.25 C 56.29 4.86 55.82 4.62 55.34 4.62 l -2.16 0 c -0.49 -0 -0.97 0.25 -1.25 0.66 -0.86 -0.51 -1.84 -0.81 -2.91 -0.81 -2.03 0 -3.83 1.08 -4.88 2.69 C 43.1 5.53 41.27 4.47 39.19 4.47 L 39.19 3 C 39.19 2.61 39.03 2.21 38.75 1.94 38.47 1.66 38.08 1.5 37.69 1.5 l -1.75 0 c -0.71 0 -1.5 0.83 -1.5 1.5 l 0 3.16 C 33.38 5.1 31.96 4.47 30.38 4.47 l -3.34 0 c -0.77 0.02 -1.47 0.72 -1.47 1.5 l 0 0.31 c -1.02 -1.12 -2.46 -1.81 -4.09 -1.81 -1.63 0 -3.07 0.7 -4.09 1.81 L 17.38 3 c -0 -0.79 -0.71 -1.5 -1.5 -1.5 L 14.5 1.5 C 13.55 1.5 12.28 1.87 11.66 2.94 l -1 1.69 -1 -1.69 C 9.03 1.87 7.77 1.5 6.81 1.5 l -1.41 0 C 5.36 1.5 5.32 1.5 5.28 1.5 z m 16.19 7.72 c 0.53 0 0.94 0.35 0.94 1.28 l 0 1.28 -0.94 0 c -0.52 0 -0.94 -0.38 -0.94 -1.28 -0 -0.9 0.42 -1.28 0.94 -1.28 z m 8.81 0 c 0.83 0 1.18 0.68 1.19 1.28 0.01 0.94 -0.62 1.28 -1.19 1.28 z m 8.72 0 c 0.72 0 1.37 0.6 1.37 1.28 0 0.77 -0.51 1.28 -1.37 1.28 z m 10.03 0 c 0.58 0 1.09 0.5 1.09 1.28 0 0.78 -0.51 1.28 -1.09 1.28 -0.58 0 -1.12 -0.5 -1.12 -1.28 0 -0.78 0.54 -1.28 1.12 -1.28 z" transform="matrix(5.7333414,0,0,5.7333414,236.93308,397.17498)" style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:17.20002365;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"/></g><g transform="matrix(0.17441836,0,0,0.17441836,220.52282,29.229342)" style="fill:#ffffff"><path d="m 5.41 3 0 12 1.75 0 0 -9.91 3.5 5.94 3.47 -5.94 0 9.91 1.75 0 0 -12 L 14.5 3 C 13.8 3 13.25 3.16 12.94 3.69 L 10.66 7.59 8.38 3.69 C 8.07 3.16 7.51 3 6.81 3 z M 36 3 l 0 12.03 3.25 0 c 2.44 0 4.38 -1.91 4.38 -4.53 0 -2.62 -1.93 -4.47 -4.38 -4.47 C 38.7 6.03 38.32 6 37.75 6 l 0 -3 z M 21.47 5.97 c -2.44 0 -4.19 1.91 -4.19 4.53 0 2.62 1.75 4.53 4.19 4.53 l 4.19 0 0 -4.53 c 0 -2.62 -1.75 -4.53 -4.19 -4.53 z m 27.56 0 c -2.41 0 -4.38 2.03 -4.38 4.53 0 2.5 1.97 4.53 4.38 4.53 2.41 0 4.34 -2.03 4.34 -4.53 0 -2.5 -1.94 -4.53 -4.34 -4.53 z m -22 0.03 0 12 1.75 0 0 -2.97 c 0.57 0 1.04 -0 1.59 0 2.44 0 4.34 -1.91 4.34 -4.53 0 -2.62 -1.9 -4.5 -4.34 -4.5 z m 26.16 0 3.03 4.38 -3.19 4.62 2.12 0 L 57.31 11.91 59.44 15 61.59 15 58.38 10.38 61.41 6 59.25 6 57.31 8.81 55.34 6 z M 21.47 7.72 c 1.4 0 2.44 1.19 2.44 2.78 l 0 2.78 -2.44 0 c -1.4 0 -2.44 -1.21 -2.44 -2.78 -0 -1.57 1.04 -2.78 2.44 -2.78 z m 27.56 0 c 1.44 0 2.59 1.24 2.59 2.78 0 1.54 -1.15 2.78 -2.59 2.78 -1.44 0 -2.62 -1.24 -2.62 -2.78 0 -1.54 1.18 -2.78 2.62 -2.78 z m -20.25 0.03 1.59 0 c 1.59 0 2.59 1.28 2.59 2.75 0 1.47 -1.13 2.78 -2.59 2.78 l -1.59 0 z m 8.97 0 1.5 0 c 1.47 0 2.62 1.28 2.62 2.75 0 1.47 -1.04 2.78 -2.62 2.78 l -1.5 0 z" transform="matrix(5.7333414,0,0,5.7333414,236.93308,397.17498)" style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"/></g></g></svg> \ No newline at end of file
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 21.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 84.49 21" style="enable-background:new 0 0 84.49 21;" xml:space="preserve">
+<style type="text/css">
+ .st0{opacity:0.9;fill:#FFFFFF;enable-background:new ;}
+ .st1{opacity:0.35;enable-background:new ;}
+</style>
+<g>
+ <path class="st0" d="M83.25,14.26c0,0.12-0.09,0.21-0.21,0.21h-1.61c-0.13,0-0.24-0.06-0.3-0.17l-1.44-2.39l-1.44,2.39
+ c-0.06,0.11-0.18,0.17-0.3,0.17h-1.61c-0.04,0-0.08-0.01-0.12-0.03c-0.09-0.06-0.13-0.19-0.06-0.28l0,0l2.43-3.68L76.2,6.84
+ c-0.02-0.03-0.03-0.07-0.03-0.12c0-0.12,0.09-0.21,0.21-0.21h1.61c0.13,0,0.24,0.06,0.3,0.17l1.41,2.36l1.4-2.35
+ c0.06-0.11,0.18-0.17,0.3-0.17H83c0.04,0,0.08,0.01,0.12,0.03c0.09,0.06,0.13,0.19,0.06,0.28l0,0l-2.37,3.63l2.43,3.67
+ C83.24,14.18,83.25,14.22,83.25,14.26z"/>
+ <path class="st0" d="M66.24,9.59c-0.39-1.88-1.96-3.28-3.84-3.28c-1.03,0-2.03,0.42-2.73,1.18V3.51c0-0.13-0.1-0.23-0.23-0.23h-1.4
+ c-0.13,0-0.23,0.11-0.23,0.23v10.72c0,0.13,0.1,0.23,0.23,0.23h1.4c0.13,0,0.23-0.11,0.23-0.23V13.5c0.71,0.75,1.7,1.18,2.73,1.18
+ c1.88,0,3.45-1.41,3.84-3.29C66.37,10.79,66.37,10.18,66.24,9.59L66.24,9.59z M62.08,13c-1.32,0-2.39-1.11-2.41-2.48v-0.06
+ c0.02-1.38,1.09-2.48,2.41-2.48s2.42,1.12,2.42,2.51S63.41,13,62.08,13z"/>
+ <path class="st0" d="M71.67,6.32c-1.98-0.01-3.72,1.35-4.16,3.29c-0.13,0.59-0.13,1.19,0,1.77c0.44,1.94,2.17,3.32,4.17,3.3
+ c2.35,0,4.26-1.87,4.26-4.19S74.04,6.32,71.67,6.32z M71.65,13.01c-1.33,0-2.42-1.12-2.42-2.51s1.08-2.52,2.42-2.52
+ c1.33,0,2.42,1.12,2.42,2.51S72.99,13,71.65,13.01L71.65,13.01z"/>
+ <path class="st1" d="M62.08,7.98c-1.32,0-2.39,1.11-2.41,2.48v0.06C59.68,11.9,60.75,13,62.08,13s2.42-1.12,2.42-2.51
+ S63.41,7.98,62.08,7.98z M62.08,11.76c-0.63,0-1.14-0.56-1.17-1.25v-0.04c0.01-0.69,0.54-1.25,1.17-1.25
+ c0.63,0,1.17,0.57,1.17,1.27C63.24,11.2,62.73,11.76,62.08,11.76z"/>
+ <path class="st1" d="M71.65,7.98c-1.33,0-2.42,1.12-2.42,2.51S70.32,13,71.65,13s2.42-1.12,2.42-2.51S72.99,7.98,71.65,7.98z
+ M71.65,11.76c-0.64,0-1.17-0.57-1.17-1.27c0-0.7,0.53-1.26,1.17-1.26s1.17,0.57,1.17,1.27C72.82,11.21,72.29,11.76,71.65,11.76z"
+ />
+ <path class="st0" d="M45.74,6.53h-1.4c-0.13,0-0.23,0.11-0.23,0.23v0.73c-0.71-0.75-1.7-1.18-2.73-1.18
+ c-2.17,0-3.94,1.87-3.94,4.19s1.77,4.19,3.94,4.19c1.04,0,2.03-0.43,2.73-1.19v0.73c0,0.13,0.1,0.23,0.23,0.23h1.4
+ c0.13,0,0.23-0.11,0.23-0.23V6.74c0-0.12-0.09-0.22-0.22-0.22C45.75,6.53,45.75,6.53,45.74,6.53z M44.12,10.53
+ C44.11,11.9,43.03,13,41.71,13s-2.42-1.12-2.42-2.51s1.08-2.52,2.4-2.52c1.33,0,2.39,1.11,2.41,2.48L44.12,10.53z"/>
+ <path class="st1" d="M41.71,7.98c-1.33,0-2.42,1.12-2.42,2.51S40.37,13,41.71,13s2.39-1.11,2.41-2.48v-0.06
+ C44.1,9.09,43.03,7.98,41.71,7.98z M40.55,10.49c0-0.7,0.52-1.27,1.17-1.27c0.64,0,1.14,0.56,1.17,1.25v0.04
+ c-0.01,0.68-0.53,1.24-1.17,1.24C41.08,11.75,40.55,11.19,40.55,10.49z"/>
+ <path class="st0" d="M52.41,6.32c-1.03,0-2.03,0.42-2.73,1.18V6.75c0-0.13-0.1-0.23-0.23-0.23h-1.4c-0.13,0-0.23,0.11-0.23,0.23
+ v10.72c0,0.13,0.1,0.23,0.23,0.23h1.4c0.13,0,0.23-0.1,0.23-0.23V13.5c0.71,0.75,1.7,1.18,2.74,1.18c2.17,0,3.94-1.87,3.94-4.19
+ S54.58,6.32,52.41,6.32z M52.08,13.01c-1.32,0-2.39-1.11-2.42-2.48v-0.07c0.02-1.38,1.09-2.49,2.4-2.49c1.32,0,2.41,1.12,2.41,2.51
+ S53.4,13,52.08,13.01L52.08,13.01z"/>
+ <path class="st1" d="M52.08,7.98c-1.32,0-2.39,1.11-2.42,2.48v0.06c0.03,1.38,1.1,2.48,2.42,2.48s2.41-1.12,2.41-2.51
+ S53.4,7.98,52.08,7.98z M52.08,11.76c-0.63,0-1.14-0.56-1.17-1.25v-0.04c0.01-0.69,0.54-1.25,1.17-1.25c0.63,0,1.17,0.58,1.17,1.27
+ S52.72,11.76,52.08,11.76z"/>
+ <path class="st0" d="M36.08,14.24c0,0.13-0.1,0.23-0.23,0.23h-1.41c-0.13,0-0.23-0.11-0.23-0.23V9.68c0-0.98-0.74-1.71-1.62-1.71
+ c-0.8,0-1.46,0.7-1.59,1.62l0.01,4.66c0,0.13-0.11,0.23-0.23,0.23h-1.41c-0.13,0-0.23-0.11-0.23-0.23V9.68
+ c0-0.98-0.74-1.71-1.62-1.71c-0.85,0-1.54,0.79-1.6,1.8v4.48c0,0.13-0.1,0.23-0.23,0.23h-1.4c-0.13,0-0.23-0.11-0.23-0.23V6.74
+ c0.01-0.13,0.1-0.22,0.23-0.22h1.4c0.13,0,0.22,0.11,0.23,0.22V7.4c0.5-0.68,1.3-1.09,2.16-1.1h0.03c1.09,0,2.09,0.6,2.6,1.55
+ c0.45-0.95,1.4-1.55,2.44-1.56c1.62,0,2.93,1.25,2.9,2.78L36.08,14.24z"/>
+ <path class="st1" d="M84.34,13.59l-0.07-0.13l-1.96-2.99l1.94-2.95c0.44-0.67,0.26-1.56-0.41-2.02c-0.02,0-0.03,0-0.04-0.01
+ c-0.23-0.15-0.5-0.22-0.78-0.22h-1.61c-0.56,0-1.08,0.29-1.37,0.78L79.72,6.6l-0.34-0.56C79.09,5.56,78.57,5.27,78,5.27h-1.6
+ c-0.6,0-1.13,0.37-1.35,0.92c-2.19-1.66-5.28-1.47-7.26,0.45c-0.35,0.34-0.65,0.72-0.89,1.14c-0.9-1.62-2.58-2.72-4.5-2.72
+ c-0.5,0-1.01,0.07-1.48,0.23V3.51c0-0.82-0.66-1.48-1.47-1.48h-1.4c-0.81,0-1.47,0.66-1.47,1.47v3.75
+ c-0.95-1.36-2.5-2.18-4.17-2.19c-0.74,0-1.46,0.16-2.12,0.47c-0.24-0.17-0.54-0.26-0.84-0.26h-1.4c-0.45,0-0.87,0.21-1.15,0.56
+ c-0.02-0.03-0.04-0.05-0.07-0.08c-0.28-0.3-0.68-0.47-1.09-0.47h-1.39c-0.3,0-0.6,0.09-0.84,0.26c-0.67-0.3-1.39-0.46-2.12-0.46
+ c-1.83,0-3.43,1-4.37,2.5c-0.2-0.46-0.48-0.89-0.83-1.25c-0.8-0.81-1.89-1.25-3.02-1.25h-0.01c-0.89,0.01-1.75,0.33-2.46,0.88
+ c-0.74-0.57-1.64-0.88-2.57-0.88H28.1c-0.29,0-0.58,0.03-0.86,0.11c-0.28,0.06-0.56,0.16-0.82,0.28c-0.21-0.12-0.45-0.18-0.7-0.18
+ h-1.4c-0.82,0-1.47,0.66-1.47,1.47v7.5c0,0.82,0.66,1.47,1.47,1.47h1.4c0.82,0,1.48-0.66,1.48-1.48l0,0V9.79
+ c0.03-0.36,0.23-0.59,0.36-0.59c0.18,0,0.38,0.18,0.38,0.47v4.57c0,0.82,0.66,1.47,1.47,1.47h1.41c0.82,0,1.47-0.66,1.47-1.47
+ l-0.01-4.57c0.06-0.32,0.25-0.47,0.35-0.47c0.18,0,0.38,0.18,0.38,0.47v4.57c0,0.82,0.66,1.47,1.47,1.47h1.41
+ c0.82,0,1.47-0.66,1.47-1.47v-0.38c0.96,1.29,2.46,2.06,4.06,2.06c0.74,0,1.46-0.16,2.12-0.47c0.24,0.17,0.54,0.26,0.84,0.26h1.39
+ c0.3,0,0.6-0.09,0.84-0.26v2.01c0,0.82,0.66,1.47,1.47,1.47h1.4c0.82,0,1.47-0.66,1.47-1.47v-1.77c0.48,0.15,0.99,0.23,1.49,0.22
+ c1.7,0,3.22-0.87,4.17-2.2v0.52c0,0.82,0.66,1.47,1.47,1.47h1.4c0.3,0,0.6-0.09,0.84-0.26c0.66,0.31,1.39,0.47,2.12,0.47
+ c1.92,0,3.6-1.1,4.49-2.73c1.54,2.65,4.95,3.53,7.58,1.98c0.18-0.11,0.36-0.22,0.53-0.36c0.22,0.55,0.76,0.91,1.35,0.9H78
+ c0.56,0,1.08-0.29,1.37-0.78l0.37-0.61l0.37,0.61c0.29,0.48,0.81,0.78,1.38,0.78h1.6c0.81,0,1.46-0.66,1.45-1.46
+ C84.49,14.02,84.44,13.8,84.34,13.59L84.34,13.59z M35.86,14.47h-1.41c-0.13,0-0.23-0.11-0.23-0.23V9.68
+ c0-0.98-0.74-1.71-1.62-1.71c-0.8,0-1.46,0.7-1.59,1.62l0.01,4.66c0,0.13-0.1,0.23-0.23,0.23h-1.41c-0.13,0-0.23-0.11-0.23-0.23
+ V9.68c0-0.98-0.74-1.71-1.62-1.71c-0.85,0-1.54,0.79-1.6,1.8v4.48c0,0.13-0.1,0.23-0.23,0.23h-1.4c-0.13,0-0.23-0.11-0.23-0.23
+ V6.74c0.01-0.13,0.11-0.22,0.23-0.22h1.4c0.13,0,0.22,0.11,0.23,0.22V7.4c0.5-0.68,1.3-1.09,2.16-1.1h0.03
+ c1.09,0,2.09,0.6,2.6,1.55c0.45-0.95,1.4-1.55,2.44-1.56c1.62,0,2.93,1.25,2.9,2.78l0.01,5.16C36.09,14.36,35.98,14.46,35.86,14.47
+ L35.86,14.47z M45.97,14.24c0,0.13-0.1,0.23-0.23,0.23h-1.4c-0.13,0-0.23-0.11-0.23-0.23V13.5c-0.7,0.76-1.69,1.18-2.72,1.18
+ c-2.17,0-3.94-1.87-3.94-4.19s1.77-4.19,3.94-4.19c1.03,0,2.02,0.43,2.73,1.18V6.74c0-0.13,0.1-0.23,0.23-0.23h1.4
+ c0.12-0.01,0.22,0.08,0.23,0.21c0,0.01,0,0.01,0,0.02v7.51h-0.01V14.24z M52.41,14.67c-1.03,0-2.02-0.43-2.73-1.18v3.97
+ c0,0.13-0.1,0.23-0.23,0.23h-1.4c-0.13,0-0.23-0.1-0.23-0.23V6.75c0-0.13,0.1-0.22,0.23-0.22h1.4c0.13,0,0.23,0.11,0.23,0.23v0.73
+ c0.71-0.76,1.7-1.18,2.73-1.18c2.17,0,3.94,1.86,3.94,4.18S54.58,14.67,52.41,14.67z M66.24,11.39c-0.39,1.87-1.96,3.29-3.84,3.29
+ c-1.03,0-2.02-0.43-2.73-1.18v0.73c0,0.13-0.1,0.23-0.23,0.23h-1.4c-0.13,0-0.23-0.11-0.23-0.23V3.51c0-0.13,0.1-0.23,0.23-0.23
+ h1.4c0.13,0,0.23,0.11,0.23,0.23v3.97c0.71-0.75,1.7-1.18,2.73-1.17c1.88,0,3.45,1.4,3.84,3.28C66.37,10.19,66.37,10.8,66.24,11.39
+ L66.24,11.39L66.24,11.39z M71.67,14.68c-2,0.01-3.73-1.35-4.17-3.3c-0.13-0.59-0.13-1.19,0-1.77c0.44-1.94,2.17-3.31,4.17-3.3
+ c2.36,0,4.26,1.87,4.26,4.19S74.03,14.68,71.67,14.68L71.67,14.68z M83.04,14.47h-1.61c-0.13,0-0.24-0.06-0.3-0.17l-1.44-2.39
+ l-1.44,2.39c-0.06,0.11-0.18,0.17-0.3,0.17h-1.61c-0.04,0-0.08-0.01-0.12-0.03c-0.09-0.06-0.13-0.19-0.06-0.28l0,0l2.43-3.68
+ L76.2,6.84c-0.02-0.03-0.03-0.07-0.03-0.12c0-0.12,0.09-0.21,0.21-0.21h1.61c0.13,0,0.24,0.06,0.3,0.17l1.41,2.36l1.41-2.36
+ c0.06-0.11,0.18-0.17,0.3-0.17h1.61c0.04,0,0.08,0.01,0.12,0.03c0.09,0.06,0.13,0.19,0.06,0.28l0,0l-2.38,3.64l2.43,3.67
+ c0.02,0.03,0.03,0.07,0.03,0.12C83.25,14.38,83.16,14.47,83.04,14.47L83.04,14.47L83.04,14.47z"/>
+ <path class="st0" d="M10.5,1.24c-5.11,0-9.25,4.15-9.25,9.25s4.15,9.25,9.25,9.25s9.25-4.15,9.25-9.25
+ C19.75,5.38,15.61,1.24,10.5,1.24z M14.89,12.77c-1.93,1.93-4.78,2.31-6.7,2.31c-0.7,0-1.41-0.05-2.1-0.16c0,0-1.02-5.64,2.14-8.81
+ c0.83-0.83,1.95-1.28,3.13-1.28c1.27,0,2.49,0.51,3.39,1.42C16.59,8.09,16.64,11,14.89,12.77z"/>
+ <path class="st1" d="M10.5-0.01C4.7-0.01,0,4.7,0,10.49s4.7,10.5,10.5,10.5S21,16.29,21,10.49C20.99,4.7,16.3-0.01,10.5-0.01z
+ M10.5,19.74c-5.11,0-9.25-4.15-9.25-9.25s4.14-9.26,9.25-9.26s9.25,4.15,9.25,9.25C19.75,15.61,15.61,19.74,10.5,19.74z"/>
+ <path class="st1" d="M14.74,6.25C12.9,4.41,9.98,4.35,8.23,6.1c-3.16,3.17-2.14,8.81-2.14,8.81s5.64,1.02,8.81-2.14
+ C16.64,11,16.59,8.09,14.74,6.25z M12.47,10.34l-0.91,1.87l-0.9-1.87L8.8,9.43l1.86-0.9l0.9-1.87l0.91,1.87l1.86,0.9L12.47,10.34z"
+ />
+ <polygon class="st0" points="14.33,9.43 12.47,10.34 11.56,12.21 10.66,10.34 8.8,9.43 10.66,8.53 11.56,6.66 12.47,8.53 "/>
+</g>
+</svg>
diff --git a/platform/default/resources/mapbox-icon-large.svg b/platform/default/resources/mapbox-icon-large.svg
deleted file mode 100644
index 099af251bf..0000000000
--- a/platform/default/resources/mapbox-icon-large.svg
+++ /dev/null
@@ -1,84 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="180"
- height="180.00002"
- id="svg7945"
- version="1.1"
- inkscape:version="0.91 r13725"
- sodipodi:docname="mapbox-icon-large.svg"
- inkscape:export-filename="/home/leith/mb/sirius-android/Sirius/src/main/res/mipmap-mdpi/mapbox_app_icon.png"
- inkscape:export-xdpi="23.999998"
- inkscape:export-ydpi="23.999998">
- <defs
- id="defs7947" />
- <sodipodi:namedview
- id="base"
- pagecolor="#3bb2d0"
- bordercolor="#666666"
- borderopacity="1.0"
- inkscape:pageopacity="1"
- inkscape:pageshadow="2"
- inkscape:zoom="1"
- inkscape:cx="-436.70454"
- inkscape:cy="68.540005"
- inkscape:document-units="px"
- inkscape:current-layer="layer1"
- showgrid="true"
- inkscape:window-width="3054"
- inkscape:window-height="1746"
- inkscape:window-x="146"
- inkscape:window-y="54"
- inkscape:window-maximized="1"
- fit-margin-top="0"
- fit-margin-left="0"
- fit-margin-right="0"
- fit-margin-bottom="0">
- <inkscape:grid
- type="xygrid"
- id="grid7978"
- empspacing="5"
- visible="true"
- enabled="true"
- snapvisiblegridlinesonly="true" />
- </sodipodi:namedview>
- <metadata
- id="metadata7950">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title></dc:title>
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- inkscape:label="Layer 1"
- inkscape:groupmode="layer"
- id="layer1"
- transform="translate(-240,-272.36215)">
- <rect
- style="color:#000000;fill:none;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- id="rect7932"
- width="180"
- height="180.00002"
- x="240"
- y="272.36215" />
- <path
- inkscape:connector-curvature="0"
- style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
- d="m 270,295.58809 0,133.54838 23.22581,0 0,-101.25 36.77418,62.47974 36.7742,-62.47974 0,101.25 23.22581,0 0,-133.54838 -17.41936,0 c -8.07193,0 -15.10353,2.202 -18.93134,8.70967 l -23.64931,40.16129 -23.64929,-40.16129 c -3.82799,-6.50767 -10.85941,-8.73559 -18.93134,-8.70967 z"
- id="path6294"
- sodipodi:nodetypes="cccccccccsccccc" />
- </g>
-</svg>
diff --git a/platform/default/run_loop.cpp b/platform/default/run_loop.cpp
index 1ebbade7ab..98d1badcb5 100644
--- a/platform/default/run_loop.cpp
+++ b/platform/default/run_loop.cpp
@@ -13,11 +13,7 @@ namespace {
using namespace mbgl::util;
static ThreadLocal<RunLoop>& current = *new ThreadLocal<RunLoop>;
-#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
-void dummyCallback(uv_async_t*, int) {}
-#else
void dummyCallback(uv_async_t*) {}
-#endif
} // namespace
@@ -84,13 +80,8 @@ public:
RunLoop::RunLoop(Type type) : impl(std::make_unique<Impl>()) {
switch (type) {
case Type::New:
-#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
- impl->loop = uv_loop_new();
- if (impl->loop == nullptr) {
-#else
impl->loop = new uv_loop_t;
if (uv_loop_init(impl->loop) != 0) {
-#endif
throw std::runtime_error("Failed to initialize loop.");
}
break;
@@ -129,14 +120,10 @@ RunLoop::~RunLoop() {
impl->async.reset();
runOnce();
-#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
- uv_loop_delete(impl->loop);
-#else
if (uv_loop_close(impl->loop) == UV_EBUSY) {
- throw std::runtime_error("Failed to close loop.");
+ assert(false && "Failed to close loop.");
}
delete impl->loop;
-#endif
}
LOOP_HANDLE RunLoop::getLoopHandle() {
diff --git a/platform/default/sqlite3.cpp b/platform/default/sqlite3.cpp
index 498ac02b2e..0707f9255c 100644
--- a/platform/default/sqlite3.cpp
+++ b/platform/default/sqlite3.cpp
@@ -30,7 +30,7 @@ public:
const int error = sqlite3_close(db);
if (error != SQLITE_OK) {
- throw Exception { error, sqlite3_errmsg(db) };
+ mbgl::Log::Error(mbgl::Event::Database, "%s (Code %i)", sqlite3_errmsg(db), error);
}
}
@@ -107,12 +107,7 @@ Database &Database::operator=(Database &&other) {
return *this;
}
-Database::~Database() {
-}
-
-Database::operator bool() const {
- return impl.operator bool();
-}
+Database::~Database() = default;
void Database::setBusyTimeout(std::chrono::milliseconds timeout) {
assert(impl);
@@ -155,12 +150,7 @@ Statement &Statement::operator=(Statement &&other) {
return *this;
}
-Statement::~Statement() {
-}
-
-Statement::operator bool() const {
- return impl.operator bool();
-}
+Statement::~Statement() = default;
template <> void Statement::bind(int offset, std::nullptr_t) {
assert(impl);
@@ -322,7 +312,7 @@ template <> std::string Statement::get(int offset) {
template <> std::vector<uint8_t> Statement::get(int offset) {
assert(impl);
- const uint8_t* begin = reinterpret_cast<const uint8_t*>(sqlite3_column_blob(impl->stmt, offset));
+ const auto* begin = reinterpret_cast<const uint8_t*>(sqlite3_column_blob(impl->stmt, offset));
const uint8_t* end = begin + sqlite3_column_bytes(impl->stmt, offset);
return { begin, end };
}
diff --git a/platform/default/sqlite3.hpp b/platform/default/sqlite3.hpp
index 2cbc3cf48b..82e3ceff6d 100644
--- a/platform/default/sqlite3.hpp
+++ b/platform/default/sqlite3.hpp
@@ -46,8 +46,6 @@ public:
~Database();
Database &operator=(Database &&);
- explicit operator bool() const;
-
void setBusyTimeout(std::chrono::milliseconds);
void exec(const std::string &sql);
Statement prepare(const char *query);
@@ -69,8 +67,6 @@ public:
~Statement();
Statement &operator=(Statement &&);
- explicit operator bool() const;
-
template <typename T> void bind(int offset, T value);
// Text
diff --git a/platform/default/timer.cpp b/platform/default/timer.cpp
index 473f059133..90a85bfc1f 100644
--- a/platform/default/timer.cpp
+++ b/platform/default/timer.cpp
@@ -4,19 +4,13 @@
#include <uv.h>
-#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
-#define UV_TIMER_PARAMS(timer) uv_timer_t *timer, int
-#else
-#define UV_TIMER_PARAMS(timer) uv_timer_t *timer
-#endif
-
namespace mbgl {
namespace util {
class Timer::Impl {
public:
Impl() : timer(new uv_timer_t) {
- uv_loop_t* loop = reinterpret_cast<uv_loop_t*>(RunLoop::getLoopHandle());
+ auto* loop = reinterpret_cast<uv_loop_t*>(RunLoop::getLoopHandle());
if (uv_timer_init(loop, timer) != 0) {
throw std::runtime_error("Failed to initialize timer.");
}
@@ -46,7 +40,7 @@ public:
}
private:
- static void timerCallback(UV_TIMER_PARAMS(handle)) {
+ static void timerCallback(uv_timer_t* handle) {
reinterpret_cast<Impl*>(handle->data)->cb();
}
diff --git a/platform/glfw/glfw_view.cpp b/platform/glfw/glfw_view.cpp
index 4070a0fe9b..29cd0dd7c3 100644
--- a/platform/glfw/glfw_view.cpp
+++ b/platform/glfw/glfw_view.cpp
@@ -1,19 +1,21 @@
#include "glfw_view.hpp"
#include <mbgl/annotation/annotation.hpp>
-#include <mbgl/sprite/sprite_image.hpp>
+#include <mbgl/style/image.hpp>
#include <mbgl/style/transition_options.hpp>
-#include <mbgl/gl/gl.hpp>
-#include <mbgl/gl/extension.hpp>
-#include <mbgl/gl/context.hpp>
#include <mbgl/util/logging.hpp>
#include <mbgl/util/platform.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/util/chrono.hpp>
+#include <mbgl/map/backend_scope.hpp>
#include <mbgl/map/camera.hpp>
-#include <mbgl/gl/state.hpp>
-#include <mbgl/gl/value.hpp>
+#if MBGL_USE_GLES2
+#define GLFW_INCLUDE_ES2
+#endif // MBGL_USE_GLES2
+
+#define GL_GLEXT_PROTOTYPES
+#include <GLFW/glfw3.h>
#include <cassert>
#include <cstdlib>
@@ -27,7 +29,7 @@ GLFWView::GLFWView(bool fullscreen_, bool benchmark_)
: fullscreen(fullscreen_), benchmark(benchmark_) {
glfwSetErrorCallback(glfwError);
- std::srand(std::time(nullptr));
+ std::srand(static_cast<unsigned int>(std::time(nullptr)));
if (!glfwInit()) {
mbgl::Log::Error(mbgl::Event::OpenGL, "failed to initialize glfw");
@@ -85,8 +87,6 @@ GLFWView::GLFWView(bool fullscreen_, bool benchmark_)
glfwSetScrollCallback(window, onScroll);
glfwSetKeyCallback(window, onKey);
- mbgl::gl::InitializeExtensions(glfwGetProcAddress);
-
glfwGetWindowSize(window, &width, &height);
glfwGetFramebufferSize(window, &fbWidth, &fbHeight);
pixelRatio = static_cast<float>(fbWidth) / width;
@@ -131,23 +131,21 @@ GLFWView::~GLFWView() {
void GLFWView::setMap(mbgl::Map *map_) {
map = map_;
- map->addAnnotationIcon("default_marker", makeSpriteImage(22, 22, 1));
+ map->addAnnotationImage(makeImage("default_marker", 22, 22, 1));
}
-void GLFWView::updateViewBinding() {
- getContext().bindFramebuffer.setCurrentValue(0);
- assert(mbgl::gl::value::BindFramebuffer::Get() == getContext().bindFramebuffer.getCurrentValue());
- getContext().viewport.setCurrentValue({ 0, 0, getFramebufferSize() });
- assert(mbgl::gl::value::Viewport::Get() == getContext().viewport.getCurrentValue());
+void GLFWView::updateAssumedState() {
+ assumeFramebufferBinding(0);
+ assumeViewportSize(getFramebufferSize());
}
void GLFWView::bind() {
- getContext().bindFramebuffer = 0;
- getContext().viewport = { 0, 0, getFramebufferSize() };
+ setFramebufferBinding(0);
+ setViewportSize(getFramebufferSize());
}
void GLFWView::onKey(GLFWwindow *window, int key, int /*scancode*/, int action, int mods) {
- GLFWView *view = reinterpret_cast<GLFWView *>(glfwGetWindowUserPointer(window));
+ auto *view = reinterpret_cast<GLFWView *>(glfwGetWindowUserPointer(window));
if (action == GLFW_RELEASE) {
switch (key) {
@@ -165,17 +163,6 @@ void GLFWView::onKey(GLFWwindow *window, int key, int /*scancode*/, int action,
if (view->changeStyleCallback)
view->changeStyleCallback();
break;
- case GLFW_KEY_R:
- if (!mods) {
- static const mbgl::style::TransitionOptions transition { { mbgl::Milliseconds(300) } };
- view->map->setTransitionOptions(transition);
- if (view->map->hasClass("night")) {
- view->map->removeClass("night");
- } else {
- view->map->addClass("night");
- }
- }
- break;
#if not MBGL_USE_GLES2
case GLFW_KEY_B: {
auto debug = view->map->getDebug();
@@ -264,11 +251,11 @@ mbgl::Point<double> GLFWView::makeRandomPoint() const {
const double x = width * double(std::rand()) / RAND_MAX;
const double y = height * double(std::rand()) / RAND_MAX;
mbgl::LatLng latLng = map->latLngForPixel({ x, y });
- return { latLng.longitude, latLng.latitude };
+ return { latLng.longitude(), latLng.latitude() };
}
-std::shared_ptr<const mbgl::SpriteImage>
-GLFWView::makeSpriteImage(int width, int height, float pixelRatio) {
+std::unique_ptr<mbgl::style::Image>
+GLFWView::makeImage(const std::string& id, int width, int height, float pixelRatio) {
const int r = 255 * (double(std::rand()) / RAND_MAX);
const int g = 255 * (double(std::rand()) / RAND_MAX);
const int b = 255 * (double(std::rand()) / RAND_MAX);
@@ -293,7 +280,7 @@ GLFWView::makeSpriteImage(int width, int height, float pixelRatio) {
}
}
- return std::make_shared<mbgl::SpriteImage>(std::move(image), pixelRatio);
+ return std::make_unique<mbgl::style::Image>(id, std::move(image), pixelRatio);
}
void GLFWView::nextOrientation() {
@@ -310,7 +297,7 @@ void GLFWView::addRandomCustomPointAnnotations(int count) {
for (int i = 0; i < count; i++) {
static int spriteID = 1;
const auto name = std::string{ "marker-" } + mbgl::util::toString(spriteID++);
- map->addAnnotationIcon(name, makeSpriteImage(22, 22, 1));
+ map->addAnnotationImage(makeImage(name, 22, 22, 1));
spriteIDs.push_back(name);
annotationIDs.push_back(map->addAnnotation(mbgl::SymbolAnnotation { makeRandomPoint(), name }));
}
@@ -358,7 +345,7 @@ void GLFWView::popAnnotation() {
}
void GLFWView::onScroll(GLFWwindow *window, double /*xOffset*/, double yOffset) {
- GLFWView *view = reinterpret_cast<GLFWView *>(glfwGetWindowUserPointer(window));
+ auto *view = reinterpret_cast<GLFWView *>(glfwGetWindowUserPointer(window));
double delta = yOffset * 40;
bool isWheel = delta != 0 && std::fmod(delta, 4.000244140625) == 0;
@@ -376,18 +363,18 @@ void GLFWView::onScroll(GLFWwindow *window, double /*xOffset*/, double yOffset)
scale = 1.0 / scale;
}
- view->map->scaleBy(scale, mbgl::ScreenCoordinate { view->lastX, view->lastY });
+ view->map->setZoom(view->map->getZoom() + std::log2(scale), mbgl::ScreenCoordinate { view->lastX, view->lastY });
}
void GLFWView::onWindowResize(GLFWwindow *window, int width, int height) {
- GLFWView *view = reinterpret_cast<GLFWView *>(glfwGetWindowUserPointer(window));
+ auto *view = reinterpret_cast<GLFWView *>(glfwGetWindowUserPointer(window));
view->width = width;
view->height = height;
view->map->setSize({ static_cast<uint32_t>(view->width), static_cast<uint32_t>(view->height) });
}
void GLFWView::onFramebufferResize(GLFWwindow *window, int width, int height) {
- GLFWView *view = reinterpret_cast<GLFWView *>(glfwGetWindowUserPointer(window));
+ auto *view = reinterpret_cast<GLFWView *>(glfwGetWindowUserPointer(window));
view->fbWidth = width;
view->fbHeight = height;
view->bind();
@@ -400,7 +387,7 @@ void GLFWView::onFramebufferResize(GLFWwindow *window, int width, int height) {
}
void GLFWView::onMouseClick(GLFWwindow *window, int button, int action, int modifiers) {
- GLFWView *view = reinterpret_cast<GLFWView *>(glfwGetWindowUserPointer(window));
+ auto *view = reinterpret_cast<GLFWView *>(glfwGetWindowUserPointer(window));
if (button == GLFW_MOUSE_BUTTON_RIGHT ||
(button == GLFW_MOUSE_BUTTON_LEFT && modifiers & GLFW_MOD_CONTROL)) {
@@ -417,9 +404,9 @@ void GLFWView::onMouseClick(GLFWwindow *window, int button, int action, int modi
double now = glfwGetTime();
if (now - view->lastClick < 0.4 /* ms */) {
if (modifiers & GLFW_MOD_SHIFT) {
- view->map->scaleBy(0.5, mbgl::ScreenCoordinate { view->lastX, view->lastY }, mbgl::AnimationOptions{{mbgl::Milliseconds(500)}});
+ view->map->setZoom(view->map->getZoom() - 1, mbgl::ScreenCoordinate { view->lastX, view->lastY }, mbgl::AnimationOptions{{mbgl::Milliseconds(500)}});
} else {
- view->map->scaleBy(2.0, mbgl::ScreenCoordinate { view->lastX, view->lastY }, mbgl::AnimationOptions{{mbgl::Milliseconds(500)}});
+ view->map->setZoom(view->map->getZoom() + 1, mbgl::ScreenCoordinate { view->lastX, view->lastY }, mbgl::AnimationOptions{{mbgl::Milliseconds(500)}});
}
}
view->lastClick = now;
@@ -428,7 +415,7 @@ void GLFWView::onMouseClick(GLFWwindow *window, int button, int action, int modi
}
void GLFWView::onMouseMove(GLFWwindow *window, double x, double y) {
- GLFWView *view = reinterpret_cast<GLFWView *>(glfwGetWindowUserPointer(window));
+ auto *view = reinterpret_cast<GLFWView *>(glfwGetWindowUserPointer(window));
if (view->tracking) {
double dx = x - view->lastX;
double dy = y - view->lastY;
@@ -461,9 +448,9 @@ void GLFWView::run() {
if (dirty) {
const double started = glfwGetTime();
- glfwMakeContextCurrent(window);
+ activate();
+ mbgl::BackendScope scope { *this, mbgl::BackendScope::ScopeType::Implicit };
- updateViewBinding();
map->render(*this);
glfwSwapBuffers(window);
@@ -497,6 +484,10 @@ mbgl::Size GLFWView::getFramebufferSize() const {
return { static_cast<uint32_t>(fbWidth), static_cast<uint32_t>(fbHeight) };
}
+mbgl::gl::ProcAddress GLFWView::initializeExtension(const char* name) {
+ return glfwGetProcAddress(name);
+}
+
void GLFWView::activate() {
glfwMakeContextCurrent(window);
}
@@ -538,16 +529,6 @@ void GLFWView::setWindowTitle(const std::string& title) {
glfwSetWindowTitle(window, (std::string { "Mapbox GL: " } + title).c_str());
}
-void GLFWView::setMapChangeCallback(std::function<void(mbgl::MapChange)> callback) {
- this->mapChangeCallback = callback;
-}
-
-void GLFWView::notifyMapChange(mbgl::MapChange change) {
- if (mapChangeCallback) {
- mapChangeCallback(change);
- }
-}
-
namespace mbgl {
namespace platform {
@@ -557,7 +538,7 @@ void showDebugImage(std::string name, const char *data, size_t width, size_t hei
static GLFWwindow *debugWindow = nullptr;
if (!debugWindow) {
- debugWindow = glfwCreateWindow(width, height, name.c_str(), nullptr, nullptr);
+ debugWindow = glfwCreateWindow(static_cast<int>(width), static_cast<int>(height), name.c_str(), nullptr, nullptr);
if (!debugWindow) {
glfwTerminate();
fprintf(stderr, "Failed to initialize window\n");
@@ -567,21 +548,16 @@ void showDebugImage(std::string name, const char *data, size_t width, size_t hei
GLFWwindow *currentWindow = glfwGetCurrentContext();
- glfwSetWindowSize(debugWindow, width, height);
+ glfwSetWindowSize(debugWindow, static_cast<int>(width), static_cast<int>(height));
glfwMakeContextCurrent(debugWindow);
int fbWidth, fbHeight;
glfwGetFramebufferSize(debugWindow, &fbWidth, &fbHeight);
float scale = static_cast<float>(fbWidth) / static_cast<float>(width);
- {
- gl::PreserveState<gl::value::PixelZoom> pixelZoom;
- gl::PreserveState<gl::value::RasterPos> rasterPos;
-
- MBGL_CHECK_ERROR(glPixelZoom(scale, -scale));
- MBGL_CHECK_ERROR(glRasterPos2f(-1.0f, 1.0f));
- MBGL_CHECK_ERROR(glDrawPixels(width, height, GL_LUMINANCE, GL_UNSIGNED_BYTE, data));
- }
+ glPixelZoom(scale, -scale);
+ glRasterPos2f(-1.0f, 1.0f);
+ glDrawPixels(width, height, GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
glfwSwapBuffers(debugWindow);
@@ -593,7 +569,7 @@ void showColorDebugImage(std::string name, const char *data, size_t logicalWidth
static GLFWwindow *debugWindow = nullptr;
if (!debugWindow) {
- debugWindow = glfwCreateWindow(logicalWidth, logicalHeight, name.c_str(), nullptr, nullptr);
+ debugWindow = glfwCreateWindow(static_cast<int>(logicalWidth), static_cast<int>(logicalHeight), name.c_str(), nullptr, nullptr);
if (!debugWindow) {
glfwTerminate();
fprintf(stderr, "Failed to initialize window\n");
@@ -603,7 +579,7 @@ void showColorDebugImage(std::string name, const char *data, size_t logicalWidth
GLFWwindow *currentWindow = glfwGetCurrentContext();
- glfwSetWindowSize(debugWindow, logicalWidth, logicalHeight);
+ glfwSetWindowSize(debugWindow, static_cast<int>(logicalWidth), static_cast<int>(logicalHeight));
glfwMakeContextCurrent(debugWindow);
int fbWidth, fbHeight;
@@ -611,21 +587,13 @@ void showColorDebugImage(std::string name, const char *data, size_t logicalWidth
float xScale = static_cast<float>(fbWidth) / static_cast<float>(width);
float yScale = static_cast<float>(fbHeight) / static_cast<float>(height);
- {
- gl::PreserveState<gl::value::ClearColor> clearColor;
- gl::PreserveState<gl::value::Blend> blend;
- gl::PreserveState<gl::value::BlendFunc> blendFunc;
- gl::PreserveState<gl::value::PixelZoom> pixelZoom;
- gl::PreserveState<gl::value::RasterPos> rasterPos;
-
- MBGL_CHECK_ERROR(glClearColor(0.8, 0.8, 0.8, 1));
- MBGL_CHECK_ERROR(glClear(GL_COLOR_BUFFER_BIT));
- MBGL_CHECK_ERROR(glEnable(GL_BLEND));
- MBGL_CHECK_ERROR(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
- MBGL_CHECK_ERROR(glPixelZoom(xScale, -yScale));
- MBGL_CHECK_ERROR(glRasterPos2f(-1.0f, 1.0f));
- MBGL_CHECK_ERROR(glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, data));
- }
+ glClearColor(0.8, 0.8, 0.8, 1);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glPixelZoom(xScale, -yScale);
+ glRasterPos2f(-1.0f, 1.0f);
+ glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, data);
glfwSwapBuffers(debugWindow);
diff --git a/platform/glfw/glfw_view.hpp b/platform/glfw/glfw_view.hpp
index a426e58a94..b5fd5856f4 100644
--- a/platform/glfw/glfw_view.hpp
+++ b/platform/glfw/glfw_view.hpp
@@ -1,6 +1,5 @@
#pragma once
-#include <mbgl/gl/gl.hpp>
#include <mbgl/map/map.hpp>
#include <mbgl/map/view.hpp>
#include <mbgl/map/backend.hpp>
@@ -8,11 +7,7 @@
#include <mbgl/util/timer.hpp>
#include <mbgl/util/geometry.hpp>
-#if MBGL_USE_GLES2
-#define GLFW_INCLUDE_ES2
-#endif
-#define GL_GLEXT_PROTOTYPES
-#include <GLFW/glfw3.h>
+struct GLFWwindow;
class GLFWView : public mbgl::View, public mbgl::Backend {
public:
@@ -38,15 +33,19 @@ public:
void run();
// mbgl::View implementation
- void updateViewBinding();
void bind() override;
mbgl::Size getSize() const;
mbgl::Size getFramebufferSize() const;
// mbgl::Backend implementation
+ void invalidate() override;
+ void updateAssumedState() override;
+
+protected:
+ // mbgl::Backend implementation
+ mbgl::gl::ProcAddress initializeExtension(const char*) override;
void activate() override;
void deactivate() override;
- void invalidate() override;
private:
// Window callbacks
@@ -60,13 +59,9 @@ private:
// Internal
void report(float duration);
- void setMapChangeCallback(std::function<void(mbgl::MapChange)> callback);
- void notifyMapChange(mbgl::MapChange change) override;
-
mbgl::Color makeRandomColor() const;
mbgl::Point<double> makeRandomPoint() const;
- static std::shared_ptr<const mbgl::SpriteImage>
- makeSpriteImage(int width, int height, float pixelRatio);
+ static std::unique_ptr<mbgl::style::Image> makeImage(const std::string& id, int width, int height, float pixelRatio);
void nextOrientation();
@@ -81,8 +76,6 @@ private:
mbgl::AnnotationIDs annotationIDs;
std::vector<std::string> spriteIDs;
- std::function<void(mbgl::MapChange)> mapChangeCallback;
-
private:
mbgl::Map* map = nullptr;
diff --git a/platform/glfw/main.cpp b/platform/glfw/main.cpp
index fbfba0b7fb..97c77b3742 100644
--- a/platform/glfw/main.cpp
+++ b/platform/glfw/main.cpp
@@ -7,7 +7,7 @@
#include <mbgl/util/default_thread_pool.hpp>
#include <mbgl/storage/default_file_source.hpp>
-#include <signal.h>
+#include <csignal>
#include <getopt.h>
#include <fstream>
#include <sstream>
@@ -19,7 +19,7 @@ namespace {
GLFWView* view = nullptr;
-}
+} // namespace
void quit_handler(int) {
if (view) {
@@ -39,15 +39,15 @@ int main(int argc, char *argv[]) {
bool skipConfig = false;
const struct option long_options[] = {
- {"fullscreen", no_argument, 0, 'f'},
- {"benchmark", no_argument, 0, 'b'},
- {"style", required_argument, 0, 's'},
- {"lon", required_argument, 0, 'x'},
- {"lat", required_argument, 0, 'y'},
- {"zoom", required_argument, 0, 'z'},
- {"bearing", required_argument, 0, 'r'},
- {"pitch", required_argument, 0, 'p'},
- {0, 0, 0, 0}
+ {"fullscreen", no_argument, nullptr, 'f'},
+ {"benchmark", no_argument, nullptr, 'b'},
+ {"style", required_argument, nullptr, 's'},
+ {"lon", required_argument, nullptr, 'x'},
+ {"lat", required_argument, nullptr, 'y'},
+ {"zoom", required_argument, nullptr, 'z'},
+ {"bearing", required_argument, nullptr, 'r'},
+ {"pitch", required_argument, nullptr, 'p'},
+ {nullptr, 0, nullptr, 0}
};
while (true) {
@@ -57,7 +57,7 @@ int main(int argc, char *argv[]) {
switch (opt)
{
case 0:
- if (long_options[option_index].flag != 0)
+ if (long_options[option_index].flag != nullptr)
break;
case 'f':
fullscreen = true;
@@ -99,7 +99,7 @@ int main(int argc, char *argv[]) {
sigIntHandler.sa_handler = quit_handler;
sigemptyset(&sigIntHandler.sa_mask);
sigIntHandler.sa_flags = 0;
- sigaction(SIGINT, &sigIntHandler, NULL);
+ sigaction(SIGINT, &sigIntHandler, nullptr);
if (benchmark) {
mbgl::Log::Info(mbgl::Event::General, "BENCHMARK MODE: Some optimizations are disabled.");
@@ -184,8 +184,8 @@ int main(int argc, char *argv[]) {
// Save settings
mbgl::LatLng latLng = map.getLatLng();
- settings.latitude = latLng.latitude;
- settings.longitude = latLng.longitude;
+ settings.latitude = latLng.latitude();
+ settings.longitude = latLng.longitude();
settings.zoom = map.getZoom();
settings.bearing = map.getBearing();
settings.pitch = map.getPitch();
@@ -194,9 +194,9 @@ int main(int argc, char *argv[]) {
settings.save();
}
mbgl::Log::Info(mbgl::Event::General,
- "Exit location: --lat=\"%f\" --lon=\"%f\" --zoom=\"%f\" --bearing \"%f\"",
+ R"(Exit location: --lat="%f" --lon="%f" --zoom="%f" --bearing "%f")",
settings.latitude, settings.longitude, settings.zoom, settings.bearing);
view = nullptr;
return 0;
-}
+} \ No newline at end of file
diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md
index d819d2fa92..e8de9e3723 100644
--- a/platform/ios/CHANGELOG.md
+++ b/platform/ios/CHANGELOG.md
@@ -2,6 +2,41 @@
Mapbox welcomes participation and contributions from everyone. Please read [CONTRIBUTING.md](../../CONTRIBUTING.md) to get started.
+## master
+
+* The previously-deprecated support for style classes has been removed. For interface compatibility, the API methods remain, but they are now non-functional.
+
+## 3.6.0
+
+### Styles
+
+* Added support for 3D extrusion of buildings and other polygonal features via the `MGLFillExtrusionStyleLayer` class and the `fill-extrusion` layer type in style JSON. ([#8431](https://github.com/mapbox/mapbox-gl-native/pull/8431))
+* MGLMapView and MGLTilePyramidOfflineRegion now default to version 10 of the Mapbox Streets style. Similarly, several style URL class methods of MGLStyle return URLs to version 10 styles. Unversioned variations of these methods are no longer deprecated. `MGLStyleDefaultVersion` should no longer be used with any style other than Streets. ([#6301](https://github.com/mapbox/mapbox-gl-native/pull/6301))
+* Added class methods to MGLStyle that correspond to the new [Traffic Day and Traffic Night](https://www.mapbox.com/blog/live-traffic-maps/) styles. ([#6301](https://github.com/mapbox/mapbox-gl-native/pull/6301))
+* MGLSymbolStyleLayer’s `iconImageName`, `iconScale`, `textFontSize`, `textOffset`, and `textRotation` properties can now be set to a source or composite function. ([#8544](https://github.com/mapbox/mapbox-gl-native/pull/8544), [#8590](https://github.com/mapbox/mapbox-gl-native/pull/8590), [#8592](https://github.com/mapbox/mapbox-gl-native/pull/8592), [#8593](https://github.com/mapbox/mapbox-gl-native/pull/8593))
+* Fixed an issue where setting the `MGLVectorStyleLayer.predicate` property failed to take effect if the relevant source was not in use by a visible layer at the time. ([#8653](https://github.com/mapbox/mapbox-gl-native/pull/8653))
+* Fixed an issue causing a composite function’s highest zoom level stop to be misinterpreted. ([#8613](https://github.com/mapbox/mapbox-gl-native/pull/8613), [#8790](https://github.com/mapbox/mapbox-gl-native/pull/8790))
+* Fixed an issue where re-adding a layer that had been previously removed from a style would reset its paint properties. Moved initializers for `MGLTileSource`, `MGLStyleLayer`, and `MGLForegroundStyleLayer` to their concrete subclasses; because these classes were already intended for initialization only via concrete subclasses, this should have no developer impact. ([#8626](https://github.com/mapbox/mapbox-gl-native/pull/8626))
+* Feature querying results now account for any changes to a feature’s size caused by a source or composite style function. ([#8665](https://github.com/mapbox/mapbox-gl-native/pull/8665))
+
+### Annotations
+
+* Fixed an issue causing a view-backed annotation to disappear immediately instead of animating when the annotation’s `coordinate` property is set to a value outside the current viewport. ([#8565](https://github.com/mapbox/mapbox-gl-native/pull/8565))
+* Fixed an issue in which `MGLMapView` overrode the tint colors of its annotation views. ([#8789](https://github.com/mapbox/mapbox-gl-native/pull/8789))
+
+### User interaction
+
+* Added a scale bar to `MGLMapView` that indicates the scale of the map. ([#7631](https://github.com/mapbox/mapbox-gl-native/pull/7631))
+* Fixed an issue where gesture recognizers associated with map view interactivity were not disabled when their related interactions were disabled. ([#8304](https://github.com/mapbox/mapbox-gl-native/pull/8304))
+
+### Other changes
+
+* Xcode 8.0 or higher is now recommended for using this SDK. ([#8775](https://github.com/mapbox/mapbox-gl-native/pull/8775))
+* Updated MGLMapView’s logo view to display [the new Mapbox logo](https://www.mapbox.com/blog/new-mapbox-logo/). ([#8771](https://github.com/mapbox/mapbox-gl-native/pull/8771), [#8773](https://github.com/mapbox/mapbox-gl-native/pull/8773))
+* Fixed a crash or console spew when MGLMapView is initialized with a frame smaller than 64 points wide by 64 points tall. ([#8562](https://github.com/mapbox/mapbox-gl-native/pull/8562))
+* The error passed into `-[MGLMapViewDelegate mapViewDidFailLoadingMap:withError:]` now includes a more specific description and failure reason. ([#8418](https://github.com/mapbox/mapbox-gl-native/pull/8418))
+* Fixed an issue rendering polylines that contain duplicate vertices. ([#8808](https://github.com/mapbox/mapbox-gl-native/pull/8808))
+
## 3.5.4 - May 9, 2017
* Fixed an issue that caused view backed annotations to become detached from the map view during pan gestures combined with animations of annotation view size or when the annotation view had no size but contained subviews with a non-zero size. ([#8926](https://github.com/mapbox/mapbox-gl-native/pull/8926))
@@ -40,7 +75,6 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT
### Styles
* Added support for data-driven styling in the form of source and composite style functions. `MGLStyleFunction` is now an abstract class, with `MGLCameraStyleFunction` providing the behavior of `MGLStyleFunction` in previous releases. New `MGLStyleFunction` subclasses allow you to vary a style attribute by the values of attributes of features in the source. ([#7596](https://github.com/mapbox/mapbox-gl-native/pull/7596))
-* Added methods to MGLShapeSource and MGLVectorSource for querying features loaded by the source, whether or not they’re visible on the map. ([#8263](https://github.com/mapbox/mapbox-gl-native/pull/8263))
* Added `circleStrokeColor`, `circleStrokeWidth`, and `circleStrokeOpacity` properties to MGLCircleStyleLayer and support for corresponding properties in style JSON files. ([#7356](https://github.com/mapbox/mapbox-gl-native/pull/7356))
* Point-placed labels in symbol style layers are now placed at more optimal locations within polygons. ([#7465](https://github.com/mapbox/mapbox-gl-native/pull/7465))
* Fixed flickering that occurred when manipulating a style layer. ([#7616](https://github.com/mapbox/mapbox-gl-native/pull/7616))
@@ -87,6 +121,8 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT
* Fixed an issue that sometimes caused crashes when the SDK interacted with the file system in the background. ([#8125](https://github.com/mapbox/mapbox-gl-native/pull/8125))
* Added a `MGLDistanceFormatter` class for formatting geographic distances. ([#7888](https://github.com/mapbox/mapbox-gl-native/pull/7888))
* Fixed an issue that was causing the system location indicator to stay on in background after telemetry was disabled. ([#7833](https://github.com/mapbox/mapbox-gl-native/pull/7833))
+* Added support for predicates in rendered feature querying [8256](https://github.com/mapbox/mapbox-gl-native/pull/8246)
+* Added a nightly build of the dynamic framework. ([#8337](https://github.com/mapbox/mapbox-gl-native/pull/8337))
## 3.4.2 - February 21, 2017
@@ -136,7 +172,7 @@ This is the final scheduled version of the Mapbox iOS SDK that supports iOS 7. (
* A source’s tiles are no longer rendered when the map is outside the source’s supported zoom levels. ([#6345](https://github.com/mapbox/mapbox-gl-native/pull/6345))
* Improved style parsing performance. ([#6170](https://github.com/mapbox/mapbox-gl-native/pull/6170))
* Improved feature querying performance. ([#6514](https://github.com/mapbox/mapbox-gl-native/pull/6514))
-* Fixed an issue where shapes that cannot currently be visually represented as annotations were still shown on the map as point annotations. ([#6764](https://github.com/mapbox/mapbox-gl-native/issues/6764))
+* Fixed an issue where shapes that cannot currently be visually represented as annotations were still shown on the map as point annotations. ([#6764](https://github.com/mapbox/mapbox-gl-native/issues/6764))
### User location
diff --git a/platform/ios/DEVELOPING.md b/platform/ios/DEVELOPING.md
index 26ab807e04..83064fbbd8 100644
--- a/platform/ios/DEVELOPING.md
+++ b/platform/ios/DEVELOPING.md
@@ -6,7 +6,7 @@ This document explains how to build the Mapbox iOS SDK from source. It is intend
The Mapbox iOS SDK and iosapp demo application require iOS 8.0 or above.
-The Mapbox iOS SDK requires Xcode 7.3 or above. The iosapp demo application requires Xcode 8.0 or above to build.
+The Mapbox iOS SDK requires Xcode 8.0 or above.
## Building the SDK
diff --git a/platform/ios/INSTALL.md b/platform/ios/INSTALL.md
index c93ab6b698..b64d9c650f 100644
--- a/platform/ios/INSTALL.md
+++ b/platform/ios/INSTALL.md
@@ -10,7 +10,7 @@ The Mapbox iOS SDK is intended to run on iOS 8.0 and above on the following devi
* iPad 2 and above (3, 4, Mini, Air, Mini 2, Air 2)
* iPod touch 5th generation and above
-The Mapbox iOS SDK requires Xcode 7.3 or higher.
+The Mapbox iOS SDK requires Xcode 8.0 or higher. To use this SDK with Xcode 7.3.1, download and use a symbols build from the [releases](https://github.com/mapbox/mapbox-gl-native/releases) page.
### Building the SDK
@@ -50,6 +50,10 @@ bash "${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/Mapbox.framework/strip-fra
(The last step, courtesy of [Realm](https://github.com/realm/realm-cocoa/), is required for working around an [iOS App Store bug](http://www.openradar.me/radar?id=6409498411401216) when archiving universal binaries.)
+##### Nightly builds
+
+A nightly build of the dynamic framework, based on the master branch, is available for download [here](https://mapbox.s3.amazonaws.com/mapbox-gl-native/ios/builds/mapbox-ios-sdk-nightly-dynamic.zip).
+
#### Static framework
You can alternatively install the SDK as a static framework:
@@ -82,7 +86,15 @@ You can alternatively install the SDK as a static framework:
To test pre-releases and/or betas, you can reference the pre-release like so in your Podfile:
```rb
-pod 'Mapbox-iOS-SDK', podspec: 'https://raw.githubusercontent.com/mapbox/mapbox-gl-native/<insert branch or tag>/ios/Mapbox-iOS-SDK.podspec'
+pod 'Mapbox-iOS-SDK', podspec: 'https://raw.githubusercontent.com/mapbox/mapbox-gl-native/<insert branch or tag>/platform/ios/Mapbox-iOS-SDK.podspec'
+```
+
+##### Testing nightly releases with CocoaPods
+
+To test a nightly dynamic framework build, update your app’s `Podfile` to point to:
+
+```rb
+pod 'Mapbox-iOS-SDK-nightly-dynamic', podspec: 'https://raw.githubusercontent.com/mapbox/mapbox-gl-native/master/platform/ios/Mapbox-iOS-SDK-nightly-dynamic.podspec'
```
##### Using your own build with CocoaPods
diff --git a/platform/ios/Mapbox-iOS-SDK-nightly-dynamic.podspec b/platform/ios/Mapbox-iOS-SDK-nightly-dynamic.podspec
new file mode 100644
index 0000000000..c7b14ead3b
--- /dev/null
+++ b/platform/ios/Mapbox-iOS-SDK-nightly-dynamic.podspec
@@ -0,0 +1,30 @@
+Pod::Spec.new do |m|
+
+ version = '3.6.0-alpha.1'
+
+ m.name = 'Mapbox-iOS-SDK-nightly-dynamic'
+ m.version = "#{version}-nightly"
+
+ m.summary = 'Open source vector map solution for iOS with full styling capabilities.'
+ m.description = 'Open source, OpenGL-based vector map solution for iOS with full styling capabilities and Cocoa Touch APIs.'
+ m.homepage = 'https://www.mapbox.com/ios-sdk/'
+ m.license = { :type => 'BSD', :file => 'LICENSE.md' }
+ m.author = { 'Mapbox' => 'mobile@mapbox.com' }
+ m.screenshot = "https://www.mapbox.com/ios-sdk/api/#{version}/img/screenshot.png"
+ m.social_media_url = 'https://twitter.com/mapbox'
+ m.documentation_url = 'https://www.mapbox.com/ios-sdk/api/'
+
+ m.source = {
+ :http => "https://mapbox.s3.amazonaws.com/mapbox-gl-native/ios/builds/mapbox-ios-sdk-nightly-dynamic.zip",
+ :flatten => true
+ }
+
+ m.platform = :ios
+ m.ios.deployment_target = '8.0'
+
+ m.requires_arc = true
+
+ m.vendored_frameworks = 'dynamic/Mapbox.framework'
+ m.module_name = 'Mapbox'
+
+end
diff --git a/platform/ios/Mapbox-iOS-SDK-symbols.podspec b/platform/ios/Mapbox-iOS-SDK-symbols.podspec
index 26ad13f5b1..f8b20777fa 100644
--- a/platform/ios/Mapbox-iOS-SDK-symbols.podspec
+++ b/platform/ios/Mapbox-iOS-SDK-symbols.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |m|
- version = '3.5.4'
+ version = '3.6.0-alpha.1'
m.name = 'Mapbox-iOS-SDK-symbols'
m.version = "#{version}-symbols"
diff --git a/platform/ios/Mapbox-iOS-SDK.podspec b/platform/ios/Mapbox-iOS-SDK.podspec
index 4661027051..15658e6241 100644
--- a/platform/ios/Mapbox-iOS-SDK.podspec
+++ b/platform/ios/Mapbox-iOS-SDK.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |m|
- version = '3.5.4'
+ version = '3.6.0-alpha.1'
m.name = 'Mapbox-iOS-SDK'
m.version = version
diff --git a/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-29@2x-1.png b/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-29@2x-1.png
index 1e609d3281..15544d2701 100644
--- a/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-29@2x-1.png
+++ b/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-29@2x-1.png
Binary files differ
diff --git a/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-29@2x.png b/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-29@2x.png
index 1e609d3281..15544d2701 100644
--- a/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-29@2x.png
+++ b/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-29@2x.png
Binary files differ
diff --git a/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-29@3x.png b/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-29@3x.png
index c7d5aea4eb..a07e385c76 100644
--- a/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-29@3x.png
+++ b/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-29@3x.png
Binary files differ
diff --git a/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-40.png b/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-40.png
index eca13393e6..c69a417af3 100644
--- a/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-40.png
+++ b/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-40.png
Binary files differ
diff --git a/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-40@2x-1.png b/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-40@2x-1.png
index 277535538a..a15e380f0f 100644
--- a/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-40@2x-1.png
+++ b/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-40@2x-1.png
Binary files differ
diff --git a/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png b/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png
index 070d037539..a15e380f0f 100644
--- a/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png
+++ b/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png
Binary files differ
diff --git a/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png b/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png
index b7f25955f5..a46522d368 100644
--- a/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png
+++ b/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png
Binary files differ
diff --git a/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png b/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png
index b00d479839..5bad7a72f7 100644
--- a/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png
+++ b/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png
Binary files differ
diff --git a/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-76.png b/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-76.png
index 895b4a1761..6866ac111b 100644
--- a/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-76.png
+++ b/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-76.png
Binary files differ
diff --git a/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png b/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png
index 7bc5208976..db8f040ca4 100644
--- a/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png
+++ b/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png
Binary files differ
diff --git a/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png b/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png
index 0082319b1e..7dc725be77 100644
--- a/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png
+++ b/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png
Binary files differ
diff --git a/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-Small.png b/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-Small.png
index aecbbc8a1d..6973929c91 100644
--- a/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-Small.png
+++ b/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-Small.png
Binary files differ
diff --git a/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-Spotlight-40@3x.png b/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-Spotlight-40@3x.png
index a3789dcb78..a46522d368 100644
--- a/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-Spotlight-40@3x.png
+++ b/platform/ios/app/Assets.xcassets/AppIcon.appiconset/Icon-Spotlight-40@3x.png
Binary files differ
diff --git a/platform/ios/app/Info.plist b/platform/ios/app/Info.plist
index d05d81e49d..d5b6825422 100644
--- a/platform/ios/app/Info.plist
+++ b/platform/ios/app/Info.plist
@@ -51,18 +51,5 @@
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
- <key>NSAppTransportSecurity</key>
- <dict>
- <key>NSExceptionDomains</key>
- <dict>
- <key>stamen.com</key>
- <dict>
- <key>NSIncludesSubdomains</key>
- <true/>
- <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
- <true/>
- </dict>
- </dict>
- </dict>
</dict>
</plist>
diff --git a/platform/ios/app/MBXAnnotationView.m b/platform/ios/app/MBXAnnotationView.m
index 5b8011c55e..6877c5cd3d 100644
--- a/platform/ios/app/MBXAnnotationView.m
+++ b/platform/ios/app/MBXAnnotationView.m
@@ -49,17 +49,4 @@
}
-- (nullable id<CAAction>)actionForLayer:(CALayer *)layer forKey:(NSString *)event
-{
- if (([event isEqualToString:@"transform"] || [event isEqualToString:@"position"])
- && self.dragState == MGLAnnotationViewDragStateNone)
- {
- CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:event];
- animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
- animation.speed = 0.1;
- return animation;
- }
- return [super actionForLayer:layer forKey:event];
-}
-
@end
diff --git a/platform/ios/app/MBXEmbeddedMapViewController.h b/platform/ios/app/MBXEmbeddedMapViewController.h
new file mode 100644
index 0000000000..976893d491
--- /dev/null
+++ b/platform/ios/app/MBXEmbeddedMapViewController.h
@@ -0,0 +1,5 @@
+#import <UIKit/UIKit.h>
+
+@interface MBXEmbeddedMapViewController : UIViewController
+
+@end
diff --git a/platform/ios/app/MBXEmbeddedMapViewController.m b/platform/ios/app/MBXEmbeddedMapViewController.m
new file mode 100644
index 0000000000..f26a007c15
--- /dev/null
+++ b/platform/ios/app/MBXEmbeddedMapViewController.m
@@ -0,0 +1,89 @@
+#import "MBXEmbeddedMapViewController.h"
+#import <Mapbox/Mapbox.h>
+
+typedef NS_ENUM(NSInteger, MBXEmbeddedControl) {
+ MBXEmbeddedControlZoom = 0,
+ MBXEmbeddedControlScroll,
+ MBXEmbeddedControlRotation,
+ MBXEmbeddedControlPitch
+};
+
+@interface MBXEmbeddedMapViewController () <UIScrollViewDelegate>
+
+@property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
+@property (weak, nonatomic) IBOutlet MGLMapView *mapView;
+
+@end
+
+@implementation MBXEmbeddedMapViewController
+
+- (void)viewDidLoad {
+ [super viewDidLoad];
+
+ self.scrollView.delegate = self;
+ self.scrollView.contentSize = self.view.bounds.size;
+}
+
+- (IBAction)didSwitch:(UISwitch *)controlSwitch {
+ [self switchControl:controlSwitch.tag];
+}
+
+- (IBAction)rotation:(UIRotationGestureRecognizer *)rotationGesture {
+ self.mapView.transform = CGAffineTransformRotate(rotationGesture.view.transform, rotationGesture.rotation);
+}
+
+- (void)switchControl:(MBXEmbeddedControl) control {
+ switch (control) {
+ case MBXEmbeddedControlZoom:
+ self.mapView.zoomEnabled = !self.mapView.zoomEnabled;
+ break;
+ case MBXEmbeddedControlScroll:
+ self.mapView.scrollEnabled = !self.mapView.scrollEnabled;
+ break;
+ case MBXEmbeddedControlRotation:
+ self.mapView.rotateEnabled = !self.mapView.rotateEnabled;
+ break;
+ case MBXEmbeddedControlPitch:
+ self.mapView.pitchEnabled = !self.mapView.pitchEnabled;
+ break;
+ }
+}
+
+- (BOOL)statusForControl:(MBXEmbeddedControl) control {
+ switch (control) {
+ case MBXEmbeddedControlZoom:
+ return self.mapView.zoomEnabled;
+ case MBXEmbeddedControlScroll:
+ return self.mapView.scrollEnabled;
+ case MBXEmbeddedControlRotation:
+ return self.mapView.rotateEnabled;
+ case MBXEmbeddedControlPitch:
+ return self.mapView.pitchEnabled;
+ }
+}
+
+#pragma mark UIScrollViewDelegate methods
+
+- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
+ return self.mapView;
+}
+
+#pragma mark Class method
+
++ (NSString *)titleForControl:(MBXEmbeddedControl) control {
+ switch (control) {
+ case MBXEmbeddedControlZoom:
+ return @"Zoom Enabled";
+ case MBXEmbeddedControlScroll:
+ return @"Scroll Enabled";
+ break;
+ case MBXEmbeddedControlRotation:
+ return @"Rotation Enabled";
+ break;
+ case MBXEmbeddedControlPitch:
+ return @"Pitch Enabled";
+ break;
+ }
+}
+
+@end
diff --git a/platform/ios/app/MBXViewController.m b/platform/ios/app/MBXViewController.m
index 25eb598231..7cbe9d594f 100644
--- a/platform/ios/app/MBXViewController.m
+++ b/platform/ios/app/MBXViewController.m
@@ -5,6 +5,7 @@
#import "MBXOfflinePacksTableViewController.h"
#import "MBXAnnotationView.h"
#import "MBXUserLocationAnnotationView.h"
+#import "MBXEmbeddedMapViewController.h"
#import <Mapbox/Mapbox.h>
@@ -43,6 +44,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsAnnotationsRows) {
MBXSettingsAnnotations100Sprites,
MBXSettingsAnnotations1000Sprites,
MBXSettingsAnnotations10000Sprites,
+ MBXSettingsAnnotationAnimation,
MBXSettingsAnnotationsTestShapes,
MBXSettingsAnnotationsCustomCallout,
MBXSettingsAnnotationsQueryAnnotations,
@@ -79,6 +81,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
MBXSettingsMiscellaneousWorldTour,
MBXSettingsMiscellaneousCustomUserDot,
MBXSettingsMiscellaneousShowZoomLevel,
+ MBXSettingsMiscellaneousScrollView,
MBXSettingsMiscellaneousPrintLogFile,
MBXSettingsMiscellaneousDeleteLogFile,
};
@@ -156,7 +159,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
[self restoreState:nil];
self.debugLoggingEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:@"MGLMapboxMetricsDebugLoggingEnabled"];
-
+ self.mapView.scaleBar.hidden = NO;
self.hudLabel.hidden = YES;
if ([MGLAccountManager accessToken].length)
@@ -312,6 +315,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
@"Add 100 Sprites",
@"Add 1,000 Sprites",
@"Add 10,000 Sprites",
+ @"Animate an Annotation View",
@"Add Test Shapes",
@"Add Point With Custom Callout",
@"Query Annotations",
@@ -350,6 +354,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
@"Start World Tour",
[NSString stringWithFormat:@"%@ Custom User Dot", (_customUserLocationAnnnotationEnabled ? @"Disable" : @"Enable")],
[NSString stringWithFormat:@"%@ Zoom Level", (_showZoomLevelEnabled ? @"Hide" :@"Show")],
+ @"Embedded Map View",
]];
if (self.debugLoggingEnabled)
@@ -495,6 +500,9 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
case MBXSettingsAnnotations10000Sprites:
[self parseFeaturesAddingCount:10000 usingViews:NO];
break;
+ case MBXSettingsAnnotationAnimation:
+ [self animateAnnotationView];
+ break;
case MBXSettingsAnnotationsTestShapes:
[self addTestShapes];
break;
@@ -615,6 +623,13 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
self.reuseQueueStatsEnabled = NO;
break;
}
+ case MBXSettingsMiscellaneousScrollView:
+ {
+ UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
+ MBXEmbeddedMapViewController *embeddedMapViewController = (MBXEmbeddedMapViewController *)[storyboard instantiateViewControllerWithIdentifier:@"MBXEmbeddedMapViewController"];
+ [self.navigationController pushViewController:embeddedMapViewController animated:YES];
+ break;
+ }
default:
NSAssert(NO, @"All miscellaneous setting rows should be implemented");
break;
@@ -703,6 +718,23 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
});
}
+- (void)animateAnnotationView
+ {
+ MGLPointAnnotation *annot = [[MGLPointAnnotation alloc] init];
+ annot.coordinate = self.mapView.centerCoordinate;
+ [self.mapView addAnnotation:annot];
+
+ // Move the annotation to a point that is offscreen.
+ CGPoint point = CGPointMake(self.view.frame.origin.x - 200, CGRectGetMidY(self.view.frame));
+
+ CLLocationCoordinate2D coord = [self.mapView convertPoint:point toCoordinateFromView:self.view];
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+ [UIView animateWithDuration:10 animations:^{
+ annot.coordinate = coord;
+ }];
+ });
+ };
+
- (void)addTestShapes
{
// Pacific Northwest triangle
@@ -1229,8 +1261,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
- (void)styleRasterSource
{
- // 3rd party raster source requires NSAppTransportSecurity exception for stamen.com
- NSArray *tileURLTemplates = @[@"http://a.tile.stamen.com/terrain-background/{z}/{x}/{y}.jpg"];
+ NSArray *tileURLTemplates = @[@"https://stamen-tiles.a.ssl.fastly.net/terrain-background/{z}/{x}/{y}.jpg"];
MGLRasterSource *rasterSource = [[MGLRasterSource alloc] initWithIdentifier:@"style-raster-source-id" tileURLTemplates:tileURLTemplates options:@{
MGLTileSourceOptionTileSize: @256,
}];
@@ -1511,14 +1542,18 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
@"Dark",
@"Satellite",
@"Satellite Streets",
+ @"Traffic Day",
+ @"Traffic Night",
];
styleURLs = @[
- [MGLStyle streetsStyleURLWithVersion:MGLStyleDefaultVersion],
- [MGLStyle outdoorsStyleURLWithVersion:MGLStyleDefaultVersion],
- [MGLStyle lightStyleURLWithVersion:MGLStyleDefaultVersion],
- [MGLStyle darkStyleURLWithVersion:MGLStyleDefaultVersion],
- [MGLStyle satelliteStyleURLWithVersion:MGLStyleDefaultVersion],
- [MGLStyle satelliteStreetsStyleURLWithVersion:MGLStyleDefaultVersion],
+ [MGLStyle streetsStyleURL],
+ [MGLStyle outdoorsStyleURL],
+ [MGLStyle lightStyleURL],
+ [MGLStyle darkStyleURL],
+ [MGLStyle satelliteStyleURL],
+ [MGLStyle satelliteStreetsStyleURL],
+ [MGLStyle trafficDayStyleURL],
+ [MGLStyle trafficNightStyleURL],
];
NSAssert(styleNames.count == styleURLs.count, @"Style names and URLs don’t match.");
diff --git a/platform/ios/app/Main.storyboard b/platform/ios/app/Main.storyboard
index 5819f17edc..40198146ab 100644
--- a/platform/ios/app/Main.storyboard
+++ b/platform/ios/app/Main.storyboard
@@ -1,9 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11201" systemVersion="16A323" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="PSe-Ot-7Ff">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11762" systemVersion="16D32" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="PSe-Ot-7Ff">
+ <device id="retina4_7" orientation="portrait">
+ <adaptation id="fullscreen"/>
+ </device>
<dependencies>
<deployment identifier="iOS"/>
- <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11161"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
+ <capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
<capability name="Navigation items with more than one left or right bar item" minToolsVersion="7.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
@@ -21,6 +25,7 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="kNe-zV-9ha" customClass="MGLMapView">
+ <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<gestureRecognizers/>
<connections>
@@ -29,6 +34,7 @@
</connections>
</view>
<label opaque="NO" userInteractionEnabled="NO" alpha="0.69999999999999996" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="58y-pX-YyB">
+ <rect key="frame" x="179" y="626" width="180" height="21"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="width" constant="180" id="OL2-l5-I2f"/>
@@ -111,21 +117,21 @@
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="Inactive" editingAccessoryType="detailDisclosureButton" textLabel="JtH-Ce-MI5" detailTextLabel="tTJ-jv-U9v" style="IBUITableViewCellStyleSubtitle" id="fGu-Ys-Eh1">
- <rect key="frame" x="0.0" y="92" width="375" height="44"/>
+ <rect key="frame" x="0.0" y="28" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="fGu-Ys-Eh1" id="sUf-bc-8xG">
- <frame key="frameInset" width="375" height="43.5"/>
+ <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="My Inactive Offline Pack" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="JtH-Ce-MI5">
- <frame key="frameInset" minX="15" minY="6" width="174.5" height="19.5"/>
+ <rect key="frame" x="15" y="6" width="174.5" height="19.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="456 resources (789 MB)" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="tTJ-jv-U9v">
- <frame key="frameInset" minX="15" minY="25.5" width="128" height="13.5"/>
+ <rect key="frame" x="15" y="25.5" width="128" height="13.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="11"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
@@ -135,21 +141,21 @@
</tableViewCellContentView>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="Active" editingAccessoryType="detailDisclosureButton" textLabel="9ZK-gS-wJ4" detailTextLabel="0xK-p8-Mmh" style="IBUITableViewCellStyleSubtitle" id="mKB-tz-Zfl">
- <rect key="frame" x="0.0" y="136" width="375" height="44"/>
+ <rect key="frame" x="0.0" y="72" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="mKB-tz-Zfl" id="nS3-aU-nBr">
- <frame key="frameInset" width="375" height="43.5"/>
+ <rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="My Active Offline Pack" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="9ZK-gS-wJ4">
- <frame key="frameInset" minX="15" minY="6" width="163" height="19.5"/>
+ <rect key="frame" x="15" y="6" width="163" height="19.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Downloading 123 of 456 resources… (789 MB downloaded)" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="0xK-p8-Mmh">
- <frame key="frameInset" minX="15" minY="25.5" width="310.5" height="13.5"/>
+ <rect key="frame" x="15" y="25.5" width="310.5" height="13.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="11"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
@@ -198,6 +204,154 @@
</objects>
<point key="canvasLocation" x="554" y="350"/>
</scene>
+ <!--Embedded Map View Controller-->
+ <scene sceneID="dGM-LS-4VE">
+ <objects>
+ <viewController storyboardIdentifier="MBXEmbeddedMapViewController" id="Tsi-Cv-L66" customClass="MBXEmbeddedMapViewController" sceneMemberID="viewController">
+ <layoutGuides>
+ <viewControllerLayoutGuide type="top" id="xne-oT-1Cv"/>
+ <viewControllerLayoutGuide type="bottom" id="bxa-Bm-Qun"/>
+ </layoutGuides>
+ <view key="view" contentMode="scaleToFill" id="vKr-y9-AZt">
+ <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" alwaysBounceHorizontal="YES" minimumZoomScale="0.5" maximumZoomScale="5" translatesAutoresizingMaskIntoConstraints="NO" id="Awd-m3-zh2">
+ <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+ <subviews>
+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="EPE-uN-4XB" customClass="MGLMapView">
+ <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+ <gestureRecognizers/>
+ <connections>
+ <outletCollection property="gestureRecognizers" destination="JkF-BS-3oQ" appends="YES" id="yaD-hc-uit"/>
+ </connections>
+ </view>
+ </subviews>
+ <constraints>
+ <constraint firstAttribute="trailing" secondItem="EPE-uN-4XB" secondAttribute="trailing" id="2sl-Ru-a5Y"/>
+ <constraint firstAttribute="bottom" secondItem="EPE-uN-4XB" secondAttribute="bottom" id="8Rw-xR-dVh"/>
+ <constraint firstItem="EPE-uN-4XB" firstAttribute="centerX" secondItem="Awd-m3-zh2" secondAttribute="centerX" id="Cj3-w6-vZ5"/>
+ <constraint firstItem="EPE-uN-4XB" firstAttribute="leading" secondItem="Awd-m3-zh2" secondAttribute="leading" id="atf-fU-XKg"/>
+ <constraint firstItem="EPE-uN-4XB" firstAttribute="centerY" secondItem="Awd-m3-zh2" secondAttribute="centerY" id="bIx-MH-m69"/>
+ <constraint firstItem="EPE-uN-4XB" firstAttribute="top" secondItem="Awd-m3-zh2" secondAttribute="top" id="eUo-r5-eDb"/>
+ </constraints>
+ </scrollView>
+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="l5l-w7-P80" userLabel="Control Panel View">
+ <rect key="frame" x="0.0" y="20" width="375" height="64"/>
+ <subviews>
+ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Zoom" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="DgB-BD-Ltx">
+ <rect key="frame" x="29.5" y="6" width="35" height="16"/>
+ <constraints>
+ <constraint firstAttribute="width" constant="35" id="DaP-YL-kD7"/>
+ </constraints>
+ <fontDescription key="fontDescription" style="UICTFontTextStyleFootnote"/>
+ <nil key="textColor"/>
+ <nil key="highlightedColor"/>
+ </label>
+ <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="g15-JY-ZNb">
+ <rect key="frame" x="22.5" y="25" width="51" height="31"/>
+ <connections>
+ <action selector="didSwitch:" destination="Tsi-Cv-L66" eventType="valueChanged" id="Obk-GN-o7t"/>
+ </connections>
+ </switch>
+ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Scroll" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="z7C-yW-Y69" userLabel="Scroll">
+ <rect key="frame" x="123" y="6" width="35" height="16"/>
+ <constraints>
+ <constraint firstAttribute="width" constant="35" id="tr6-4a-XN7"/>
+ </constraints>
+ <fontDescription key="fontDescription" style="UICTFontTextStyleFootnote"/>
+ <nil key="textColor"/>
+ <nil key="highlightedColor"/>
+ </label>
+ <switch opaque="NO" tag="1" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="tqS-cU-tlc">
+ <rect key="frame" x="116" y="25" width="51" height="31"/>
+ <connections>
+ <action selector="didSwitch:" destination="Tsi-Cv-L66" eventType="valueChanged" id="Dhk-0Y-V4f"/>
+ </connections>
+ </switch>
+ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Rotation" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Vio-XU-tgS">
+ <rect key="frame" x="209.5" y="6" width="50.5" height="16"/>
+ <constraints>
+ <constraint firstAttribute="width" constant="50.5" id="OiV-2P-9xm"/>
+ </constraints>
+ <fontDescription key="fontDescription" style="UICTFontTextStyleFootnote"/>
+ <nil key="textColor"/>
+ <nil key="highlightedColor"/>
+ </label>
+ <switch opaque="NO" tag="2" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="e57-jT-2xD">
+ <rect key="frame" x="210" y="25" width="51" height="31"/>
+ <connections>
+ <action selector="didSwitch:" destination="Tsi-Cv-L66" eventType="valueChanged" id="DNZ-Uw-kDg"/>
+ </connections>
+ </switch>
+ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Pitch" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="0uK-zq-Ys2">
+ <rect key="frame" x="312" y="6" width="31" height="16"/>
+ <constraints>
+ <constraint firstAttribute="width" constant="31" id="gM8-I7-4d3"/>
+ </constraints>
+ <fontDescription key="fontDescription" style="UICTFontTextStyleFootnote"/>
+ <nil key="textColor"/>
+ <nil key="highlightedColor"/>
+ </label>
+ <switch opaque="NO" tag="3" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="KcQ-OU-a39">
+ <rect key="frame" x="303.5" y="25" width="51" height="31"/>
+ <connections>
+ <action selector="didSwitch:" destination="Tsi-Cv-L66" eventType="valueChanged" id="WhV-yJ-avj"/>
+ </connections>
+ </switch>
+ </subviews>
+ <color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
+ <gestureRecognizers/>
+ <constraints>
+ <constraint firstItem="KcQ-OU-a39" firstAttribute="centerX" secondItem="l5l-w7-P80" secondAttribute="centerX" multiplier="1.75" id="4KT-16-PTD"/>
+ <constraint firstItem="g15-JY-ZNb" firstAttribute="top" secondItem="DgB-BD-Ltx" secondAttribute="bottom" constant="3" id="85K-VT-rjv"/>
+ <constraint firstItem="tqS-cU-tlc" firstAttribute="centerX" secondItem="l5l-w7-P80" secondAttribute="centerX" multiplier="0.75" id="8jz-5L-klT"/>
+ <constraint firstItem="z7C-yW-Y69" firstAttribute="centerX" secondItem="tqS-cU-tlc" secondAttribute="centerX" id="DXz-6O-RE3"/>
+ <constraint firstItem="0uK-zq-Ys2" firstAttribute="centerX" secondItem="KcQ-OU-a39" secondAttribute="centerX" id="Mde-fT-Bcq"/>
+ <constraint firstItem="z7C-yW-Y69" firstAttribute="bottom" secondItem="DgB-BD-Ltx" secondAttribute="bottom" id="PnN-Hv-drW"/>
+ <constraint firstItem="z7C-yW-Y69" firstAttribute="top" secondItem="DgB-BD-Ltx" secondAttribute="top" id="Q2C-Qw-gvB"/>
+ <constraint firstAttribute="bottom" secondItem="e57-jT-2xD" secondAttribute="bottom" constant="8" id="WWq-zC-XdG"/>
+ <constraint firstItem="0uK-zq-Ys2" firstAttribute="bottom" secondItem="DgB-BD-Ltx" secondAttribute="bottom" id="aBL-og-FYW"/>
+ <constraint firstItem="Vio-XU-tgS" firstAttribute="bottom" secondItem="DgB-BD-Ltx" secondAttribute="bottom" id="aMh-TW-sMO"/>
+ <constraint firstAttribute="height" constant="64" id="aSG-KD-M7a"/>
+ <constraint firstAttribute="bottom" secondItem="KcQ-OU-a39" secondAttribute="bottom" constant="8" id="cdo-Mc-M8y"/>
+ <constraint firstItem="e57-jT-2xD" firstAttribute="centerX" secondItem="l5l-w7-P80" secondAttribute="centerX" multiplier="1.25" id="e4H-V7-rMk"/>
+ <constraint firstAttribute="bottom" secondItem="tqS-cU-tlc" secondAttribute="bottom" constant="8" id="e6X-7b-GNt"/>
+ <constraint firstItem="Vio-XU-tgS" firstAttribute="top" secondItem="DgB-BD-Ltx" secondAttribute="top" id="g0I-sb-f7w"/>
+ <constraint firstItem="Vio-XU-tgS" firstAttribute="centerX" secondItem="e57-jT-2xD" secondAttribute="centerX" id="gXC-pq-4Aa"/>
+ <constraint firstAttribute="bottom" secondItem="g15-JY-ZNb" secondAttribute="bottom" constant="8" id="kBT-94-cqr"/>
+ <constraint firstItem="DgB-BD-Ltx" firstAttribute="centerX" secondItem="g15-JY-ZNb" secondAttribute="centerX" id="wjr-6Z-EUS"/>
+ <constraint firstItem="g15-JY-ZNb" firstAttribute="centerX" secondItem="l5l-w7-P80" secondAttribute="centerX" multiplier="0.25" id="xsC-iQ-ytS"/>
+ <constraint firstItem="0uK-zq-Ys2" firstAttribute="top" secondItem="DgB-BD-Ltx" secondAttribute="top" id="zK5-CA-VoR"/>
+ </constraints>
+ </view>
+ </subviews>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+ <constraints>
+ <constraint firstAttribute="trailing" secondItem="l5l-w7-P80" secondAttribute="trailing" id="3lX-X1-azn"/>
+ <constraint firstItem="Awd-m3-zh2" firstAttribute="leading" secondItem="vKr-y9-AZt" secondAttribute="leading" id="9yi-vl-QxH"/>
+ <constraint firstItem="l5l-w7-P80" firstAttribute="top" secondItem="xne-oT-1Cv" secondAttribute="bottom" id="AN8-3I-WUs"/>
+ <constraint firstAttribute="trailing" secondItem="Awd-m3-zh2" secondAttribute="trailing" id="IfY-Eb-UaJ"/>
+ <constraint firstItem="Awd-m3-zh2" firstAttribute="top" secondItem="vKr-y9-AZt" secondAttribute="top" id="ZCQ-9O-kJP"/>
+ <constraint firstItem="l5l-w7-P80" firstAttribute="leading" secondItem="vKr-y9-AZt" secondAttribute="leading" id="gGq-lE-d7X"/>
+ <constraint firstItem="Awd-m3-zh2" firstAttribute="bottom" secondItem="bxa-Bm-Qun" secondAttribute="top" id="tV3-fH-i8W"/>
+ </constraints>
+ </view>
+ <connections>
+ <outlet property="mapView" destination="EPE-uN-4XB" id="EDJ-xp-uBi"/>
+ <outlet property="scrollView" destination="Awd-m3-zh2" id="TJn-gU-Hgs"/>
+ </connections>
+ </viewController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="k2c-Gr-mpl" userLabel="First Responder" sceneMemberID="firstResponder"/>
+ <rotationGestureRecognizer id="JkF-BS-3oQ">
+ <connections>
+ <action selector="rotation:" destination="Tsi-Cv-L66" id="Zba-E5-Dmz"/>
+ </connections>
+ </rotationGestureRecognizer>
+ </objects>
+ <point key="canvasLocation" x="594.39999999999998" y="1083.5082458770617"/>
+ </scene>
</scenes>
<resources>
<image name="TrackingLocationOffMask.png" width="23" height="23"/>
diff --git a/platform/ios/bitrise.yml b/platform/ios/bitrise.yml
index 93d1d4afd8..53287ec06d 100644
--- a/platform/ios/bitrise.yml
+++ b/platform/ios/bitrise.yml
@@ -11,22 +11,7 @@ workflows:
primary:
steps:
- script:
- title: Check for skipping CI
- inputs:
- - content: |-
- #!/bin/bash
-
- if [[ -n "$(echo $GIT_CLONE_COMMIT_MESSAGE_SUBJECT | sed -n '/\[skip ci\]/p')" ||
- -n "$(echo $GIT_CLONE_COMMIT_MESSAGE_SUBJECT | sed -n '/\[ci skip\]/p')" ||
- -n "$(echo $GIT_CLONE_COMMIT_MESSAGE_BODY | sed -n 's/\[skip ci\]/p')" ||
- -n "$(echo $GIT_CLONE_COMMIT_MESSAGE_BODY | sed -n 's/\[ci skip\]/p')" ]]; then
- envman add --key SKIPCI --value true
- else
- envman add --key SKIPCI --value false
- fi
- - script:
title: Install Dependencies
- run_if: '{{enveq "SKIPCI" "false"}}'
inputs:
- content: |-
#!/bin/bash
@@ -37,7 +22,6 @@ workflows:
- is_debug: 'yes'
- script:
title: Generate Workspace
- run_if: '{{enveq "SKIPCI" "false"}}'
inputs:
- content: |-
#!/bin/bash
@@ -47,18 +31,15 @@ workflows:
- is_debug: 'yes'
- xcode-test:
title: Run SDK Unit Tests
- run_if: '{{enveq "SKIPCI" "false"}}'
inputs:
- project_path: platform/ios/ios.xcworkspace
- scheme: CI
- deploy-to-bitrise-io:
title: Deploy to Bitrise.io
- run_if: '{{enveq "SKIPCI" "false"}}'
inputs:
- notify_user_groups: none
- slack:
title: Post to Slack
- run_if: '{{enveq "SKIPCI" "false"}}'
inputs:
- webhook_url: "$SLACK_HOOK_URL"
- channel: "#gl-bots"
@@ -102,4 +83,20 @@ workflows:
export FORMAT=dynamic
make ipackage-strip
CLOUDWATCH=true platform/ios/scripts/metrics.sh
+ platform/ios/scripts/deploy-nightly.sh
- is_debug: 'yes'
+ - slack:
+ title: Post to Slack
+ inputs:
+ - webhook_url: "$SLACK_HOOK_URL"
+ - channel: "#gl-bots"
+ - from_username: 'Bitrise iOS Nightly \U0001F31D'
+ - from_username_on_error: 'Bitrise iOS Nightly \U0001F31D'
+ - message: '<${BITRISE_BUILD_URL}|Build #${BITRISE_BUILD_NUMBER}>
+ for <https://github.com/mapbox/mapbox-gl-native/compare/${BITRISE_GIT_BRANCH}@%7B1day%7D...${BITRISE_GIT_BRANCH}|mapbox/mapbox-gl-native@${BITRISE_GIT_BRANCH}>
+ completed successfully.'
+ - message_on_error: '<${BITRISE_BUILD_URL}|Build #${BITRISE_BUILD_NUMBER}>
+ for <https://github.com/mapbox/mapbox-gl-native/compare/${BITRISE_GIT_BRANCH}@%7B1day%7D...${BITRISE_GIT_BRANCH}|mapbox/mapbox-gl-native@${BITRISE_GIT_BRANCH}>
+ failed.'
+ - icon_url: https://bitrise-public-content-production.s3.amazonaws.com/slack/bitrise-slack-icon-128.png
+ - icon_url_on_error: https://bitrise-public-content-production.s3.amazonaws.com/slack/bitrise-slack-error-icon-128.png
diff --git a/platform/ios/config.cmake b/platform/ios/config.cmake
index cab8fd1357..fdb286a6d1 100644
--- a/platform/ios/config.cmake
+++ b/platform/ios/config.cmake
@@ -65,7 +65,7 @@ macro(mbgl_platform_core)
)
target_add_mason_package(mbgl-core PUBLIC geojson)
- target_add_mason_package(mbgl-core PUBLIC icu)
+ target_add_mason_package(mbgl-core PRIVATE icu)
target_compile_options(mbgl-core
PRIVATE -fobjc-arc
@@ -84,6 +84,13 @@ macro(mbgl_platform_core)
)
target_link_libraries(mbgl-core
- PUBLIC -lz
+ PUBLIC "-lz"
+ PUBLIC "-framework Foundation"
+ PUBLIC "-framework CoreGraphics"
+ PUBLIC "-framework OpenGLES"
+ PUBLIC "-framework ImageIO"
+ PUBLIC "-framework MobileCoreServices"
+ PUBLIC "-framework SystemConfiguration"
+ PUBLIC "-lsqlite3"
)
endmacro()
diff --git a/platform/ios/docs/guides/For Style Authors.md b/platform/ios/docs/guides/For Style Authors.md
index ed9018b121..734e0dc9ee 100644
--- a/platform/ios/docs/guides/For Style Authors.md
+++ b/platform/ios/docs/guides/For Style Authors.md
@@ -107,7 +107,6 @@ the following terms for concepts defined in the style specification:
In the style specification | In the SDK
---------------------------|---------
-class | style class
filter | predicate
function type | interpolation mode
id | identifier
@@ -181,6 +180,7 @@ In style JSON | In the SDK
`background` | `MGLBackgroundStyleLayer`
`circle` | `MGLCircleStyleLayer`
`fill` | `MGLFillStyleLayer`
+`fill-extrusion` | `MGLFillExtrusionStyleLayer`
`line` | `MGLLineStyleLayer`
`raster` | `MGLRasterStyleLayer`
`symbol` | `MGLSymbolStyleLayer`
@@ -206,6 +206,13 @@ In style JSON | In Objective-C | In Swift
`fill-translate` | `MGLFillStyleLayer.fillTranslation` | `MGLFillStyleLayer.fillTranslation`
`fill-translate-anchor` | `MGLFillStyleLayer.fillTranslationAnchor` | `MGLFillStyleLayer.fillTranslationAnchor`
+### Fill extrusion style layers
+
+In style JSON | In Objective-C | In Swift
+--------------|----------------|---------
+`fill-extrusion-translate` | `MGLFillExtrusionStyleLayer.fillExtrusionTranslation` | `MGLFillExtrusionStyleLayer.fillExtrusionTranslation`
+`fill-extrusion-translate-anchor` | `MGLFillExtrusionStyleLayer.fillExtrusionTranslationAnchor` | `MGLFillExtrusionStyleLayer.fillExtrusionTranslationAnchor`
+
### Line style layers
In style JSON | In Objective-C | In Swift
diff --git a/platform/ios/docs/guides/Using Style Functions at Runtime.md b/platform/ios/docs/guides/Using Style Functions at Runtime.md
index 13c4cc0bbc..c1fcaa00e9 100644
--- a/platform/ios/docs/guides/Using Style Functions at Runtime.md
+++ b/platform/ios/docs/guides/Using Style Functions at Runtime.md
@@ -1,4 +1,3 @@
-
<!--
This file is generated.
Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
@@ -31,11 +30,13 @@ The documentation for each individual style layer property notes which style fun
Stops are key-value pairs that that determine a style value. With a `MGLCameraSourceFunction` stop, you can use a dictionary with a zoom level for a key and a `MGLStyleValue` for the value. For example, you can use a stops dictionary with zoom levels 0, 10, and 20 as keys, and yellow, orange, and red as the values. A `MGLSourceStyleFunction` uses the relevant attribute value as the key.
```swift
-let stops = [0: MGLStyleValue<UIColor>(rawValue: .yellow),
- 2.5: MGLStyleValue(rawValue: .orange),
- 5: MGLStyleValue(rawValue: .red),
- 7.5: MGLStyleValue(rawValue: .blue),
- 10: MGLStyleValue(rawValue: .white)]
+let stops = [
+ 0: MGLStyleValue<UIColor>(rawValue: .yellow),
+ 2.5: MGLStyleValue(rawValue: .orange),
+ 5: MGLStyleValue(rawValue: .red),
+ 7.5: MGLStyleValue(rawValue: .blue),
+ 10: MGLStyleValue(rawValue: .white),
+]
```
## Interpolation mode
@@ -48,19 +49,21 @@ The effect a key has on the style value is determined by the interpolation mode.
The stops dictionary below, for example, shows colors that continuously shift from yellow to orange to red to blue to white based on the attribute value.
-``` swift
-let url = URL(string: "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_week.geojson")
+```swift
+let url = URL(string: "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_week.geojson")!
let symbolSource = MGLSource(identifier: "source")
let symbolLayer = MGLSymbolStyleLayer(identifier: "place-city-sm", source: symbolSource)
let source = MGLShapeSource(identifier: "earthquakes", url: url, options: nil)
-style.addSource(source)
+mapView.style?.addSource(source)
-let stops = [0: MGLStyleValue<UIColor>(rawValue: .yellow),
- 2.5: MGLStyleValue(rawValue: .orange),
- 5: MGLStyleValue(rawValue: .red),
- 7.5: MGLStyleValue(rawValue: .blue),
- 10: MGLStyleValue(rawValue: .white)]
+let stops = [
+ 0: MGLStyleValue<UIColor>(rawValue: .yellow),
+ 2.5: MGLStyleValue(rawValue: .orange),
+ 5: MGLStyleValue(rawValue: .red),
+ 7.5: MGLStyleValue(rawValue: .blue),
+ 10: MGLStyleValue(rawValue: .white),
+]
let layer = MGLCircleStyleLayer(identifier: "circles", source: source)
layer.circleColor = MGLStyleValue(interpolationMode: .exponential,
@@ -68,7 +71,7 @@ layer.circleColor = MGLStyleValue(interpolationMode: .exponential,
attributeName: "mag",
options: [.defaultValue: MGLStyleValue<UIColor>(rawValue: .green)])
layer.circleRadius = MGLStyleValue(rawValue: 10)
-style.insertLayer(layer, below: symbolLayer)
+mapView.style?.insertLayer(layer, below: symbolLayer)
```
![exponential mode](img/data-driven-styling/exponential.png)
@@ -85,13 +88,15 @@ Here’s a visualization from Mapbox Studio (see [Working with Mapbox Studio](wo
The example below increases a layer’s `circleRadius` exponentially based on a map’s zoom level. The `MGLStyleFunctionOptionInterpolationBase` is `1.5`.
```swift
-let stops = [12: MGLStyleValue(rawValue: 0.5),
- 14: MGLStyleValue(rawValue: 2),
- 18: MGLStyleValue(rawValue: 18)]
+let stops = [
+ 12: MGLStyleValue<NSNumber>(rawValue: 0.5),
+ 14: MGLStyleValue(rawValue: 2),
+ 18: MGLStyleValue(rawValue: 18),
+]
layer.circleRadius = MGLStyleValue(interpolationMode: .exponential,
- cameraStops: stops,
- options: [.interpolationBase: 1.5])
+ cameraStops: stops,
+ options: [.interpolationBase: 1.5])
```
### Interval
@@ -100,12 +105,14 @@ layer.circleRadius = MGLStyleValue(interpolationMode: .exponential,
When we use the stops dictionary given above with an interval interpolation mode, we create ranges where earthquakes with a magnitude of 0 to just less than 2.5 would be yellow, 2.5 to just less than 5 would be orange, and so on.
-``` swift
-let stops = [0: MGLStyleValue<UIColor>(rawValue: .yellow),
- 2.5: MGLStyleValue(rawValue: .orange),
- 5: MGLStyleValue(rawValue: .red),
- 7.5: MGLStyleValue(rawValue: .blue),
- 10: MGLStyleValue(rawValue: .white)]
+```swift
+let stops = [
+ 0: MGLStyleValue<UIColor>(rawValue: .yellow),
+ 2.5: MGLStyleValue(rawValue: .orange),
+ 5: MGLStyleValue(rawValue: .red),
+ 7.5: MGLStyleValue(rawValue: .blue),
+ 10: MGLStyleValue(rawValue: .white),
+]
layer.circleColor = MGLStyleValue(interpolationMode: .interval,
sourceStops: stops,
@@ -121,16 +128,17 @@ At each stop, `MGLInterpolationModeCategorical` produces an output value equal t
There are three main types of events in the dataset: earthquakes, explosions, and quarry blasts. In this case, the color of the circle layer will be determined by the type of event, with a default value of blue to catch any events that do not fall into any of those categories.
-``` swift
-let categoricalStops = ["earthquake": MGLStyleValue<UIColor>(rawValue: .orange),
- "explosion": MGLStyleValue(rawValue: .red),
- "quarry blast": MGLStyleValue(rawValue: .yellow)]
+```swift
+let categoricalStops = [
+ "earthquake": MGLStyleValue<UIColor>(rawValue: .orange),
+ "explosion": MGLStyleValue(rawValue: .red),
+ "quarry blast": MGLStyleValue(rawValue: .yellow),
+]
layer.circleColor = MGLStyleValue(interpolationMode: .categorical,
sourceStops: categoricalStops,
attributeName: "type",
options: [.defaultValue: MGLStyleValue<UIColor>(rawValue: .blue)])
-
```
![categorical mode](img/data-driven-styling/categorical1.png) ![categorical mode](img/data-driven-styling/categorical2.png)
@@ -139,12 +147,11 @@ layer.circleColor = MGLStyleValue(interpolationMode: .categorical,
`MGLInterpolationModeIdentity` uses the attribute’s value as the style value. For example, you can set the `circleRadius` to the earthquake’s magnitude. Since the attribute value itself will be used as the style value, `sourceStops` should be set to `nil`.
-``` swift
+```swift
layer.circleRadius = MGLStyleValue(interpolationMode: .identity,
sourceStops: nil,
attributeName: "mag",
options: [.defaultValue: MGLStyleValue<NSNumber>(rawValue: 0)])
-
```
![identity mode](img/data-driven-styling/identity.png)
diff --git a/platform/ios/docs/pod-README.md b/platform/ios/docs/pod-README.md
index 2e5b024fdc..0a7edc5a41 100644
--- a/platform/ios/docs/pod-README.md
+++ b/platform/ios/docs/pod-README.md
@@ -10,7 +10,7 @@ For more information, check out the [Mapbox iOS SDK homepage](https://www.mapbox
The Mapbox iOS SDK may be installed as either a dynamic framework or a static framework. (To reduce the download size, the static framework is omitted from some distributions; you may need to download the full package from the [release page](https://github.com/mapbox/mapbox-gl-native/releases/).)
-Integrating the Mapbox iOS SDK requires Xcode 7.3 or higher.
+Integrating the Mapbox iOS SDK requires Xcode 8.0 or higher. To use this SDK with Xcode 7.3.1, download and use a symbols build from the [releases](https://github.com/mapbox/mapbox-gl-native/releases) page.
{{DYNAMIC}}
diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj
index d856424be2..215d31810d 100644
--- a/platform/ios/ios.xcodeproj/project.pbxproj
+++ b/platform/ios/ios.xcodeproj/project.pbxproj
@@ -53,8 +53,8 @@
35305D4A1D22AA6A0007D005 /* NSData+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 35305D461D22AA450007D005 /* NSData+MGLAdditions.h */; };
3538AA1D1D542239008EC33D /* MGLForegroundStyleLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 3538AA1B1D542239008EC33D /* MGLForegroundStyleLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
3538AA1E1D542239008EC33D /* MGLForegroundStyleLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 3538AA1B1D542239008EC33D /* MGLForegroundStyleLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
- 3538AA1F1D542239008EC33D /* MGLForegroundStyleLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3538AA1C1D542239008EC33D /* MGLForegroundStyleLayer.m */; };
- 3538AA201D542239008EC33D /* MGLForegroundStyleLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3538AA1C1D542239008EC33D /* MGLForegroundStyleLayer.m */; };
+ 3538AA1F1D542239008EC33D /* MGLForegroundStyleLayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3538AA1C1D542239008EC33D /* MGLForegroundStyleLayer.mm */; };
+ 3538AA201D542239008EC33D /* MGLForegroundStyleLayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3538AA1C1D542239008EC33D /* MGLForegroundStyleLayer.mm */; };
353933F21D3FB753003F57D7 /* MGLCircleStyleLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 353933F11D3FB753003F57D7 /* MGLCircleStyleLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
353933F31D3FB753003F57D7 /* MGLCircleStyleLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 353933F11D3FB753003F57D7 /* MGLCircleStyleLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
353933F51D3FB785003F57D7 /* MGLBackgroundStyleLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 353933F41D3FB785003F57D7 /* MGLBackgroundStyleLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -81,6 +81,8 @@
3557F7B21E1D27D300CCA5E6 /* MGLDistanceFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 3557F7AF1E1D27D300CCA5E6 /* MGLDistanceFormatter.m */; };
35599DED1D46F14E0048254D /* MGLStyleValue.mm in Sources */ = {isa = PBXBuildFile; fileRef = 35599DEA1D46F14E0048254D /* MGLStyleValue.mm */; };
35599DEE1D46F14E0048254D /* MGLStyleValue.mm in Sources */ = {isa = PBXBuildFile; fileRef = 35599DEA1D46F14E0048254D /* MGLStyleValue.mm */; };
+ 355AE0011E9281DA00F3939D /* MGLScaleBar.mm in Sources */ = {isa = PBXBuildFile; fileRef = 355ADFFC1E9281DA00F3939D /* MGLScaleBar.mm */; };
+ 355AE0021E9281DA00F3939D /* MGLScaleBar.mm in Sources */ = {isa = PBXBuildFile; fileRef = 355ADFFC1E9281DA00F3939D /* MGLScaleBar.mm */; };
3566C7661D4A77BA008152BC /* MGLShapeSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 3566C7641D4A77BA008152BC /* MGLShapeSource.h */; settings = {ATTRIBUTES = (Public, ); }; };
3566C7671D4A77BA008152BC /* MGLShapeSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 3566C7641D4A77BA008152BC /* MGLShapeSource.h */; settings = {ATTRIBUTES = (Public, ); }; };
3566C7681D4A77BA008152BC /* MGLShapeSource.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3566C7651D4A77BA008152BC /* MGLShapeSource.mm */; };
@@ -121,6 +123,8 @@
35D13AC41D3D19DD00AFB4E0 /* MGLFillStyleLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 35D13AC11D3D19DD00AFB4E0 /* MGLFillStyleLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
35D13AC51D3D19DD00AFB4E0 /* MGLFillStyleLayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 35D13AC21D3D19DD00AFB4E0 /* MGLFillStyleLayer.mm */; };
35D13AC61D3D19DD00AFB4E0 /* MGLFillStyleLayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 35D13AC21D3D19DD00AFB4E0 /* MGLFillStyleLayer.mm */; };
+ 35D3A1E61E9BE7EB002B38EE /* MGLScaleBar.h in Headers */ = {isa = PBXBuildFile; fileRef = 355ADFFB1E9281DA00F3939D /* MGLScaleBar.h */; };
+ 35D3A1E71E9BE7EC002B38EE /* MGLScaleBar.h in Headers */ = {isa = PBXBuildFile; fileRef = 355ADFFB1E9281DA00F3939D /* MGLScaleBar.h */; };
35D9DDE21DA25EEC00DAAD69 /* MGLCodingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 35D9DDE11DA25EEC00DAAD69 /* MGLCodingTests.m */; };
35E0CFE61D3E501500188327 /* MGLStyle_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 35E0CFE51D3E501500188327 /* MGLStyle_Private.h */; };
35E0CFE71D3E501500188327 /* MGLStyle_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 35E0CFE51D3E501500188327 /* MGLStyle_Private.h */; };
@@ -138,6 +142,7 @@
4018B1C91CDC288A00F666AF /* MGLAnnotationView_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 4018B1C31CDC277F00F666AF /* MGLAnnotationView_Private.h */; };
4018B1CA1CDC288E00F666AF /* MGLAnnotationView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4018B1C51CDC277F00F666AF /* MGLAnnotationView.h */; settings = {ATTRIBUTES = (Public, ); }; };
4018B1CB1CDC288E00F666AF /* MGLAnnotationView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4018B1C51CDC277F00F666AF /* MGLAnnotationView.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 4031ACFF1E9FD29F00A3EA26 /* MGLSDKTestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4031ACFE1E9FD29F00A3EA26 /* MGLSDKTestHelpers.swift */; };
404326891D5B9B27007111BD /* MGLAnnotationContainerView_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 404326881D5B9B1A007111BD /* MGLAnnotationContainerView_Private.h */; };
4049C29D1DB6CD6C00B3F799 /* MGLPointCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = 4049C29B1DB6CD6C00B3F799 /* MGLPointCollection.h */; settings = {ATTRIBUTES = (Public, ); }; };
4049C29E1DB6CD6C00B3F799 /* MGLPointCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = 4049C29B1DB6CD6C00B3F799 /* MGLPointCollection.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -160,6 +165,7 @@
408AA8571DAEDA1700022900 /* NSDictionary+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 408AA8551DAEDA0800022900 /* NSDictionary+MGLAdditions.h */; };
408AA8581DAEDA1E00022900 /* NSDictionary+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 408AA8561DAEDA0800022900 /* NSDictionary+MGLAdditions.mm */; };
408AA8591DAEDA1E00022900 /* NSDictionary+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 408AA8561DAEDA0800022900 /* NSDictionary+MGLAdditions.mm */; };
+ 409F43FD1E9E781C0048729D /* MGLMapViewDelegateIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 409F43FC1E9E781C0048729D /* MGLMapViewDelegateIntegrationTests.swift */; };
40CF6DBB1DAC3C6600A4D18B /* MGLShape_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 40CF6DBA1DAC3C1800A4D18B /* MGLShape_Private.h */; };
40CFA6511D7875BB008103BD /* MGLShapeSourceTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 40CFA6501D787579008103BD /* MGLShapeSourceTests.mm */; };
40EDA1C01CFE0E0200D9EA68 /* MGLAnnotationContainerView.h in Headers */ = {isa = PBXBuildFile; fileRef = 40EDA1BD1CFE0D4A00D9EA68 /* MGLAnnotationContainerView.h */; };
@@ -168,7 +174,6 @@
40F887701D7A1E58008ECB67 /* MGLShapeSource_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 40F8876F1D7A1DB8008ECB67 /* MGLShapeSource_Private.h */; };
40F887711D7A1E59008ECB67 /* MGLShapeSource_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 40F8876F1D7A1DB8008ECB67 /* MGLShapeSource_Private.h */; };
40FDA76B1CCAAA6800442548 /* MBXAnnotationView.m in Sources */ = {isa = PBXBuildFile; fileRef = 40FDA76A1CCAAA6800442548 /* MBXAnnotationView.m */; };
- 554180421D2E97DE00012372 /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 554180411D2E97DE00012372 /* OpenGLES.framework */; };
556660CA1E1BF3A900E2C41B /* MGLFoundation.h in Headers */ = {isa = PBXBuildFile; fileRef = 556660C91E1BF3A900E2C41B /* MGLFoundation.h */; settings = {ATTRIBUTES = (Public, ); }; };
556660D81E1D085500E2C41B /* MGLVersionNumber.m in Sources */ = {isa = PBXBuildFile; fileRef = 556660D71E1D085500E2C41B /* MGLVersionNumber.m */; };
556660DB1E1D8E8D00E2C41B /* MGLFoundation.h in Headers */ = {isa = PBXBuildFile; fileRef = 556660C91E1BF3A900E2C41B /* MGLFoundation.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -176,8 +181,8 @@
558DE7A11E5615E400C7916D /* MGLFoundation_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 558DE79E1E5615E400C7916D /* MGLFoundation_Private.h */; };
558DE7A21E5615E400C7916D /* MGLFoundation.mm in Sources */ = {isa = PBXBuildFile; fileRef = 558DE79F1E5615E400C7916D /* MGLFoundation.mm */; };
558DE7A31E5615E400C7916D /* MGLFoundation.mm in Sources */ = {isa = PBXBuildFile; fileRef = 558DE79F1E5615E400C7916D /* MGLFoundation.mm */; };
- 55D8C9961D0F18CE00F42F10 /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 55D8C9951D0F18CE00F42F10 /* libsqlite3.tbd */; };
55E2AD131E5B125400E8C587 /* MGLOfflineStorageTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 55E2AD121E5B125400E8C587 /* MGLOfflineStorageTests.mm */; };
+ 632281DF1E6F855900D75A5D /* MBXEmbeddedMapViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 632281DE1E6F855900D75A5D /* MBXEmbeddedMapViewController.m */; };
6407D6701E0085FD00F6A9C3 /* MGLDocumentationExampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6407D66F1E0085FD00F6A9C3 /* MGLDocumentationExampleTests.swift */; };
7E016D7E1D9E86BE00A29A21 /* MGLPolyline+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 7E016D7C1D9E86BE00A29A21 /* MGLPolyline+MGLAdditions.h */; };
7E016D7F1D9E86BE00A29A21 /* MGLPolyline+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 7E016D7C1D9E86BE00A29A21 /* MGLPolyline+MGLAdditions.h */; };
@@ -188,7 +193,6 @@
7E016D861D9E890300A29A21 /* MGLPolygon+MGLAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 7E016D831D9E890300A29A21 /* MGLPolygon+MGLAdditions.m */; };
7E016D871D9E890300A29A21 /* MGLPolygon+MGLAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 7E016D831D9E890300A29A21 /* MGLPolygon+MGLAdditions.m */; };
920A3E5D1E6F995200C16EFC /* MGLSourceQueryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 920A3E5C1E6F995200C16EFC /* MGLSourceQueryTests.m */; };
- 9221B2F11E6F9D1400A2385E /* query-style.json in Resources */ = {isa = PBXBuildFile; fileRef = 9221B2F01E6F9D1400A2385E /* query-style.json */; };
9620BB381E69FE1700705A1D /* MGLSDKUpdateChecker.h in Headers */ = {isa = PBXBuildFile; fileRef = 9620BB361E69FE1700705A1D /* MGLSDKUpdateChecker.h */; };
9620BB391E69FE1700705A1D /* MGLSDKUpdateChecker.h in Headers */ = {isa = PBXBuildFile; fileRef = 9620BB361E69FE1700705A1D /* MGLSDKUpdateChecker.h */; };
9620BB3A1E69FE1700705A1D /* MGLSDKUpdateChecker.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9620BB371E69FE1700705A1D /* MGLSDKUpdateChecker.mm */; };
@@ -212,6 +216,7 @@
DA1DC99B1CB6E064006E619F /* MBXViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DA1DC99A1CB6E064006E619F /* MBXViewController.m */; };
DA1DC99D1CB6E076006E619F /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA1DC99C1CB6E076006E619F /* Default-568h@2x.png */; };
DA1DC99F1CB6E088006E619F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DA1DC99E1CB6E088006E619F /* Assets.xcassets */; };
+ DA1F8F3D1EBD287B00367E42 /* MGLDocumentationGuideTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA1F8F3C1EBD287B00367E42 /* MGLDocumentationGuideTests.swift */; };
DA2207BF1DC0805F0002F84D /* MGLStyleValueTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA2207BE1DC0805F0002F84D /* MGLStyleValueTests.swift */; };
DA25D5C01CCD9F8400607828 /* Root.plist in Resources */ = {isa = PBXBuildFile; fileRef = DA25D5BF1CCD9F8400607828 /* Root.plist */; };
DA25D5C61CCDA06800607828 /* Root.strings in Resources */ = {isa = PBXBuildFile; fileRef = DA25D5C41CCDA06800607828 /* Root.strings */; };
@@ -358,8 +363,6 @@
DA8963391CC549A100684375 /* styles in Resources */ = {isa = PBXBuildFile; fileRef = DA8963351CC549A100684375 /* styles */; };
DA89633A1CC549A100684375 /* tiles in Resources */ = {isa = PBXBuildFile; fileRef = DA8963361CC549A100684375 /* tiles */; };
DAA32CC31E4C6B65006F8D24 /* MGLDistanceFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 3557F7AF1E1D27D300CCA5E6 /* MGLDistanceFormatter.m */; };
- DAA4E4051CBB5C9E00178DFB /* ImageIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAA4E4041CBB5C9E00178DFB /* ImageIO.framework */; };
- DAA4E4071CBB5CBF00178DFB /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAA4E4061CBB5CBF00178DFB /* MobileCoreServices.framework */; };
DAA4E4081CBB6C9500178DFB /* Mapbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA8847D21CBAF91600AB86E3 /* Mapbox.framework */; };
DAA4E4091CBB6C9500178DFB /* Mapbox.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = DA8847D21CBAF91600AB86E3 /* Mapbox.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
DAA4E41C1CBB730400178DFB /* MGLAccountManager.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8848001CBAFA6200AB86E3 /* MGLAccountManager.m */; };
@@ -454,6 +457,11 @@
DD9BE4F81EB263C50079A3AF /* UIViewController+MGLAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = DD9BE4F61EB263C50079A3AF /* UIViewController+MGLAdditions.m */; };
DD9BE4F91EB263D20079A3AF /* UIViewController+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = DD9BE4F51EB263C50079A3AF /* UIViewController+MGLAdditions.h */; };
DD9BE4FA1EB263F40079A3AF /* UIViewController+MGLAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = DD9BE4F61EB263C50079A3AF /* UIViewController+MGLAdditions.m */; };
+ FA68F14A1E9D656600F9F6C2 /* MGLFillExtrusionStyleLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = FA68F1481E9D656600F9F6C2 /* MGLFillExtrusionStyleLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ FA68F14B1E9D656600F9F6C2 /* MGLFillExtrusionStyleLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = FA68F1481E9D656600F9F6C2 /* MGLFillExtrusionStyleLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ FA68F14D1E9D656600F9F6C2 /* MGLFillExtrusionStyleLayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = FA68F1491E9D656600F9F6C2 /* MGLFillExtrusionStyleLayer.mm */; };
+ FA68F14E1E9D656600F9F6C2 /* MGLFillExtrusionStyleLayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = FA68F1491E9D656600F9F6C2 /* MGLFillExtrusionStyleLayer.mm */; };
+ FAE1CDCB1E9D79CB00C40B5B /* MGLFillExtrusionStyleLayerTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = FAE1CDC81E9D79C600C40B5B /* MGLFillExtrusionStyleLayerTests.mm */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -563,7 +571,7 @@
35305D461D22AA450007D005 /* NSData+MGLAdditions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSData+MGLAdditions.h"; sourceTree = "<group>"; };
35305D471D22AA450007D005 /* NSData+MGLAdditions.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSData+MGLAdditions.mm"; sourceTree = "<group>"; };
3538AA1B1D542239008EC33D /* MGLForegroundStyleLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLForegroundStyleLayer.h; sourceTree = "<group>"; };
- 3538AA1C1D542239008EC33D /* MGLForegroundStyleLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLForegroundStyleLayer.m; sourceTree = "<group>"; };
+ 3538AA1C1D542239008EC33D /* MGLForegroundStyleLayer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLForegroundStyleLayer.mm; sourceTree = "<group>"; };
353933F11D3FB753003F57D7 /* MGLCircleStyleLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLCircleStyleLayer.h; sourceTree = "<group>"; };
353933F41D3FB785003F57D7 /* MGLBackgroundStyleLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLBackgroundStyleLayer.h; sourceTree = "<group>"; };
353933F71D3FB79F003F57D7 /* MGLLineStyleLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLLineStyleLayer.h; sourceTree = "<group>"; };
@@ -580,6 +588,8 @@
3557F7AE1E1D27D300CCA5E6 /* MGLDistanceFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLDistanceFormatter.h; sourceTree = "<group>"; };
3557F7AF1E1D27D300CCA5E6 /* MGLDistanceFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLDistanceFormatter.m; sourceTree = "<group>"; };
35599DEA1D46F14E0048254D /* MGLStyleValue.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLStyleValue.mm; sourceTree = "<group>"; };
+ 355ADFFB1E9281DA00F3939D /* MGLScaleBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLScaleBar.h; sourceTree = "<group>"; };
+ 355ADFFC1E9281DA00F3939D /* MGLScaleBar.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLScaleBar.mm; sourceTree = "<group>"; };
3566C7641D4A77BA008152BC /* MGLShapeSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLShapeSource.h; sourceTree = "<group>"; };
3566C7651D4A77BA008152BC /* MGLShapeSource.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLShapeSource.mm; sourceTree = "<group>"; };
3566C76A1D4A8DFA008152BC /* MGLRasterSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLRasterSource.h; sourceTree = "<group>"; };
@@ -607,6 +617,7 @@
35D13AC11D3D19DD00AFB4E0 /* MGLFillStyleLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLFillStyleLayer.h; sourceTree = "<group>"; };
35D13AC21D3D19DD00AFB4E0 /* MGLFillStyleLayer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLFillStyleLayer.mm; sourceTree = "<group>"; };
35D9DDE11DA25EEC00DAAD69 /* MGLCodingTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLCodingTests.m; path = ../../darwin/test/MGLCodingTests.m; sourceTree = "<group>"; };
+ 35DE35531EB7CBA8004917C5 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = sv; path = sv.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
35E0CFE51D3E501500188327 /* MGLStyle_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLStyle_Private.h; sourceTree = "<group>"; };
35E1A4D71D74336F007AA97F /* MGLValueEvaluator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLValueEvaluator.h; sourceTree = "<group>"; };
35E208A61D24210F00EC9A46 /* MGLNSDataAdditionsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLNSDataAdditionsTests.m; sourceTree = "<group>"; };
@@ -619,6 +630,7 @@
4018B1C41CDC277F00F666AF /* MGLAnnotationView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLAnnotationView.mm; sourceTree = "<group>"; };
4018B1C51CDC277F00F666AF /* MGLAnnotationView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAnnotationView.h; sourceTree = "<group>"; };
402E9DE01CD2C76200FD4519 /* Mapbox.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = Mapbox.playground; sourceTree = "<group>"; };
+ 4031ACFE1E9FD29F00A3EA26 /* MGLSDKTestHelpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MGLSDKTestHelpers.swift; path = ../../darwin/test/MGLSDKTestHelpers.swift; sourceTree = "<group>"; };
404326881D5B9B1A007111BD /* MGLAnnotationContainerView_Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLAnnotationContainerView_Private.h; sourceTree = "<group>"; };
4049C29B1DB6CD6C00B3F799 /* MGLPointCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLPointCollection.h; sourceTree = "<group>"; };
4049C29C1DB6CD6C00B3F799 /* MGLPointCollection.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLPointCollection.mm; sourceTree = "<group>"; };
@@ -632,6 +644,7 @@
4085AF081D933DEA00F11B22 /* MGLTileSetTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLTileSetTests.mm; path = ../../darwin/test/MGLTileSetTests.mm; sourceTree = "<group>"; };
408AA8551DAEDA0800022900 /* NSDictionary+MGLAdditions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+MGLAdditions.h"; sourceTree = "<group>"; };
408AA8561DAEDA0800022900 /* NSDictionary+MGLAdditions.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSDictionary+MGLAdditions.mm"; sourceTree = "<group>"; };
+ 409F43FC1E9E781C0048729D /* MGLMapViewDelegateIntegrationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MGLMapViewDelegateIntegrationTests.swift; sourceTree = "<group>"; };
40CF6DBA1DAC3C1800A4D18B /* MGLShape_Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLShape_Private.h; sourceTree = "<group>"; };
40CFA6501D787579008103BD /* MGLShapeSourceTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLShapeSourceTests.mm; path = ../../darwin/test/MGLShapeSourceTests.mm; sourceTree = "<group>"; };
40EDA1BD1CFE0D4A00D9EA68 /* MGLAnnotationContainerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAnnotationContainerView.h; sourceTree = "<group>"; };
@@ -647,13 +660,14 @@
55D8C9941D0F133500F42F10 /* config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = config.xcconfig; path = ../../build/ios/config.xcconfig; sourceTree = "<group>"; };
55D8C9951D0F18CE00F42F10 /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = usr/lib/libsqlite3.tbd; sourceTree = SDKROOT; };
55E2AD121E5B125400E8C587 /* MGLOfflineStorageTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLOfflineStorageTests.mm; path = ../../darwin/test/MGLOfflineStorageTests.mm; sourceTree = "<group>"; };
+ 632281DD1E6F855900D75A5D /* MBXEmbeddedMapViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MBXEmbeddedMapViewController.h; sourceTree = "<group>"; };
+ 632281DE1E6F855900D75A5D /* MBXEmbeddedMapViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MBXEmbeddedMapViewController.m; sourceTree = "<group>"; };
6407D66F1E0085FD00F6A9C3 /* MGLDocumentationExampleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MGLDocumentationExampleTests.swift; path = ../../darwin/test/MGLDocumentationExampleTests.swift; sourceTree = "<group>"; };
7E016D7C1D9E86BE00A29A21 /* MGLPolyline+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MGLPolyline+MGLAdditions.h"; sourceTree = "<group>"; };
7E016D7D1D9E86BE00A29A21 /* MGLPolyline+MGLAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MGLPolyline+MGLAdditions.m"; sourceTree = "<group>"; };
7E016D821D9E890300A29A21 /* MGLPolygon+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MGLPolygon+MGLAdditions.h"; sourceTree = "<group>"; };
7E016D831D9E890300A29A21 /* MGLPolygon+MGLAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MGLPolygon+MGLAdditions.m"; sourceTree = "<group>"; };
920A3E5C1E6F995200C16EFC /* MGLSourceQueryTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLSourceQueryTests.m; path = ../../darwin/test/MGLSourceQueryTests.m; sourceTree = "<group>"; };
- 9221B2F01E6F9D1400A2385E /* query-style.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "query-style.json"; path = "../../darwin/test/query-style.json"; sourceTree = "<group>"; };
9620BB361E69FE1700705A1D /* MGLSDKUpdateChecker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLSDKUpdateChecker.h; sourceTree = "<group>"; };
9620BB371E69FE1700705A1D /* MGLSDKUpdateChecker.mm */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = MGLSDKUpdateChecker.mm; sourceTree = "<group>"; };
9660916B1E5BBFD700A9A03B /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = "<group>"; };
@@ -694,6 +708,7 @@
DA1DC99A1CB6E064006E619F /* MBXViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MBXViewController.m; sourceTree = "<group>"; };
DA1DC99C1CB6E076006E619F /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = "<group>"; };
DA1DC99E1CB6E088006E619F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
+ DA1F8F3C1EBD287B00367E42 /* MGLDocumentationGuideTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MGLDocumentationGuideTests.swift; path = ../../darwin/test/MGLDocumentationGuideTests.swift; sourceTree = "<group>"; };
DA2207BE1DC0805F0002F84D /* MGLStyleValueTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MGLStyleValueTests.swift; path = ../../darwin/test/MGLStyleValueTests.swift; sourceTree = "<group>"; };
DA25D5B91CCD9EDE00607828 /* Settings.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Settings.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
DA25D5BF1CCD9F8400607828 /* Root.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Root.plist; sourceTree = "<group>"; };
@@ -723,6 +738,9 @@
DA35D0871E1A6309007DED41 /* one-liner.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "one-liner.json"; path = "../../darwin/test/one-liner.json"; sourceTree = "<group>"; };
DA3C6FF21E2859E700F962BE /* test-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "test-Bridging-Header.h"; path = "../../darwin/test/test-Bridging-Header.h"; sourceTree = "<group>"; };
DA4A26961CB6E795000B7809 /* Mapbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Mapbox.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ DA57D4AA1EBA8ED300793288 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = es; path = es.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
+ DA57D4AB1EBA909900793288 /* lt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = lt; path = lt.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
+ DA57D4AC1EBA922A00793288 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = vi; path = vi.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
DA6023F11E4CE94300DBFF23 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Foundation.strings; sourceTree = "<group>"; };
DA6023F21E4CE94800DBFF23 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = sv; path = sv.lproj/Foundation.stringsdict; sourceTree = "<group>"; };
DA618B111E68823600CB7F44 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ru; path = ru.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
@@ -894,6 +912,7 @@
DAE7DEC11E245455007505A6 /* MGLNSStringAdditionsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLNSStringAdditionsTests.m; path = ../../darwin/test/MGLNSStringAdditionsTests.m; sourceTree = "<group>"; };
DAE8CCAD1E6E8C70009B5CB0 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = "<group>"; };
DAE8CCAE1E6E8C76009B5CB0 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Root.strings; sourceTree = "<group>"; };
+ DAE9E0F11EB7BF1B001E8E8B /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Foundation.strings; sourceTree = "<group>"; };
DAED38611D62D0FC00D7640F /* NSURL+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSURL+MGLAdditions.h"; sourceTree = "<group>"; };
DAED38621D62D0FC00D7640F /* NSURL+MGLAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSURL+MGLAdditions.m"; sourceTree = "<group>"; };
DAEDC4331D603417000224FF /* MGLAttributionInfoTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLAttributionInfoTests.m; path = ../../darwin/test/MGLAttributionInfoTests.m; sourceTree = "<group>"; };
@@ -911,6 +930,9 @@
DD58A4C51D822BD000E1F038 /* MGLExpressionTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLExpressionTests.mm; path = ../../darwin/test/MGLExpressionTests.mm; sourceTree = "<group>"; };
DD9BE4F51EB263C50079A3AF /* UIViewController+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIViewController+MGLAdditions.h"; sourceTree = "<group>"; };
DD9BE4F61EB263C50079A3AF /* UIViewController+MGLAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIViewController+MGLAdditions.m"; sourceTree = "<group>"; };
+ FA68F1481E9D656600F9F6C2 /* MGLFillExtrusionStyleLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLFillExtrusionStyleLayer.h; sourceTree = "<group>"; };
+ FA68F1491E9D656600F9F6C2 /* MGLFillExtrusionStyleLayer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLFillExtrusionStyleLayer.mm; sourceTree = "<group>"; };
+ FAE1CDC81E9D79C600C40B5B /* MGLFillExtrusionStyleLayerTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLFillExtrusionStyleLayerTests.mm; path = ../../darwin/test/MGLFillExtrusionStyleLayerTests.mm; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -919,7 +941,6 @@
buildActionMask = 2147483647;
files = (
DA8847D91CBAF91600AB86E3 /* Mapbox.framework in Frameworks */,
- 554180421D2E97DE00012372 /* OpenGLES.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -936,10 +957,7 @@
buildActionMask = 2147483647;
files = (
DAABF73D1CBC59BB005B1825 /* libmbgl-core.a in Frameworks */,
- 55D8C9961D0F18CE00F42F10 /* libsqlite3.tbd in Frameworks */,
DA27C24E1CBB3811000B0ECD /* GLKit.framework in Frameworks */,
- DAA4E4051CBB5C9E00178DFB /* ImageIO.framework in Frameworks */,
- DAA4E4071CBB5CBF00178DFB /* MobileCoreServices.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -991,10 +1009,12 @@
35136D381D42271A00C20EFD /* MGLBackgroundStyleLayer.mm */,
353933F11D3FB753003F57D7 /* MGLCircleStyleLayer.h */,
35136D3B1D42272500C20EFD /* MGLCircleStyleLayer.mm */,
+ FA68F1481E9D656600F9F6C2 /* MGLFillExtrusionStyleLayer.h */,
+ FA68F1491E9D656600F9F6C2 /* MGLFillExtrusionStyleLayer.mm */,
35D13AC11D3D19DD00AFB4E0 /* MGLFillStyleLayer.h */,
35D13AC21D3D19DD00AFB4E0 /* MGLFillStyleLayer.mm */,
3538AA1B1D542239008EC33D /* MGLForegroundStyleLayer.h */,
- 3538AA1C1D542239008EC33D /* MGLForegroundStyleLayer.m */,
+ 3538AA1C1D542239008EC33D /* MGLForegroundStyleLayer.mm */,
353933F71D3FB79F003F57D7 /* MGLLineStyleLayer.h */,
35136D3E1D42273000C20EFD /* MGLLineStyleLayer.mm */,
DA7262091DEEE3480043BB89 /* MGLOpenGLStyleLayer.h */,
@@ -1035,6 +1055,15 @@
name = Categories;
sourceTree = "<group>";
};
+ 355ADFF91E9281C300F3939D /* Views */ = {
+ isa = PBXGroup;
+ children = (
+ 355ADFFB1E9281DA00F3939D /* MGLScaleBar.h */,
+ 355ADFFC1E9281DA00F3939D /* MGLScaleBar.mm */,
+ );
+ name = Views;
+ sourceTree = "<group>";
+ };
357579811D502AD4000B822E /* Styling */ = {
isa = PBXGroup;
children = (
@@ -1053,6 +1082,7 @@
DA2DBBCC1D51E80400D38FF9 /* MGLStyleLayerTests.h */,
DA2DBBCD1D51E80400D38FF9 /* MGLStyleLayerTests.m */,
DA3C6FF21E2859E700F962BE /* test-Bridging-Header.h */,
+ FAE1CDC81E9D79C600C40B5B /* MGLFillExtrusionStyleLayerTests.mm */,
3575797F1D501E09000B822E /* MGLFillStyleLayerTests.mm */,
357579821D502AE6000B822E /* MGLRasterStyleLayerTests.mm */,
357579841D502AF5000B822E /* MGLSymbolStyleLayerTests.mm */,
@@ -1086,6 +1116,22 @@
name = Playground;
sourceTree = "<group>";
};
+ 4031ACFD1E9FD26900A3EA26 /* Test Helpers */ = {
+ isa = PBXGroup;
+ children = (
+ 4031ACFE1E9FD29F00A3EA26 /* MGLSDKTestHelpers.swift */,
+ );
+ name = "Test Helpers";
+ sourceTree = "<group>";
+ };
+ 409F43FB1E9E77D10048729D /* Swift Integration */ = {
+ isa = PBXGroup;
+ children = (
+ 409F43FC1E9E781C0048729D /* MGLMapViewDelegateIntegrationTests.swift */,
+ );
+ name = "Swift Integration";
+ sourceTree = "<group>";
+ };
40CFA64E1D78754A008103BD /* Sources */ = {
isa = PBXGroup;
children = (
@@ -1139,6 +1185,8 @@
DA1DC9691CB6C6B7006E619F /* MBXOfflinePacksTableViewController.m */,
DA1DC9531CB6C1C2006E619F /* MBXViewController.h */,
DA1DC99A1CB6E064006E619F /* MBXViewController.m */,
+ 632281DD1E6F855900D75A5D /* MBXEmbeddedMapViewController.h */,
+ 632281DE1E6F855900D75A5D /* MBXEmbeddedMapViewController.m */,
DA821D051CCC6D59007508D4 /* Main.storyboard */,
DA821D041CCC6D59007508D4 /* LaunchScreen.storyboard */,
DA1DC99E1CB6E088006E619F /* Assets.xcassets */,
@@ -1196,6 +1244,8 @@
DA2E88521CC036F400F24E7B /* SDK Tests */ = {
isa = PBXGroup;
children = (
+ 4031ACFD1E9FD26900A3EA26 /* Test Helpers */,
+ 409F43FB1E9E77D10048729D /* Swift Integration */,
357579811D502AD4000B822E /* Styling */,
DAEDC4331D603417000224FF /* MGLAttributionInfoTests.m */,
353D23951D0B0DFE002BE09D /* MGLAnnotationViewTests.m */,
@@ -1204,6 +1254,7 @@
DA35A2C41CCA9F8300E826B2 /* MGLCompassDirectionFormatterTests.m */,
DA35A2A91CCA058D00E826B2 /* MGLCoordinateFormatterTests.m */,
6407D66F1E0085FD00F6A9C3 /* MGLDocumentationExampleTests.swift */,
+ DA1F8F3C1EBD287B00367E42 /* MGLDocumentationGuideTests.swift */,
DD58A4C51D822BD000E1F038 /* MGLExpressionTests.mm */,
3598544C1E1D38AA00B29F84 /* MGLDistanceFormatterTests.m */,
DA0CD58F1CF56F6A00A5F5A5 /* MGLFeatureTests.mm */,
@@ -1220,7 +1271,6 @@
DA2E88551CC036F400F24E7B /* Info.plist */,
DA2784FB1DF02FF4001D5B8D /* Media.xcassets */,
DA35D0871E1A6309007DED41 /* one-liner.json */,
- 9221B2F01E6F9D1400A2385E /* query-style.json */,
);
name = "SDK Tests";
path = test;
@@ -1279,6 +1329,7 @@
DA8848331CBAFB2A00AB86E3 /* Kit */ = {
isa = PBXGroup;
children = (
+ 355ADFF91E9281C300F3939D /* Views */,
35CE617F1D4165C2004F2359 /* Categories */,
DAD165841CF4D06B001FF4B9 /* Annotations */,
DAD165851CF4D08B001FF4B9 /* Telemetry */,
@@ -1610,6 +1661,7 @@
40CF6DBB1DAC3C6600A4D18B /* MGLShape_Private.h in Headers */,
4018B1CA1CDC288E00F666AF /* MGLAnnotationView.h in Headers */,
35E79F201D41266300957B9E /* MGLStyleLayer_Private.h in Headers */,
+ FA68F14A1E9D656600F9F6C2 /* MGLFillExtrusionStyleLayer.h in Headers */,
353933FB1D3FB7C0003F57D7 /* MGLRasterStyleLayer.h in Headers */,
DA8847EF1CBAFA5100AB86E3 /* MGLAccountManager.h in Headers */,
DA8848511CBAFB9800AB86E3 /* MGLAPIClient.h in Headers */,
@@ -1618,6 +1670,7 @@
DA6408DB1DA4E7D300908C90 /* MGLVectorStyleLayer.h in Headers */,
DD0902AB1DB192A800C5BDCE /* MGLNetworkConfiguration.h in Headers */,
DA8848571CBAFB9800AB86E3 /* MGLMapboxEvents.h in Headers */,
+ 35D3A1E61E9BE7EB002B38EE /* MGLScaleBar.h in Headers */,
DA8848311CBAFA6200AB86E3 /* NSString+MGLAdditions.h in Headers */,
353933F81D3FB79F003F57D7 /* MGLLineStyleLayer.h in Headers */,
DAAF722D1DA903C700312FA4 /* MGLStyleValue_Private.h in Headers */,
@@ -1692,6 +1745,7 @@
35B82BF91D6C5F8400B1B721 /* NSPredicate+MGLAdditions.h in Headers */,
DA35A2CA1CCAAAD200E826B2 /* NSValue+MGLAdditions.h in Headers */,
350098BC1D480108004B2AF0 /* MGLVectorSource.h in Headers */,
+ FA68F14B1E9D656600F9F6C2 /* MGLFillExtrusionStyleLayer.h in Headers */,
353933FC1D3FB7C0003F57D7 /* MGLRasterStyleLayer.h in Headers */,
3566C76D1D4A8DFA008152BC /* MGLRasterSource.h in Headers */,
DAED38641D62D0FC00D7640F /* NSURL+MGLAdditions.h in Headers */,
@@ -1704,6 +1758,7 @@
404C26E31D89B877000AA13D /* MGLTileSource.h in Headers */,
DABFB8611CBE99E500D62B32 /* MGLMultiPoint.h in Headers */,
3510FFF11D6D9D8C00F413B2 /* NSExpression+MGLAdditions.h in Headers */,
+ 35D3A1E71E9BE7EC002B38EE /* MGLScaleBar.h in Headers */,
35E0CFE71D3E501500188327 /* MGLStyle_Private.h in Headers */,
DABFB86D1CBE9A0F00D62B32 /* MGLAnnotationImage.h in Headers */,
DABFB8721CBE9A0F00D62B32 /* MGLUserLocation.h in Headers */,
@@ -2008,7 +2063,6 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- 9221B2F11E6F9D1400A2385E /* query-style.json in Resources */,
DA2784FC1DF02FF4001D5B8D /* Media.xcassets in Resources */,
353BAEF71D646370009A8DA9 /* amsterdam.geojson in Resources */,
DA35D0881E1A6309007DED41 /* one-liner.json in Resources */,
@@ -2089,6 +2143,7 @@
DA1DC96A1CB6C6B7006E619F /* MBXCustomCalloutView.m in Sources */,
DA1DC99B1CB6E064006E619F /* MBXViewController.m in Sources */,
40FDA76B1CCAAA6800442548 /* MBXAnnotationView.m in Sources */,
+ 632281DF1E6F855900D75A5D /* MBXEmbeddedMapViewController.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -2099,10 +2154,12 @@
6407D6701E0085FD00F6A9C3 /* MGLDocumentationExampleTests.swift in Sources */,
DA2E88631CC0382C00F24E7B /* MGLOfflineRegionTests.m in Sources */,
3599A3E61DF708BC00E77FB2 /* MGLStyleValueTests.m in Sources */,
+ 409F43FD1E9E781C0048729D /* MGLMapViewDelegateIntegrationTests.swift in Sources */,
DA2E88651CC0382C00F24E7B /* MGLStyleTests.mm in Sources */,
DA2E88611CC0382C00F24E7B /* MGLGeometryTests.mm in Sources */,
357579801D501E09000B822E /* MGLFillStyleLayerTests.mm in Sources */,
35D9DDE21DA25EEC00DAAD69 /* MGLCodingTests.m in Sources */,
+ DA1F8F3D1EBD287B00367E42 /* MGLDocumentationGuideTests.swift in Sources */,
3598544D1E1D38AA00B29F84 /* MGLDistanceFormatterTests.m in Sources */,
DA2DBBCE1D51E80400D38FF9 /* MGLStyleLayerTests.m in Sources */,
DA35A2C61CCA9F8300E826B2 /* MGLCompassDirectionFormatterTests.m in Sources */,
@@ -2122,12 +2179,14 @@
DA2E88621CC0382C00F24E7B /* MGLOfflinePackTests.m in Sources */,
55E2AD131E5B125400E8C587 /* MGLOfflineStorageTests.mm in Sources */,
920A3E5D1E6F995200C16EFC /* MGLSourceQueryTests.m in Sources */,
+ FAE1CDCB1E9D79CB00C40B5B /* MGLFillExtrusionStyleLayerTests.mm in Sources */,
DA35A2AA1CCA058D00E826B2 /* MGLCoordinateFormatterTests.m in Sources */,
357579831D502AE6000B822E /* MGLRasterStyleLayerTests.mm in Sources */,
353D23961D0B0DFE002BE09D /* MGLAnnotationViewTests.m in Sources */,
35E208A71D24210F00EC9A46 /* MGLNSDataAdditionsTests.m in Sources */,
DA0CD5901CF56F6A00A5F5A5 /* MGLFeatureTests.mm in Sources */,
556660D81E1D085500E2C41B /* MGLVersionNumber.m in Sources */,
+ 4031ACFF1E9FD29F00A3EA26 /* MGLSDKTestHelpers.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -2154,7 +2213,7 @@
3566C7681D4A77BA008152BC /* MGLShapeSource.mm in Sources */,
400533021DB0862B0069F638 /* NSArray+MGLAdditions.mm in Sources */,
35136D421D42274500C20EFD /* MGLRasterStyleLayer.mm in Sources */,
- 3538AA1F1D542239008EC33D /* MGLForegroundStyleLayer.m in Sources */,
+ 3538AA1F1D542239008EC33D /* MGLForegroundStyleLayer.mm in Sources */,
DA00FC901D5EEB0D009AABC8 /* MGLAttributionInfo.mm in Sources */,
DA88482D1CBAFA6200AB86E3 /* NSBundle+MGLAdditions.m in Sources */,
DA88485B1CBAFB9800AB86E3 /* MGLUserLocation.m in Sources */,
@@ -2187,7 +2246,9 @@
DA88481F1CBAFA6200AB86E3 /* MGLMultiPoint.mm in Sources */,
DA88482B1CBAFA6200AB86E3 /* MGLTypes.m in Sources */,
4018B1C71CDC287F00F666AF /* MGLAnnotationView.mm in Sources */,
+ FA68F14D1E9D656600F9F6C2 /* MGLFillExtrusionStyleLayer.mm in Sources */,
404C26E41D89B877000AA13D /* MGLTileSource.mm in Sources */,
+ 355AE0011E9281DA00F3939D /* MGLScaleBar.mm in Sources */,
DA88481D1CBAFA6200AB86E3 /* MGLMapCamera.mm in Sources */,
DA8848261CBAFA6200AB86E3 /* MGLPolygon.mm in Sources */,
35B82BFA1D6C5F8400B1B721 /* NSPredicate+MGLAdditions.mm in Sources */,
@@ -2233,7 +2294,7 @@
3566C7691D4A77BA008152BC /* MGLShapeSource.mm in Sources */,
400533031DB086490069F638 /* NSArray+MGLAdditions.mm in Sources */,
35136D431D42274500C20EFD /* MGLRasterStyleLayer.mm in Sources */,
- 3538AA201D542239008EC33D /* MGLForegroundStyleLayer.m in Sources */,
+ 3538AA201D542239008EC33D /* MGLForegroundStyleLayer.mm in Sources */,
DA00FC911D5EEB0D009AABC8 /* MGLAttributionInfo.mm in Sources */,
DAA4E4201CBB730400178DFB /* MGLOfflinePack.mm in Sources */,
DAA4E4331CBB730400178DFB /* MGLUserLocation.m in Sources */,
@@ -2266,7 +2327,9 @@
DAA4E4301CBB730400178DFB /* MGLLocationManager.m in Sources */,
DAA4E4321CBB730400178DFB /* MGLMapView.mm in Sources */,
DAA4E41E1CBB730400178DFB /* MGLMapCamera.mm in Sources */,
+ FA68F14E1E9D656600F9F6C2 /* MGLFillExtrusionStyleLayer.mm in Sources */,
404C26E51D89B877000AA13D /* MGLTileSource.mm in Sources */,
+ 355AE0021E9281DA00F3939D /* MGLScaleBar.mm in Sources */,
4018B1C81CDC287F00F666AF /* MGLAnnotationView.mm in Sources */,
DAA4E4341CBB730400178DFB /* MGLFaux3DUserLocationAnnotationView.m in Sources */,
35B82BFB1D6C5F8400B1B721 /* NSPredicate+MGLAdditions.mm in Sources */,
@@ -2416,6 +2479,7 @@
DA6023F11E4CE94300DBFF23 /* sv */,
DA618B1C1E6888EC00CB7F44 /* ca */,
DA618B251E68920500CB7F44 /* lt */,
+ DAE9E0F11EB7BF1B001E8E8B /* es */,
);
name = Foundation.strings;
sourceTree = "<group>";
@@ -2455,6 +2519,10 @@
DA9C012B1E4C7AD900C4742A /* pt-BR */,
DA618B111E68823600CB7F44 /* ru */,
DA618B191E68883700CB7F44 /* ca */,
+ 35DE35531EB7CBA8004917C5 /* sv */,
+ DA57D4AA1EBA8ED300793288 /* es */,
+ DA57D4AB1EBA909900793288 /* lt */,
+ DA57D4AC1EBA922A00793288 /* vi */,
);
name = Localizable.stringsdict;
sourceTree = "<group>";
@@ -2623,6 +2691,7 @@
"$(geometry_cflags)",
"$(geojson_cflags)",
);
+ OTHER_SWIFT_FLAGS = "-warnings-as-errors";
PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.test;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "../darwin/test/test-Bridging-Header.h";
@@ -2646,6 +2715,7 @@
"$(geometry_cflags)",
"$(geojson_cflags)",
);
+ OTHER_SWIFT_FLAGS = "-warnings-as-errors";
PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.test;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "../darwin/test/test-Bridging-Header.h";
diff --git a/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/iosapp.xcscheme b/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/iosapp.xcscheme
index f1227ac139..035c7818ae 100644
--- a/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/iosapp.xcscheme
+++ b/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/iosapp.xcscheme
@@ -61,13 +61,6 @@
ReferencedContainer = "container:ios.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
- <EnvironmentVariables>
- <EnvironmentVariable
- key = "OS_ACTIVITY_MODE"
- value = "disable"
- isEnabled = "YES">
- </EnvironmentVariable>
- </EnvironmentVariables>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
diff --git a/platform/ios/jazzy.yml b/platform/ios/jazzy.yml
index 87af09a9b9..e0ce29beba 100644
--- a/platform/ios/jazzy.yml
+++ b/platform/ios/jazzy.yml
@@ -85,6 +85,7 @@ custom_categories:
- MGLVectorStyleLayer
- MGLCircleStyleLayer
- MGLFillStyleLayer
+ - MGLFillExtrusionStyleLayer
- MGLLineStyleLayer
- MGLSymbolStyleLayer
- name: Offline Maps
diff --git a/platform/ios/resources/Base.lproj/Localizable.strings b/platform/ios/resources/Base.lproj/Localizable.strings
index ab071a4505..3f59262d71 100644
--- a/platform/ios/resources/Base.lproj/Localizable.strings
+++ b/platform/ios/resources/Base.lproj/Localizable.strings
@@ -10,6 +10,9 @@
/* No comment provided by engineer. */
"CANCEL" = "Cancel";
+/* Accessibility hint for closing the selected annotation’s callout view and returning to the map */
+"CLOSE_CALLOUT_A11Y_HINT" = "Returns to the map";
+
/* Accessibility hint */
"COMPASS_A11Y_HINT" = "Rotates the map to face due north";
@@ -31,6 +34,12 @@
/* Accessibility label */
"INFO_A11Y_LABEL" = "About this map";
+/* User-friendly error description */
+"LOAD_MAP_FAILED_DESC" = "The map failed to load because an unknown error occurred.";
+
+/* User-friendly error description */
+"LOAD_STYLE_FAILED_DESC" = "The map failed to load because the style can't be loaded.";
+
/* Accessibility label */
"LOGO_A11Y_LABEL" = "Mapbox";
@@ -40,12 +49,18 @@
/* Map accessibility value */
"MAP_A11Y_VALUE" = "Zoom %1$dx\n%2$ld annotation(s) visible";
+/* User-friendly error description */
+"PARSE_STYLE_FAILED_DESC" = "The map failed to load because the style is corrupted.";
+
/* Action sheet title */
"SDK_NAME" = "Mapbox iOS SDK";
/* Developer-only SDK update notification; {latest version, in format x.x.x} */
"SDK_UPDATE_AVAILABLE" = "Mapbox iOS SDK version %@ is now available:";
+/* User-friendly error description */
+"STYLE_NOT_FOUND_DESC" = "The map failed to load because the style can’t be found or is incompatible.";
+
/* Telemetry prompt message */
"TELEMETRY_DISABLED_MSG" = "You can help make OpenStreetMap and Mapbox maps better by contributing anonymous usage data.";
diff --git a/platform/ios/resources/ca.lproj/Localizable.strings b/platform/ios/resources/ca.lproj/Localizable.strings
index aec7226e6b..ae655f282d 100644
--- a/platform/ios/resources/ca.lproj/Localizable.strings
+++ b/platform/ios/resources/ca.lproj/Localizable.strings
@@ -10,6 +10,9 @@
/* No comment provided by engineer. */
"CANCEL" = "Cancel·lar";
+/* Accessibility hint for closing the selected annotation’s callout view and returning to the map */
+"CLOSE_CALLOUT_A11Y_HINT" = "Torna al mapa";
+
/* Accessibility hint */
"COMPASS_A11Y_HINT" = "Orienta el mapa amb rumb nord";
@@ -31,6 +34,12 @@
/* Accessibility label */
"INFO_A11Y_LABEL" = "Sobre aquest mapa";
+/* User-friendly error description */
+"LOAD_MAP_FAILED_DESC" = "El mapa no s’ha carregat a causa d’un error desconegut.";
+
+/* User-friendly error description */
+"LOAD_STYLE_FAILED_DESC" = "El mapa no s’ha carregat perquè l’estil no es pot carregar.";
+
/* Accessibility label */
"LOGO_A11Y_LABEL" = "Mapbox";
@@ -40,9 +49,18 @@
/* Map accessibility value */
"MAP_A11Y_VALUE" = "Zoom %1$dx\n%2$ld anotació (ns) visibles";
+/* User-friendly error description */
+"PARSE_STYLE_FAILED_DESC" = "El mapa no s’ha carregat perquè s’ha corromput l’estil.";
+
/* Action sheet title */
"SDK_NAME" = "Mapbox iOS SDK";
+/* Developer-only SDK update notification; {latest version, in format x.x.x} */
+"SDK_UPDATE_AVAILABLE" = "La versió %@ del Mapbox iOS SDK està disponible:";
+
+/* User-friendly error description */
+"STYLE_NOT_FOUND_DESC" = "El mapa no s’ha carregat perquè no es troba l’estil o bé és incompatible.";
+
/* Telemetry prompt message */
"TELEMETRY_DISABLED_MSG" = "Pots ajudar a millorar els mapes d’OpenStreetMap i de Mapbox aportant dades d’ús anònimes.";
diff --git a/platform/ios/resources/ca.lproj/Localizable.stringsdict b/platform/ios/resources/ca.lproj/Localizable.stringsdict
index 85a839d870..45d4842ff6 100644
--- a/platform/ios/resources/ca.lproj/Localizable.stringsdict
+++ b/platform/ios/resources/ca.lproj/Localizable.stringsdict
@@ -5,8 +5,19 @@
<key>MAP_A11Y_VALUE</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
- <string>Zoom %dx
-%#@count@ visible</string>
+ <string>%#@level@
+%#@count@</string>
+ <key>level</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>Zoom %dx</string>
+ <key>other</key>
+ <string>Zoom %dx</string>
+ </dict>
<key>count</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
@@ -14,9 +25,9 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
- <string>%d anotació</string>
+ <string>%d anotació visible</string>
<key>other</key>
- <string>%d anotacions</string>
+ <string>%d anotacions visibles</string>
</dict>
</dict>
</dict>
diff --git a/platform/ios/resources/de.lproj/Localizable.stringsdict b/platform/ios/resources/de.lproj/Localizable.stringsdict
index a41ddac14e..7d334c77f8 100644
--- a/platform/ios/resources/de.lproj/Localizable.stringsdict
+++ b/platform/ios/resources/de.lproj/Localizable.stringsdict
@@ -5,8 +5,19 @@
<key>MAP_A11Y_VALUE</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
- <string>Zoomstufe %d
-%#@count@ sichtbar</string>
+ <string>%#@level@
+%#@count@</string>
+ <key>level</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>Zoomstufe %d</string>
+ <key>other</key>
+ <string>Zoomstufe %d</string>
+ </dict>
<key>count</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
@@ -14,9 +25,9 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
- <string>%d Anmerkung</string>
+ <string>%d Anmerkung sichtbar</string>
<key>other</key>
- <string>%d Anmerkungen</string>
+ <string>%d Anmerkungen sichtbar</string>
</dict>
</dict>
</dict>
diff --git a/platform/ios/resources/en.lproj/Localizable.stringsdict b/platform/ios/resources/en.lproj/Localizable.stringsdict
index ee4de02116..e849318fe5 100644
--- a/platform/ios/resources/en.lproj/Localizable.stringsdict
+++ b/platform/ios/resources/en.lproj/Localizable.stringsdict
@@ -5,8 +5,19 @@
<key>MAP_A11Y_VALUE</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
- <string>Zoom %dx
-%#@count@ visible</string>
+ <string>%#@level@
+%#@count@</string>
+ <key>level</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>Zoom %dx</string>
+ <key>other</key>
+ <string>Zoom %dx</string>
+ </dict>
<key>count</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
@@ -14,9 +25,9 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
- <string>%d annotation</string>
+ <string>%d annotation visible</string>
<key>other</key>
- <string>%d annotations</string>
+ <string>%d annotations visible</string>
</dict>
</dict>
</dict>
diff --git a/platform/ios/resources/es.lproj/Localizable.strings b/platform/ios/resources/es.lproj/Localizable.strings
index 88a7d8b42f..6fbfb23dda 100644
--- a/platform/ios/resources/es.lproj/Localizable.strings
+++ b/platform/ios/resources/es.lproj/Localizable.strings
@@ -38,7 +38,7 @@
"MAP_A11Y_LABEL" = "Mapa";
/* Map accessibility value */
-"MAP_A11Y_VALUE" = "Zoom %1$dx\n%2$ld annotation(s) visible";
+"MAP_A11Y_VALUE" = "Zoom %1$dx\nAnotaciones visibles: %2$ld";
/* Action sheet title */
"SDK_NAME" = "Mapbox iOS SDK";
diff --git a/platform/ios/resources/es.lproj/Localizable.stringsdict b/platform/ios/resources/es.lproj/Localizable.stringsdict
new file mode 100644
index 0000000000..9532801ffa
--- /dev/null
+++ b/platform/ios/resources/es.lproj/Localizable.stringsdict
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>MAP_A11Y_VALUE</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>%#@level@
+%#@count@</string>
+ <key>level</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>Zoom %dx</string>
+ <key>other</key>
+ <string>Zoom %dx</string>
+ </dict>
+ <key>count</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>ld</string>
+ <key>one</key>
+ <string>%d anotación visible</string>
+ <key>other</key>
+ <string>%d anotaciones visibles</string>
+ </dict>
+ </dict>
+</dict>
+</plist>
diff --git a/platform/ios/resources/fr.lproj/Localizable.stringsdict b/platform/ios/resources/fr.lproj/Localizable.stringsdict
index 76a698053f..4222421a12 100644
--- a/platform/ios/resources/fr.lproj/Localizable.stringsdict
+++ b/platform/ios/resources/fr.lproj/Localizable.stringsdict
@@ -5,8 +5,19 @@
<key>MAP_A11Y_VALUE</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
- <string>Zoom %dx
+ <string>%#@level@
%#@count@</string>
+ <key>level</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>Zoom %dx</string>
+ <key>other</key>
+ <string>Zoom %dx</string>
+ </dict>
<key>count</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
diff --git a/platform/ios/resources/lt.lproj/Localizable.strings b/platform/ios/resources/lt.lproj/Localizable.strings
index d160895ea6..3ac683fe40 100644
--- a/platform/ios/resources/lt.lproj/Localizable.strings
+++ b/platform/ios/resources/lt.lproj/Localizable.strings
@@ -10,6 +10,9 @@
/* No comment provided by engineer. */
"CANCEL" = "Atšaukti";
+/* Accessibility hint for closing the selected annotation’s callout view and returning to the map */
+"CLOSE_CALLOUT_A11Y_HINT" = "Grįžta į žemėlapį.";
+
/* Accessibility hint */
"COMPASS_A11Y_HINT" = "Pasuka žemėlapį šiaure į viršų";
@@ -31,6 +34,12 @@
/* Accessibility label */
"INFO_A11Y_LABEL" = "Apie šį žemėlapį";
+/* User-friendly error description */
+"LOAD_MAP_FAILED_DESC" = "Nepavyko užkrauti žemėlapio dėl nežinomos klaidos.";
+
+/* User-friendly error description */
+"LOAD_STYLE_FAILED_DESC" = "Nepavyko užkrauti žemėlapio, nes nepavyko užkrauti stiliaus.";
+
/* Accessibility label */
"LOGO_A11Y_LABEL" = "Mapbox";
@@ -38,11 +47,20 @@
"MAP_A11Y_LABEL" = "Žemėlapis";
/* Map accessibility value */
-"MAP_A11Y_VALUE" = "Priartinimas: %1$dx\nMatomos anotacijos: %2$ld ";
+"MAP_A11Y_VALUE" = "Priartinimas: %1$dx\nMatomos anotacijos: %2$ld";
+
+/* User-friendly error description */
+"PARSE_STYLE_FAILED_DESC" = "Nepavyko užkrauti žemėlapio, nes stilius yra netinkamo formato.";
/* Action sheet title */
"SDK_NAME" = "Mapbox iOS SDK";
+/* Developer-only SDK update notification; {latest version, in format x.x.x} */
+"SDK_UPDATE_AVAILABLE" = "Mapbox iOS SDK versija %@ jau prieinama.";
+
+/* User-friendly error description */
+"STYLE_NOT_FOUND_DESC" = "Nepavyko užkrauti žemėlapio, nes neįmanoma rasti stiliaus arba jis nėra suderinamas.";
+
/* Telemetry prompt message */
"TELEMETRY_DISABLED_MSG" = "Padėkite padaryti OpenStreetMap ir Mapbox žemėlapius geresniais dalindamiesi anoniminiais naudojimosi duomenimis.";
diff --git a/platform/ios/resources/lt.lproj/Localizable.stringsdict b/platform/ios/resources/lt.lproj/Localizable.stringsdict
new file mode 100644
index 0000000000..0200327f04
--- /dev/null
+++ b/platform/ios/resources/lt.lproj/Localizable.stringsdict
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>MAP_A11Y_VALUE</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>%#@level@
+%#@count@</string>
+ <key>level</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>Priartinimas: %dx</string>
+ <key>few</key>
+ <string>Priartinimas: %dx</string>
+ <key>other</key>
+ <string>Priartinimas: %dx</string>
+ </dict>
+ <key>count</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>ld</string>
+ <key>one</key>
+ <string>Matomos anotacijos: %d anotacija</string>
+ <key>few</key>
+ <string>Matomos anotacijos: %d anotacijos</string>
+ <key>other</key>
+ <string>Matomos anotacijos: %d anotacijų</string>
+ </dict>
+ </dict>
+</dict>
+</plist>
diff --git a/platform/ios/resources/mapbox.png b/platform/ios/resources/mapbox.png
index 533ad9f723..00bc897a58 100644
--- a/platform/ios/resources/mapbox.png
+++ b/platform/ios/resources/mapbox.png
Binary files differ
diff --git a/platform/ios/resources/mapbox@2x.png b/platform/ios/resources/mapbox@2x.png
index 51ad74adcb..206ed5883e 100644
--- a/platform/ios/resources/mapbox@2x.png
+++ b/platform/ios/resources/mapbox@2x.png
Binary files differ
diff --git a/platform/ios/resources/mapbox@3x.png b/platform/ios/resources/mapbox@3x.png
index 1fb83c149b..efd631b587 100644
--- a/platform/ios/resources/mapbox@3x.png
+++ b/platform/ios/resources/mapbox@3x.png
Binary files differ
diff --git a/platform/ios/resources/pt-BR.lproj/Localizable.stringsdict b/platform/ios/resources/pt-BR.lproj/Localizable.stringsdict
index 2b4bf30cba..c3185c4168 100644
--- a/platform/ios/resources/pt-BR.lproj/Localizable.stringsdict
+++ b/platform/ios/resources/pt-BR.lproj/Localizable.stringsdict
@@ -5,8 +5,19 @@
<key>MAP_A11Y_VALUE</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
- <string>Zoom %dx
+ <string>%#@level@
%#@count@</string>
+ <key>level</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>Zoom %dx</string>
+ <key>other</key>
+ <string>Zoom %dx</string>
+ </dict>
<key>count</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
diff --git a/platform/ios/resources/ru.lproj/Localizable.stringsdict b/platform/ios/resources/ru.lproj/Localizable.stringsdict
index 49f9cc4621..81877703b1 100644
--- a/platform/ios/resources/ru.lproj/Localizable.stringsdict
+++ b/platform/ios/resources/ru.lproj/Localizable.stringsdict
@@ -5,8 +5,23 @@
<key>MAP_A11Y_VALUE</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
- <string>Zoom %dx
-%#@count@ visible</string>
+ <string>%#@level@
+%#@count@</string>
+ <key>level</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>Масштаб %dx</string>
+ <key>few</key>
+ <string>Масштаб %dx</string>
+ <key>many</key>
+ <string>Масштаб %dx</string>
+ <key>other</key>
+ <string>Масштаб %dx</string>
+ </dict>
<key>count</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
@@ -14,13 +29,13 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
- <string>%d аннотация</string>
+ <string>%d аннотация видны</string>
<key>few</key>
- <string>%d аннотации</string>
+ <string>%d аннотации видны</string>
<key>many</key>
- <string>%d аннотаций</string>
+ <string>%d аннотаций видны</string>
<key>other</key>
- <string>%d аннотации</string>
+ <string>%d аннотации видны</string>
</dict>
</dict>
</dict>
diff --git a/platform/ios/resources/sv.lproj/Localizable.strings b/platform/ios/resources/sv.lproj/Localizable.strings
index 1f1aac2d78..fb787b973a 100644
--- a/platform/ios/resources/sv.lproj/Localizable.strings
+++ b/platform/ios/resources/sv.lproj/Localizable.strings
@@ -10,6 +10,9 @@
/* No comment provided by engineer. */
"CANCEL" = "Avbryt";
+/* Accessibility hint for closing the selected annotation’s callout view and returning to the map */
+"CLOSE_CALLOUT_A11Y_HINT" = "Återgår till kartan";
+
/* Accessibility hint */
"COMPASS_A11Y_HINT" = "Roterar kartan mot norr";
@@ -31,6 +34,12 @@
/* Accessibility label */
"INFO_A11Y_LABEL" = "Om den här kartan";
+/* User-friendly error description */
+"LOAD_MAP_FAILED_DESC" = "Kartan kunde inte laddas på grund av att ett okänt fel inträffade.";
+
+/* User-friendly error description */
+"LOAD_STYLE_FAILED_DESC" = "The map failed to load because the style can't be loaded.";
+
/* Accessibility label */
"LOGO_A11Y_LABEL" = "Mapbox";
@@ -38,11 +47,20 @@
"MAP_A11Y_LABEL" = "Karta";
/* Map accessibility value */
-"MAP_A11Y_VALUE" = "Zoom %1$dx\n%2$ld annotation(s) visible";
+"MAP_A11Y_VALUE" = "Zoom %1$dx\n%2$ld annotering(ar) synliga";
+
+/* User-friendly error description */
+"PARSE_STYLE_FAILED_DESC" = "The map failed to load because the style is corrupted.";
/* Action sheet title */
"SDK_NAME" = "Mapbox iOS SDK";
+/* Developer-only SDK update notification; {latest version, in format x.x.x} */
+"SDK_UPDATE_AVAILABLE" = "Mapbox iOS SDK version %@ är nu tillgängligt:";
+
+/* User-friendly error description */
+"STYLE_NOT_FOUND_DESC" = "The map failed to load because the style can’t be found or is incompatible.";
+
/* Telemetry prompt message */
"TELEMETRY_DISABLED_MSG" = "Du kan hjälpa till att göra OpenStreetMap och Mapbox karttjänster bättre genom att bidra med anonymiserad användningsdata.";
@@ -71,5 +89,5 @@
"TELEMETRY_TITLE" = "Gör Mapbox kartor bättre";
/* Default user location annotation title */
-"USER_DOT_TITLE" = "Där är här";
+"USER_DOT_TITLE" = "Du är här";
diff --git a/platform/ios/resources/sv.lproj/Localizable.stringsdict b/platform/ios/resources/sv.lproj/Localizable.stringsdict
new file mode 100644
index 0000000000..90115bd803
--- /dev/null
+++ b/platform/ios/resources/sv.lproj/Localizable.stringsdict
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>MAP_A11Y_VALUE</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>%#@level@
+%#@count@</string>
+ <key>level</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>Zoom %dx</string>
+ <key>other</key>
+ <string>Zoom %dx</string>
+ </dict>
+ <key>count</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>ld</string>
+ <key>one</key>
+ <string>%d annotering synlig</string>
+ <key>other</key>
+ <string>%d annoteringar synliga</string>
+ </dict>
+ </dict>
+</dict>
+</plist>
diff --git a/platform/ios/resources/vi.lproj/Localizable.strings b/platform/ios/resources/vi.lproj/Localizable.strings
index c730ea71c7..8a35d5d5d6 100644
--- a/platform/ios/resources/vi.lproj/Localizable.strings
+++ b/platform/ios/resources/vi.lproj/Localizable.strings
@@ -10,6 +10,9 @@
/* No comment provided by engineer. */
"CANCEL" = "Hủy bỏ";
+/* Accessibility hint for closing the selected annotation’s callout view and returning to the map */
+"CLOSE_CALLOUT_A11Y_HINT" = "Quay lại bản đồ";
+
/* Accessibility hint */
"COMPASS_A11Y_HINT" = "Quay bản đồ về hướng bắc";
@@ -31,6 +34,12 @@
/* Accessibility label */
"INFO_A11Y_LABEL" = "Giới thiệu về bản đồ này";
+/* User-friendly error description */
+"LOAD_MAP_FAILED_DESC" = "Bản đồ bị thất bại khi tải vì lỗi không rõ.";
+
+/* User-friendly error description */
+"LOAD_STYLE_FAILED_DESC" = "Bản đồ bị thất bại khi tải vì không thể tải bảng kiểu.";
+
/* Accessibility label */
"LOGO_A11Y_LABEL" = "Mapbox";
@@ -40,9 +49,18 @@
/* Map accessibility value */
"MAP_A11Y_VALUE" = "Thu phóng gấp %1$d lần\n%2$ld chú thích đang xuất hiện";
+/* User-friendly error description */
+"PARSE_STYLE_FAILED_DESC" = "Bản đồ bị thất bại khi tải vì bảng kiểu bị hỏng.";
+
/* Action sheet title */
"SDK_NAME" = "Mapbox iOS SDK";
+/* Developer-only SDK update notification; {latest version, in format x.x.x} */
+"SDK_UPDATE_AVAILABLE" = "Mapbox iOS SDK mới ra phiên bản %@:";
+
+/* User-friendly error description */
+"STYLE_NOT_FOUND_DESC" = "Bản đồ bị thất bại khi tải vì không tìm thấy bảng kiểu hoặc bảng kiểu không tương thích.";
+
/* Telemetry prompt message */
"TELEMETRY_DISABLED_MSG" = "Hãy giúp cải tiến các bản đồ OpenStreetMap và Mapbox bằng cách đóng góp dữ liệu vô danh hóa về cách sử dụng.";
diff --git a/platform/ios/resources/vi.lproj/Localizable.stringsdict b/platform/ios/resources/vi.lproj/Localizable.stringsdict
new file mode 100644
index 0000000000..9044588f50
--- /dev/null
+++ b/platform/ios/resources/vi.lproj/Localizable.stringsdict
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>MAP_A11Y_VALUE</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>%#@level@
+%#@count@</string>
+ <key>level</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>other</key>
+ <string>Thu phóng gấp %d lần</string>
+ </dict>
+ <key>count</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>ld</string>
+ <key>other</key>
+ <string>%d chú thích đang xuất hiện</string>
+ </dict>
+ </dict>
+</dict>
+</plist>
diff --git a/platform/ios/resources/zh-Hans.lproj/Localizable.strings b/platform/ios/resources/zh-Hans.lproj/Localizable.strings
index 087a09dbb8..5167e93c1b 100644
--- a/platform/ios/resources/zh-Hans.lproj/Localizable.strings
+++ b/platform/ios/resources/zh-Hans.lproj/Localizable.strings
@@ -1,4 +1,4 @@
-/* Accessibility hint */
+/* Accessibility hint */
"ANNOTATION_A11Y_HINT" = "显示信息";
/* No comment provided by engineer. */
@@ -10,6 +10,9 @@
/* No comment provided by engineer. */
"CANCEL" = "取消";
+/* Accessibility hint for closing the selected annotation’s callout view and returning to the map */
+"CLOSE_CALLOUT_A11Y_HINT" = "Returns to the map";
+
/* Accessibility hint */
"COMPASS_A11Y_HINT" = "旋转地图使正北朝上";
@@ -19,12 +22,6 @@
/* Compass abbreviation for north */
"COMPASS_NORTH" = "北";
-/* Copyright notice in attribution sheet */
-"COPY_MAPBOX" = "© Mapbox";
-
-/* Copyright notice in attribution sheet */
-"COPY_OSM" = "© OpenStreetMap";
-
/* Instructions in Interface Builder designable; {key}, {plist file name} */
"DESIGNABLE" = "在%2$@中将你的access token设为%1$@可在这里显示Mapbox上的地图\n\n更多说明请见";
@@ -37,6 +34,12 @@
/* Accessibility label */
"INFO_A11Y_LABEL" = "关于这个地图";
+/* User-friendly error description */
+"LOAD_MAP_FAILED_DESC" = "The map failed to load because an unknown error occurred.";
+
+/* User-friendly error description */
+"LOAD_STYLE_FAILED_DESC" = "The map failed to load because the style can't be loaded.";
+
/* Accessibility label */
"LOGO_A11Y_LABEL" = "Mapbox";
@@ -46,12 +49,18 @@
/* Map accessibility value */
"MAP_A11Y_VALUE" = "地图缩放%1$d倍\n有%2$ld处标记可见";
-/* Action in attribution sheet */
-"MAP_FEEDBACK" = "改进地图";
+/* User-friendly error description */
+"PARSE_STYLE_FAILED_DESC" = "The map failed to load because the style is corrupted.";
/* Action sheet title */
"SDK_NAME" = "Mapbox iOS SDK";
+/* Developer-only SDK update notification; {latest version, in format x.x.x} */
+"SDK_UPDATE_AVAILABLE" = "Mapbox iOS SDK version %@ is now available:";
+
+/* User-friendly error description */
+"STYLE_NOT_FOUND_DESC" = "The map failed to load because the style can’t be found or is incompatible.";
+
/* Telemetry prompt message */
"TELEMETRY_DISABLED_MSG" = "你可以提供匿名数据来帮助OpenStreetMap和Mapbox的地图变得更好。";
diff --git a/platform/ios/scripts/deploy-nightly.sh b/platform/ios/scripts/deploy-nightly.sh
new file mode 100755
index 0000000000..9fec4df58a
--- /dev/null
+++ b/platform/ios/scripts/deploy-nightly.sh
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+
+set -e
+set -o pipefail
+set -u
+
+function step { >&2 echo -e "\033[1m\033[36m* $@\033[0m"; }
+function finish { >&2 echo -en "\033[0m"; }
+trap finish EXIT
+
+export TRAVIS_REPO_SLUG=mapbox-gl-native
+
+DATE=`date +%Y-%m-%d`
+NIGHTLY_TYPE="nightly-dynamic"
+
+step "Uploading ${NIGHTLY_TYPE} build for ${DATE} to s3…"
+
+./platform/ios/scripts/publish.sh "${NIGHTLY_TYPE}" "${DATE}"
+
+step "Finished deploying ${NIGHTLY_TYPE} build in $(($SECONDS / 60)) minutes and $(($SECONDS % 60)) seconds"
diff --git a/platform/ios/scripts/publish.sh b/platform/ios/scripts/publish.sh
index 117a4ec0db..80ae1ff4e0 100755
--- a/platform/ios/scripts/publish.sh
+++ b/platform/ios/scripts/publish.sh
@@ -24,7 +24,7 @@ fi
# zip
#
cd build/ios/pkg
-ZIP=mapbox-ios-sdk-${PUBLISH_VERSION}${PUBLISH_STYLE}.zip
+ZIP="mapbox-ios-sdk-${PUBLISH_VERSION}${PUBLISH_STYLE}.zip"
step "Compressing ${ZIP}…"
rm -f ../${ZIP}
zip -yr ../${ZIP} *
@@ -35,4 +35,15 @@ zip -yr ../${ZIP} *
step "Uploading ${ZIP} to s3…"
REPO_NAME=$(basename $TRAVIS_REPO_SLUG)
aws s3 cp ../${ZIP} s3://mapbox/$REPO_NAME/ios/builds/ --acl public-read
-echo http://mapbox.s3.amazonaws.com/$REPO_NAME/ios/builds/${ZIP}
+echo "URL: https://mapbox.s3.amazonaws.com/$REPO_NAME/ios/builds/${ZIP}"
+
+#
+# update nightly
+#
+if [[ ${PUBLISH_VERSION} =~ "nightly" ]]; then
+ step "Updating ${PUBLISH_VERSION} to ${PUBLISH_STYLE}…"
+ GENERIC_NIGHTLY_FILENAME="mapbox-ios-sdk-${PUBLISH_VERSION}.zip"
+ aws s3 cp \
+ s3://mapbox/$REPO_NAME/ios/builds/${ZIP} \
+ s3://mapbox/$REPO_NAME/ios/builds/${GENERIC_NIGHTLY_FILENAME} --acl public-read
+fi
diff --git a/platform/ios/src/MGLMapView.h b/platform/ios/src/MGLMapView.h
index 4872ff2448..8d26b1c90e 100644
--- a/platform/ios/src/MGLMapView.h
+++ b/platform/ios/src/MGLMapView.h
@@ -226,6 +226,12 @@ IB_DESIGNABLE
- (IBAction)reloadStyle:(id)sender;
/**
+ A control indicating the scale of the map. The scale bar is positioned in the
+ upper-left corner. The scale bar is hidden by default.
+ */
+@property (nonatomic, readonly) UIView *scaleBar;
+
+/**
A control indicating the map’s direction and allowing the user to manipulate
the direction, positioned in the upper-right corner.
*/
@@ -264,13 +270,25 @@ IB_DESIGNABLE
*/
@property (nonatomic, readonly) UIButton *attributionButton;
-@property (nonatomic) NS_ARRAY_OF(NSString *) *styleClasses __attribute__((deprecated("Use style.styleClasses.")));
+/**
+ Support for style classes has been removed. This property always returns an empty array.
+ */
+@property (nonatomic) NS_ARRAY_OF(NSString *) *styleClasses __attribute__((deprecated("This property is non-functional.")));
-- (BOOL)hasStyleClass:(NSString *)styleClass __attribute__((deprecated("Use style.hasStyleClass:.")));
+/**
+ Support for style classes has been removed. This property always returns NO.
+ */
+- (BOOL)hasStyleClass:(NSString *)styleClass __attribute__((deprecated("This method is non-functional.")));
-- (void)addStyleClass:(NSString *)styleClass __attribute__((deprecated("Use style.addStyleClass:.")));
+/**
+ Support for style classes has been removed. This property is a no-op.
+ */
+- (void)addStyleClass:(NSString *)styleClass __attribute__((deprecated("This method is non-functional.")));
-- (void)removeStyleClass:(NSString *)styleClass __attribute__((deprecated("Use style.removeStyleClass:.")));
+/**
+ Support for style classes has been removed. This property is a no-op.
+ */
+- (void)removeStyleClass:(NSString *)styleClass __attribute__((deprecated("This method is non-functional.")));
#pragma mark Displaying the User’s Location
diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm
index 51b65f11b1..8cba1187ea 100644
--- a/platform/ios/src/MGLMapView.mm
+++ b/platform/ios/src/MGLMapView.mm
@@ -1,8 +1,6 @@
#import "MGLMapView_Private.h"
#include <mbgl/util/logging.hpp>
-#include <mbgl/gl/extension.hpp>
-#include <mbgl/gl/context.hpp>
#import <GLKit/GLKit.h>
#import <OpenGLES/EAGL.h>
@@ -10,7 +8,6 @@
#include <mbgl/map/map.hpp>
#include <mbgl/map/view.hpp>
#include <mbgl/annotation/annotation.hpp>
-#include <mbgl/sprite/sprite_image.hpp>
#include <mbgl/map/camera.hpp>
#include <mbgl/map/mode.hpp>
#include <mbgl/util/platform.hpp>
@@ -18,10 +15,13 @@
#include <mbgl/util/default_thread_pool.hpp>
#include <mbgl/storage/default_file_source.hpp>
#include <mbgl/storage/network_status.hpp>
+#include <mbgl/style/image.hpp>
#include <mbgl/style/transition_options.hpp>
#include <mbgl/style/layers/custom_layer.hpp>
#include <mbgl/map/backend.hpp>
+#include <mbgl/map/backend_scope.hpp>
#include <mbgl/math/wrap.hpp>
+#include <mbgl/util/exception.hpp>
#include <mbgl/util/geo.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/image.hpp>
@@ -30,6 +30,8 @@
#include <mbgl/util/chrono.hpp>
#include <mbgl/util/run_loop.hpp>
#include <mbgl/util/shared_thread_pool.hpp>
+#include <mbgl/util/string.hpp>
+#include <mbgl/util/projection.hpp>
#import "Mapbox.h"
#import "MGLFeature_Private.h"
@@ -54,6 +56,7 @@
#import "MGLUserLocation_Private.h"
#import "MGLAnnotationImage_Private.h"
#import "MGLAnnotationView_Private.h"
+#import "MGLScaleBar.h"
#import "MGLStyle_Private.h"
#import "MGLStyleLayer_Private.h"
#import "MGLMapboxEvents.h"
@@ -209,7 +212,7 @@ public:
{
self.accessibilityTraits = UIAccessibilityTraitButton;
self.accessibilityLabel = [self.accessibilityContainer accessibilityLabel];
- self.accessibilityHint = @"Returns to the map";
+ self.accessibilityHint = NSLocalizedStringWithDefaultValue(@"CLOSE_CALLOUT_A11Y_HINT", nil, nil, @"Returns to the map", @"Accessibility hint for closing the selected annotation’s callout view and returning to the map");
}
return self;
}
@@ -229,6 +232,8 @@ public:
@property (nonatomic) EAGLContext *context;
@property (nonatomic) GLKView *glView;
@property (nonatomic) UIImageView *glSnapshotView;
+@property (nonatomic, readwrite) MGLScaleBar *scaleBar;
+@property (nonatomic) NS_MUTABLE_ARRAY_OF(NSLayoutConstraint *) *scaleBarConstraints;
@property (nonatomic, readwrite) UIImageView *compassView;
@property (nonatomic) NS_MUTABLE_ARRAY_OF(NSLayoutConstraint *) *compassViewConstraints;
@property (nonatomic, readwrite) UIImageView *logoView;
@@ -237,6 +242,8 @@ public:
@property (nonatomic) NS_MUTABLE_ARRAY_OF(NSLayoutConstraint *) *attributionButtonConstraints;
@property (nonatomic, readwrite) MGLStyle *style;
@property (nonatomic) UITapGestureRecognizer *singleTapGestureRecognizer;
+@property (nonatomic) UITapGestureRecognizer *doubleTap;
+@property (nonatomic) UITapGestureRecognizer *twoFingerTap;
@property (nonatomic) UIPanGestureRecognizer *pan;
@property (nonatomic) UIPinchGestureRecognizer *pinch;
@property (nonatomic) UIRotationGestureRecognizer *rotate;
@@ -460,7 +467,7 @@ public:
// setup logo bug
//
- UIImage *logo = [[MGLMapView resourceImageNamed:@"mapbox.png"] imageWithAlignmentRectInsets:UIEdgeInsetsMake(1.5, 4, 3.5, 2)];
+ UIImage *logo = [MGLMapView resourceImageNamed:@"mapbox.png"];
_logoView = [[UIImageView alloc] initWithImage:logo];
_logoView.accessibilityTraits = UIAccessibilityTraitStaticText;
_logoView.accessibilityLabel = NSLocalizedStringWithDefaultValue(@"LOGO_A11Y_LABEL", nil, nil, @"Mapbox", @"Accessibility label");
@@ -491,7 +498,14 @@ public:
_compassView.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:_compassView];
_compassViewConstraints = [NSMutableArray array];
-
+
+ // setup scale control
+ //
+ _scaleBar = [[MGLScaleBar alloc] init];
+ _scaleBar.translatesAutoresizingMaskIntoConstraints = NO;
+ [self addSubview:_scaleBar];
+ _scaleBarConstraints = [NSMutableArray array];
+
// setup interaction
//
_pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)];
@@ -510,26 +524,26 @@ public:
[self addGestureRecognizer:_rotate];
_rotateEnabled = YES;
- UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTapGesture:)];
- doubleTap.numberOfTapsRequired = 2;
- [self addGestureRecognizer:doubleTap];
+ _doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTapGesture:)];
+ _doubleTap.numberOfTapsRequired = 2;
+ [self addGestureRecognizer:_doubleTap];
_singleTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTapGesture:)];
- [_singleTapGestureRecognizer requireGestureRecognizerToFail:doubleTap];
+ [_singleTapGestureRecognizer requireGestureRecognizerToFail:_doubleTap];
_singleTapGestureRecognizer.delegate = self;
[self addGestureRecognizer:_singleTapGestureRecognizer];
- UITapGestureRecognizer *twoFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTwoFingerTapGesture:)];
- twoFingerTap.numberOfTouchesRequired = 2;
- [twoFingerTap requireGestureRecognizerToFail:_pinch];
- [twoFingerTap requireGestureRecognizerToFail:_rotate];
- [self addGestureRecognizer:twoFingerTap];
+ _twoFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTwoFingerTapGesture:)];
+ _twoFingerTap.numberOfTouchesRequired = 2;
+ [_twoFingerTap requireGestureRecognizerToFail:_pinch];
+ [_twoFingerTap requireGestureRecognizerToFail:_rotate];
+ [self addGestureRecognizer:_twoFingerTap];
_twoFingerDrag = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleTwoFingerDragGesture:)];
_twoFingerDrag.minimumNumberOfTouches = 2;
_twoFingerDrag.maximumNumberOfTouches = 2;
_twoFingerDrag.delegate = self;
- [_twoFingerDrag requireGestureRecognizerToFail:twoFingerTap];
+ [_twoFingerDrag requireGestureRecognizerToFail:_twoFingerTap];
[_twoFingerDrag requireGestureRecognizerToFail:_pan];
[self addGestureRecognizer:_twoFingerDrag];
_pitchEnabled = YES;
@@ -539,7 +553,7 @@ public:
_quickZoom = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleQuickZoomGesture:)];
_quickZoom.numberOfTapsRequired = 1;
_quickZoom.minimumPressDuration = 0;
- [_quickZoom requireGestureRecognizerToFail:doubleTap];
+ [_quickZoom requireGestureRecognizerToFail:_doubleTap];
[self addGestureRecognizer:_quickZoom];
// observe app activity
@@ -571,8 +585,11 @@ public:
- (mbgl::Size)size
{
- return { static_cast<uint32_t>(self.bounds.size.width),
- static_cast<uint32_t>(self.bounds.size.height) };
+ // check for minimum texture size supported by OpenGL ES 2.0
+ //
+ CGSize size = CGSizeMake(MAX(self.bounds.size.width, 64), MAX(self.bounds.size.height, 64));
+ return { static_cast<uint32_t>(size.width),
+ static_cast<uint32_t>(size.height) };
}
- (mbgl::Size)framebufferSize
@@ -603,21 +620,6 @@ public:
[_glView bindDrawable];
[self insertSubview:_glView atIndex:0];
_glView.contentMode = UIViewContentModeCenter;
-
- // load extensions
- //
- mbgl::gl::InitializeExtensions([](const char * name) {
- static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengles"));
- if (!framework) {
- throw std::runtime_error("Failed to load OpenGL framework.");
- }
-
- CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingASCII);
- void* symbol = CFBundleGetFunctionPointerForName(framework, str);
- CFRelease(str);
-
- return reinterpret_cast<mbgl::gl::glProc>(symbol);
- });
}
- (UIImage *)compassImage
@@ -784,6 +786,31 @@ public:
- (void)updateConstraints
{
+ // scale control
+ //
+ [self removeConstraints:self.scaleBarConstraints];
+ [self.scaleBarConstraints removeAllObjects];
+
+ [self.scaleBarConstraints addObject:
+ [NSLayoutConstraint constraintWithItem:self.scaleBar
+ attribute:NSLayoutAttributeTop
+ relatedBy:NSLayoutRelationEqual
+ toItem:self
+ attribute:NSLayoutAttributeTop
+ multiplier:1
+ constant:5+self.contentInset.top]];
+
+ [self.scaleBarConstraints addObject:
+ [NSLayoutConstraint constraintWithItem:self.scaleBar
+ attribute:NSLayoutAttributeLeading
+ relatedBy:NSLayoutRelationEqual
+ toItem:self
+ attribute:NSLayoutAttributeLeading
+ multiplier:1
+ constant:8 + self.contentInset.left]];
+
+ [self addConstraints:self.scaleBarConstraints];
+
// compass
//
[self removeConstraints:self.compassViewConstraints];
@@ -875,7 +902,9 @@ public:
{
if ( ! self.dormant)
{
- _mbglView->updateViewBinding();
+ // The OpenGL implementation automatically enables the OpenGL context for us.
+ mbgl::BackendScope scope { *_mbglView, mbgl::BackendScope::ScopeType::Implicit };
+
_mbglMap->render(*_mbglView);
[self updateUserLocationAnnotationView];
@@ -1134,6 +1163,9 @@ public:
- (void)updateTintColorForView:(UIView *)view
{
+ // stop at recursing container & annotation views (#8522)
+ if ([view isEqual:self.annotationContainerView]) return;
+
if ([view respondsToSelector:@selector(setTintColor:)]) view.tintColor = self.tintColor;
for (UIView *subview in view.subviews) [self updateTintColorForView:subview];
@@ -1164,7 +1196,8 @@ public:
}
- (void)notifyGestureDidBegin {
- [self notifyMapChange:mbgl::MapChangeRegionWillChange];
+ BOOL animated = NO;
+ [self cameraWillChangeAnimated:animated];
_mbglMap->setGestureInProgress(true);
_changeDelimiterSuppressionDepth++;
}
@@ -1178,7 +1211,8 @@ public:
}
if ( ! drift)
{
- [self notifyMapChange:mbgl::MapChangeRegionDidChange];
+ BOOL animated = NO;
+ [self cameraDidChangeAnimated:animated];
}
}
@@ -1215,7 +1249,7 @@ public:
[pan setTranslation:CGPointZero inView:pan.view];
}
- [self notifyMapChange:mbgl::MapChangeRegionIsChanging];
+ [self cameraIsChanging];
}
else if (pan.state == UIGestureRecognizerStateEnded || pan.state == UIGestureRecognizerStateCancelled)
{
@@ -1270,7 +1304,7 @@ public:
{
[self trackGestureEvent:MGLEventGesturePinchStart forRecognizer:pinch];
- self.scale = _mbglMap->getScale();
+ self.scale = powf(2, _mbglMap->getZoom());
[self notifyGestureDidBegin];
}
@@ -1286,7 +1320,7 @@ public:
if (![self.delegate respondsToSelector:@selector(mapView:shouldChangeFromCamera:toCamera:)] ||
[self.delegate mapView:self shouldChangeFromCamera:oldCamera toCamera:toCamera])
{
- _mbglMap->setScale(newScale, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y });
+ _mbglMap->setZoom(zoom, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y });
}
// The gesture recognizer only reports the gesture’s current center
// point, so use the previous center point to anchor the transition.
@@ -1298,7 +1332,7 @@ public:
_mbglMap->setLatLng(MGLLatLngFromLocationCoordinate2D(centerCoordinate),
mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y });
}
- [self notifyMapChange:mbgl::MapChangeRegionIsChanging];
+ [self cameraIsChanging];
}
else if (pinch.state == UIGestureRecognizerStateEnded || pinch.state == UIGestureRecognizerStateCancelled)
{
@@ -1344,7 +1378,7 @@ public:
} else {
if (drift)
{
- _mbglMap->setScale(newScale, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }, MGLDurationFromTimeInterval(duration));
+ _mbglMap->setZoom(zoom, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }, MGLDurationFromTimeInterval(duration));
}
}
@@ -1397,9 +1431,8 @@ public:
{
_mbglMap->setBearing(newDegrees, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y });
}
-
- [self notifyMapChange:mbgl::MapChangeRegionIsChanging];
-
+
+ [self cameraIsChanging];
}
else if (rotate.state == UIGestureRecognizerStateEnded || rotate.state == UIGestureRecognizerStateCancelled)
{
@@ -1571,6 +1604,8 @@ public:
{
[weakSelf unrotateIfNeededForGesture];
}];
+ } else {
+ [self unrotateIfNeededForGesture];
}
}
}
@@ -1623,7 +1658,7 @@ public:
{
[self trackGestureEvent:MGLEventGestureQuickZoom forRecognizer:quickZoom];
- self.scale = _mbglMap->getScale();
+ self.scale = powf(2, _mbglMap->getZoom());
self.quickZoomStart = [quickZoom locationInView:quickZoom.view].y;
@@ -1640,21 +1675,15 @@ public:
CGPoint centerPoint = [self anchorPointForGesture:quickZoom];
MGLMapCamera *oldCamera = self.camera;
-
- double zoom = self.zoomLevel;
- double scale = powf(2, newZoom) / _mbglMap->getScale();
-
- double estimatedZoom = zoom * scale;
-
- MGLMapCamera *toCamera = [self cameraByZoomingToZoomLevel:estimatedZoom aroundAnchorPoint:centerPoint];
+ MGLMapCamera *toCamera = [self cameraByZoomingToZoomLevel:newZoom aroundAnchorPoint:centerPoint];
if (![self.delegate respondsToSelector:@selector(mapView:shouldChangeFromCamera:toCamera:)] ||
[self.delegate mapView:self shouldChangeFromCamera:oldCamera toCamera:toCamera])
{
- _mbglMap->scaleBy(scale, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y });
+ _mbglMap->setZoom(newZoom, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y });
}
- [self notifyMapChange:mbgl::MapChangeRegionIsChanging];
+ [self cameraIsChanging];
}
else if (quickZoom.state == UIGestureRecognizerStateEnded || quickZoom.state == UIGestureRecognizerStateCancelled)
{
@@ -1693,7 +1722,7 @@ public:
_mbglMap->setPitch(pitchNew, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y });
}
- [self notifyMapChange:mbgl::MapChangeRegionIsChanging];
+ [self cameraIsChanging];
}
else if (twoFingerDrag.state == UIGestureRecognizerStateEnded || twoFingerDrag.state == UIGestureRecognizerStateCancelled)
{
@@ -2154,6 +2183,33 @@ public:
_mbglMap->onLowMemory();
}
+- (void)setZoomEnabled:(BOOL)zoomEnabled
+{
+ _zoomEnabled = zoomEnabled;
+ self.pinch.enabled = zoomEnabled;
+ self.doubleTap.enabled = zoomEnabled;
+ self.quickZoom.enabled = zoomEnabled;
+ self.twoFingerTap.enabled = zoomEnabled;
+}
+
+- (void)setScrollEnabled:(BOOL)scrollEnabled
+{
+ _scrollEnabled = scrollEnabled;
+ self.pan.enabled = scrollEnabled;
+}
+
+- (void)setRotateEnabled:(BOOL)rotateEnabled
+{
+ _rotateEnabled = rotateEnabled;
+ self.rotate.enabled = rotateEnabled;
+}
+
+- (void)setPitchEnabled:(BOOL)pitchEnabled
+{
+ _pitchEnabled = pitchEnabled;
+ self.twoFingerDrag.enabled = pitchEnabled;
+}
+
#pragma mark - Accessibility -
- (NSString *)accessibilityValue
@@ -2384,7 +2440,7 @@ public:
{
centerPoint = self.userLocationAnnotationViewCenter;
}
- _mbglMap->scaleBy(scaleFactor, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y });
+ _mbglMap->setZoom(_mbglMap->getZoom() + log2(scaleFactor), mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y });
[self unrotateIfNeededForGesture];
UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, self.accessibilityValue);
@@ -2872,6 +2928,10 @@ public:
- (CGPoint)convertCoordinate:(CLLocationCoordinate2D)coordinate toPointToView:(nullable UIView *)view
{
+ if ( ! CLLocationCoordinate2DIsValid(coordinate))
+ {
+ return CGPointMake(NAN, NAN);
+ }
return [self convertLatLng:MGLLatLngFromLocationCoordinate2D(coordinate) toPointToView:view];
}
@@ -2889,6 +2949,10 @@ public:
- (CGRect)convertCoordinateBounds:(MGLCoordinateBounds)bounds toRectToView:(nullable UIView *)view
{
+ if ( ! CLLocationCoordinate2DIsValid(bounds.sw) || ! CLLocationCoordinate2DIsValid(bounds.ne))
+ {
+ return CGRectNull;
+ }
return [self convertLatLngBounds:MGLLatLngBoundsFromCoordinateBounds(bounds) toRectToView:view];
}
@@ -2940,7 +3004,7 @@ public:
- (CLLocationDistance)metersPerPointAtLatitude:(CLLocationDegrees)latitude
{
- return _mbglMap->getMetersPerPixelAtLatitude(latitude, self.zoomLevel);
+ return mbgl::Projection::getMetersPerPixelAtLatitude(latitude, self.zoomLevel);
}
- (CLLocationDistance)metersPerPixelAtLatitude:(CLLocationDegrees)latitude
@@ -3385,8 +3449,7 @@ public:
annotationImage.delegate = self;
// add sprite
- std::shared_ptr<mbgl::SpriteImage> sprite(annotationImage.image.mgl_spriteImage);
- _mbglMap->addAnnotationIcon(iconIdentifier.UTF8String, sprite);
+ _mbglMap->addAnnotationImage([annotationImage.image mgl_styleImageWithIdentifier:iconIdentifier]);
// Create a slop area with a “radius” equal in size to the annotation
// image’s alignment rect, allowing the eventual tap to be on any point
@@ -4030,7 +4093,7 @@ public:
// Remove the old icon from the style.
if ( ! [iconIdentifier isEqualToString:fallbackIconIdentifier]) {
- _mbglMap->removeAnnotationIcon(iconIdentifier.UTF8String);
+ _mbglMap->removeAnnotationImage(iconIdentifier.UTF8String);
}
if (annotationImage.image)
@@ -4534,8 +4597,8 @@ public:
mbgl::LatLng targetLatLng = MGLLatLngFromLocationCoordinate2D(self.targetCoordinate);
mbgl::ProjectedMeters userMeters = mbgl::Projection::projectedMetersForLatLng(userLatLng);
mbgl::ProjectedMeters targetMeters = mbgl::Projection::projectedMetersForLatLng(targetLatLng);
- double angle = atan2(targetMeters.easting - userMeters.easting,
- targetMeters.northing - userMeters.northing);
+ double angle = atan2(targetMeters.easting() - userMeters.easting(),
+ targetMeters.northing() - userMeters.northing());
direction = mbgl::util::wrap(MGLDegreesFromRadians(angle), 0., 360.);
}
else
@@ -4769,150 +4832,164 @@ public:
}
}
-- (void)notifyMapChange:(mbgl::MapChange)change
-{
- // Ignore map updates when the Map object isn't set.
+- (void)cameraWillChangeAnimated:(BOOL)animated {
if (!_mbglMap) {
return;
}
- switch (change)
+ if ( ! _userLocationAnnotationIsSelected
+ || self.userTrackingMode == MGLUserTrackingModeNone
+ || self.userTrackingState != MGLUserTrackingStateChanged)
{
- case mbgl::MapChangeRegionWillChange:
- case mbgl::MapChangeRegionWillChangeAnimated:
+ UIView<MGLCalloutView> *calloutView = self.calloutViewForSelectedAnnotation;
+ BOOL dismissesAutomatically = (calloutView
+ && [calloutView respondsToSelector:@selector(dismissesAutomatically)]
+ && calloutView.dismissesAutomatically);
+ // dismissesAutomatically is an optional property and we want to dismiss
+ // the callout view if it's unimplemented.
+ if (dismissesAutomatically || (calloutView && ![calloutView respondsToSelector:@selector(dismissesAutomatically)]))
{
- if ( ! _userLocationAnnotationIsSelected
- || self.userTrackingMode == MGLUserTrackingModeNone
- || self.userTrackingState != MGLUserTrackingStateChanged)
- {
- UIView<MGLCalloutView> *calloutView = self.calloutViewForSelectedAnnotation;
- BOOL dismissesAutomatically = (calloutView
- && [calloutView respondsToSelector:@selector(dismissesAutomatically)]
- && calloutView.dismissesAutomatically);
- // dismissesAutomatically is an optional property and we want to dismiss
- // the callout view if it's unimplemented.
- if (dismissesAutomatically || (calloutView && ![calloutView respondsToSelector:@selector(dismissesAutomatically)]))
- {
- [self deselectAnnotation:self.selectedAnnotation animated:NO];
- }
- }
-
- if ( ! [self isSuppressingChangeDelimiters] && [self.delegate respondsToSelector:@selector(mapView:regionWillChangeAnimated:)])
- {
- BOOL animated = change == mbgl::MapChangeRegionWillChangeAnimated;
- [self.delegate mapView:self regionWillChangeAnimated:animated];
- }
- break;
+ [self deselectAnnotation:self.selectedAnnotation animated:NO];
}
- case mbgl::MapChangeRegionIsChanging:
- {
- [self updateCompass];
+ }
- if ([self.delegate respondsToSelector:@selector(mapViewRegionIsChanging:)])
- {
- [self.delegate mapViewRegionIsChanging:self];
- }
- break;
- }
- case mbgl::MapChangeRegionDidChange:
- case mbgl::MapChangeRegionDidChangeAnimated:
- {
- [self updateCompass];
+ if ( ! [self isSuppressingChangeDelimiters] && [self.delegate respondsToSelector:@selector(mapView:regionWillChangeAnimated:)])
+ {
+ [self.delegate mapView:self regionWillChangeAnimated:animated];
+ }
+}
- if ( ! [self isSuppressingChangeDelimiters] && [self.delegate respondsToSelector:@selector(mapView:regionDidChangeAnimated:)])
- {
- if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive)
- {
- UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil);
- }
- BOOL animated = change == mbgl::MapChangeRegionDidChangeAnimated;
- [self.delegate mapView:self regionDidChangeAnimated:animated];
- }
- break;
- }
- case mbgl::MapChangeWillStartLoadingMap:
- {
- if ([self.delegate respondsToSelector:@selector(mapViewWillStartLoadingMap:)])
- {
- [self.delegate mapViewWillStartLoadingMap:self];
- }
- break;
- }
- case mbgl::MapChangeDidFinishLoadingMap:
- {
- [self.style willChangeValueForKey:@"sources"];
- [self.style didChangeValueForKey:@"sources"];
- [self.style willChangeValueForKey:@"layers"];
- [self.style didChangeValueForKey:@"layers"];
- if ([self.delegate respondsToSelector:@selector(mapViewDidFinishLoadingMap:)])
- {
- [self.delegate mapViewDidFinishLoadingMap:self];
- }
- break;
- }
- case mbgl::MapChangeDidFailLoadingMap:
- {
- if ([self.delegate respondsToSelector:@selector(mapViewDidFailLoadingMap:withError:)])
- {
- NSError *error = [NSError errorWithDomain:MGLErrorDomain code:0 userInfo:nil];
- [self.delegate mapViewDidFailLoadingMap:self withError:error];
- }
- break;
- }
- case mbgl::MapChangeWillStartRenderingMap:
- {
- if ([self.delegate respondsToSelector:@selector(mapViewWillStartRenderingMap:)])
- {
- [self.delegate mapViewWillStartRenderingMap:self];
- }
- break;
- }
- case mbgl::MapChangeDidFinishRenderingMap:
- case mbgl::MapChangeDidFinishRenderingMapFullyRendered:
- {
- if ([self.delegate respondsToSelector:@selector(mapViewDidFinishRenderingMap:fullyRendered:)])
- {
- [self.delegate mapViewDidFinishRenderingMap:self fullyRendered:(change == mbgl::MapChangeDidFinishRenderingMapFullyRendered)];
- }
- break;
- }
- case mbgl::MapChangeWillStartRenderingFrame:
- {
- if ([self.delegate respondsToSelector:@selector(mapViewWillStartRenderingFrame:)])
- {
- [self.delegate mapViewWillStartRenderingFrame:self];
- }
- break;
- }
- case mbgl::MapChangeDidFinishRenderingFrame:
- case mbgl::MapChangeDidFinishRenderingFrameFullyRendered:
- {
- if (_isChangingAnnotationLayers)
- {
- _isChangingAnnotationLayers = NO;
- [self.style didChangeValueForKey:@"layers"];
- }
- [self updateAnnotationViews];
- [self updateCalloutView];
- if ([self.delegate respondsToSelector:@selector(mapViewDidFinishRenderingFrame:fullyRendered:)])
- {
- [self.delegate mapViewDidFinishRenderingFrame:self fullyRendered:(change == mbgl::MapChangeDidFinishRenderingFrameFullyRendered)];
- }
- break;
- }
- case mbgl::MapChangeDidFinishLoadingStyle:
- {
- self.style = [[MGLStyle alloc] initWithMapView:self];
- if ([self.delegate respondsToSelector:@selector(mapView:didFinishLoadingStyle:)])
- {
- [self.delegate mapView:self didFinishLoadingStyle:self.style];
- }
- break;
- }
- case mbgl::MapChangeSourceDidChange:
+- (void)cameraIsChanging {
+ if (!_mbglMap) {
+ return;
+ }
+
+ [self updateCompass];
+
+ if (!self.scaleBar.hidden) {
+ [(MGLScaleBar *)self.scaleBar setMetersPerPoint:[self metersPerPointAtLatitude:self.centerCoordinate.latitude]];
+ }
+
+ if ([self.delegate respondsToSelector:@selector(mapViewRegionIsChanging:)])
+ {
+ [self.delegate mapViewRegionIsChanging:self];
+ }
+}
+
+- (void)cameraDidChangeAnimated:(BOOL)animated {
+ if (!_mbglMap) {
+ return;
+ }
+
+ [self updateCompass];
+
+ if ( ! [self isSuppressingChangeDelimiters] && [self.delegate respondsToSelector:@selector(mapView:regionDidChangeAnimated:)])
+ {
+ if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive)
{
- break;
+ UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil);
}
+ [self.delegate mapView:self regionDidChangeAnimated:animated];
+ }
+}
+
+- (void)mapViewWillStartLoadingMap {
+ if (!_mbglMap) {
+ return;
+ }
+
+ if ([self.delegate respondsToSelector:@selector(mapViewWillStartLoadingMap:)])
+ {
+ [self.delegate mapViewWillStartLoadingMap:self];
+ }
+}
+
+- (void)mapViewDidFinishLoadingMap {
+ if (!_mbglMap) {
+ return;
+ }
+
+ [self.style willChangeValueForKey:@"sources"];
+ [self.style didChangeValueForKey:@"sources"];
+ [self.style willChangeValueForKey:@"layers"];
+ [self.style didChangeValueForKey:@"layers"];
+ if ([self.delegate respondsToSelector:@selector(mapViewDidFinishLoadingMap:)])
+ {
+ [self.delegate mapViewDidFinishLoadingMap:self];
+ }
+}
+
+- (void)mapViewDidFailLoadingMapWithError:(NSError *)error {
+ if (!_mbglMap) {
+ return;
+ }
+
+ if ([self.delegate respondsToSelector:@selector(mapViewDidFailLoadingMap:withError:)])
+ {
+ [self.delegate mapViewDidFailLoadingMap:self withError:error];
+ }
+}
+
+- (void)mapViewWillStartRenderingFrame {
+ if (!_mbglMap) {
+ return;
+ }
+
+ if ([self.delegate respondsToSelector:@selector(mapViewWillStartRenderingFrame:)])
+ {
+ [self.delegate mapViewWillStartRenderingFrame:self];
+ }
+}
+
+- (void)mapViewDidFinishRenderingFrameFullyRendered:(BOOL)fullyRendered {
+ if (!_mbglMap) {
+ return;
+ }
+
+ if (_isChangingAnnotationLayers)
+ {
+ _isChangingAnnotationLayers = NO;
+ [self.style didChangeValueForKey:@"layers"];
+ }
+ [self updateAnnotationViews];
+ [self updateCalloutView];
+ if ([self.delegate respondsToSelector:@selector(mapViewDidFinishRenderingFrame:fullyRendered:)])
+ {
+ [self.delegate mapViewDidFinishRenderingFrame:self fullyRendered:fullyRendered];
+ }
+}
+
+- (void)mapViewWillStartRenderingMap {
+ if (!_mbglMap) {
+ return;
+ }
+
+ if ([self.delegate respondsToSelector:@selector(mapViewWillStartRenderingMap:)])
+ {
+ [self.delegate mapViewWillStartRenderingMap:self];
+ }
+}
+
+- (void)mapViewDidFinishRenderingMapFullyRendered:(BOOL)fullyRendered {
+ if (!_mbglMap) {
+ return;
+ }
+
+ if ([self.delegate respondsToSelector:@selector(mapViewDidFinishRenderingMap:fullyRendered:)])
+ {
+ [self.delegate mapViewDidFinishRenderingMap:self fullyRendered:fullyRendered];
+ }
+}
+
+- (void)didFinishLoadingStyle {
+ if (!_mbglMap) {
+ return;
+ }
+
+ self.style = [[MGLStyle alloc] initWithMapView:self];
+ if ([self.delegate respondsToSelector:@selector(mapView:didFinishLoadingStyle:)])
+ {
+ [self.delegate mapView:self didFinishLoadingStyle:self.style];
}
}
@@ -5014,6 +5091,9 @@ public:
}
else
{
+ if (annotationView.layer.animationKeys.count > 0) {
+ continue;
+ }
// Move the annotation view far out of view to the left
CGRect adjustedFrame = annotationView.frame;
adjustedFrame.origin.x = -CGRectGetWidth(self.frame) * 10.0;
@@ -5355,37 +5435,110 @@ public:
MBGLView(MGLMapView* nativeView_) : nativeView(nativeView_) {
}
- mbgl::gl::value::Viewport::Type getViewport() const {
- return { 0, 0, nativeView.framebufferSize };
- }
-
/// This function is called before we start rendering, when iOS invokes our rendering method.
/// iOS already sets the correct framebuffer and viewport for us, so we need to update the
/// context state with the anticipated values.
- void updateViewBinding() {
- // We are using 0 as the placeholder value for the GLKView's framebuffer.
- getContext().bindFramebuffer.setCurrentValue(0);
- getContext().viewport.setCurrentValue(getViewport());
- assert(mbgl::gl::value::Viewport::Get() == getContext().viewport.getCurrentValue());
+ void updateAssumedState() override {
+ assumeFramebufferBinding(ImplicitFramebufferBinding);
+ assumeViewportSize(nativeView.framebufferSize);
}
void bind() override {
- if (getContext().bindFramebuffer != 0) {
+ if (!implicitFramebufferBound()) {
// Something modified our state, and we need to bind the original drawable again.
// Doing this also sets the viewport to the full framebuffer.
// Note that in reality, iOS does not use the Framebuffer 0 (it's typically 1), and we
// only use this is a placeholder value.
[nativeView.glView bindDrawable];
- updateViewBinding();
+ updateAssumedState();
} else {
// Our framebuffer is still bound, but the viewport might have changed.
- getContext().viewport = getViewport();
+ setViewportSize(nativeView.framebufferSize);
}
}
- void notifyMapChange(mbgl::MapChange change) override
- {
- [nativeView notifyMapChange:change];
+ void onCameraWillChange(mbgl::MapObserver::CameraChangeMode mode) override {
+ bool animated = mode == mbgl::MapObserver::CameraChangeMode::Animated;
+ [nativeView cameraWillChangeAnimated:animated];
+ }
+
+ void onCameraIsChanging() override {
+ [nativeView cameraIsChanging];
+ }
+
+ void onCameraDidChange(mbgl::MapObserver::CameraChangeMode mode) override {
+ bool animated = mode == mbgl::MapObserver::CameraChangeMode::Animated;
+ [nativeView cameraDidChangeAnimated:animated];
+ }
+
+ void onWillStartLoadingMap() override {
+ [nativeView mapViewWillStartLoadingMap];
+ }
+
+ void onDidFinishLoadingMap() override {
+ [nativeView mapViewDidFinishLoadingMap];
+ }
+
+ void onDidFailLoadingMap(std::exception_ptr exception) override {
+ NSString *description;
+ MGLErrorCode code;
+ try {
+ std::rethrow_exception(exception);
+ } catch (const mbgl::util::StyleParseException&) {
+ code = MGLErrorCodeParseStyleFailed;
+ description = NSLocalizedStringWithDefaultValue(@"PARSE_STYLE_FAILED_DESC", nil, nil, @"The map failed to load because the style is corrupted.", @"User-friendly error description");
+ } catch (const mbgl::util::StyleLoadException&) {
+ code = MGLErrorCodeLoadStyleFailed;
+ description = NSLocalizedStringWithDefaultValue(@"LOAD_STYLE_FAILED_DESC", nil, nil, @"The map failed to load because the style can't be loaded.", @"User-friendly error description");
+ } catch (const mbgl::util::NotFoundException&) {
+ code = MGLErrorCodeNotFound;
+ description = NSLocalizedStringWithDefaultValue(@"STYLE_NOT_FOUND_DESC", nil, nil, @"The map failed to load because the style can’t be found or is incompatible.", @"User-friendly error description");
+ } catch (...) {
+ code = MGLErrorCodeUnknown;
+ description = NSLocalizedStringWithDefaultValue(@"LOAD_MAP_FAILED_DESC", nil, nil, @"The map failed to load because an unknown error occurred.", @"User-friendly error description");
+ }
+ NSDictionary *userInfo = @{
+ NSLocalizedDescriptionKey: description,
+ NSLocalizedFailureReasonErrorKey: @(mbgl::util::toString(exception).c_str()),
+ };
+ NSError *error = [NSError errorWithDomain:MGLErrorDomain code:code userInfo:userInfo];
+ [nativeView mapViewDidFailLoadingMapWithError:error];
+ }
+
+ void onWillStartRenderingFrame() override {
+ [nativeView mapViewWillStartRenderingFrame];
+ }
+
+ void onDidFinishRenderingFrame(mbgl::MapObserver::RenderMode mode) override {
+ bool fullyRendered = mode == mbgl::MapObserver::RenderMode::Full;
+ [nativeView mapViewDidFinishRenderingFrameFullyRendered:fullyRendered];
+ }
+
+ void onWillStartRenderingMap() override {
+ [nativeView mapViewWillStartRenderingMap];
+ }
+
+ void onDidFinishRenderingMap(mbgl::MapObserver::RenderMode mode) override {
+ bool fullyRendered = mode == mbgl::MapObserver::RenderMode::Full;
+ [nativeView mapViewDidFinishRenderingMapFullyRendered:fullyRendered];
+ }
+
+ void onDidFinishLoadingStyle() override {
+ [nativeView didFinishLoadingStyle];
+ }
+
+ mbgl::gl::ProcAddress initializeExtension(const char* name) override {
+ static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengles"));
+ if (!framework) {
+ throw std::runtime_error("Failed to load OpenGL framework.");
+ }
+
+ CFStringRef str =
+ CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingASCII);
+ void* symbol = CFBundleGetFunctionPointerForName(framework, str);
+ CFRelease(str);
+
+ return reinterpret_cast<mbgl::gl::ProcAddress>(symbol);
}
void invalidate() override
diff --git a/platform/ios/src/MGLScaleBar.h b/platform/ios/src/MGLScaleBar.h
new file mode 100644
index 0000000000..77fd6736b5
--- /dev/null
+++ b/platform/ios/src/MGLScaleBar.h
@@ -0,0 +1,9 @@
+#import <UIKit/UIKit.h>
+#import <CoreLocation/CoreLocation.h>
+
+@interface MGLScaleBar : UIView
+
+// Sets the scale and redraws the scale bar
+@property (nonatomic, assign) CLLocationDistance metersPerPoint;
+
+@end
diff --git a/platform/ios/src/MGLScaleBar.mm b/platform/ios/src/MGLScaleBar.mm
new file mode 100644
index 0000000000..1216e400b3
--- /dev/null
+++ b/platform/ios/src/MGLScaleBar.mm
@@ -0,0 +1,366 @@
+#import <Mapbox/Mapbox.h>
+#import "MGLScaleBar.h"
+
+static const CGFloat MGLFeetPerMile = 5280;
+
+struct MGLRow {
+ CLLocationDistance distance;
+ NSUInteger numberOfBars;
+};
+
+static const MGLRow MGLMetricTable[] = {
+ {.distance = 1, .numberOfBars = 2},
+ {.distance = 2, .numberOfBars = 2},
+ {.distance = 4, .numberOfBars = 2},
+ {.distance = 10, .numberOfBars = 2},
+ {.distance = 20, .numberOfBars = 2},
+ {.distance = 50, .numberOfBars = 2},
+ {.distance = 75, .numberOfBars = 3},
+ {.distance = 100, .numberOfBars = 2},
+ {.distance = 150, .numberOfBars = 2},
+ {.distance = 200, .numberOfBars = 2},
+ {.distance = 300, .numberOfBars = 3},
+ {.distance = 500, .numberOfBars = 2},
+ {.distance = 1000, .numberOfBars = 2},
+ {.distance = 1500, .numberOfBars = 2},
+ {.distance = 3000, .numberOfBars = 3},
+ {.distance = 5000, .numberOfBars = 2},
+ {.distance = 10000, .numberOfBars = 2},
+ {.distance = 20000, .numberOfBars = 2},
+ {.distance = 30000, .numberOfBars = 3},
+ {.distance = 50000, .numberOfBars = 2},
+ {.distance = 100000, .numberOfBars = 2},
+ {.distance = 200000, .numberOfBars = 2},
+ {.distance = 300000, .numberOfBars = 3},
+ {.distance = 400000, .numberOfBars = 2},
+ {.distance = 500000, .numberOfBars = 2},
+ {.distance = 600000, .numberOfBars = 3},
+ {.distance = 800000, .numberOfBars = 2},
+};
+
+static const MGLRow MGLImperialTable[] ={
+ {.distance = 4, .numberOfBars = 2},
+ {.distance = 6, .numberOfBars = 2},
+ {.distance = 10, .numberOfBars = 2},
+ {.distance = 20, .numberOfBars = 2},
+ {.distance = 30, .numberOfBars = 2},
+ {.distance = 50, .numberOfBars = 2},
+ {.distance = 75, .numberOfBars = 3},
+ {.distance = 100, .numberOfBars = 2},
+ {.distance = 200, .numberOfBars = 2},
+ {.distance = 300, .numberOfBars = 3},
+ {.distance = 400, .numberOfBars = 2},
+ {.distance = 600, .numberOfBars = 3},
+ {.distance = 800, .numberOfBars = 2},
+ {.distance = 1000, .numberOfBars = 2},
+ {.distance = 0.25f*MGLFeetPerMile, .numberOfBars = 2},
+ {.distance = 0.5f*MGLFeetPerMile, .numberOfBars = 2},
+ {.distance = 1*MGLFeetPerMile, .numberOfBars = 2},
+ {.distance = 2*MGLFeetPerMile, .numberOfBars = 2},
+ {.distance = 3*MGLFeetPerMile, .numberOfBars = 3},
+ {.distance = 4*MGLFeetPerMile, .numberOfBars = 2},
+ {.distance = 8*MGLFeetPerMile, .numberOfBars = 2},
+ {.distance = 12*MGLFeetPerMile, .numberOfBars = 2},
+ {.distance = 15*MGLFeetPerMile, .numberOfBars = 3},
+ {.distance = 20*MGLFeetPerMile, .numberOfBars = 2},
+ {.distance = 30*MGLFeetPerMile, .numberOfBars = 3},
+ {.distance = 40*MGLFeetPerMile, .numberOfBars = 2},
+ {.distance = 80*MGLFeetPerMile, .numberOfBars = 2},
+ {.distance = 120*MGLFeetPerMile, .numberOfBars = 2},
+ {.distance = 200*MGLFeetPerMile, .numberOfBars = 2},
+ {.distance = 300*MGLFeetPerMile, .numberOfBars = 3},
+ {.distance = 400*MGLFeetPerMile, .numberOfBars = 2},
+};
+
+@class MGLScaleBarLabel;
+
+@interface MGLScaleBar()
+@property (nonatomic) NSArray<MGLScaleBarLabel *> *labels;
+@property (nonatomic) NSArray<UIView *> *bars;
+@property (nonatomic) UIView *containerView;
+@property (nonatomic) MGLDistanceFormatter *formatter;
+@property (nonatomic, assign) MGLRow row;
+@property (nonatomic) UIColor *primaryColor;
+@property (nonatomic) UIColor *secondaryColor;
+@property (nonatomic) CALayer *borderLayer;
+@property (nonatomic, assign) CGFloat borderWidth;
+@end
+
+static const CGFloat MGLBarHeight = 4;
+static const CGFloat MGLFeetPerMeter = 3.28084;
+
+@interface MGLScaleBarLabel : UILabel
+@end
+
+@implementation MGLScaleBarLabel
+
+- (void)drawTextInRect:(CGRect)rect {
+ CGSize shadowOffset = self.shadowOffset;
+ UIColor *textColor = self.textColor;
+
+ CGContextRef context = UIGraphicsGetCurrentContext();
+ CGContextSetLineWidth(context, 2);
+ CGContextSetLineJoin(context, kCGLineJoinRound);
+
+ CGContextSetTextDrawingMode(context, kCGTextStroke);
+ self.textColor = [UIColor whiteColor];
+ [super drawTextInRect:rect];
+
+ CGContextSetTextDrawingMode(context, kCGTextFill);
+ self.textColor = textColor;
+ self.shadowOffset = CGSizeMake(0, 0);
+ [super drawTextInRect:rect];
+
+ self.shadowOffset = shadowOffset;
+}
+
+@end
+
+@implementation MGLScaleBar
+
+- (instancetype)initWithCoder:(NSCoder *)decoder {
+ if (self = [super initWithCoder:decoder]) {
+ [self commonInit];
+ }
+ return self;
+}
+
+- (instancetype)initWithFrame:(CGRect)frame {
+ if (self = [super initWithFrame:frame]) {
+ [self commonInit];
+ }
+ return self;
+}
+
+- (void)commonInit {
+ _primaryColor = [UIColor colorWithRed:18.0/255.0 green:45.0/255.0 blue:17.0/255.0 alpha:1];
+ _secondaryColor = [UIColor colorWithRed:247.0/255.0 green:247.0/255.0 blue:247.0/255.0 alpha:1];
+ _borderWidth = 1.0f;
+
+ self.clipsToBounds = NO;
+ self.hidden = YES;
+
+ _containerView = [[UIView alloc] init];
+ _containerView.clipsToBounds = YES;
+ _containerView.backgroundColor = self.secondaryColor;
+ [self addSubview:_containerView];
+
+ _borderLayer = [CAShapeLayer layer];
+ _borderLayer.borderColor = [self.primaryColor CGColor];
+ _borderLayer.borderWidth = 1.0f / [[UIScreen mainScreen] scale];
+
+ [_containerView.layer addSublayer:_borderLayer];
+
+ _formatter = [[MGLDistanceFormatter alloc] init];
+}
+
+#pragma mark - Dimensions
+
+- (CGSize)intrinsicContentSize {
+ return CGSizeMake(self.actualWidth, 16);
+}
+
+- (CGFloat)actualWidth {
+ CGFloat width = self.row.distance / [self unitsPerPoint];
+ return !isnan(width) ? width : 0;
+}
+
+- (CGFloat)maximumWidth {
+ CGFloat fullWidth = CGRectGetWidth(self.superview.bounds);
+ CGFloat padding = [self usesRightToLeftLayout] ? fullWidth - CGRectGetMaxX(self.frame) : CGRectGetMinX(self.frame);
+ return floorf(fullWidth / 2 - padding);
+}
+
+- (CGFloat)unitsPerPoint {
+ return [self usesMetricSystem] ? self.metersPerPoint : self.metersPerPoint * MGLFeetPerMeter;
+}
+
+#pragma mark - Convenient methods
+
+- (BOOL)usesRightToLeftLayout {
+ return [UIView userInterfaceLayoutDirectionForSemanticContentAttribute:self.superview.semanticContentAttribute] == UIUserInterfaceLayoutDirectionRightToLeft;
+}
+
+- (BOOL)usesMetricSystem {
+ NSLocale *locale = [NSLocale currentLocale];
+ return [[locale objectForKey:NSLocaleUsesMetricSystem] boolValue];
+}
+
+- (MGLRow)preferredRow {
+ CLLocationDistance maximumDistance = [self maximumWidth] * [self unitsPerPoint];
+ MGLRow row;
+
+ BOOL useMetric = [self usesMetricSystem];
+ NSUInteger count = useMetric
+ ? sizeof(MGLMetricTable) / sizeof(MGLMetricTable[0])
+ : sizeof(MGLImperialTable) / sizeof(MGLImperialTable[0]);
+
+ for (NSUInteger i = 0; i < count; i++) {
+ CLLocationDistance distance = useMetric ? MGLMetricTable[i].distance : MGLImperialTable[i].distance;
+ if (distance <= maximumDistance) {
+ row = useMetric ? MGLMetricTable[i] : MGLImperialTable[i];
+ } else {
+ break;
+ }
+ }
+
+ return row;
+}
+
+#pragma mark - Setters
+
+- (void)setMetersPerPoint:(CLLocationDistance)metersPerPoint {
+ if (_metersPerPoint == metersPerPoint) {
+ return;
+ }
+
+ _metersPerPoint = metersPerPoint;
+
+ [self updateVisibility];
+
+ self.row = [self preferredRow];
+
+ [self invalidateIntrinsicContentSize];
+ [self setNeedsLayout];
+}
+
+- (void)updateVisibility {
+ BOOL metric = [self usesMetricSystem];
+
+ NSUInteger count = metric
+ ? sizeof(MGLMetricTable) / sizeof(MGLMetricTable[0])
+ : sizeof(MGLImperialTable) / sizeof(MGLImperialTable[0]);
+
+ CLLocationDistance maximumDistance = [self maximumWidth] * [self unitsPerPoint];
+ CLLocationDistance allowedDistance = metric
+ ? MGLMetricTable[count-1].distance
+ : MGLImperialTable[count-1].distance;
+
+ CGFloat alpha = maximumDistance > allowedDistance ? .0f : 1.0f;
+
+ if(self.alpha != alpha) {
+ [UIView animateWithDuration:.2f delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
+ self.alpha = alpha;
+ } completion:nil];
+ }
+}
+
+- (void)setRow:(MGLRow)row {
+ if (_row.distance == row.distance) {
+ return;
+ }
+
+ _row = row;
+ [_bars makeObjectsPerformSelector:@selector(removeFromSuperview)];
+ [_labels makeObjectsPerformSelector:@selector(removeFromSuperview)];
+ _bars = nil;
+ _labels = nil;
+}
+
+#pragma mark - Views
+
+- (NSArray<UIView *> *)bars {
+ if (!_bars) {
+ NSMutableArray *bars = [NSMutableArray array];
+ for (NSUInteger i = 0; i < self.row.numberOfBars; i++) {
+ UIView *bar = [[UIView alloc] init];
+ [bars addObject:bar];
+ [self.containerView addSubview:bar];
+ }
+ _bars = bars;
+ }
+ return _bars;
+}
+
+- (NSArray<UILabel *> *)labels {
+ if (!_labels) {
+ NSDecimalNumber *zeroNumber = [NSDecimalNumber decimalNumberWithString:@"0"];
+ NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
+ NSMutableArray *labels = [NSMutableArray array];
+
+ for (NSUInteger i = 0; i <= self.row.numberOfBars; i++) {
+ UILabel *label = [[MGLScaleBarLabel alloc] init];
+ label.font = [UIFont systemFontOfSize:8 weight:UIFontWeightMedium];
+ label.text = [formatter stringFromNumber:zeroNumber];
+ label.clipsToBounds = NO;
+ [label setNeedsDisplay];
+ [label sizeToFit];
+ [labels addObject:label];
+ [self addSubview:label];
+ }
+ _labels = labels;
+ }
+ return _labels;
+}
+
+#pragma mark - Layout
+
+- (void)layoutSubviews {
+ [super layoutSubviews];
+
+ if (!self.row.numberOfBars) {
+ // Current distance is not within allowed range
+ return;
+ }
+
+ [self updateLabels];
+ [self layoutBars];
+ [self layoutLabels];
+}
+
+- (void)updateLabels {
+ NSArray *labels = [self.labels subarrayWithRange:NSMakeRange(1, self.labels.count-1)];
+ BOOL useMetric = [self usesMetricSystem];
+ NSUInteger i = 0;
+
+ for (MGLScaleBarLabel *label in labels) {
+ CLLocationDistance barDistance = (self.row.distance / self.row.numberOfBars) * (i + 1);
+
+ if (!useMetric) {
+ barDistance /= MGLFeetPerMeter;
+ }
+
+ label.text = [self.formatter stringFromDistance:barDistance];
+ [label setNeedsDisplay];
+ [label sizeToFit];
+ i++;
+ }
+}
+
+- (void)layoutBars {
+ CGFloat barWidth = (CGRectGetWidth(self.bounds) - self.borderWidth * 2.0f) / self.bars.count;
+
+ NSUInteger i = 0;
+ for (UIView *bar in self.bars) {
+ CGFloat xPosition = barWidth * i + self.borderWidth;
+ bar.backgroundColor = (i % 2 == 0) ? self.primaryColor : self.secondaryColor;
+ bar.frame = CGRectMake(xPosition, self.borderWidth, barWidth, MGLBarHeight);
+ i++;
+ }
+
+ self.containerView.frame = CGRectMake(CGRectGetMinX(self.bars.firstObject.frame),
+ CGRectGetMaxY(self.bounds)-MGLBarHeight,
+ self.actualWidth,
+ MGLBarHeight+self.borderWidth*2);
+
+ [CATransaction begin];
+ [CATransaction setDisableActions:YES];
+ self.borderLayer.frame = CGRectInset(self.containerView.bounds, self.borderWidth, self.borderWidth);
+ self.borderLayer.zPosition = FLT_MAX;
+ [CATransaction commit];
+}
+
+- (void)layoutLabels {
+ CGFloat barWidth = self.bounds.size.width / self.bars.count;
+ BOOL RTL = [self usesRightToLeftLayout];
+ NSUInteger i = RTL ? self.bars.count : 0;
+ for (MGLScaleBarLabel *label in self.labels) {
+ CGFloat xPosition = barWidth * i - CGRectGetMidX(label.bounds) + self.borderWidth;
+ label.frame = CGRectMake(xPosition, 0,
+ CGRectGetWidth(label.bounds),
+ CGRectGetHeight(label.bounds));
+ i = RTL ? i-1 : i+1;
+ }
+}
+
+@end
diff --git a/platform/ios/src/Mapbox.h b/platform/ios/src/Mapbox.h
index 2623777d8f..9a9dc702ca 100644
--- a/platform/ios/src/Mapbox.h
+++ b/platform/ios/src/Mapbox.h
@@ -38,6 +38,7 @@ FOUNDATION_EXPORT MGL_EXPORT const unsigned char MapboxVersionString[];
#import "MGLStyleLayer.h"
#import "MGLForegroundStyleLayer.h"
#import "MGLVectorStyleLayer.h"
+#import "MGLFillExtrusionStyleLayer.h"
#import "MGLFillStyleLayer.h"
#import "MGLLineStyleLayer.h"
#import "MGLSymbolStyleLayer.h"
diff --git a/platform/ios/src/UIImage+MGLAdditions.h b/platform/ios/src/UIImage+MGLAdditions.h
index f291a302c9..0b4cb4c015 100644
--- a/platform/ios/src/UIImage+MGLAdditions.h
+++ b/platform/ios/src/UIImage+MGLAdditions.h
@@ -1,14 +1,14 @@
#import <UIKit/UIKit.h>
-#include <mbgl/sprite/sprite_image.hpp>
+#include <mbgl/style/image.hpp>
NS_ASSUME_NONNULL_BEGIN
@interface UIImage (MGLAdditions)
-- (nullable instancetype)initWithMGLSpriteImage:(const mbgl::SpriteImage *)spriteImage;
+- (nullable instancetype)initWithMGLStyleImage:(const mbgl::style::Image *)styleImage;
-- (std::unique_ptr<mbgl::SpriteImage>)mgl_spriteImage;
+- (std::unique_ptr<mbgl::style::Image>)mgl_styleImageWithIdentifier:(NSString *)identifier;
@end
diff --git a/platform/ios/src/UIImage+MGLAdditions.mm b/platform/ios/src/UIImage+MGLAdditions.mm
index d99a1f73ed..b10c48a62a 100644
--- a/platform/ios/src/UIImage+MGLAdditions.mm
+++ b/platform/ios/src/UIImage+MGLAdditions.mm
@@ -4,16 +4,16 @@
@implementation UIImage (MGLAdditions)
-- (nullable instancetype)initWithMGLSpriteImage:(const mbgl::SpriteImage *)spriteImage
+- (nullable instancetype)initWithMGLStyleImage:(const mbgl::style::Image *)styleImage
{
- CGImageRef image = CGImageFromMGLPremultipliedImage(spriteImage->image.clone());
+ CGImageRef image = CGImageFromMGLPremultipliedImage(styleImage->getImage().clone());
if (!image) {
return nil;
}
- if (self = [self initWithCGImage:image scale:spriteImage->pixelRatio orientation:UIImageOrientationUp])
+ if (self = [self initWithCGImage:image scale:styleImage->getPixelRatio() orientation:UIImageOrientationUp])
{
- if (spriteImage->sdf)
+ if (styleImage->isSdf())
{
self = [self imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
}
@@ -22,10 +22,11 @@
return self;
}
-- (std::unique_ptr<mbgl::SpriteImage>)mgl_spriteImage {
+- (std::unique_ptr<mbgl::style::Image>)mgl_styleImageWithIdentifier:(NSString *)identifier {
BOOL isTemplate = self.renderingMode == UIImageRenderingModeAlwaysTemplate;
- return std::make_unique<mbgl::SpriteImage>(MGLPremultipliedImageFromCGImage(self.CGImage),
- float(self.scale), isTemplate);
+ return std::make_unique<mbgl::style::Image>([identifier UTF8String],
+ MGLPremultipliedImageFromCGImage(self.CGImage),
+ float(self.scale), isTemplate);
}
@end
diff --git a/platform/ios/test/MGLAnnotationViewTests.m b/platform/ios/test/MGLAnnotationViewTests.m
index 212de9a405..c0978eaf65 100644
--- a/platform/ios/test/MGLAnnotationViewTests.m
+++ b/platform/ios/test/MGLAnnotationViewTests.m
@@ -51,7 +51,7 @@ static NSString * const MGLTestAnnotationReuseIdentifer = @"MGLTestAnnotationReu
- (void)setUp
{
[super setUp];
- _mapView = [[MGLMapView alloc] initWithFrame:CGRectZero];
+ _mapView = [[MGLMapView alloc] initWithFrame:CGRectMake(0, 0, 64, 64)];
_mapView.delegate = self;
}
diff --git a/platform/ios/test/MGLMapViewDelegateIntegrationTests.swift b/platform/ios/test/MGLMapViewDelegateIntegrationTests.swift
new file mode 100644
index 0000000000..50f101e86b
--- /dev/null
+++ b/platform/ios/test/MGLMapViewDelegateIntegrationTests.swift
@@ -0,0 +1,82 @@
+import XCTest
+import Mapbox
+
+class MGLMapViewDelegateIntegrationTests: XCTestCase {
+
+ func testCoverage() {
+ MGLSDKTestHelpers.checkTestsContainAllMethods(testClass: MGLMapViewDelegateIntegrationTests.self, in: MGLMapViewDelegate.self)
+ }
+
+}
+
+extension MGLMapViewDelegateIntegrationTests: MGLMapViewDelegate {
+
+ func mapViewRegionIsChanging(_ mapView: MGLMapView) {}
+
+ func mapView(_ mapView: MGLMapView, didChange mode: MGLUserTrackingMode, animated: Bool) {}
+
+ func mapViewDidFinishLoadingMap(_ mapView: MGLMapView) {}
+
+ func mapViewDidStopLocatingUser(_ mapView: MGLMapView) {}
+
+ func mapViewWillStartLoadingMap(_ mapView: MGLMapView) {}
+
+ func mapViewWillStartLocatingUser(_ mapView: MGLMapView) {}
+
+ func mapViewWillStartRenderingMap(_ mapView: MGLMapView) {}
+
+ func mapViewWillStartRenderingFrame(_ mapView: MGLMapView) {}
+
+ func mapView(_ mapView: MGLMapView, didFinishLoading style: MGLStyle) {}
+
+ func mapView(_ mapView: MGLMapView, didSelect annotation: MGLAnnotation) {}
+
+ func mapView(_ mapView: MGLMapView, didDeselect annotation: MGLAnnotation) {}
+
+ func mapView(_ mapView: MGLMapView, regionDidChangeAnimated animated: Bool) {}
+
+ func mapView(_ mapView: MGLMapView, regionWillChangeAnimated animated: Bool) {}
+
+ func mapViewDidFailLoadingMap(_ mapView: MGLMapView, withError error: Error) {}
+
+ func mapView(_ mapView: MGLMapView, didUpdate userLocation: MGLUserLocation?) {}
+
+ func mapViewDidFinishRenderingMap(_ mapView: MGLMapView, fullyRendered: Bool) {}
+
+ func mapView(_ mapView: MGLMapView, didFailToLocateUserWithError error: Error) {}
+
+ func mapView(_ mapView: MGLMapView, tapOnCalloutFor annotation: MGLAnnotation) {}
+
+ func mapViewDidFinishRenderingFrame(_ mapView: MGLMapView, fullyRendered: Bool) {}
+
+ func mapView(_ mapView: MGLMapView, didAdd annotationViews: [MGLAnnotationView]) {}
+
+ func mapView(_ mapView: MGLMapView, didSelect annotationView: MGLAnnotationView) {}
+
+ func mapView(_ mapView: MGLMapView, didDeselect annotationView: MGLAnnotationView) {}
+
+ func mapView(_ mapView: MGLMapView, alphaForShapeAnnotation annotation: MGLShape) -> CGFloat { return 0 }
+
+ func mapView(_ mapView: MGLMapView, viewFor annotation: MGLAnnotation) -> MGLAnnotationView? { return nil }
+
+ func mapView(_ mapView: MGLMapView, imageFor annotation: MGLAnnotation) -> MGLAnnotationImage? { return nil }
+
+ func mapView(_ mapView: MGLMapView, annotationCanShowCallout annotation: MGLAnnotation) -> Bool { return false }
+
+ func mapView(_ mapView: MGLMapView, calloutViewFor annotation: MGLAnnotation) -> MGLCalloutView? { return nil }
+
+ func mapView(_ mapView: MGLMapView, strokeColorForShapeAnnotation annotation: MGLShape) -> UIColor { return .black }
+
+ func mapView(_ mapView: MGLMapView, fillColorForPolygonAnnotation annotation: MGLPolygon) -> UIColor { return .black }
+
+ func mapView(_ mapView: MGLMapView, leftCalloutAccessoryViewFor annotation: MGLAnnotation) -> UIView? { return nil }
+
+ func mapView(_ mapView: MGLMapView, lineWidthForPolylineAnnotation annotation: MGLPolyline) -> CGFloat { return 0 }
+
+ func mapView(_ mapView: MGLMapView, rightCalloutAccessoryViewFor annotation: MGLAnnotation) -> UIView? { return nil }
+
+ func mapView(_ mapView: MGLMapView, annotation: MGLAnnotation, calloutAccessoryControlTapped control: UIControl) {}
+
+ func mapView(_ mapView: MGLMapView, shouldChangeFrom oldCamera: MGLMapCamera, to newCamera: MGLMapCamera) -> Bool { return false }
+
+}
diff --git a/platform/ios/test/MGLSourceTests.m b/platform/ios/test/MGLSourceTests.m
deleted file mode 100644
index 2e4942cbe9..0000000000
--- a/platform/ios/test/MGLSourceTests.m
+++ /dev/null
@@ -1,24 +0,0 @@
-#import "MGLMapViewTests.h"
-
-@interface MGLSourceTests : MGLMapViewTests
-
-@end
-
-@implementation MGLSourceTests
-
-- (void)testDuplicateSources {
- MGLVectorSource *source1 = [[MGLVectorSource alloc] initWithIdentifier:@"my-source" URL:[NSURL URLWithString:@"mapbox://mapbox.mapbox-terrain-v2"]];
- MGLVectorSource *source2 = [[MGLVectorSource alloc] initWithIdentifier:@"my-source" URL:[NSURL URLWithString:@"mapbox://mapbox.mapbox-terrain-v2"]];
-
- [self.mapView.style addSource: source1];
-
- @try {
- [self.mapView.style addSource: source2];
- XCTFail(@"Should not have reached this point");
- }
- @catch (NSException *e) {
- XCTAssertNotNil(e, @"Should have thrown an exception");
- }
-}
-
-@end
diff --git a/platform/ios/vendor/SMCalloutView b/platform/ios/vendor/SMCalloutView
-Subproject d6ecaba377c9f963aef630faf86e3b8f8cdb88d
+Subproject 2aede5d8d1577101bf18405246220e7a710df60
diff --git a/platform/linux/config.cmake b/platform/linux/config.cmake
index ff2dcf4cfa..41e7f71b99 100644
--- a/platform/linux/config.cmake
+++ b/platform/linux/config.cmake
@@ -11,7 +11,9 @@ mason_use(gtest VERSION 1.8.0${MASON_CXXABI_SUFFIX})
mason_use(benchmark VERSION 1.0.0-1)
mason_use(icu VERSION 58.1-min-size)
-include(cmake/loop-uv.cmake)
+# Link with libuv. This is not part of loop-uv.cmake because loop-uv.cmake is also
+# used by node.cmake, where we want to link with the libuv provided by node itself.
+target_add_mason_package(mbgl-loop-uv PUBLIC libuv)
macro(mbgl_platform_core)
target_add_mason_package(mbgl-core PUBLIC mesa)
@@ -86,6 +88,7 @@ macro(mbgl_platform_core)
# Thread pool
PRIVATE platform/default/mbgl/util/default_thread_pool.cpp
PRIVATE platform/default/mbgl/util/default_thread_pool.cpp
+ PRIVATE platform/default/mbgl/util/shared_thread_pool.cpp
)
target_include_directories(mbgl-core
@@ -97,7 +100,7 @@ macro(mbgl_platform_core)
target_add_mason_package(mbgl-core PUBLIC libpng)
target_add_mason_package(mbgl-core PUBLIC libjpeg-turbo)
target_add_mason_package(mbgl-core PUBLIC webp)
- target_add_mason_package(mbgl-core PUBLIC icu)
+ target_add_mason_package(mbgl-core PRIVATE icu)
target_link_libraries(mbgl-core
PUBLIC -lz
@@ -108,7 +111,7 @@ endmacro()
macro(mbgl_platform_glfw)
target_link_libraries(mbgl-glfw
- PRIVATE mbgl-loop
+ PRIVATE mbgl-loop-uv
)
add_custom_command(
@@ -122,14 +125,14 @@ endmacro()
macro(mbgl_platform_render)
target_link_libraries(mbgl-render
- PRIVATE mbgl-loop
+ PRIVATE mbgl-loop-uv
)
endmacro()
macro(mbgl_platform_offline)
target_link_libraries(mbgl-offline
- PRIVATE mbgl-loop
+ PRIVATE mbgl-loop-uv
)
endmacro()
@@ -146,7 +149,7 @@ macro(mbgl_platform_test)
)
target_link_libraries(mbgl-test
- PRIVATE mbgl-loop
+ PRIVATE mbgl-loop-uv
)
endmacro()
@@ -163,7 +166,7 @@ macro(mbgl_platform_benchmark)
)
target_link_libraries(mbgl-benchmark
- PRIVATE mbgl-loop
+ PRIVATE mbgl-loop-uv
)
endmacro()
diff --git a/platform/linux/src/headless_backend_egl.cpp b/platform/linux/src/headless_backend_egl.cpp
index df0ecc8dff..d98b2edc03 100644
--- a/platform/linux/src/headless_backend_egl.cpp
+++ b/platform/linux/src/headless_backend_egl.cpp
@@ -14,11 +14,13 @@ struct EGLImpl : public HeadlessBackend::Impl {
: glContext(glContext_),
display(display_),
config(config_) {
-#if __ANDROID__
- // Create a pixel buffer surface (in conjunction with EGL_SURFACE_TYPE, EGL_PBUFFER_BIT).
+ // Create a dummy pbuffer. We will render to framebuffers anyway, but we need a pbuffer to
+ // activate the context.
+ // Note that to be able to create pbuffer surfaces, we need to choose a config that
+ // includes EGL_SURFACE_TYPE, EGL_PBUFFER_BIT in HeadlessDisplay.
const EGLint surfAttribs[] = {
- EGL_WIDTH, 512,
- EGL_HEIGHT, 512,
+ EGL_WIDTH, 8,
+ EGL_HEIGHT, 8,
EGL_LARGEST_PBUFFER, EGL_TRUE,
EGL_NONE
};
@@ -27,19 +29,18 @@ struct EGLImpl : public HeadlessBackend::Impl {
if (glSurface == EGL_NO_SURFACE) {
throw std::runtime_error("Could not create surface: " + std::to_string(eglGetError()));
}
-#endif // __ANDROID__
}
~EGLImpl() {
- if (!eglDestroyContext(display, glContext)) {
- throw std::runtime_error("Failed to destroy EGL context.\n");
- }
if (glSurface != EGL_NO_SURFACE) {
if (!eglDestroySurface(display, glSurface)) {
- throw std::runtime_error("Failed to destroy EGL context.\n");
+ throw std::runtime_error("Failed to destroy EGL surface.\n");
}
glSurface = EGL_NO_SURFACE;
}
+ if (!eglDestroyContext(display, glContext)) {
+ throw std::runtime_error("Failed to destroy EGL context.\n");
+ }
}
void activateContext() final {
@@ -60,7 +61,7 @@ struct EGLImpl : public HeadlessBackend::Impl {
EGLSurface glSurface = EGL_NO_SURFACE;
};
-gl::glProc HeadlessBackend::initializeExtension(const char* name) {
+gl::ProcAddress HeadlessBackend::initializeExtension(const char* name) {
return eglGetProcAddress(name);
}
diff --git a/platform/linux/src/headless_backend_glx.cpp b/platform/linux/src/headless_backend_glx.cpp
index 5791f1892f..eec0e7656f 100644
--- a/platform/linux/src/headless_backend_glx.cpp
+++ b/platform/linux/src/headless_backend_glx.cpp
@@ -17,7 +17,7 @@ struct GLXImpl : public HeadlessBackend::Impl {
fbConfigs(fbConfigs_) {
}
- ~GLXImpl() {
+ ~GLXImpl() override {
if (glxPbuffer) {
glXDestroyPbuffer(xDisplay, glxPbuffer);
}
@@ -44,7 +44,7 @@ struct GLXImpl : public HeadlessBackend::Impl {
GLXFBConfig* fbConfigs = nullptr;
};
-gl::glProc HeadlessBackend::initializeExtension(const char* name) {
+gl::ProcAddress HeadlessBackend::initializeExtension(const char* name) {
return glXGetProcAddress(reinterpret_cast<const GLubyte*>(name));
}
@@ -58,8 +58,8 @@ bool HeadlessBackend::hasDisplay() {
void HeadlessBackend::createContext() {
assert(!hasContext());
- Display* xDisplay = display->attribute<Display*>();
- GLXFBConfig* fbConfigs = display->attribute<GLXFBConfig*>();
+ auto* xDisplay = display->attribute<Display*>();
+ auto* fbConfigs = display->attribute<GLXFBConfig*>();
// Try to create a legacy context.
GLXContext glContext = glXCreateNewContext(xDisplay, fbConfigs[0], GLX_RGBA_TYPE, None, True);
@@ -81,7 +81,7 @@ void HeadlessBackend::createContext() {
};
GLXPbuffer glxPbuffer = glXCreatePbuffer(xDisplay, fbConfigs[0], pbufferAttributes);
- impl.reset(new GLXImpl(glContext, glxPbuffer, xDisplay, fbConfigs));
+ impl = std::make_unique<mbgl::GLXImpl>(glContext, glxPbuffer, xDisplay, fbConfigs);
}
} // namespace mbgl
diff --git a/platform/linux/src/headless_display_egl.cpp b/platform/linux/src/headless_display_egl.cpp
index eddc05feaf..03c8e16a59 100644
--- a/platform/linux/src/headless_display_egl.cpp
+++ b/platform/linux/src/headless_display_egl.cpp
@@ -32,11 +32,7 @@ HeadlessDisplay::Impl::Impl() {
}
const EGLint attribs[] = {
-#if __ANDROID__
- // Android emulator requires a pixel buffer to generate renderable unit
- // test results.
EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
-#endif // __ANDROID__
EGL_NONE
};
diff --git a/platform/linux/src/headless_display_glx.cpp b/platform/linux/src/headless_display_glx.cpp
index 4275ebb646..5dc342154d 100644
--- a/platform/linux/src/headless_display_glx.cpp
+++ b/platform/linux/src/headless_display_glx.cpp
@@ -27,7 +27,7 @@ HeadlessDisplay::Impl::Impl() {
throw std::runtime_error("Failed to open X display.");
}
- const char *extensions = reinterpret_cast<const char *>(glXQueryServerString(xDisplay, DefaultScreen(xDisplay), GLX_EXTENSIONS));
+ const auto *extensions = reinterpret_cast<const char *>(glXQueryServerString(xDisplay, DefaultScreen(xDisplay), GLX_EXTENSIONS));
if (!extensions) {
throw std::runtime_error("Cannot read GLX extensions.");
}
@@ -73,7 +73,6 @@ HeadlessDisplay::HeadlessDisplay()
: impl(std::make_unique<Impl>()) {
}
-HeadlessDisplay::~HeadlessDisplay() {
-}
+HeadlessDisplay::~HeadlessDisplay() = default;
} // namespace mbgl
diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md
index 85047bf02e..377c321452 100644
--- a/platform/macos/CHANGELOG.md
+++ b/platform/macos/CHANGELOG.md
@@ -1,6 +1,32 @@
# Changelog for Mapbox macOS SDK
-## 0.4.1
+## master
+
+* The previously-deprecated support for style classes has been removed. For interface compatibility, the API methods remain, but they are now non-functional.
+
+## 0.5.0
+
+### Styles
+
+* Added support for 3D extrusion of buildings and other polygonal features via the `MGLFillExtrusionStyleLayer` class and the `fill-extrusion` layer type in style JSON. ([#8431](https://github.com/mapbox/mapbox-gl-native/pull/8431))
+* MGLMapView and MGLTilePyramidOfflineRegion now default to version 10 of the Mapbox Streets style. Similarly, several style URL class methods of MGLStyle return URLs to version 10 styles. Unversioned variations of these methods are no longer deprecated. `MGLStyleDefaultVersion` should no longer be used with any style other than Streets. ([#6301](https://github.com/mapbox/mapbox-gl-native/pull/6301))
+* Added class methods to MGLStyle that correspond to the new [Traffic Day and Traffic Night](https://www.mapbox.com/blog/live-traffic-maps/) styles. ([#6301](https://github.com/mapbox/mapbox-gl-native/pull/6301))
+* MGLSymbolStyleLayer’s `iconImageName`, `iconScale`, `textFontSize`, `textOffset`, and `textRotation` properties can now be set to a source or composite function. ([#8544](https://github.com/mapbox/mapbox-gl-native/pull/8544), [#8590](https://github.com/mapbox/mapbox-gl-native/pull/8590), [#8592](https://github.com/mapbox/mapbox-gl-native/pull/8592), [#8593](https://github.com/mapbox/mapbox-gl-native/pull/8593))
+* Fixed an issue where setting the `MGLVectorStyleLayer.predicate` property failed to take effect if the relevant source was not in use by a visible layer at the time. ([#8653](https://github.com/mapbox/mapbox-gl-native/pull/8653))
+* Fixed an issue causing a composite function’s highest zoom level stop to be misinterpreted. ([#8613](https://github.com/mapbox/mapbox-gl-native/pull/8613), [#8790](https://github.com/mapbox/mapbox-gl-native/pull/8790))
+* Fixed an issue where re-adding a layer that had been previously removed from a style would reset its paint properties. Moved initializers for `MGLTileSource`, `MGLStyleLayer`, and `MGLForegroundStyleLayer` to their concrete subclasses; because these classes were already intended for initialization only via concrete subclasses, this should have no developer impact. ([#8626](https://github.com/mapbox/mapbox-gl-native/pull/8626))
+* Feature querying results now account for any changes to a feature’s size caused by a source or composite style function. ([#8665](https://github.com/mapbox/mapbox-gl-native/pull/8665))
+
+### Other changes
+
+* Xcode 8.0 or higher is now recommended for using this SDK. ([#8775](https://github.com/mapbox/mapbox-gl-native/pull/8775))
+* Updated MGLMapView’s logo view to display [the new Mapbox logo](https://www.mapbox.com/blog/new-mapbox-logo/). ([#8771](https://github.com/mapbox/mapbox-gl-native/pull/8771), [#8773](https://github.com/mapbox/mapbox-gl-native/pull/8773))
+* Fixed an issue causing attribution button text to appear blue instead of black. ([#8701](https://github.com/mapbox/mapbox-gl-native/pull/8701))
+* Fixed a crash or console spew when MGLMapView is initialized with a frame smaller than 64 points wide by 64 points tall. ([#8562](https://github.com/mapbox/mapbox-gl-native/pull/8562))
+* The error passed into `-[MGLMapViewDelegate mapViewDidFailLoadingMap:withError:]` now includes a more specific description and failure reason. ([#8418](https://github.com/mapbox/mapbox-gl-native/pull/8418))
+* Fixed an issue rendering polylines that contain duplicate vertices. ([#8808](https://github.com/mapbox/mapbox-gl-native/pull/8808))
+
+## 0.4.1 - April 8, 2017
This version of the Mapbox macOS SDK corresponds to version 3.5.2 of the Mapbox iOS SDK.
diff --git a/platform/macos/DEVELOPING.md b/platform/macos/DEVELOPING.md
index bc91e69456..fecde1fb38 100644
--- a/platform/macos/DEVELOPING.md
+++ b/platform/macos/DEVELOPING.md
@@ -6,7 +6,7 @@ This document explains how to build the Mapbox macOS SDK from source. It is inte
The Mapbox macOS SDK and the macosapp demo application run on macOS 10.10.0 or above.
-The Mapbox macOS SDK requires Xcode 7.3 or above.
+The Mapbox macOS SDK requires Xcode 8.0 or above.
## Building the SDK
diff --git a/platform/macos/INSTALL.md b/platform/macos/INSTALL.md
index ef04267c47..cbb9d7d8a6 100644
--- a/platform/macos/INSTALL.md
+++ b/platform/macos/INSTALL.md
@@ -4,7 +4,7 @@ This document explains how to build a development version of the Mapbox macOS SD
### Requirements
-The Mapbox macOS SDK requires the macOS 10.10.0 SDK (or above) and Xcode 7.3 (or above).
+The Mapbox macOS SDK requires the macOS 10.10.0 SDK (or above) and Xcode 8.0 (or above). To use this SDK with Xcode 7.3.1, download and use a symbols build from the [releases](https://github.com/mapbox/mapbox-gl-native/releases) page.
### Building the SDK from source
diff --git a/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon128x128.png b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon128x128.png
index 145d5a7d85..fbf35e5d61 100644
--- a/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon128x128.png
+++ b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon128x128.png
Binary files differ
diff --git a/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon128x128@2x.png b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon128x128@2x.png
new file mode 100644
index 0000000000..e60680874a
--- /dev/null
+++ b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon128x128@2x.png
Binary files differ
diff --git a/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon16x16.png b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon16x16.png
index fa2588dec3..361198da92 100644
--- a/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon16x16.png
+++ b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon16x16.png
Binary files differ
diff --git a/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon16x16@2x.png b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon16x16@2x.png
new file mode 100644
index 0000000000..f6bf78a4b4
--- /dev/null
+++ b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon16x16@2x.png
Binary files differ
diff --git a/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon256x256-1.png b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon256x256-1.png
deleted file mode 100644
index 18fec77f84..0000000000
--- a/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon256x256-1.png
+++ /dev/null
Binary files differ
diff --git a/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon256x256.png b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon256x256.png
index 18fec77f84..e60680874a 100644
--- a/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon256x256.png
+++ b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon256x256.png
Binary files differ
diff --git a/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon256x256@2x.png b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon256x256@2x.png
new file mode 100644
index 0000000000..e7c0271490
--- /dev/null
+++ b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon256x256@2x.png
Binary files differ
diff --git a/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon32x32-1.png b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon32x32-1.png
deleted file mode 100644
index bf3acc1282..0000000000
--- a/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon32x32-1.png
+++ /dev/null
Binary files differ
diff --git a/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon32x32.png b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon32x32.png
index bf3acc1282..e919899269 100644
--- a/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon32x32.png
+++ b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon32x32.png
Binary files differ
diff --git a/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon32x32@2x.png b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon32x32@2x.png
new file mode 100644
index 0000000000..5035f60941
--- /dev/null
+++ b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon32x32@2x.png
Binary files differ
diff --git a/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon512x512-1.png b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon512x512-1.png
deleted file mode 100644
index 1ea7683696..0000000000
--- a/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon512x512-1.png
+++ /dev/null
Binary files differ
diff --git a/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon512x512.png b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon512x512.png
index 1ea7683696..e7c0271490 100644
--- a/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon512x512.png
+++ b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon512x512.png
Binary files differ
diff --git a/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon512x512@2x.png b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon512x512@2x.png
new file mode 100644
index 0000000000..a2e1dfd02b
--- /dev/null
+++ b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon512x512@2x.png
Binary files differ
diff --git a/platform/macos/app/Assets.xcassets/AppIcon.appiconset/Contents.json b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/Contents.json
index 58e739d056..068d0fbd00 100644
--- a/platform/macos/app/Assets.xcassets/AppIcon.appiconset/Contents.json
+++ b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -9,7 +9,7 @@
{
"size" : "16x16",
"idiom" : "mac",
- "filename" : "AppIcon32x32-1.png",
+ "filename" : "AppIcon16x16@2x.png",
"scale" : "2x"
},
{
@@ -21,7 +21,7 @@
{
"size" : "32x32",
"idiom" : "mac",
- "filename" : "icon-1.png",
+ "filename" : "AppIcon32x32@2x.png",
"scale" : "2x"
},
{
@@ -33,7 +33,7 @@
{
"size" : "128x128",
"idiom" : "mac",
- "filename" : "AppIcon256x256-1.png",
+ "filename" : "AppIcon128x128@2x.png",
"scale" : "2x"
},
{
@@ -45,7 +45,7 @@
{
"size" : "256x256",
"idiom" : "mac",
- "filename" : "AppIcon512x512-1.png",
+ "filename" : "AppIcon256x256@2x.png",
"scale" : "2x"
},
{
@@ -57,7 +57,7 @@
{
"size" : "512x512",
"idiom" : "mac",
- "filename" : "icon.png",
+ "filename" : "AppIcon512x512@2x.png",
"scale" : "2x"
}
],
diff --git a/platform/macos/app/Assets.xcassets/AppIcon.appiconset/icon-1.png b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/icon-1.png
deleted file mode 100644
index 36dd7acf90..0000000000
--- a/platform/macos/app/Assets.xcassets/AppIcon.appiconset/icon-1.png
+++ /dev/null
Binary files differ
diff --git a/platform/macos/app/Assets.xcassets/AppIcon.appiconset/icon.png b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/icon.png
deleted file mode 100644
index fdee900aa4..0000000000
--- a/platform/macos/app/Assets.xcassets/AppIcon.appiconset/icon.png
+++ /dev/null
Binary files differ
diff --git a/platform/macos/app/Base.lproj/MainMenu.xib b/platform/macos/app/Base.lproj/MainMenu.xib
index 941bed2136..20a4f65b3f 100644
--- a/platform/macos/app/Base.lproj/MainMenu.xib
+++ b/platform/macos/app/Base.lproj/MainMenu.xib
@@ -1,7 +1,7 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11762" systemVersion="15G1217" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="12120" systemVersion="16E195" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
- <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11762"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="12120"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@@ -395,6 +395,16 @@
<action selector="showStyle:" target="-1" id="NTT-Y1-EqU"/>
</connections>
</menuItem>
+ <menuItem title="Traffic Day" tag="7" keyEquivalent="7" id="m9S-sv-Dch">
+ <connections>
+ <action selector="showStyle:" target="-1" id="lXM-BW-dDw"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Traffic Night" tag="8" keyEquivalent="8" id="yVS-VL-Xsy">
+ <connections>
+ <action selector="showStyle:" target="-1" id="eAD-br-oBB"/>
+ </connections>
+ </menuItem>
<menuItem title="Custom Style…" id="L0h-86-2cU">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
@@ -643,7 +653,7 @@ CA
<rect key="frame" x="0.0" y="0.0" width="350" height="84"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
- <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="0IK-AW-Gg3">
+ <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="0IK-AW-Gg3">
<rect key="frame" x="18" y="45" width="89" height="17"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Access token:" id="Ptd-FI-M5A">
<font key="font" metaFont="system"/>
@@ -654,7 +664,7 @@ CA
<accessibilityConnection property="link" destination="7sb-sf-oJU" id="U0t-jC-oQ7"/>
</connections>
</textField>
- <textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="7sb-sf-oJU">
+ <textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="7sb-sf-oJU">
<rect key="frame" x="113" y="42" width="197" height="22"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" drawsBackground="YES" id="jlV-TC-NUv">
<font key="font" metaFont="system"/>
@@ -723,7 +733,7 @@ CA
<rect key="frame" x="-1" y="20" width="402" height="281"/>
<clipView key="contentView" id="J9U-Yx-o2S">
<rect key="frame" x="1" y="0.0" width="400" height="280"/>
- <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <autoresizingMask key="autoresizingMask"/>
<subviews>
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" autosaveColumns="NO" headerView="MAZ-Iq-hBi" id="Ato-Vu-HYT">
<rect key="frame" x="0.0" y="0.0" width="423" height="257"/>
diff --git a/platform/macos/app/Base.lproj/MapDocument.xib b/platform/macos/app/Base.lproj/MapDocument.xib
index b658b52cc2..d95f21b2e9 100644
--- a/platform/macos/app/Base.lproj/MapDocument.xib
+++ b/platform/macos/app/Base.lproj/MapDocument.xib
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11762" systemVersion="16D32" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
+<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="12120" systemVersion="16E195" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
- <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11762"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="12120"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@@ -48,7 +48,7 @@
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES" fullSizeContentView="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="388" y="211" width="642" height="480"/>
- <rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/>
+ <rect key="screenRect" x="0.0" y="0.0" width="1280" height="777"/>
<view key="contentView" id="TuG-C5-zLS">
<rect key="frame" x="0.0" y="0.0" width="642" height="480"/>
<autoresizingMask key="autoresizingMask"/>
@@ -183,9 +183,9 @@
<toolbarItem implicitItemIdentifier="BA3542AF-D63A-4893-9CC7-8F67EF2E82B0" label="Style" paletteLabel="Style" id="u23-0z-Otl" customClass="ValidatedToolbarItem">
<nil key="toolTip"/>
<size key="minSize" width="100" height="26"/>
- <size key="maxSize" width="120" height="26"/>
+ <size key="maxSize" width="150" height="26"/>
<popUpButton key="view" verticalHuggingPriority="750" id="Tzm-Cy-dQg">
- <rect key="frame" x="0.0" y="14" width="120" height="26"/>
+ <rect key="frame" x="0.0" y="14" width="150" height="26"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<popUpButtonCell key="cell" type="roundTextured" title="Streets" bezelStyle="texturedRounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="border" tag="1" imageScaling="proportionallyDown" inset="2" selectedItem="wvt-tP-O3a" id="3PJ-qK-Oh3">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
@@ -204,6 +204,12 @@
<menuItem title="Satellite Streets" tag="6" id="7ly-oA-0ND">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
+ <menuItem title="Traffic Day" tag="7" id="Vz7-9Z-EFq">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ </menuItem>
+ <menuItem title="Traffic Night" tag="8" id="zh7-LM-dmF">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ </menuItem>
</items>
</menu>
</popUpButtonCell>
@@ -240,12 +246,17 @@
</connections>
</toolbar>
<connections>
- <binding destination="-2" name="displayPatternTitle1" keyPath="mapView.centerCoordinate" id="wtz-AV-bG1">
+ <binding destination="-2" name="displayPatternTitle1" keyPath="mapView.centerCoordinate" id="p1k-yo-4Nb">
<dictionary key="options">
- <string key="NSDisplayPattern">%{title1}@</string>
+ <string key="NSDisplayPattern">%{title1}@ @ %{title2}@</string>
<string key="NSValueTransformerName">LocationCoordinate2DTransformer</string>
</dictionary>
</binding>
+ <binding destination="-2" name="displayPatternTitle2" keyPath="mapView.zoomLevel" previousBinding="p1k-yo-4Nb" id="HBB-y3-89c">
+ <dictionary key="options">
+ <string key="NSDisplayPattern">%{title1}@ @ %{title2}@</string>
+ </dictionary>
+ </binding>
<outlet property="delegate" destination="-2" id="HEo-Qf-o6o"/>
</connections>
</window>
diff --git a/platform/macos/app/MapDocument.m b/platform/macos/app/MapDocument.m
index ec90888084..59c1817f63 100644
--- a/platform/macos/app/MapDocument.m
+++ b/platform/macos/app/MapDocument.m
@@ -156,7 +156,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
#pragma mark View methods
- (IBAction)showStyle:(id)sender {
- NSInteger tag;
+ NSInteger tag = -1;
if ([sender isKindOfClass:[NSMenuItem class]]) {
tag = [sender tag];
} else if ([sender isKindOfClass:[NSPopUpButton class]]) {
@@ -165,22 +165,28 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
NSURL *styleURL;
switch (tag) {
case 1:
- styleURL = [MGLStyle streetsStyleURLWithVersion:MGLStyleDefaultVersion];
+ styleURL = [MGLStyle streetsStyleURL];
break;
case 2:
- styleURL = [MGLStyle outdoorsStyleURLWithVersion:MGLStyleDefaultVersion];
+ styleURL = [MGLStyle outdoorsStyleURL];
break;
case 3:
- styleURL = [MGLStyle lightStyleURLWithVersion:MGLStyleDefaultVersion];
+ styleURL = [MGLStyle lightStyleURL];
break;
case 4:
- styleURL = [MGLStyle darkStyleURLWithVersion:MGLStyleDefaultVersion];
+ styleURL = [MGLStyle darkStyleURL];
break;
case 5:
- styleURL = [MGLStyle satelliteStyleURLWithVersion:MGLStyleDefaultVersion];
+ styleURL = [MGLStyle satelliteStyleURL];
break;
case 6:
- styleURL = [MGLStyle satelliteStreetsStyleURLWithVersion:MGLStyleDefaultVersion];
+ styleURL = [MGLStyle satelliteStreetsStyleURL];
+ break;
+ case 7:
+ styleURL = [MGLStyle trafficDayStyleURL];
+ break;
+ case 8:
+ styleURL = [MGLStyle trafficNightStyleURL];
break;
default:
NSAssert(NO, @"Cannot set style from control with tag %li", (long)tag);
@@ -424,8 +430,11 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
// Temporarily set the display name to the default center coordinate instead
// of “Untitled” until the binding kicks in.
NSValue *coordinateValue = [NSValue valueWithMGLCoordinate:self.mapView.centerCoordinate];
- self.displayName = [[NSValueTransformer valueTransformerForName:@"LocationCoordinate2DTransformer"]
+ NSString *coordinateString = [[NSValueTransformer valueTransformerForName:@"LocationCoordinate2DTransformer"]
transformedValue:coordinateValue];
+
+
+ self.displayName = [NSString stringWithFormat:@"%@ @ %f", coordinateString, _mapView.zoomLevel];
}
#pragma mark Debug methods
@@ -778,22 +787,25 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
NSCellStateValue state;
switch (menuItem.tag) {
case 1:
- state = [styleURL isEqual:[MGLStyle streetsStyleURLWithVersion:MGLStyleDefaultVersion]];
+ state = [styleURL isEqual:[MGLStyle streetsStyleURL]];
break;
case 2:
- state = [styleURL isEqual:[MGLStyle outdoorsStyleURLWithVersion:MGLStyleDefaultVersion]];
+ state = [styleURL isEqual:[MGLStyle outdoorsStyleURL]];
break;
case 3:
- state = [styleURL isEqual:[MGLStyle lightStyleURLWithVersion:MGLStyleDefaultVersion]];
+ state = [styleURL isEqual:[MGLStyle lightStyleURL]];
break;
case 4:
- state = [styleURL isEqual:[MGLStyle darkStyleURLWithVersion:MGLStyleDefaultVersion]];
+ state = [styleURL isEqual:[MGLStyle darkStyleURL]];
break;
case 5:
- state = [styleURL isEqual:[MGLStyle satelliteStyleURLWithVersion:MGLStyleDefaultVersion]];
+ state = [styleURL isEqual:[MGLStyle satelliteStyleURL]];
break;
case 6:
- state = [styleURL isEqual:[MGLStyle satelliteStreetsStyleURLWithVersion:MGLStyleDefaultVersion]];
+ state = [styleURL isEqual:[MGLStyle satelliteStreetsStyleURL]];
+ break;
+ case 7:
+ state = [styleURL isEqual:[MGLStyle trafficDayStyleURL]];
break;
default:
return NO;
@@ -951,12 +963,14 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
}
NSArray *styleURLs = @[
- [MGLStyle streetsStyleURLWithVersion:MGLStyleDefaultVersion],
- [MGLStyle outdoorsStyleURLWithVersion:MGLStyleDefaultVersion],
- [MGLStyle lightStyleURLWithVersion:MGLStyleDefaultVersion],
- [MGLStyle darkStyleURLWithVersion:MGLStyleDefaultVersion],
- [MGLStyle satelliteStyleURLWithVersion:MGLStyleDefaultVersion],
- [MGLStyle satelliteStreetsStyleURLWithVersion:MGLStyleDefaultVersion],
+ [MGLStyle streetsStyleURL],
+ [MGLStyle outdoorsStyleURL],
+ [MGLStyle lightStyleURL],
+ [MGLStyle darkStyleURL],
+ [MGLStyle satelliteStyleURL],
+ [MGLStyle satelliteStreetsStyleURL],
+ [MGLStyle trafficDayStyleURL],
+ [MGLStyle trafficNightStyleURL],
];
return [styleURLs indexOfObject:self.mapView.styleURL];
}
diff --git a/platform/macos/bitrise.yml b/platform/macos/bitrise.yml
index 2de6bce1fc..1f2495dab2 100644
--- a/platform/macos/bitrise.yml
+++ b/platform/macos/bitrise.yml
@@ -12,59 +12,24 @@ workflows:
primary:
steps:
- script:
- title: Check for skipping CI
- inputs:
- - content: |-
- #!/bin/bash
- if [[ -n "$(echo $GIT_CLONE_COMMIT_MESSAGE_SUBJECT | sed -n '/\[skip ci\]/p')" ||
- -n "$(echo $GIT_CLONE_COMMIT_MESSAGE_SUBJECT | sed -n '/\[ci skip\]/p')" ||
- -n "$(echo $GIT_CLONE_COMMIT_MESSAGE_BODY | sed -n 's/\[skip ci\]/p')" ||
- -n "$(echo $GIT_CLONE_COMMIT_MESSAGE_BODY | sed -n 's/\[ci skip\]/p')" ]]; then
- envman add --key SKIPCI --value true
- else
- envman add --key SKIPCI --value false
- fi
- - script:
- title: Install Dependencies
- run_if: '{{enveq "SKIPCI" "false"}}'
+ title: Build
inputs:
- content: |-
#!/bin/bash
set -eu -o pipefail
brew install cmake
gem install xcpretty --no-rdoc --no-ri
- - is_debug: 'yes'
- - script:
- title: Generate Workspace
- run_if: '{{enveq "SKIPCI" "false"}}'
- inputs:
- - content: |-
- #!/bin/bash
- set -eu -o pipefail
- export BUILDTYPE=Debug
- make xproj
- - is_debug: 'yes'
- - script:
- title: Run Core and SDK Unit Tests
- run_if: '{{enveq "SKIPCI" "false"}}'
- inputs:
- - content: |-
- #!/bin/bash
- set -eu -o pipefail
export BUILDTYPE=Debug
export XCPRETTY="| tee ${BITRISE_DEPLOY_DIR}/raw-xcodebuild-output.txt | xcpretty --color --report html --output ${BITRISE_DEPLOY_DIR}/xcode-test-results.html"
make run-test
- - is_debug: 'yes'
- deploy-to-bitrise-io:
title: Deploy to Bitrise.io
- run_if: '{{enveq "SKIPCI" "false"}}'
inputs:
- deploy_path: "test/fixtures"
- notify_user_groups: none
- is_compress: 'true'
- slack:
title: Post to Slack
- run_if: '{{enveq "SKIPCI" "false"}}'
inputs:
- webhook_url: "$SLACK_HOOK_URL"
- channel: "#gl-bots"
@@ -83,28 +48,13 @@ workflows:
nightly-release:
steps:
- script:
- title: Install Dependencies
+ title: Build
inputs:
- content: |-
#!/bin/bash
set -eu -o pipefail
brew install cmake
- - is_debug: 'yes'
- - script:
- title: Configure AWS-CLI
- inputs:
- - content: |-
- #!/bin/bash
- apt-get install -y python-pip python-dev build-essential
pip install awscli
- - script:
- title: Build package
- inputs:
- - content: |-
- #!/bin/bash
- set -eu -o pipefail
- export BUILDTYPE=Release
- export SYMBOLS=NO
- make xpackage
+ gem install xcpretty --no-rdoc --no-ri
+ BUILDTYPE=Release SYMBOLS=NO make xpackage
CLOUDWATCH=true platform/macos/scripts/metrics.sh
- - is_debug: 'yes'
diff --git a/platform/macos/config.cmake b/platform/macos/config.cmake
index cbaf3d492e..8dc3c38245 100644
--- a/platform/macos/config.cmake
+++ b/platform/macos/config.cmake
@@ -61,7 +61,7 @@ macro(mbgl_platform_core)
)
target_add_mason_package(mbgl-core PUBLIC geojson)
- target_add_mason_package(mbgl-core PUBLIC icu)
+ target_add_mason_package(mbgl-core PRIVATE icu)
target_compile_options(mbgl-core
PRIVATE -fobjc-arc
@@ -74,42 +74,35 @@ macro(mbgl_platform_core)
)
target_link_libraries(mbgl-core
- PUBLIC -lz
+ PUBLIC "-lz"
+ PUBLIC "-framework Foundation"
+ PUBLIC "-framework CoreGraphics"
+ PUBLIC "-framework OpenGL"
+ PUBLIC "-framework ImageIO"
+ PUBLIC "-framework CoreServices"
+ PUBLIC "-framework SystemConfiguration"
+ PUBLIC "-lsqlite3"
)
endmacro()
macro(mbgl_platform_glfw)
target_link_libraries(mbgl-glfw
- PRIVATE mbgl-loop
- PRIVATE "-framework OpenGL"
- PRIVATE "-lsqlite3"
+ PRIVATE mbgl-loop-darwin
)
endmacro()
macro(mbgl_platform_render)
target_link_libraries(mbgl-render
- PRIVATE mbgl-loop
- PRIVATE "-framework Foundation"
- PRIVATE "-framework CoreGraphics"
- PRIVATE "-framework OpenGL"
- PRIVATE "-framework ImageIO"
- PRIVATE "-framework CoreServices"
- PRIVATE "-lsqlite3"
+ PRIVATE mbgl-loop-darwin
)
endmacro()
macro(mbgl_platform_offline)
target_link_libraries(mbgl-offline
- PRIVATE mbgl-loop
- PRIVATE "-framework Foundation"
- PRIVATE "-framework CoreGraphics"
- PRIVATE "-framework OpenGL"
- PRIVATE "-framework ImageIO"
- PRIVATE "-framework CoreServices"
- PRIVATE "-lsqlite3"
+ PRIVATE mbgl-loop-darwin
)
endmacro()
@@ -130,13 +123,7 @@ macro(mbgl_platform_test)
)
target_link_libraries(mbgl-test
- PRIVATE mbgl-loop
- PRIVATE "-framework Foundation"
- PRIVATE "-framework CoreGraphics"
- PRIVATE "-framework OpenGL"
- PRIVATE "-framework ImageIO"
- PRIVATE "-framework CoreServices"
- PRIVATE "-lsqlite3"
+ PRIVATE mbgl-loop-darwin
)
endmacro()
@@ -156,13 +143,7 @@ macro(mbgl_platform_benchmark)
)
target_link_libraries(mbgl-benchmark
- PRIVATE mbgl-loop
- PRIVATE "-framework Foundation"
- PRIVATE "-framework CoreGraphics"
- PRIVATE "-framework OpenGL"
- PRIVATE "-framework ImageIO"
- PRIVATE "-framework CoreServices"
- PRIVATE "-lsqlite3"
+ PRIVATE mbgl-loop-darwin
)
endmacro()
@@ -172,8 +153,6 @@ macro(mbgl_platform_node)
)
target_link_libraries(mbgl-node
- PRIVATE "-framework Foundation"
- PRIVATE "-framework OpenGL"
PRIVATE "-Wl,-bind_at_load"
)
endmacro()
diff --git a/platform/macos/docs/guides/For Style Authors.md b/platform/macos/docs/guides/For Style Authors.md
index 9ed69ac9ea..164b1b58bf 100644
--- a/platform/macos/docs/guides/For Style Authors.md
+++ b/platform/macos/docs/guides/For Style Authors.md
@@ -96,7 +96,6 @@ the following terms for concepts defined in the style specification:
In the style specification | In the SDK
---------------------------|---------
-class | style class
filter | predicate
function type | interpolation mode
id | identifier
@@ -170,6 +169,7 @@ In style JSON | In the SDK
`background` | `MGLBackgroundStyleLayer`
`circle` | `MGLCircleStyleLayer`
`fill` | `MGLFillStyleLayer`
+`fill-extrusion` | `MGLFillExtrusionStyleLayer`
`line` | `MGLLineStyleLayer`
`raster` | `MGLRasterStyleLayer`
`symbol` | `MGLSymbolStyleLayer`
@@ -195,6 +195,13 @@ In style JSON | In Objective-C | In Swift
`fill-translate` | `MGLFillStyleLayer.fillTranslation` | `MGLFillStyleLayer.fillTranslation`
`fill-translate-anchor` | `MGLFillStyleLayer.fillTranslationAnchor` | `MGLFillStyleLayer.fillTranslationAnchor`
+### Fill extrusion style layers
+
+In style JSON | In Objective-C | In Swift
+--------------|----------------|---------
+`fill-extrusion-translate` | `MGLFillExtrusionStyleLayer.fillExtrusionTranslation` | `MGLFillExtrusionStyleLayer.fillExtrusionTranslation`
+`fill-extrusion-translate-anchor` | `MGLFillExtrusionStyleLayer.fillExtrusionTranslationAnchor` | `MGLFillExtrusionStyleLayer.fillExtrusionTranslationAnchor`
+
### Line style layers
In style JSON | In Objective-C | In Swift
diff --git a/platform/macos/docs/guides/Using Style Functions at Runtime.md b/platform/macos/docs/guides/Using Style Functions at Runtime.md
index b3098dfe04..ea772a93a2 100644
--- a/platform/macos/docs/guides/Using Style Functions at Runtime.md
+++ b/platform/macos/docs/guides/Using Style Functions at Runtime.md
@@ -1,4 +1,3 @@
-
<!--
This file is generated.
Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
@@ -31,11 +30,13 @@ The documentation for each individual style layer property notes which style fun
Stops are key-value pairs that that determine a style value. With a `MGLCameraSourceFunction` stop, you can use a dictionary with a zoom level for a key and a `MGLStyleValue` for the value. For example, you can use a stops dictionary with zoom levels 0, 10, and 20 as keys, and yellow, orange, and red as the values. A `MGLSourceStyleFunction` uses the relevant attribute value as the key.
```swift
-let stops = [0: MGLStyleValue<NSColor>(rawValue: .yellow),
- 2.5: MGLStyleValue(rawValue: .orange),
- 5: MGLStyleValue(rawValue: .red),
- 7.5: MGLStyleValue(rawValue: .blue),
- 10: MGLStyleValue(rawValue: .white)]
+let stops = [
+ 0: MGLStyleValue<NSColor>(rawValue: .yellow),
+ 2.5: MGLStyleValue(rawValue: .orange),
+ 5: MGLStyleValue(rawValue: .red),
+ 7.5: MGLStyleValue(rawValue: .blue),
+ 10: MGLStyleValue(rawValue: .white),
+]
```
## Interpolation mode
@@ -48,19 +49,21 @@ The effect a key has on the style value is determined by the interpolation mode.
The stops dictionary below, for example, shows colors that continuously shift from yellow to orange to red to blue to white based on the attribute value.
-``` swift
-let url = URL(string: "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_week.geojson")
+```swift
+let url = URL(string: "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_week.geojson")!
let symbolSource = MGLSource(identifier: "source")
let symbolLayer = MGLSymbolStyleLayer(identifier: "place-city-sm", source: symbolSource)
let source = MGLShapeSource(identifier: "earthquakes", url: url, options: nil)
-style.addSource(source)
+mapView.style?.addSource(source)
-let stops = [0: MGLStyleValue<NSColor>(rawValue: .yellow),
- 2.5: MGLStyleValue(rawValue: .orange),
- 5: MGLStyleValue(rawValue: .red),
- 7.5: MGLStyleValue(rawValue: .blue),
- 10: MGLStyleValue(rawValue: .white)]
+let stops = [
+ 0: MGLStyleValue<NSColor>(rawValue: .yellow),
+ 2.5: MGLStyleValue(rawValue: .orange),
+ 5: MGLStyleValue(rawValue: .red),
+ 7.5: MGLStyleValue(rawValue: .blue),
+ 10: MGLStyleValue(rawValue: .white),
+]
let layer = MGLCircleStyleLayer(identifier: "circles", source: source)
layer.circleColor = MGLStyleValue(interpolationMode: .exponential,
@@ -68,7 +71,7 @@ layer.circleColor = MGLStyleValue(interpolationMode: .exponential,
attributeName: "mag",
options: [.defaultValue: MGLStyleValue<NSColor>(rawValue: .green)])
layer.circleRadius = MGLStyleValue(rawValue: 10)
-style.insertLayer(layer, below: symbolLayer)
+mapView.style?.insertLayer(layer, below: symbolLayer)
```
![exponential mode](img/data-driven-styling/exponential.png)
@@ -85,13 +88,15 @@ Here’s a visualization from Mapbox Studio (see [Working with Mapbox Studio](wo
The example below increases a layer’s `circleRadius` exponentially based on a map’s zoom level. The `MGLStyleFunctionOptionInterpolationBase` is `1.5`.
```swift
-let stops = [12: MGLStyleValue(rawValue: 0.5),
- 14: MGLStyleValue(rawValue: 2),
- 18: MGLStyleValue(rawValue: 18)]
+let stops = [
+ 12: MGLStyleValue<NSNumber>(rawValue: 0.5),
+ 14: MGLStyleValue(rawValue: 2),
+ 18: MGLStyleValue(rawValue: 18),
+]
layer.circleRadius = MGLStyleValue(interpolationMode: .exponential,
- cameraStops: stops,
- options: [.interpolationBase: 1.5])
+ cameraStops: stops,
+ options: [.interpolationBase: 1.5])
```
### Interval
@@ -100,12 +105,14 @@ layer.circleRadius = MGLStyleValue(interpolationMode: .exponential,
When we use the stops dictionary given above with an interval interpolation mode, we create ranges where earthquakes with a magnitude of 0 to just less than 2.5 would be yellow, 2.5 to just less than 5 would be orange, and so on.
-``` swift
-let stops = [0: MGLStyleValue<NSColor>(rawValue: .yellow),
- 2.5: MGLStyleValue(rawValue: .orange),
- 5: MGLStyleValue(rawValue: .red),
- 7.5: MGLStyleValue(rawValue: .blue),
- 10: MGLStyleValue(rawValue: .white)]
+```swift
+let stops = [
+ 0: MGLStyleValue<NSColor>(rawValue: .yellow),
+ 2.5: MGLStyleValue(rawValue: .orange),
+ 5: MGLStyleValue(rawValue: .red),
+ 7.5: MGLStyleValue(rawValue: .blue),
+ 10: MGLStyleValue(rawValue: .white),
+]
layer.circleColor = MGLStyleValue(interpolationMode: .interval,
sourceStops: stops,
@@ -121,16 +128,17 @@ At each stop, `MGLInterpolationModeCategorical` produces an output value equal t
There are three main types of events in the dataset: earthquakes, explosions, and quarry blasts. In this case, the color of the circle layer will be determined by the type of event, with a default value of blue to catch any events that do not fall into any of those categories.
-``` swift
-let categoricalStops = ["earthquake": MGLStyleValue<NSColor>(rawValue: .orange),
- "explosion": MGLStyleValue(rawValue: .red),
- "quarry blast": MGLStyleValue(rawValue: .yellow)]
+```swift
+let categoricalStops = [
+ "earthquake": MGLStyleValue<NSColor>(rawValue: .orange),
+ "explosion": MGLStyleValue(rawValue: .red),
+ "quarry blast": MGLStyleValue(rawValue: .yellow),
+]
layer.circleColor = MGLStyleValue(interpolationMode: .categorical,
sourceStops: categoricalStops,
attributeName: "type",
options: [.defaultValue: MGLStyleValue<NSColor>(rawValue: .blue)])
-
```
![categorical mode](img/data-driven-styling/categorical1.png) ![categorical mode](img/data-driven-styling/categorical2.png)
@@ -139,12 +147,11 @@ layer.circleColor = MGLStyleValue(interpolationMode: .categorical,
`MGLInterpolationModeIdentity` uses the attribute’s value as the style value. For example, you can set the `circleRadius` to the earthquake’s magnitude. Since the attribute value itself will be used as the style value, `sourceStops` should be set to `nil`.
-``` swift
+```swift
layer.circleRadius = MGLStyleValue(interpolationMode: .identity,
sourceStops: nil,
attributeName: "mag",
options: [.defaultValue: MGLStyleValue<NSNumber>(rawValue: 0)])
-
```
![identity mode](img/data-driven-styling/identity.png)
diff --git a/platform/macos/jazzy.yml b/platform/macos/jazzy.yml
index 1f0e2fbc74..3c24b351cc 100644
--- a/platform/macos/jazzy.yml
+++ b/platform/macos/jazzy.yml
@@ -71,6 +71,7 @@ custom_categories:
- MGLVectorStyleLayer
- MGLCircleStyleLayer
- MGLFillStyleLayer
+ - MGLFillExtrusionStyleLayer
- MGLLineStyleLayer
- MGLSymbolStyleLayer
- name: Offline Maps
diff --git a/platform/macos/macos.xcodeproj/project.pbxproj b/platform/macos/macos.xcodeproj/project.pbxproj
index 0db0acb5b0..9a18ce4a0e 100644
--- a/platform/macos/macos.xcodeproj/project.pbxproj
+++ b/platform/macos/macos.xcodeproj/project.pbxproj
@@ -35,7 +35,7 @@
35602BFB1D3EA99F0050646F /* MGLFillStyleLayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 35602BF91D3EA99F0050646F /* MGLFillStyleLayer.mm */; };
35602BFF1D3EA9B40050646F /* MGLStyleLayer_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 35602BFC1D3EA9B40050646F /* MGLStyleLayer_Private.h */; };
35602C001D3EA9B40050646F /* MGLForegroundStyleLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 35602BFD1D3EA9B40050646F /* MGLForegroundStyleLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
- 35602C011D3EA9B40050646F /* MGLForegroundStyleLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 35602BFE1D3EA9B40050646F /* MGLForegroundStyleLayer.m */; };
+ 35602C011D3EA9B40050646F /* MGLForegroundStyleLayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 35602BFE1D3EA9B40050646F /* MGLForegroundStyleLayer.mm */; };
35724FC41D630502002A4AB4 /* amsterdam.geojson in Resources */ = {isa = PBXBuildFile; fileRef = 358EB3AE1D61F0DB00E46D9C /* amsterdam.geojson */; };
359819591E02F611008FC139 /* NSCoder+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 359819571E02F611008FC139 /* NSCoder+MGLAdditions.h */; };
3598195A1E02F611008FC139 /* NSCoder+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 359819581E02F611008FC139 /* NSCoder+MGLAdditions.mm */; };
@@ -49,6 +49,8 @@
35C6DF871E214C1800ACA483 /* MGLDistanceFormatterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 35C6DF861E214C1800ACA483 /* MGLDistanceFormatterTests.m */; };
35D65C5A1D65AD5500722C23 /* NSDate+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 35D65C581D65AD5500722C23 /* NSDate+MGLAdditions.h */; };
35D65C5B1D65AD5500722C23 /* NSDate+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 35D65C591D65AD5500722C23 /* NSDate+MGLAdditions.mm */; };
+ 4031ACFC1E9EB3C100A3EA26 /* MGLMapViewDelegateIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4031ACFB1E9EB3C100A3EA26 /* MGLMapViewDelegateIntegrationTests.swift */; };
+ 4031AD031E9FD6AA00A3EA26 /* MGLSDKTestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4031AD011E9FD6A300A3EA26 /* MGLSDKTestHelpers.swift */; };
4049C2A51DB6CE7F00B3F799 /* MGLPointCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = 4049C2A11DB6CE7800B3F799 /* MGLPointCollection.h */; settings = {ATTRIBUTES = (Public, ); }; };
4049C2AD1DB8020600B3F799 /* MGLPointCollection.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4049C2A71DB6D09B00B3F799 /* MGLPointCollection.mm */; };
408AA85B1DAEECFE00022900 /* MGLShape_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 408AA85A1DAEECF100022900 /* MGLShape_Private.h */; };
@@ -62,17 +64,15 @@
40B77E451DB11BC9003DA2FE /* NSArray+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 40B77E431DB11BB0003DA2FE /* NSArray+MGLAdditions.h */; };
40B77E461DB11BCD003DA2FE /* NSArray+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 40B77E421DB11BB0003DA2FE /* NSArray+MGLAdditions.mm */; };
40E1601D1DF217D6005EA6D9 /* MGLStyleLayerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 40E1601B1DF216E6005EA6D9 /* MGLStyleLayerTests.m */; };
- 52BECB0A1CC5A26F009CD791 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52BECB091CC5A26F009CD791 /* SystemConfiguration.framework */; };
+ 52B5D17F1E5E26DF00BBCB48 /* libmbgl-loop-darwin.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5548BE7B1D0ACBBD005DDE81 /* libmbgl-loop-darwin.a */; };
+ 52B5D1801E5E26DF00BBCB48 /* libmbgl-loop-darwin.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5548BE7B1D0ACBBD005DDE81 /* libmbgl-loop-darwin.a */; };
5548BE781D09E718005DDE81 /* libmbgl-core.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAE6C3451CC31D1200DB3429 /* libmbgl-core.a */; };
556660C61E1BEA0100E2C41B /* MGLFoundation.h in Headers */ = {isa = PBXBuildFile; fileRef = 556660C51E1BEA0100E2C41B /* MGLFoundation.h */; settings = {ATTRIBUTES = (Public, ); }; };
556660D61E1D07E400E2C41B /* MGLVersionNumber.m in Sources */ = {isa = PBXBuildFile; fileRef = 556660D51E1D07E400E2C41B /* MGLVersionNumber.m */; };
558DE7A61E56161C00C7916D /* MGLFoundation_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 558DE7A41E56161C00C7916D /* MGLFoundation_Private.h */; };
558DE7A71E56161C00C7916D /* MGLFoundation.mm in Sources */ = {isa = PBXBuildFile; fileRef = 558DE7A51E56161C00C7916D /* MGLFoundation.mm */; };
- 558F18221D0B13B100123F46 /* libmbgl-loop.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 558F18211D0B13B000123F46 /* libmbgl-loop.a */; };
- 55D9B4B11D005D3900C1CCE2 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 55D9B4B01D005D3900C1CCE2 /* libz.tbd */; };
55E2AD111E5B0A6900E8C587 /* MGLOfflineStorageTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 55E2AD101E5B0A6900E8C587 /* MGLOfflineStorageTests.mm */; };
920A3E591E6F859D00C16EFC /* MGLSourceQueryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 920A3E581E6F859D00C16EFC /* MGLSourceQueryTests.m */; };
- 920A3E5B1E6F8E0700C16EFC /* query-style.json in Resources */ = {isa = PBXBuildFile; fileRef = 920A3E5A1E6F8E0700C16EFC /* query-style.json */; };
96E027311E57C9A7004B8E66 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 96E027331E57C9A7004B8E66 /* Localizable.strings */; };
DA00FC8A1D5EEAC3009AABC8 /* MGLAttributionInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = DA00FC881D5EEAC3009AABC8 /* MGLAttributionInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };
DA00FC8B1D5EEAC3009AABC8 /* MGLAttributionInfo.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA00FC891D5EEAC3009AABC8 /* MGLAttributionInfo.mm */; };
@@ -96,6 +96,7 @@
DA551B831DB496AC0009AFAF /* MGLTileSource_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DA551B801DB496AC0009AFAF /* MGLTileSource_Private.h */; };
DA551B841DB496AC0009AFAF /* MGLTileSource.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA551B811DB496AC0009AFAF /* MGLTileSource.mm */; };
DA5589771D320C41006B7F64 /* wms.json in Resources */ = {isa = PBXBuildFile; fileRef = DA5589761D320C41006B7F64 /* wms.json */; };
+ DA57D4B11EBC699800793288 /* MGLDocumentationGuideTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA57D4B01EBC699800793288 /* MGLDocumentationGuideTests.swift */; };
DA6408D71DA4E5DA00908C90 /* MGLVectorStyleLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = DA6408D51DA4E5DA00908C90 /* MGLVectorStyleLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
DA6408D81DA4E5DA00908C90 /* MGLVectorStyleLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = DA6408D61DA4E5DA00908C90 /* MGLVectorStyleLayer.m */; };
DA7262071DEEDD460043BB89 /* MGLOpenGLStyleLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = DA7262051DEEDD460043BB89 /* MGLOpenGLStyleLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -137,8 +138,10 @@
DA8F259C1D51CB000010E6B5 /* MGLStyleValue_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8F259B1D51CB000010E6B5 /* MGLStyleValue_Private.h */; };
DA8F25B21D51CB270010E6B5 /* NSValue+MGLStyleAttributeAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8F25A61D51CB270010E6B5 /* NSValue+MGLStyleAttributeAdditions.h */; };
DA8F25B31D51CB270010E6B5 /* NSValue+MGLStyleAttributeAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA8F25A71D51CB270010E6B5 /* NSValue+MGLStyleAttributeAdditions.mm */; };
- DAA1BB4A1E2D425C00ABB750 /* libmbgl-loop.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAA1BB491E2D425C00ABB750 /* libmbgl-loop.a */; };
DAA48EFD1D6A4731006A7E36 /* StyleLayerIconTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = DAA48EFC1D6A4731006A7E36 /* StyleLayerIconTransformer.m */; };
+ DAA998FB1E9F545C002E6EA6 /* MGLFillExtrusionStyleLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = DAA998F91E9F545C002E6EA6 /* MGLFillExtrusionStyleLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ DAA998FC1E9F545C002E6EA6 /* MGLFillExtrusionStyleLayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = DAA998FA1E9F545C002E6EA6 /* MGLFillExtrusionStyleLayer.mm */; };
+ DAA999011E9F5EC5002E6EA6 /* MGLFillExtrusionStyleLayerTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DAA999001E9F5EC5002E6EA6 /* MGLFillExtrusionStyleLayerTests.mm */; };
DAB2CCE51DF632ED001B2FE1 /* LimeGreenStyleLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB2CCE41DF632ED001B2FE1 /* LimeGreenStyleLayer.m */; };
DAC2ABC51CC6D343006D18C4 /* MGLAnnotationImage_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DAC2ABC41CC6D343006D18C4 /* MGLAnnotationImage_Private.h */; };
DACB0C391E18DFFD005DDBEA /* MGLStyle+MBXAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = DACB0C381E18DFFD005DDBEA /* MGLStyle+MBXAdditions.m */; };
@@ -215,7 +218,6 @@
DAE6C3BE1CC31F2E00DB3429 /* default_marker.pdf in Resources */ = {isa = PBXBuildFile; fileRef = DAE6C3BB1CC31F2E00DB3429 /* default_marker.pdf */; };
DAE6C3BF1CC31F2E00DB3429 /* mapbox.pdf in Resources */ = {isa = PBXBuildFile; fileRef = DAE6C3BC1CC31F2E00DB3429 /* mapbox.pdf */; };
DAE6C3C21CC31F4500DB3429 /* Mapbox.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C3C11CC31F4500DB3429 /* Mapbox.h */; settings = {ATTRIBUTES = (Public, ); }; };
- DAE6C3C71CC3499100DB3429 /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = DAE6C3C61CC3499100DB3429 /* libsqlite3.tbd */; };
DAE6C3D21CC34C9900DB3429 /* MGLGeometryTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C3C81CC34BD800DB3429 /* MGLGeometryTests.mm */; };
DAE6C3D31CC34C9900DB3429 /* MGLOfflinePackTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C3C91CC34BD800DB3429 /* MGLOfflinePackTests.m */; };
DAE6C3D41CC34C9900DB3429 /* MGLOfflineRegionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C3CA1CC34BD800DB3429 /* MGLOfflineRegionTests.m */; };
@@ -293,7 +295,7 @@
35602BF91D3EA99F0050646F /* MGLFillStyleLayer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLFillStyleLayer.mm; sourceTree = "<group>"; };
35602BFC1D3EA9B40050646F /* MGLStyleLayer_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLStyleLayer_Private.h; sourceTree = "<group>"; };
35602BFD1D3EA9B40050646F /* MGLForegroundStyleLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLForegroundStyleLayer.h; sourceTree = "<group>"; };
- 35602BFE1D3EA9B40050646F /* MGLForegroundStyleLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLForegroundStyleLayer.m; sourceTree = "<group>"; };
+ 35602BFE1D3EA9B40050646F /* MGLForegroundStyleLayer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLForegroundStyleLayer.mm; sourceTree = "<group>"; };
358EB3AE1D61F0DB00E46D9C /* amsterdam.geojson */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = amsterdam.geojson; path = ../../darwin/test/amsterdam.geojson; sourceTree = "<group>"; };
359819571E02F611008FC139 /* NSCoder+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSCoder+MGLAdditions.h"; sourceTree = "<group>"; };
359819581E02F611008FC139 /* NSCoder+MGLAdditions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSCoder+MGLAdditions.mm"; sourceTree = "<group>"; };
@@ -308,6 +310,8 @@
35C6DF861E214C1800ACA483 /* MGLDistanceFormatterTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLDistanceFormatterTests.m; path = ../../darwin/test/MGLDistanceFormatterTests.m; sourceTree = "<group>"; };
35D65C581D65AD5500722C23 /* NSDate+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDate+MGLAdditions.h"; sourceTree = "<group>"; };
35D65C591D65AD5500722C23 /* NSDate+MGLAdditions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSDate+MGLAdditions.mm"; sourceTree = "<group>"; };
+ 4031ACFB1E9EB3C100A3EA26 /* MGLMapViewDelegateIntegrationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MGLMapViewDelegateIntegrationTests.swift; sourceTree = "<group>"; };
+ 4031AD011E9FD6A300A3EA26 /* MGLSDKTestHelpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MGLSDKTestHelpers.swift; path = ../../darwin/test/MGLSDKTestHelpers.swift; sourceTree = "<group>"; };
4049C2A11DB6CE7800B3F799 /* MGLPointCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLPointCollection.h; sourceTree = "<group>"; };
4049C2A71DB6D09B00B3F799 /* MGLPointCollection.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLPointCollection.mm; sourceTree = "<group>"; };
405C03961DB0004E001AC280 /* NSImage+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSImage+MGLAdditions.h"; sourceTree = "<group>"; };
@@ -324,18 +328,15 @@
40E1601A1DF216E6005EA6D9 /* MGLStyleLayerTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLStyleLayerTests.h; sourceTree = "<group>"; };
40E1601B1DF216E6005EA6D9 /* MGLStyleLayerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLStyleLayerTests.m; sourceTree = "<group>"; };
52BECB091CC5A26F009CD791 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
- 5548BE791D0ACBB2005DDE81 /* libmbgl-loop-darwin.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libmbgl-loop-darwin.a"; path = "cmake/Debug/libmbgl-loop-darwin.a"; sourceTree = "<group>"; };
5548BE7B1D0ACBBD005DDE81 /* libmbgl-loop-darwin.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libmbgl-loop-darwin.a"; path = "cmake/Debug/libmbgl-loop-darwin.a"; sourceTree = "<group>"; };
556660C51E1BEA0100E2C41B /* MGLFoundation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLFoundation.h; sourceTree = "<group>"; };
556660D51E1D07E400E2C41B /* MGLVersionNumber.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = MGLVersionNumber.m; path = ../../darwin/test/MGLVersionNumber.m; sourceTree = "<group>"; };
558DE7A41E56161C00C7916D /* MGLFoundation_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLFoundation_Private.h; sourceTree = "<group>"; };
558DE7A51E56161C00C7916D /* MGLFoundation.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLFoundation.mm; sourceTree = "<group>"; };
- 558F18211D0B13B000123F46 /* libmbgl-loop.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libmbgl-loop.a"; path = "../../build/osx/Debug/libmbgl-loop.a"; sourceTree = "<group>"; };
55D9B4B01D005D3900C1CCE2 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
55E2AD101E5B0A6900E8C587 /* MGLOfflineStorageTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLOfflineStorageTests.mm; path = ../../darwin/test/MGLOfflineStorageTests.mm; sourceTree = "<group>"; };
55FE0E8D1D100A0900FD240B /* config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = config.xcconfig; path = ../../build/macos/config.xcconfig; sourceTree = "<group>"; };
920A3E581E6F859D00C16EFC /* MGLSourceQueryTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLSourceQueryTests.m; sourceTree = "<group>"; };
- 920A3E5A1E6F8E0700C16EFC /* query-style.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "query-style.json"; path = "../../darwin/test/query-style.json"; sourceTree = "<group>"; };
966091701E5BBFF700A9A03B /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = "<group>"; };
966091711E5BBFF900A9A03B /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = "<group>"; };
966091721E5BBFFA00A9A03B /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/Localizable.strings; sourceTree = "<group>"; };
@@ -374,6 +375,7 @@
DA551B801DB496AC0009AFAF /* MGLTileSource_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLTileSource_Private.h; sourceTree = "<group>"; };
DA551B811DB496AC0009AFAF /* MGLTileSource.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLTileSource.mm; sourceTree = "<group>"; };
DA5589761D320C41006B7F64 /* wms.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = wms.json; sourceTree = "<group>"; };
+ DA57D4B01EBC699800793288 /* MGLDocumentationGuideTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MGLDocumentationGuideTests.swift; path = ../../darwin/test/MGLDocumentationGuideTests.swift; sourceTree = "<group>"; };
DA6023EF1E4CE8E500DBFF23 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Foundation.strings; sourceTree = "<group>"; };
DA6023F01E4CE8FF00DBFF23 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = sv; path = sv.lproj/Foundation.stringsdict; sourceTree = "<group>"; };
DA618B131E68850300CB7F44 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = "<group>"; };
@@ -442,7 +444,6 @@
DA8F25B71D51D2240010E6B5 /* MGLStyleLayer.mm.ejs */ = {isa = PBXFileReference; lastKnownFileType = text; path = MGLStyleLayer.mm.ejs; sourceTree = "<group>"; };
DA9C01301E4C7B9300C4742A /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "pt-BR"; path = "pt-BR.lproj/Foundation.stringsdict"; sourceTree = "<group>"; };
DA9C01311E4C7B9F00C4742A /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = "<group>"; };
- DAA1BB491E2D425C00ABB750 /* libmbgl-loop.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libmbgl-loop.a"; path = "../../build/macos/Debug/libmbgl-loop.a"; sourceTree = "<group>"; };
DAA32CA61E4C4849006F8D24 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = "<group>"; };
DAA32CA71E4C486D006F8D24 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Foundation.strings; sourceTree = "<group>"; };
DAA32CA81E4C48B9006F8D24 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = de; path = de.lproj/Foundation.stringsdict; sourceTree = "<group>"; };
@@ -455,6 +456,9 @@
DAA32CC11E4C4F93006F8D24 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Localizable.strings; sourceTree = "<group>"; };
DAA48EFB1D6A4731006A7E36 /* StyleLayerIconTransformer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StyleLayerIconTransformer.h; sourceTree = "<group>"; };
DAA48EFC1D6A4731006A7E36 /* StyleLayerIconTransformer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StyleLayerIconTransformer.m; sourceTree = "<group>"; };
+ DAA998F91E9F545C002E6EA6 /* MGLFillExtrusionStyleLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLFillExtrusionStyleLayer.h; sourceTree = "<group>"; };
+ DAA998FA1E9F545C002E6EA6 /* MGLFillExtrusionStyleLayer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLFillExtrusionStyleLayer.mm; sourceTree = "<group>"; };
+ DAA999001E9F5EC5002E6EA6 /* MGLFillExtrusionStyleLayerTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLFillExtrusionStyleLayerTests.mm; sourceTree = "<group>"; };
DAB2CCE31DF632ED001B2FE1 /* LimeGreenStyleLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LimeGreenStyleLayer.h; sourceTree = "<group>"; };
DAB2CCE41DF632ED001B2FE1 /* LimeGreenStyleLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LimeGreenStyleLayer.m; sourceTree = "<group>"; };
DAC2ABC41CC6D343006D18C4 /* MGLAnnotationImage_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAnnotationImage_Private.h; sourceTree = "<group>"; };
@@ -548,6 +552,7 @@
DAE8CCAA1E6E8605009B5CB0 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ru; path = ru.lproj/Foundation.stringsdict; sourceTree = "<group>"; };
DAE8CCAB1E6E8B72009B5CB0 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = "<group>"; };
DAE8CCAC1E6E8B8D009B5CB0 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = "<group>"; };
+ DAE9E0F21EB7BF39001E8E8B /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Foundation.strings; sourceTree = "<group>"; };
DAED385D1D62CED700D7640F /* NSURL+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSURL+MGLAdditions.h"; sourceTree = "<group>"; };
DAED385E1D62CED700D7640F /* NSURL+MGLAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSURL+MGLAdditions.m"; sourceTree = "<group>"; };
DAEDC4311D6033F1000224FF /* MGLAttributionInfoTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLAttributionInfoTests.m; path = ../../darwin/test/MGLAttributionInfoTests.m; sourceTree = "<group>"; };
@@ -576,11 +581,8 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 52BECB0A1CC5A26F009CD791 /* SystemConfiguration.framework in Frameworks */,
5548BE781D09E718005DDE81 /* libmbgl-core.a in Frameworks */,
- 558F18221D0B13B100123F46 /* libmbgl-loop.a in Frameworks */,
- DAE6C3C71CC3499100DB3429 /* libsqlite3.tbd in Frameworks */,
- 55D9B4B11D005D3900C1CCE2 /* libz.tbd in Frameworks */,
+ 52B5D17F1E5E26DF00BBCB48 /* libmbgl-loop-darwin.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -588,9 +590,9 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- DAA1BB4A1E2D425C00ABB750 /* libmbgl-loop.a in Frameworks */,
DAE0DD7A1D5F015A005A6BB1 /* libmbgl-core.a in Frameworks */,
DAE6C3321CC30DB200DB3429 /* Mapbox.framework in Frameworks */,
+ 52B5D1801E5E26DF00BBCB48 /* libmbgl-loop-darwin.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -604,10 +606,12 @@
DA8F25861D51C9E10010E6B5 /* MGLBackgroundStyleLayer.mm */,
3527428B1D4C24AB00A1ECE6 /* MGLCircleStyleLayer.h */,
3527428C1D4C24AB00A1ECE6 /* MGLCircleStyleLayer.mm */,
+ DAA998F91E9F545C002E6EA6 /* MGLFillExtrusionStyleLayer.h */,
+ DAA998FA1E9F545C002E6EA6 /* MGLFillExtrusionStyleLayer.mm */,
35602BF81D3EA99F0050646F /* MGLFillStyleLayer.h */,
35602BF91D3EA99F0050646F /* MGLFillStyleLayer.mm */,
35602BFD1D3EA9B40050646F /* MGLForegroundStyleLayer.h */,
- 35602BFE1D3EA9B40050646F /* MGLForegroundStyleLayer.m */,
+ 35602BFE1D3EA9B40050646F /* MGLForegroundStyleLayer.mm */,
DA8F25891D51CA540010E6B5 /* MGLLineStyleLayer.h */,
DA8F258A1D51CA540010E6B5 /* MGLLineStyleLayer.mm */,
DA7262051DEEDD460043BB89 /* MGLOpenGLStyleLayer.h */,
@@ -670,6 +674,22 @@
name = Styling;
sourceTree = "<group>";
};
+ 4031ACFA1E9EB39A00A3EA26 /* Swift Integration */ = {
+ isa = PBXGroup;
+ children = (
+ 4031ACFB1E9EB3C100A3EA26 /* MGLMapViewDelegateIntegrationTests.swift */,
+ );
+ name = "Swift Integration";
+ sourceTree = "<group>";
+ };
+ 4031AD001E9FD61000A3EA26 /* Test Helpers */ = {
+ isa = PBXGroup;
+ children = (
+ 4031AD011E9FD6A300A3EA26 /* MGLSDKTestHelpers.swift */,
+ );
+ name = "Test Helpers";
+ sourceTree = "<group>";
+ };
DA839E891CC2E3400062CAFB = {
isa = PBXGroup;
children = (
@@ -774,6 +794,7 @@
40E1601A1DF216E6005EA6D9 /* MGLStyleLayerTests.h */,
40E1601B1DF216E6005EA6D9 /* MGLStyleLayerTests.m */,
DA2207BA1DC076930002F84D /* test-Bridging-Header.h */,
+ DAA999001E9F5EC5002E6EA6 /* MGLFillExtrusionStyleLayerTests.mm */,
DA8F25741D51C5F40010E6B5 /* MGLFillStyleLayerTests.mm */,
DA8F25751D51C5F40010E6B5 /* MGLRasterStyleLayerTests.mm */,
DA8F25761D51C5F40010E6B5 /* MGLSymbolStyleLayerTests.mm */,
@@ -924,10 +945,7 @@
DAE6C31E1CC308BC00DB3429 /* Frameworks */ = {
isa = PBXGroup;
children = (
- DAA1BB491E2D425C00ABB750 /* libmbgl-loop.a */,
- 558F18211D0B13B000123F46 /* libmbgl-loop.a */,
5548BE7B1D0ACBBD005DDE81 /* libmbgl-loop-darwin.a */,
- 5548BE791D0ACBB2005DDE81 /* libmbgl-loop-darwin.a */,
55D9B4B01D005D3900C1CCE2 /* libz.tbd */,
52BECB091CC5A26F009CD791 /* SystemConfiguration.framework */,
DAE6C3451CC31D1200DB3429 /* libmbgl-core.a */,
@@ -955,6 +973,8 @@
DAE6C3371CC30DB200DB3429 /* SDK Tests */ = {
isa = PBXGroup;
children = (
+ 4031AD001E9FD61000A3EA26 /* Test Helpers */,
+ 4031ACFA1E9EB39A00A3EA26 /* Swift Integration */,
DA8F257D1D51C5F40010E6B5 /* Styling */,
DAEDC4311D6033F1000224FF /* MGLAttributionInfoTests.m */,
DAEDC4361D606291000224FF /* MGLAttributionButtonTests.m */,
@@ -963,6 +983,7 @@
DA35A2B51CCA14D700E826B2 /* MGLCompassDirectionFormatterTests.m */,
DA35A2A71CC9F41600E826B2 /* MGLCoordinateFormatterTests.m */,
DA2987591E1A4290002299F5 /* MGLDocumentationExampleTests.swift */,
+ DA57D4B01EBC699800793288 /* MGLDocumentationGuideTests.swift */,
DD58A4C71D822C6200E1F038 /* MGLExpressionTests.mm */,
35C6DF861E214C1800ACA483 /* MGLDistanceFormatterTests.m */,
1F95931A1E6DE2B600D5B294 /* MGLNSDateAdditionsTests.mm */,
@@ -978,7 +999,6 @@
DAE6C33A1CC30DB200DB3429 /* Info.plist */,
DA2784FD1DF03060001D5B8D /* Media.xcassets */,
DA35D0891E1A631B007DED41 /* one-liner.json */,
- 920A3E5A1E6F8E0700C16EFC /* query-style.json */,
);
name = "SDK Tests";
path = test;
@@ -1068,6 +1088,7 @@
3527428D1D4C24AB00A1ECE6 /* MGLCircleStyleLayer.h in Headers */,
DA00FC8A1D5EEAC3009AABC8 /* MGLAttributionInfo.h in Headers */,
DAE6C3B21CC31EF300DB3429 /* MGLAttributionButton.h in Headers */,
+ DAA998FB1E9F545C002E6EA6 /* MGLFillExtrusionStyleLayer.h in Headers */,
40B77E451DB11BC9003DA2FE /* NSArray+MGLAdditions.h in Headers */,
35C5D8471D6DD66D00E95907 /* NSComparisonPredicate+MGLAdditions.h in Headers */,
DAE6C3A31CC31E9400DB3429 /* MGLAnnotationImage.h in Headers */,
@@ -1237,6 +1258,7 @@
TargetAttributes = {
DA839E911CC2E3400062CAFB = {
CreatedOnToolsVersion = 7.3;
+ LastSwiftMigration = 0830;
};
DAAA17961CE13BAE00731EFE = {
CreatedOnToolsVersion = 7.3.1;
@@ -1319,7 +1341,6 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- 920A3E5B1E6F8E0700C16EFC /* query-style.json in Resources */,
35724FC41D630502002A4AB4 /* amsterdam.geojson in Resources */,
DA2784FE1DF03060001D5B8D /* Media.xcassets in Resources */,
DA35D08A1E1A631B007DED41 /* one-liner.json in Resources */,
@@ -1374,7 +1395,7 @@
DAE6C3941CC31E2A00DB3429 /* MGLStyle.mm in Sources */,
DAE6C3871CC31E2A00DB3429 /* MGLGeometry.mm in Sources */,
3527428E1D4C24AB00A1ECE6 /* MGLCircleStyleLayer.mm in Sources */,
- 35602C011D3EA9B40050646F /* MGLForegroundStyleLayer.m in Sources */,
+ 35602C011D3EA9B40050646F /* MGLForegroundStyleLayer.mm in Sources */,
408AA86A1DAEEE5D00022900 /* NSDictionary+MGLAdditions.mm in Sources */,
DA8F25881D51C9E10010E6B5 /* MGLBackgroundStyleLayer.mm in Sources */,
DA551B841DB496AC0009AFAF /* MGLTileSource.mm in Sources */,
@@ -1394,6 +1415,7 @@
DAE6C3911CC31E2A00DB3429 /* MGLPolygon.mm in Sources */,
35C6DF851E214C0400ACA483 /* MGLDistanceFormatter.m in Sources */,
DAE6C39B1CC31E2A00DB3429 /* NSProcessInfo+MGLAdditions.m in Sources */,
+ DAA998FC1E9F545C002E6EA6 /* MGLFillExtrusionStyleLayer.mm in Sources */,
DAE6C38F1CC31E2A00DB3429 /* MGLOfflineStorage.mm in Sources */,
DAED38601D62CED700D7640F /* NSURL+MGLAdditions.m in Sources */,
35C5D84A1D6DD66D00E95907 /* NSCompoundPredicate+MGLAdditions.mm in Sources */,
@@ -1435,7 +1457,10 @@
DA87A9A61DCACC5000810D09 /* MGLCircleStyleLayerTests.mm in Sources */,
DA87A99E1DC9DC2100810D09 /* MGLPredicateTests.mm in Sources */,
DD58A4C91D822C6700E1F038 /* MGLExpressionTests.mm in Sources */,
+ 4031ACFC1E9EB3C100A3EA26 /* MGLMapViewDelegateIntegrationTests.swift in Sources */,
+ 4031AD031E9FD6AA00A3EA26 /* MGLSDKTestHelpers.swift in Sources */,
DA87A9A71DCACC5000810D09 /* MGLBackgroundStyleLayerTests.mm in Sources */,
+ DAA999011E9F5EC5002E6EA6 /* MGLFillExtrusionStyleLayerTests.mm in Sources */,
DA29875A1E1A4290002299F5 /* MGLDocumentationExampleTests.swift in Sources */,
DAE6C3D31CC34C9900DB3429 /* MGLOfflinePackTests.m in Sources */,
DA87A9A51DCACC5000810D09 /* MGLLineStyleLayerTests.mm in Sources */,
@@ -1448,6 +1473,7 @@
3526EABD1DF9B19800006B43 /* MGLCodingTests.m in Sources */,
DA87A9A21DC9DCF100810D09 /* MGLFillStyleLayerTests.mm in Sources */,
3599A3E81DF70E2000E77FB2 /* MGLStyleValueTests.m in Sources */,
+ DA57D4B11EBC699800793288 /* MGLDocumentationGuideTests.swift in Sources */,
DAEDC4321D6033F1000224FF /* MGLAttributionInfoTests.m in Sources */,
DA0CD58E1CF56F5800A5F5A5 /* MGLFeatureTests.mm in Sources */,
556660D61E1D07E400E2C41B /* MGLVersionNumber.m in Sources */,
@@ -1555,6 +1581,7 @@
DA6023EF1E4CE8E500DBFF23 /* sv */,
DA618B171E68876C00CB7F44 /* ca */,
DA618B231E6891ED00CB7F44 /* lt */,
+ DAE9E0F21EB7BF39001E8E8B /* es */,
);
name = Foundation.strings;
sourceTree = "<group>";
@@ -1673,12 +1700,15 @@
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = "$(SRCROOT)/app/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
OTHER_CFLAGS = "-fvisibility=hidden";
PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.MapboxGL;
PRODUCT_NAME = "Mapbox GL";
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 3.0;
};
name = Debug;
};
@@ -1686,12 +1716,14 @@
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = "$(SRCROOT)/app/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
OTHER_CFLAGS = "-fvisibility=hidden";
PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.MapboxGL;
PRODUCT_NAME = "Mapbox GL";
+ SWIFT_VERSION = 3.0;
};
name = Release;
};
@@ -1731,13 +1763,14 @@
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_VERSION = A;
- HEADER_SEARCH_PATHS = (
- "$(mbgl_core_INCLUDE_DIRECTORIES)",
- "$(mbgl_loop_INCLUDE_DIRECTORIES)",
- );
+ HEADER_SEARCH_PATHS = "$(mbgl_core_INCLUDE_DIRECTORIES)";
INFOPLIST_FILE = "$(SRCROOT)/sdk/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
+ LIBRARY_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(PROJECT_DIR)/cmake/Debug",
+ );
OTHER_CFLAGS = "-fvisibility=hidden";
OTHER_LDFLAGS = (
"$(mbgl_core_LINK_LIBRARIES)",
@@ -1764,10 +1797,7 @@
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_VERSION = A;
- HEADER_SEARCH_PATHS = (
- "$(mbgl_core_INCLUDE_DIRECTORIES)",
- "$(mbgl_loop_INCLUDE_DIRECTORIES)",
- );
+ HEADER_SEARCH_PATHS = "$(mbgl_core_INCLUDE_DIRECTORIES)";
INFOPLIST_FILE = "$(SRCROOT)/sdk/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
@@ -1794,6 +1824,10 @@
HEADER_SEARCH_PATHS = "$(mbgl_core_INCLUDE_DIRECTORIES)";
INFOPLIST_FILE = test/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
+ LIBRARY_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(PROJECT_DIR)/cmake/Debug",
+ );
OTHER_CFLAGS = "-fvisibility=hidden";
OTHER_CPLUSPLUSFLAGS = (
"$(OTHER_CFLAGS)",
@@ -1801,6 +1835,7 @@
"$(geometry_cflags)",
"$(geojson_cflags)",
);
+ OTHER_SWIFT_FLAGS = "-warnings-as-errors";
PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.test;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "../darwin/test/test-Bridging-Header.h";
@@ -1825,6 +1860,7 @@
"$(geometry_cflags)",
"$(geojson_cflags)",
);
+ OTHER_SWIFT_FLAGS = "-warnings-as-errors";
PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.test;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "../darwin/test/test-Bridging-Header.h";
diff --git a/platform/macos/sdk/Base.lproj/Localizable.strings b/platform/macos/sdk/Base.lproj/Localizable.strings
index b7a4a21173..68360320eb 100644
--- a/platform/macos/sdk/Base.lproj/Localizable.strings
+++ b/platform/macos/sdk/Base.lproj/Localizable.strings
@@ -1,6 +1,18 @@
+/* User-friendly error description */
+"LOAD_MAP_FAILED_DESC" = "The map failed to load because an unknown error occurred.";
+
+/* User-friendly error description */
+"LOAD_STYLE_FAILED_DESC" = "The map failed to load because the style can't be loaded.";
+
/* Accessibility title */
"MAP_A11Y_TITLE" = "Mapbox";
+/* User-friendly error description */
+"PARSE_STYLE_FAILED_DESC" = "The map failed to load because the style is corrupted.";
+
+/* User-friendly error description */
+"STYLE_NOT_FOUND_DESC" = "The map failed to load because the style can’t be found or is incompatible.";
+
/* Label of Zoom In button */
"ZOOM_IN_LABEL" = "+";
diff --git a/platform/macos/sdk/lt.lproj/Localizable.strings b/platform/macos/sdk/lt.lproj/Localizable.strings
index 8e93c86963..0e2e604e84 100644
--- a/platform/macos/sdk/lt.lproj/Localizable.strings
+++ b/platform/macos/sdk/lt.lproj/Localizable.strings
@@ -1,6 +1,18 @@
-/* Accessibility title */
+/* User-friendly error description */
+"LOAD_MAP_FAILED_DESC" = "Nepavyko užkrauti žemėlapio dėl nežinomos klaidos.";
+
+/* User-friendly error description */
+"LOAD_STYLE_FAILED_DESC" = "Nepavyko užkrauti žemėlapio, nes nepavyko užkrauti stiliaus.";
+
+/* Accessibility title */
"MAP_A11Y_TITLE" = "Mapbox";
+/* User-friendly error description */
+"PARSE_STYLE_FAILED_DESC" = "Nepavyko užkrauti žemėlapio, nes stilius yra netinkamo formato.";
+
+/* User-friendly error description */
+"STYLE_NOT_FOUND_DESC" = "Nepavyko užkrauti žemėlapio, nes neįmanoma rasti stiliaus arba jis nėra suderinamas.";
+
/* Label of Zoom In button */
"ZOOM_IN_LABEL" = "+";
diff --git a/platform/macos/sdk/mapbox.pdf b/platform/macos/sdk/mapbox.pdf
index c08a0e3135..fbe86d3a43 100644
--- a/platform/macos/sdk/mapbox.pdf
+++ b/platform/macos/sdk/mapbox.pdf
Binary files differ
diff --git a/platform/macos/sdk/sv.lproj/Localizable.strings b/platform/macos/sdk/sv.lproj/Localizable.strings
index 34841108a7..c94660d7d4 100644
--- a/platform/macos/sdk/sv.lproj/Localizable.strings
+++ b/platform/macos/sdk/sv.lproj/Localizable.strings
@@ -1,6 +1,18 @@
-/* Accessibility title */
+/* User-friendly error description */
+"LOAD_MAP_FAILED_DESC" = "Kartan kunde inte laddas på grund av ett okänt fel.";
+
+/* User-friendly error description */
+"LOAD_STYLE_FAILED_DESC" = "Kartan kunde inte laddas på grund av att stilen inte kunde laddas.";
+
+/* Accessibility title */
"MAP_A11Y_TITLE" = "Mapbox";
+/* User-friendly error description */
+"PARSE_STYLE_FAILED_DESC" = "Kartan kunde inte laddas på grund av att stilen är skadad.";
+
+/* User-friendly error description */
+"STYLE_NOT_FOUND_DESC" = "Kartan kunde inte laddas på grund av att stilen saknas eller är inkompatibel.";
+
/* Label of Zoom In button */
"ZOOM_IN_LABEL" = "+";
diff --git a/platform/macos/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm
index a873d9ef82..59951f946d 100644
--- a/platform/macos/src/MGLMapView.mm
+++ b/platform/macos/src/MGLMapView.mm
@@ -26,17 +26,19 @@
#import <mbgl/map/camera.hpp>
#import <mbgl/storage/reachability.h>
#import <mbgl/util/default_thread_pool.hpp>
-#import <mbgl/gl/extension.hpp>
-#import <mbgl/gl/context.hpp>
#import <mbgl/map/backend.hpp>
-#import <mbgl/sprite/sprite_image.hpp>
+#import <mbgl/map/backend_scope.hpp>
+#import <mbgl/style/image.hpp>
#import <mbgl/storage/default_file_source.hpp>
#import <mbgl/storage/network_status.hpp>
#import <mbgl/math/wrap.hpp>
#import <mbgl/util/constants.hpp>
#import <mbgl/util/chrono.hpp>
+#import <mbgl/util/exception.hpp>
#import <mbgl/util/run_loop.hpp>
#import <mbgl/util/shared_thread_pool.hpp>
+#import <mbgl/util/string.hpp>
+#import <mbgl/util/projection.hpp>
#import <map>
#import <unordered_map>
@@ -53,6 +55,7 @@
#import "NSPredicate+MGLAdditions.h"
#import <QuartzCore/QuartzCore.h>
+#import <OpenGL/gl.h>
class MGLMapViewImpl;
class MGLAnnotationContext;
@@ -155,7 +158,7 @@ public:
NSMagnificationGestureRecognizer *_magnificationGestureRecognizer;
NSRotationGestureRecognizer *_rotationGestureRecognizer;
NSClickGestureRecognizer *_singleClickRecognizer;
- double _scaleAtBeginningOfGesture;
+ double _zoomAtBeginningOfGesture;
CLLocationDirection _directionAtBeginningOfGesture;
CGFloat _pitchAtBeginningOfGesture;
BOOL _didHideCursorDuringGesture;
@@ -305,8 +308,11 @@ public:
}
- (mbgl::Size)size {
- return { static_cast<uint32_t>(self.bounds.size.width),
- static_cast<uint32_t>(self.bounds.size.height) };
+ // check for minimum texture size supported by OpenGL ES 2.0
+ //
+ CGSize size = CGSizeMake(MAX(self.bounds.size.width, 64), MAX(self.bounds.size.height, 64));
+ return { static_cast<uint32_t>(size.width),
+ static_cast<uint32_t>(size.height) };
}
- (mbgl::Size)framebufferSize {
@@ -357,7 +363,7 @@ public:
NSImage *logoImage = [[NSImage alloc] initWithContentsOfFile:
[[NSBundle mgl_frameworkBundle] pathForResource:@"mapbox" ofType:@"pdf"]];
// Account for the image’s built-in padding when aligning other controls to the logo.
- logoImage.alignmentRect = NSInsetRect(logoImage.alignmentRect, 3, 3);
+ logoImage.alignmentRect = NSInsetRect(logoImage.alignmentRect, 0, 3);
_logoView.image = logoImage;
_logoView.translatesAutoresizingMaskIntoConstraints = NO;
_logoView.accessibilityTitle = NSLocalizedStringWithDefaultValue(@"MAP_A11Y_TITLE", nil, nil, @"Mapbox", @"Accessibility title");
@@ -765,21 +771,9 @@ public:
- (void)renderSync {
if (!self.dormant) {
- // Enable vertex buffer objects.
- mbgl::gl::InitializeExtensions([](const char *name) {
- static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
- if (!framework) {
- throw std::runtime_error("Failed to load OpenGL framework.");
- }
-
- CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingASCII);
- void *symbol = CFBundleGetFunctionPointerForName(framework, str);
- CFRelease(str);
-
- return reinterpret_cast<mbgl::gl::glProc>(symbol);
- });
+ // The OpenGL implementation automatically enables the OpenGL context for us.
+ mbgl::BackendScope scope { *_mbglView, mbgl::BackendScope::ScopeType::Implicit };
- _mbglView->updateViewBinding();
_mbglMap->render(*_mbglView);
if (_isPrinting) {
@@ -813,133 +807,150 @@ public:
[self.layer setNeedsDisplay];
}
-- (void)notifyMapChange:(mbgl::MapChange)change {
- // Ignore map updates when the Map object isn't set.
+- (void)cameraWillChangeAnimated:(BOOL)animated {
if (!_mbglMap) {
return;
}
- switch (change) {
- case mbgl::MapChangeRegionWillChange:
- case mbgl::MapChangeRegionWillChangeAnimated:
- {
- if ([self.delegate respondsToSelector:@selector(mapView:cameraWillChangeAnimated:)]) {
- BOOL animated = change == mbgl::MapChangeRegionWillChangeAnimated;
- [self.delegate mapView:self cameraWillChangeAnimated:animated];
- }
- break;
- }
- case mbgl::MapChangeRegionIsChanging:
- {
- // Update a minimum of UI that needs to stay attached to the map
- // while animating.
- [self updateCompass];
- [self updateAnnotationCallouts];
+ if ([self.delegate respondsToSelector:@selector(mapView:cameraWillChangeAnimated:)]) {
+ [self.delegate mapView:self cameraWillChangeAnimated:animated];
+ }
+}
- if ([self.delegate respondsToSelector:@selector(mapViewCameraIsChanging:)]) {
- [self.delegate mapViewCameraIsChanging:self];
- }
- break;
- }
- case mbgl::MapChangeRegionDidChange:
- case mbgl::MapChangeRegionDidChangeAnimated:
- {
- // Update all UI at the end of an animation or atomic change to the
- // viewport. More expensive updates can happen here, but care should
- // still be taken to minimize the work done here because scroll
- // gesture recognition and momentum scrolling is performed as a
- // series of atomic changes, not an animation.
- [self updateZoomControls];
- [self updateCompass];
- [self updateAnnotationCallouts];
- [self updateAnnotationTrackingAreas];
+- (void)cameraIsChanging {
+ if (!_mbglMap) {
+ return;
+ }
- if ([self.delegate respondsToSelector:@selector(mapView:cameraDidChangeAnimated:)]) {
- BOOL animated = change == mbgl::MapChangeRegionDidChangeAnimated;
- [self.delegate mapView:self cameraDidChangeAnimated:animated];
- }
- break;
- }
- case mbgl::MapChangeWillStartLoadingMap:
- {
- if ([self.delegate respondsToSelector:@selector(mapViewWillStartLoadingMap:)]) {
- [self.delegate mapViewWillStartLoadingMap:self];
- }
- break;
- }
- case mbgl::MapChangeDidFinishLoadingMap:
- {
- [self.style willChangeValueForKey:@"sources"];
- [self.style didChangeValueForKey:@"sources"];
- [self.style willChangeValueForKey:@"layers"];
- [self.style didChangeValueForKey:@"layers"];
- if ([self.delegate respondsToSelector:@selector(mapViewDidFinishLoadingMap:)]) {
- [self.delegate mapViewDidFinishLoadingMap:self];
- }
- break;
- }
- case mbgl::MapChangeDidFailLoadingMap:
- {
- if ([self.delegate respondsToSelector:@selector(mapViewDidFailLoadingMap:withError:)]) {
- NSError *error = [NSError errorWithDomain:MGLErrorDomain code:0 userInfo:nil];
- [self.delegate mapViewDidFailLoadingMap:self withError:error];
- }
- break;
- }
- case mbgl::MapChangeWillStartRenderingMap:
- {
- if ([self.delegate respondsToSelector:@selector(mapViewWillStartRenderingMap:)]) {
- [self.delegate mapViewWillStartRenderingMap:self];
- }
- break;
- }
- case mbgl::MapChangeDidFinishRenderingMap:
- case mbgl::MapChangeDidFinishRenderingMapFullyRendered:
- {
- if ([self.delegate respondsToSelector:@selector(mapViewDidFinishRenderingMap:fullyRendered:)]) {
- BOOL fullyRendered = change == mbgl::MapChangeDidFinishRenderingMapFullyRendered;
- [self.delegate mapViewDidFinishRenderingMap:self fullyRendered:fullyRendered];
- }
- break;
- }
- case mbgl::MapChangeWillStartRenderingFrame:
- {
- if ([self.delegate respondsToSelector:@selector(mapViewWillStartRenderingFrame:)]) {
- [self.delegate mapViewWillStartRenderingFrame:self];
- }
- break;
- }
- case mbgl::MapChangeDidFinishRenderingFrame:
- case mbgl::MapChangeDidFinishRenderingFrameFullyRendered:
- {
- if (_isChangingAnnotationLayers) {
- _isChangingAnnotationLayers = NO;
- [self.style didChangeValueForKey:@"layers"];
- }
- if ([self.delegate respondsToSelector:@selector(mapViewDidFinishRenderingFrame:fullyRendered:)]) {
- BOOL fullyRendered = change == mbgl::MapChangeDidFinishRenderingFrameFullyRendered;
- [self.delegate mapViewDidFinishRenderingFrame:self fullyRendered:fullyRendered];
- }
- break;
- }
- case mbgl::MapChangeDidFinishLoadingStyle:
- {
- self.style = [[MGLStyle alloc] initWithMapView:self];
- if ([self.delegate respondsToSelector:@selector(mapView:didFinishLoadingStyle:)])
- {
- [self.delegate mapView:self didFinishLoadingStyle:self.style];
- }
- break;
- }
- case mbgl::MapChangeSourceDidChange:
- {
- [self installAttributionView];
- self.needsUpdateConstraints = YES;
- break;
- }
+ // Update a minimum of UI that needs to stay attached to the map
+ // while animating.
+ [self updateCompass];
+ [self updateAnnotationCallouts];
+
+ if ([self.delegate respondsToSelector:@selector(mapViewCameraIsChanging:)]) {
+ [self.delegate mapViewCameraIsChanging:self];
+ }
+}
+
+- (void)cameraDidChangeAnimated:(BOOL)animated {
+ if (!_mbglMap) {
+ return;
+ }
+
+ // Update all UI at the end of an animation or atomic change to the
+ // viewport. More expensive updates can happen here, but care should
+ // still be taken to minimize the work done here because scroll
+ // gesture recognition and momentum scrolling is performed as a
+ // series of atomic changes, not an animation.
+ [self updateZoomControls];
+ [self updateCompass];
+ [self updateAnnotationCallouts];
+ [self updateAnnotationTrackingAreas];
+
+ if ([self.delegate respondsToSelector:@selector(mapView:cameraDidChangeAnimated:)]) {
+ [self.delegate mapView:self cameraDidChangeAnimated:animated];
+ }
+}
+
+- (void)mapViewWillStartLoadingMap {
+ if (!_mbglMap) {
+ return;
+ }
+
+ if ([self.delegate respondsToSelector:@selector(mapViewWillStartLoadingMap:)]) {
+ [self.delegate mapViewWillStartLoadingMap:self];
}
}
+- (void)mapViewDidFinishLoadingMap {
+ if (!_mbglMap) {
+ return;
+ }
+
+ [self.style willChangeValueForKey:@"sources"];
+ [self.style didChangeValueForKey:@"sources"];
+ [self.style willChangeValueForKey:@"layers"];
+ [self.style didChangeValueForKey:@"layers"];
+ if ([self.delegate respondsToSelector:@selector(mapViewDidFinishLoadingMap:)]) {
+ [self.delegate mapViewDidFinishLoadingMap:self];
+ }
+}
+
+- (void)mapViewDidFailLoadingMapWithError:(NSError *)error {
+ if (!_mbglMap) {
+ return;
+ }
+
+ if ([self.delegate respondsToSelector:@selector(mapViewDidFailLoadingMap:withError:)]) {
+ [self.delegate mapViewDidFailLoadingMap:self withError:error];
+ }
+}
+
+- (void)mapViewWillStartRenderingFrame {
+ if (!_mbglMap) {
+ return;
+ }
+
+ if ([self.delegate respondsToSelector:@selector(mapViewWillStartRenderingFrame:)]) {
+ [self.delegate mapViewWillStartRenderingFrame:self];
+ }
+}
+
+- (void)mapViewDidFinishRenderingFrameFullyRendered:(BOOL)fullyRendered {
+ if (!_mbglMap) {
+ return;
+ }
+
+ if (_isChangingAnnotationLayers) {
+ _isChangingAnnotationLayers = NO;
+ [self.style didChangeValueForKey:@"layers"];
+ }
+ if ([self.delegate respondsToSelector:@selector(mapViewDidFinishRenderingFrame:fullyRendered:)]) {
+ [self.delegate mapViewDidFinishRenderingFrame:self fullyRendered:fullyRendered];
+ }
+}
+
+- (void)mapViewWillStartRenderingMap {
+ if (!_mbglMap) {
+ return;
+ }
+
+ if ([self.delegate respondsToSelector:@selector(mapViewWillStartRenderingMap:)]) {
+ [self.delegate mapViewWillStartRenderingMap:self];
+ }
+}
+
+- (void)mapViewDidFinishRenderingMapFullyRendered:(BOOL)fullyRendered {
+ if (!_mbglMap) {
+ return;
+ }
+
+ if ([self.delegate respondsToSelector:@selector(mapViewDidFinishRenderingMap:fullyRendered:)]) {
+ [self.delegate mapViewDidFinishRenderingMap:self fullyRendered:fullyRendered];
+ }
+}
+
+- (void)mapViewDidFinishLoadingStyle {
+ if (!_mbglMap) {
+ return;
+ }
+
+ self.style = [[MGLStyle alloc] initWithMapView:self];
+ if ([self.delegate respondsToSelector:@selector(mapView:didFinishLoadingStyle:)])
+ {
+ [self.delegate mapView:self didFinishLoadingStyle:self.style];
+ }
+}
+
+- (void)sourceDidChange {
+ if (!_mbglMap) {
+ return;
+ }
+
+ [self installAttributionView];
+ self.needsUpdateConstraints = YES;
+}
+
#pragma mark Printing
- (void)print:(__unused id)sender {
@@ -1027,31 +1038,12 @@ public:
[self didChangeValueForKey:@"zoomLevel"];
}
-- (void)zoomBy:(double)zoomDelta animated:(BOOL)animated {
- [self setZoomLevel:round(self.zoomLevel) + zoomDelta animated:animated];
-}
-
-- (void)zoomBy:(double)zoomDelta atPoint:(NSPoint)point animated:(BOOL)animated {
+- (void)setZoomLevel:(double)zoomLevel atPoint:(NSPoint)point animated:(BOOL)animated {
[self willChangeValueForKey:@"centerCoordinate"];
[self willChangeValueForKey:@"zoomLevel"];
- double newZoom = round(self.zoomLevel) + zoomDelta;
MGLMapCamera *oldCamera = self.camera;
mbgl::ScreenCoordinate center(point.x, self.bounds.size.height - point.y);
- _mbglMap->setZoom(newZoom, center, MGLDurationFromTimeInterval(animated ? MGLAnimationDuration : 0));
- if ([self.delegate respondsToSelector:@selector(mapView:shouldChangeFromCamera:toCamera:)]
- && ![self.delegate mapView:self shouldChangeFromCamera:oldCamera toCamera:self.camera]) {
- self.camera = oldCamera;
- }
- [self didChangeValueForKey:@"zoomLevel"];
- [self didChangeValueForKey:@"centerCoordinate"];
-}
-
-- (void)scaleBy:(double)scaleFactor atPoint:(NSPoint)point animated:(BOOL)animated {
- [self willChangeValueForKey:@"centerCoordinate"];
- [self willChangeValueForKey:@"zoomLevel"];
- MGLMapCamera *oldCamera = self.camera;
- mbgl::ScreenCoordinate center(point.x, self.bounds.size.height - point.y);
- _mbglMap->scaleBy(scaleFactor, center, MGLDurationFromTimeInterval(animated ? MGLAnimationDuration : 0));
+ _mbglMap->setZoom(zoomLevel, center, MGLDurationFromTimeInterval(animated ? MGLAnimationDuration : 0));
if ([self.delegate respondsToSelector:@selector(mapView:shouldChangeFromCamera:toCamera:)]
&& ![self.delegate mapView:self shouldChangeFromCamera:oldCamera toCamera:self.camera]) {
self.camera = oldCamera;
@@ -1392,10 +1384,10 @@ public:
_mbglMap->cancelTransitions();
if (gestureRecognizer.state == NSGestureRecognizerStateBegan) {
- _scaleAtBeginningOfGesture = _mbglMap->getScale();
+ _zoomAtBeginningOfGesture = _mbglMap->getZoom();
} else if (gestureRecognizer.state == NSGestureRecognizerStateChanged) {
- CGFloat newZoomLevel = log2f(_scaleAtBeginningOfGesture) - delta.y / 75;
- [self scaleBy:powf(2, newZoomLevel) / _mbglMap->getScale() atPoint:startPoint animated:NO];
+ CGFloat newZoomLevel = _zoomAtBeginningOfGesture - delta.y / 75;
+ [self setZoomLevel:newZoomLevel atPoint:startPoint animated:NO];
}
} else if (flags & NSAlternateKeyMask) {
// Option-drag to rotate and/or tilt.
@@ -1456,7 +1448,7 @@ public:
if (gestureRecognizer.state == NSGestureRecognizerStateBegan) {
_mbglMap->setGestureInProgress(true);
- _scaleAtBeginningOfGesture = _mbglMap->getScale();
+ _zoomAtBeginningOfGesture = _mbglMap->getZoom();
} else if (gestureRecognizer.state == NSGestureRecognizerStateChanged) {
NSPoint zoomInPoint = [gestureRecognizer locationInView:self];
mbgl::ScreenCoordinate center(zoomInPoint.x, self.bounds.size.height - zoomInPoint.y);
@@ -1464,7 +1456,7 @@ public:
[self willChangeValueForKey:@"zoomLevel"];
[self willChangeValueForKey:@"centerCoordinate"];
MGLMapCamera *oldCamera = self.camera;
- _mbglMap->setScale(_scaleAtBeginningOfGesture * (1 + gestureRecognizer.magnification), center);
+ _mbglMap->setZoom(_zoomAtBeginningOfGesture + log2(1 + gestureRecognizer.magnification), center);
if ([self.delegate respondsToSelector:@selector(mapView:shouldChangeFromCamera:toCamera:)]
&& ![self.delegate mapView:self shouldChangeFromCamera:oldCamera toCamera:self.camera]) {
self.camera = oldCamera;
@@ -1516,7 +1508,7 @@ public:
_mbglMap->cancelTransitions();
NSPoint gesturePoint = [gestureRecognizer locationInView:self];
- [self zoomBy:1 atPoint:gesturePoint animated:YES];
+ [self setZoomLevel:round(self.zoomLevel) + 1 atPoint:gesturePoint animated:YES];
}
- (void)smartMagnifyWithEvent:(NSEvent *)event {
@@ -1528,7 +1520,7 @@ public:
// Tap with two fingers (“right-click”) to zoom out on mice but not trackpads.
NSPoint gesturePoint = [self convertPoint:event.locationInWindow fromView:nil];
- [self zoomBy:-1 atPoint:gesturePoint animated:YES];
+ [self setZoomLevel:round(self.zoomLevel) - 1 atPoint:gesturePoint animated:YES];
}
/// Rotate fingers to rotate.
@@ -1581,7 +1573,7 @@ public:
}
NSPoint gesturePoint = [self convertPoint:event.locationInWindow fromView:nil];
- [self scaleBy:scale atPoint:gesturePoint animated:NO];
+ [self setZoomLevel:self.zoomLevel + log2(scale) atPoint:gesturePoint animated:NO];
}
}
} else if (self.scrollEnabled
@@ -1689,13 +1681,13 @@ public:
- (IBAction)moveToBeginningOfParagraph:(__unused id)sender {
if (self.zoomEnabled) {
- [self zoomBy:1 animated:YES];
+ [self setZoomLevel:round(self.zoomLevel) + 1 animated:YES];
}
}
- (IBAction)moveToEndOfParagraph:(__unused id)sender {
if (self.zoomEnabled) {
- [self zoomBy:-1 animated:YES];
+ [self setZoomLevel:round(self.zoomLevel) - 1 animated:YES];
}
}
@@ -1957,8 +1949,7 @@ public:
return;
}
- std::shared_ptr<mbgl::SpriteImage> sprite(annotationImage.image.mgl_spriteImage);
- _mbglMap->addAnnotationIcon(iconIdentifier.UTF8String, sprite);
+ _mbglMap->addAnnotationImage([annotationImage.image mgl_styleImageWithIdentifier:iconIdentifier]);
// Create a slop area with a “radius” equal to the annotation image’s entire
// size, allowing the eventual click to be on any point within this image.
@@ -2620,6 +2611,9 @@ public:
#pragma mark Geometric methods
- (NSPoint)convertCoordinate:(CLLocationCoordinate2D)coordinate toPointToView:(nullable NSView *)view {
+ if (!CLLocationCoordinate2DIsValid(coordinate)) {
+ return NSMakePoint(NAN, NAN);
+ }
return [self convertLatLng:MGLLatLngFromLocationCoordinate2D(coordinate) toPointToView:view];
}
@@ -2646,6 +2640,9 @@ public:
}
- (NSRect)convertCoordinateBounds:(MGLCoordinateBounds)bounds toRectToView:(nullable NSView *)view {
+ if (!CLLocationCoordinate2DIsValid(bounds.sw) || !CLLocationCoordinate2DIsValid(bounds.ne)) {
+ return CGRectNull;
+ }
return [self convertLatLngBounds:MGLLatLngBoundsFromCoordinateBounds(bounds) toRectToView:view];
}
@@ -2678,7 +2675,7 @@ public:
(bounds.south() + bounds.north()) / 2,
bounds.west() - 1,
};
- } else if (bounds.northeast().longitude < 180) {
+ } else if (bounds.northeast().longitude() < 180) {
outsideLatLng = {
(bounds.south() + bounds.north()) / 2,
bounds.east() + 1,
@@ -2695,7 +2692,7 @@ public:
}
- (CLLocationDistance)metersPerPointAtLatitude:(CLLocationDegrees)latitude {
- return _mbglMap->getMetersPerPixelAtLatitude(latitude, self.zoomLevel);
+ return mbgl::Projection::getMetersPerPixelAtLatitude(latitude, self.zoomLevel);
}
#pragma mark Debugging
@@ -2759,8 +2756,91 @@ public:
MGLMapViewImpl(MGLMapView *nativeView_)
: nativeView(nativeView_) {}
- void notifyMapChange(mbgl::MapChange change) override {
- [nativeView notifyMapChange:change];
+ void onCameraWillChange(mbgl::MapObserver::CameraChangeMode mode) override {
+ bool animated = mode == mbgl::MapObserver::CameraChangeMode::Animated;
+ [nativeView cameraWillChangeAnimated:animated];
+ }
+
+ void onCameraIsChanging() override {
+ [nativeView cameraIsChanging];
+ }
+
+ void onCameraDidChange(mbgl::MapObserver::CameraChangeMode mode) override {
+ bool animated = mode == mbgl::MapObserver::CameraChangeMode::Animated;
+ [nativeView cameraDidChangeAnimated:animated];
+ }
+
+ void onWillStartLoadingMap() override {
+ [nativeView mapViewWillStartLoadingMap];
+ }
+
+ void onDidFinishLoadingMap() override {
+ [nativeView mapViewDidFinishLoadingMap];
+ }
+
+ void onDidFailLoadingMap(std::exception_ptr exception) override {
+ NSString *description;
+ MGLErrorCode code;
+ try {
+ std::rethrow_exception(exception);
+ } catch (const mbgl::util::StyleParseException&) {
+ code = MGLErrorCodeParseStyleFailed;
+ description = NSLocalizedStringWithDefaultValue(@"PARSE_STYLE_FAILED_DESC", nil, nil, @"The map failed to load because the style is corrupted.", @"User-friendly error description");
+ } catch (const mbgl::util::StyleLoadException&) {
+ code = MGLErrorCodeLoadStyleFailed;
+ description = NSLocalizedStringWithDefaultValue(@"LOAD_STYLE_FAILED_DESC", nil, nil, @"The map failed to load because the style can't be loaded.", @"User-friendly error description");
+ } catch (const mbgl::util::NotFoundException&) {
+ code = MGLErrorCodeNotFound;
+ description = NSLocalizedStringWithDefaultValue(@"STYLE_NOT_FOUND_DESC", nil, nil, @"The map failed to load because the style can’t be found or is incompatible.", @"User-friendly error description");
+ } catch (...) {
+ code = MGLErrorCodeUnknown;
+ description = NSLocalizedStringWithDefaultValue(@"LOAD_MAP_FAILED_DESC", nil, nil, @"The map failed to load because an unknown error occurred.", @"User-friendly error description");
+ }
+ NSDictionary *userInfo = @{
+ NSLocalizedDescriptionKey: description,
+ NSLocalizedFailureReasonErrorKey: @(mbgl::util::toString(exception).c_str()),
+ };
+ NSError *error = [NSError errorWithDomain:MGLErrorDomain code:code userInfo:userInfo];
+ [nativeView mapViewDidFailLoadingMapWithError:error];
+ }
+
+ void onWillStartRenderingFrame() override {
+ [nativeView mapViewWillStartRenderingFrame];
+ }
+
+ void onDidFinishRenderingFrame(mbgl::MapObserver::RenderMode mode) override {
+ bool fullyRendered = mode == mbgl::MapObserver::RenderMode::Full;
+ [nativeView mapViewDidFinishRenderingFrameFullyRendered:fullyRendered];
+ }
+
+ void onWillStartRenderingMap() override {
+ [nativeView mapViewWillStartRenderingMap];
+ }
+
+ void onDidFinishRenderingMap(mbgl::MapObserver::RenderMode mode) override {
+ bool fullyRendered = mode == mbgl::MapObserver::RenderMode::Full;
+ [nativeView mapViewDidFinishRenderingMapFullyRendered:fullyRendered];
+ }
+
+ void onDidFinishLoadingStyle() override {
+ [nativeView mapViewDidFinishLoadingStyle];
+ }
+
+ void onSourceChanged(mbgl::style::Source&) override {
+ [nativeView sourceDidChange];
+ }
+
+ mbgl::gl::ProcAddress initializeExtension(const char* name) override {
+ static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
+ if (!framework) {
+ throw std::runtime_error("Failed to load OpenGL framework.");
+ }
+
+ CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingASCII);
+ void *symbol = CFBundleGetFunctionPointerForName(framework, str);
+ CFRelease(str);
+
+ return reinterpret_cast<mbgl::gl::ProcAddress>(symbol);
}
void invalidate() override {
@@ -2784,24 +2864,19 @@ public:
[NSOpenGLContext clearCurrentContext];
}
- mbgl::gl::value::Viewport::Type getViewport() const {
- return { 0, 0, nativeView.framebufferSize };
- }
-
- void updateViewBinding() {
- fbo = mbgl::gl::value::BindFramebuffer::Get();
- getContext().bindFramebuffer.setCurrentValue(fbo);
- getContext().viewport.setCurrentValue(getViewport());
- assert(mbgl::gl::value::Viewport::Get() == getContext().viewport.getCurrentValue());
+ void updateAssumedState() override {
+ glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fbo);
+ assumeFramebufferBinding(fbo);
+ assumeViewportSize(nativeView.framebufferSize);
}
void bind() override {
- getContext().bindFramebuffer = fbo;
- getContext().viewport = getViewport();
+ setFramebufferBinding(fbo);
+ setViewportSize(nativeView.framebufferSize);
}
mbgl::PremultipliedImage readStillImage() {
- return getContext().readFramebuffer<mbgl::PremultipliedImage>(nativeView.framebufferSize);
+ return readFramebuffer(nativeView.framebufferSize);
}
private:
diff --git a/platform/macos/src/Mapbox.h b/platform/macos/src/Mapbox.h
index 79ecfb21dc..dcb5b50b8f 100644
--- a/platform/macos/src/Mapbox.h
+++ b/platform/macos/src/Mapbox.h
@@ -37,6 +37,7 @@ FOUNDATION_EXPORT MGL_EXPORT const unsigned char MapboxVersionString[];
#import "MGLForegroundStyleLayer.h"
#import "MGLVectorStyleLayer.h"
#import "MGLFillStyleLayer.h"
+#import "MGLFillExtrusionStyleLayer.h"
#import "MGLLineStyleLayer.h"
#import "MGLSymbolStyleLayer.h"
#import "MGLRasterStyleLayer.h"
diff --git a/platform/macos/src/NSImage+MGLAdditions.h b/platform/macos/src/NSImage+MGLAdditions.h
index c6a80e372d..1bcec00e8b 100644
--- a/platform/macos/src/NSImage+MGLAdditions.h
+++ b/platform/macos/src/NSImage+MGLAdditions.h
@@ -1,6 +1,6 @@
#import <Cocoa/Cocoa.h>
-#include <mbgl/sprite/sprite_image.hpp>
+#include <mbgl/style/image.hpp>
NS_ASSUME_NONNULL_BEGIN
@@ -8,9 +8,9 @@ NS_ASSUME_NONNULL_BEGIN
- (nullable instancetype)initWithMGLPremultipliedImage:(mbgl::PremultipliedImage&&)image;
-- (nullable instancetype)initWithMGLSpriteImage:(const mbgl::SpriteImage *)spriteImage;
+- (nullable instancetype)initWithMGLStyleImage:(const mbgl::style::Image *)image;
-- (std::unique_ptr<mbgl::SpriteImage>)mgl_spriteImage;
+- (std::unique_ptr<mbgl::style::Image>)mgl_styleImageWithIdentifier:(NSString *)identifier;
@end
diff --git a/platform/macos/src/NSImage+MGLAdditions.mm b/platform/macos/src/NSImage+MGLAdditions.mm
index 397e291431..ecd8aabe15 100644
--- a/platform/macos/src/NSImage+MGLAdditions.mm
+++ b/platform/macos/src/NSImage+MGLAdditions.mm
@@ -15,22 +15,24 @@
return self;
}
-- (nullable instancetype)initWithMGLSpriteImage:(const mbgl::SpriteImage *)spriteImage {
- CGImageRef image = CGImageFromMGLPremultipliedImage(spriteImage->image.clone());
+- (nullable instancetype)initWithMGLStyleImage:(const mbgl::style::Image *)styleImage {
+ CGImageRef image = CGImageFromMGLPremultipliedImage(styleImage->getImage().clone());
if (!image) {
return nil;
}
NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initWithCGImage:image];
CGImageRelease(image);
- if (self = [self initWithSize:NSMakeSize(spriteImage->getWidth(), spriteImage->getHeight())]) {
+ CGFloat w = styleImage->getImage().size.width / styleImage->getPixelRatio();
+ CGFloat h = styleImage->getImage().size.height / styleImage->getPixelRatio();
+ if (self = [self initWithSize:NSMakeSize(w, h)]) {
[self addRepresentation:rep];
- [self setTemplate:spriteImage->sdf];
+ [self setTemplate:styleImage->isSdf()];
}
return self;
}
-- (std::unique_ptr<mbgl::SpriteImage>)mgl_spriteImage {
+- (std::unique_ptr<mbgl::style::Image>)mgl_styleImageWithIdentifier:(NSString *)identifier {
// Create a bitmap image representation from the image, respecting backing
// scale factor and any resizing done on the image at runtime.
// http://www.cocoabuilder.com/archive/cocoa/82430-nsimage-getting-raw-bitmap-data.html#82431
@@ -40,9 +42,10 @@
mbgl::PremultipliedImage cPremultipliedImage({ static_cast<uint32_t>(rep.pixelsWide), static_cast<uint32_t>(rep.pixelsHigh) });
std::copy(rep.bitmapData, rep.bitmapData + cPremultipliedImage.bytes(), cPremultipliedImage.data.get());
- return std::make_unique<mbgl::SpriteImage>(std::move(cPremultipliedImage),
- (float)(rep.pixelsWide / self.size.width),
- [self isTemplate]);
+ return std::make_unique<mbgl::style::Image>([identifier UTF8String],
+ std::move(cPremultipliedImage),
+ (float)(rep.pixelsWide / self.size.width),
+ [self isTemplate]);
}
@end
diff --git a/platform/macos/test/MGLMapViewDelegateIntegrationTests.swift b/platform/macos/test/MGLMapViewDelegateIntegrationTests.swift
new file mode 100644
index 0000000000..3f82e7c61a
--- /dev/null
+++ b/platform/macos/test/MGLMapViewDelegateIntegrationTests.swift
@@ -0,0 +1,56 @@
+import XCTest
+import Mapbox
+
+class MGLMapViewDelegateIntegrationTests: XCTestCase {
+
+ func testCoverage() {
+ MGLSDKTestHelpers.checkTestsContainAllMethods(testClass: MGLMapViewDelegateIntegrationTests.self, in: MGLMapViewDelegate.self)
+ }
+
+}
+
+extension MGLMapViewDelegateIntegrationTests: MGLMapViewDelegate {
+
+ func mapView(_ mapView: MGLMapView, shouldChangeFrom oldCamera: MGLMapCamera, to newCamera: MGLMapCamera) -> Bool { return false }
+
+ func mapView(_ mapView: MGLMapView, lineWidthForPolylineAnnotation annotation: MGLPolyline) -> CGFloat { return 0 }
+
+ func mapView(_ mapView: MGLMapView, annotationCanShowCallout annotation: MGLAnnotation) -> Bool { return false }
+
+ func mapView(_ mapView: MGLMapView, imageFor annotation: MGLAnnotation) -> MGLAnnotationImage? { return nil }
+
+ func mapView(_ mapView: MGLMapView, alphaForShapeAnnotation annotation: MGLShape) -> CGFloat { return 0 }
+
+ func mapViewDidFinishRenderingFrame(_ mapView: MGLMapView, fullyRendered: Bool) {}
+
+ func mapViewDidFinishRenderingMap(_ mapView: MGLMapView, fullyRendered: Bool) {}
+
+ func mapViewDidFailLoadingMap(_ mapView: MGLMapView, withError error: Error) {}
+
+ func mapView(_ mapView: MGLMapView, didDeselect annotation: MGLAnnotation) {}
+
+ func mapView(_ mapView: MGLMapView, didSelect annotation: MGLAnnotation) {}
+
+ func mapView(_ mapView: MGLMapView, didFinishLoading style: MGLStyle) {}
+
+ func mapViewWillStartRenderingFrame(_ mapView: MGLMapView) {}
+
+ func mapViewWillStartRenderingMap(_ mapView: MGLMapView) {}
+
+ func mapViewWillStartLoadingMap(_ mapView: MGLMapView) {}
+
+ func mapViewDidFinishLoadingMap(_ mapView: MGLMapView) {}
+
+ func mapViewCameraIsChanging(_ mapView: MGLMapView) {}
+
+ func mapView(_ mapView: MGLMapView, cameraDidChangeAnimated animated: Bool) {}
+
+ func mapView(_ mapView: MGLMapView, cameraWillChangeAnimated animated: Bool) {}
+
+ func mapView(_ mapView: MGLMapView, strokeColorForShapeAnnotation annotation: MGLShape) -> NSColor { return .black }
+
+ func mapView(_ mapView: MGLMapView, fillColorForPolygonAnnotation annotation: MGLPolygon) -> NSColor { return .black }
+
+ func mapView(_ mapView: MGLMapView, calloutViewControllerFor annotation: MGLAnnotation) -> NSViewController? { return nil }
+
+}
diff --git a/platform/node/CHANGELOG.md b/platform/node/CHANGELOG.md
index 6f5afbbd6c..e77ceff31f 100644
--- a/platform/node/CHANGELOG.md
+++ b/platform/node/CHANGELOG.md
@@ -1,3 +1,26 @@
+# 3.5.1 - May 8, 2017
+
+- Adds Node v6 binaries. **Note, Node v4 binaries will be removed on August 1st.** ([#8884](https://github.com/mapbox/mapbox-gl-native/pull/8884))
+- Adds linux debug binaries ([#8865](https://github.com/mapbox/mapbox-gl-native/pull/8865))
+
+# 3.5.0 - April 20, 2017
+
+- Fixed an issue where raster tiles that were not found caused `map.render()` to hang ([#8769](https://github.com/mapbox/mapbox-gl-native/pull/8769))
+- Adds method `map.cancel()` which cancels an ongoing `render` call. ([#8249](https://github.com/mapbox/mapbox-gl-native/pull/8249))
+
+# 3.4.7 - March 15, 2017
+
+- Fixed MacOS Release builds ([8409](https://github.com/mapbox/mapbox-gl-native/pull/8409))
+
+# 3.4.6 - March 14, 2017
+
+- Publishes `Release` build on Mac ([#8407](https://github.com/mapbox/mapbox-gl-native/pull/8407))
+- Fixes the publish binary build process ([#8406](https://github.com/mapbox/mapbox-gl-native/pull/8406))
+
+# 3.4.5 - March 14, 2017
+
+- Fixed a memory hang issue after GlyphAtlas was refactored ([#8394](https://github.com/mapbox/mapbox-gl-native/pull/8394))
+
# 3.4.4 - January 10, 2017
- Updates the node binary publish location on s3 to reflect new package name ([#7653](https://github.com/mapbox/mapbox-gl-native/pull/7653))
diff --git a/platform/node/README.md b/platform/node/README.md
index 545d87861f..d19b2a9343 100644
--- a/platform/node/README.md
+++ b/platform/node/README.md
@@ -1,6 +1,6 @@
# node-mapbox-gl-native
-[![NPM](https://nodei.co/npm/mapbox-gl-native.png)](https://npmjs.org/package/mapbox-gl-native)
+[![NPM](https://nodei.co/npm/@mapbox/mapbox-gl-native.png)](https://npmjs.org/package/@mapbox/mapbox-gl-native)
## Installing
@@ -14,7 +14,7 @@ By default, installs binaries. On these platforms no additional dependencies are
Run:
```
-npm install mapbox-gl-native
+npm install @mapbox/mapbox-gl-native
```
Other platforms will fall back to a source compile with `make node`; see INSTALL.md in the repository root directory for prequisites.
@@ -31,7 +31,7 @@ npm run test-suite
```js
var fs = require('fs');
var path = require('path');
-var mbgl = require('mapbox-gl-native');
+var mbgl = require('@mapbox/mapbox-gl-native');
var sharp = require('sharp');
var options = {
diff --git a/platform/node/bitrise.yml b/platform/node/bitrise.yml
index 20dcfb1908..00005f0f36 100644
--- a/platform/node/bitrise.yml
+++ b/platform/node/bitrise.yml
@@ -3,85 +3,72 @@ default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git
trigger_map:
- tag: "node-v*"
- workflow: primary
+ workflow: publish
- push_branch: "*"
workflow: primary
- pull_request_target_branch: "*"
workflow: primary
+shortcuts:
+ slack: &slack
+ title: Post to Slack
+ inputs:
+ - webhook_url: "$SLACK_HOOK_URL"
+ - channel: "#gl-bots"
+ - from_username: 'Bitrise Node macOS'
+ - from_username_on_error: 'Bitrise Node macOS'
+ - message: '<${BITRISE_BUILD_URL}|Build #${BITRISE_BUILD_NUMBER}>
+ for <https://github.com/mapbox/mapbox-gl-native/compare/${BITRISE_GIT_BRANCH}|mapbox/mapbox-gl-native@${BITRISE_GIT_BRANCH}>
+ by ${GIT_CLONE_COMMIT_COMMITER_NAME}
+ passed'
+ - message_on_error: '<${BITRISE_BUILD_URL}|Build #${BITRISE_BUILD_NUMBER}>
+ for <https://github.com/mapbox/mapbox-gl-native/compare/${BITRISE_GIT_BRANCH}|mapbox/mapbox-gl-native@${BITRISE_GIT_BRANCH}>
+ by ${GIT_CLONE_COMMIT_COMMITER_NAME}
+ failed'
+ - icon_url: https://bitrise-public-content-production.s3.amazonaws.com/slack/bitrise-slack-icon-128.png
+ - icon_url_on_error: https://bitrise-public-content-production.s3.amazonaws.com/slack/bitrise-slack-error-icon-128.png
+
workflows:
primary:
steps:
- script:
- title: Check for skipping CI
- inputs:
- - content: |-
- #!/bin/bash
- if [[ -n "$(echo $GIT_CLONE_COMMIT_MESSAGE_SUBJECT | sed -n '/\[skip ci\]/p')" ||
- -n "$(echo $GIT_CLONE_COMMIT_MESSAGE_SUBJECT | sed -n '/\[ci skip\]/p')" ||
- -n "$(echo $GIT_CLONE_COMMIT_MESSAGE_BODY | sed -n 's/\[skip ci\]/p')" ||
- -n "$(echo $GIT_CLONE_COMMIT_MESSAGE_BODY | sed -n 's/\[ci skip\]/p')" ]]; then
- envman add --key SKIPCI --value true
- else
- envman add --key SKIPCI --value false
- fi
- - script:
- title: Check for publishing
- run_if: '{{enveq "SKIPCI" "false"}}'
- inputs:
- - content: |-
- #!/bin/bash
- PACKAGE_JSON_VERSION=$(node -e "console.log(require('./package.json').version)")
- if [[ "${BITRISE_GIT_TAG:-}" == "node-v${PACKAGE_JSON_VERSION}" ]]; then
- envman add --key PUBLISH --value true
- fi
- - script:
- title: Run build script
- run_if: '{{enveq "SKIPCI" "false"}}'
+ title: Test
inputs:
- content: |-
#!/bin/bash
set -eu -o pipefail
brew update
- brew install cmake
brew unlink node
- brew install awscli node@4
+ brew install cmake awscli node@4 node@6
brew link node@4 --force
gem install xcpretty --no-rdoc --no-ri
- make node
- - script:
- title: Run test script
- run_if: '{{and (enveq "SKIPCI" "false") (enveq "PUBLISH" "")}}'
- inputs:
- - content: |-
- #!/bin/bash
- set -eu -o pipefail
- make test-node || envman add --key RESULT --value $?
+ make test-node || RESULT=$?
+ brew unlink node@4
+ brew link --overwrite node@6 --force
+ make clean
+ make test-node || RESULT=$?
./platform/node/scripts/after_script.sh ${BITRISE_BUILD_NUMBER}
+ exit ${RESULT:-0}
+ - slack: *slack
+
+ publish:
+ steps:
- script:
- title: Run publish script
- run_if: '{{enveq "SKIPCI" "false"}}'
+ title: Publish
inputs:
- content: |-
#!/bin/bash
set -eu -o pipefail
- ./platform/node/scripts/after_success.sh
- exit ${RESULT:-0}
- - slack:
- title: Post to Slack
- run_if: '{{enveq "SKIPCI" "false"}}'
- inputs:
- - webhook_url: "$SLACK_HOOK_URL"
- - channel: "#gl-bots"
- - from_username: 'Bitrise Node macOS'
- - from_username_on_error: 'Bitrise Node macOS'
- - message: '<${BITRISE_BUILD_URL}|Build #${BITRISE_BUILD_NUMBER}>
- for <https://github.com/mapbox/mapbox-gl-native/compare/${BITRISE_GIT_BRANCH}|mapbox/mapbox-gl-native@${BITRISE_GIT_BRANCH}>
- by ${GIT_CLONE_COMMIT_COMMITER_NAME}
- passed'
- - message_on_error: '<${BITRISE_BUILD_URL}|Build #${BITRISE_BUILD_NUMBER}>
- for <https://github.com/mapbox/mapbox-gl-native/compare/${BITRISE_GIT_BRANCH}|mapbox/mapbox-gl-native@${BITRISE_GIT_BRANCH}>
- by ${GIT_CLONE_COMMIT_COMMITER_NAME}
- failed'
- - icon_url: https://bitrise-public-content-production.s3.amazonaws.com/slack/bitrise-slack-icon-128.png
- - icon_url_on_error: https://bitrise-public-content-production.s3.amazonaws.com/slack/bitrise-slack-error-icon-128.png
+ brew update
+ brew unlink node
+ brew install cmake awscli node@4 node@6
+ brew link node@4 --force
+ gem install xcpretty --no-rdoc --no-ri
+ export BUILDTYPE=Release
+ export PUBLISH=true
+ make test-node && ./platform/node/scripts/after_success.sh
+ brew unlink node@4
+ brew link --overwrite node@6 --force
+ make clean
+ make test-node && ./platform/node/scripts/after_success.sh
+ - slack: *slack
diff --git a/platform/node/scripts/after_success.sh b/platform/node/scripts/after_success.sh
index 7ef8f53545..ae34446927 100755
--- a/platform/node/scripts/after_success.sh
+++ b/platform/node/scripts/after_success.sh
@@ -4,10 +4,9 @@ set -e
set -o pipefail
if [[ -n ${PUBLISH:-} ]]; then
- if [[ "${BUILDTYPE}" == "Debug" ]]; then
- echo "Please run this script in release mode (BUILDTYPE=Release)."
- exit 1
- else
+ if [[ "${BUILDTYPE}" == "Release" ]]; then
./node_modules/.bin/node-pre-gyp package publish info
+ else
+ ./node_modules/.bin/node-pre-gyp package publish info --debug
fi
fi
diff --git a/platform/node/src/node_geojson.hpp b/platform/node/src/node_geojson.hpp
index ace4c91426..9bae86b76a 100644
--- a/platform/node/src/node_geojson.hpp
+++ b/platform/node/src/node_geojson.hpp
@@ -5,8 +5,9 @@ namespace style {
namespace conversion {
template <>
-Result<GeoJSON> convertGeoJSON(const v8::Local<v8::Value>&) {
- return Error { "not implemented" };
+optional<GeoJSON> Converter<GeoJSON>::operator()(const v8::Local<v8::Value>&, Error& error) const {
+ error = { "not implemented" };
+ return {};
}
} // namespace conversion
diff --git a/platform/node/src/node_map.cpp b/platform/node/src/node_map.cpp
index f6b672efee..7261b33740 100644
--- a/platform/node/src/node_map.cpp
+++ b/platform/node/src/node_map.cpp
@@ -9,17 +9,13 @@
#include <mbgl/style/conversion/source.hpp>
#include <mbgl/style/conversion/layer.hpp>
#include <mbgl/style/conversion/filter.hpp>
-#include <mbgl/sprite/sprite_image.cpp>
+#include <mbgl/style/image.hpp>
+#include <mbgl/map/backend_scope.hpp>
#include <mbgl/map/query.hpp>
+#include <mbgl/util/premultiply.hpp>
#include <unistd.h>
-#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
-#define UV_ASYNC_PARAMS(handle) uv_async_t *handle, int
-#else
-#define UV_ASYNC_PARAMS(handle) uv_async_t *handle
-#endif
-
namespace node_mbgl {
struct NodeMap::RenderOptions {
@@ -45,6 +41,13 @@ static const char* releasedMessage() {
return "Map resources have already been released";
}
+NodeBackend::NodeBackend()
+ : HeadlessBackend(sharedDisplay()) {}
+
+void NodeBackend::onDidFailLoadingMap(std::exception_ptr error) {
+ std::rethrow_exception(error);
+}
+
void NodeMap::Init(v8::Local<v8::Object> target) {
v8::Local<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>(New);
@@ -55,13 +58,13 @@ void NodeMap::Init(v8::Local<v8::Object> target) {
Nan::SetPrototypeMethod(tpl, "loaded", Loaded);
Nan::SetPrototypeMethod(tpl, "render", Render);
Nan::SetPrototypeMethod(tpl, "release", Release);
+ Nan::SetPrototypeMethod(tpl, "cancel", Cancel);
- Nan::SetPrototypeMethod(tpl, "addClass", AddClass);
Nan::SetPrototypeMethod(tpl, "addSource", AddSource);
Nan::SetPrototypeMethod(tpl, "addLayer", AddLayer);
Nan::SetPrototypeMethod(tpl, "removeLayer", RemoveLayer);
Nan::SetPrototypeMethod(tpl, "addImage", AddImage);
- Nan::SetPrototypeMethod(tpl, "removeImage", RemoveLayer);
+ Nan::SetPrototypeMethod(tpl, "removeImage", RemoveImage);
Nan::SetPrototypeMethod(tpl, "setLayoutProperty", SetLayoutProperty);
Nan::SetPrototypeMethod(tpl, "setPaintProperty", SetPaintProperty);
Nan::SetPrototypeMethod(tpl, "setFilter", SetFilter);
@@ -274,7 +277,7 @@ NodeMap::RenderOptions NodeMap::ParseOptions(v8::Local<v8::Object> obj) {
const int length = classes->Length();
options.classes.reserve(length);
for (int i = 0; i < length; i++) {
- options.classes.push_back(std::string { *Nan::Utf8String(Nan::To<v8::String>(Nan::Get(classes, i).ToLocalChecked()).ToLocalChecked()) });
+ options.classes.emplace_back(std::string { *Nan::Utf8String(Nan::To<v8::String>(Nan::Get(classes, i).ToLocalChecked()).ToLocalChecked()) });
}
}
@@ -368,13 +371,10 @@ void NodeMap::startRender(NodeMap::RenderOptions options) {
static_cast<uint32_t>(options.height * pixelRatio) };
if (!view || view->getSize() != fbSize) {
view.reset();
+ mbgl::BackendScope scope { backend };
view = std::make_unique<mbgl::OffscreenView>(backend.getContext(), fbSize);
}
- if (map->getClasses() != options.classes) {
- map->setClasses(options.classes);
- }
-
if (map->getZoom() != options.zoom) {
map->setZoom(options.zoom);
}
@@ -505,16 +505,20 @@ void NodeMap::release() {
map.reset();
}
-void NodeMap::AddClass(const Nan::FunctionCallbackInfo<v8::Value>& info) {
+/**
+ * Cancel an ongoing render request. The callback will be called with
+ * the error set to "Canceled". Will throw if no rendering is in progress.
+ * @name cancel
+ * @returns {undefined}
+ */
+void NodeMap::Cancel(const Nan::FunctionCallbackInfo<v8::Value>& info) {
auto nodeMap = Nan::ObjectWrap::Unwrap<NodeMap>(info.Holder());
- if (!nodeMap->map) return Nan::ThrowError(releasedMessage());
- if (info.Length() <= 0 || !info[0]->IsString()) {
- return Nan::ThrowTypeError("First argument must be a string");
- }
+ if (!nodeMap->map) return Nan::ThrowError(releasedMessage());
+ if (!nodeMap->callback) return Nan::ThrowError("No render in progress");
try {
- nodeMap->map->addClass(*Nan::Utf8String(info[0]));
+ nodeMap->cancel();
} catch (const std::exception &ex) {
return Nan::ThrowError(ex.what());
}
@@ -522,6 +526,21 @@ void NodeMap::AddClass(const Nan::FunctionCallbackInfo<v8::Value>& info) {
info.GetReturnValue().SetUndefined();
}
+void NodeMap::cancel() {
+ auto style = map->getStyleJSON();
+
+ map = std::make_unique<mbgl::Map>(backend, mbgl::Size{ 256, 256 },
+ pixelRatio, *this, threadpool, mbgl::MapMode::Still);
+
+ // FIXME: Reload the style after recreating the map. We need to find
+ // a better way of canceling an ongoing rendering on the core level
+ // without resetting the map, which is way too expensive.
+ map->setStyleJSON(style);
+
+ error = std::make_exception_ptr(std::runtime_error("Canceled"));
+ renderFinished();
+}
+
void NodeMap::AddSource(const Nan::FunctionCallbackInfo<v8::Value>& info) {
using namespace mbgl::style;
using namespace mbgl::style::conversion;
@@ -537,9 +556,10 @@ void NodeMap::AddSource(const Nan::FunctionCallbackInfo<v8::Value>& info) {
return Nan::ThrowTypeError("First argument must be a string");
}
- Result<std::unique_ptr<Source>> source = convert<std::unique_ptr<Source>>(info[1], *Nan::Utf8String(info[0]));
+ Error error;
+ mbgl::optional<std::unique_ptr<Source>> source = convert<std::unique_ptr<Source>>(info[1], error, *Nan::Utf8String(info[0]));
if (!source) {
- Nan::ThrowTypeError(source.error().message.c_str());
+ Nan::ThrowTypeError(error.message.c_str());
return;
}
@@ -557,9 +577,10 @@ void NodeMap::AddLayer(const Nan::FunctionCallbackInfo<v8::Value>& info) {
return Nan::ThrowTypeError("One argument required");
}
- Result<std::unique_ptr<Layer>> layer = convert<std::unique_ptr<Layer>>(info[0]);
+ Error error;
+ mbgl::optional<std::unique_ptr<Layer>> layer = convert<std::unique_ptr<Layer>>(info[0], error);
if (!layer) {
- Nan::ThrowTypeError(layer.error().message.c_str());
+ Nan::ThrowTypeError(error.message.c_str());
return;
}
@@ -630,16 +651,20 @@ void NodeMap::AddImage(const Nan::FunctionCallbackInfo<v8::Value>& info) {
uint32_t pixelRatio = Nan::Get(optionObject, Nan::New("pixelRatio").ToLocalChecked()).ToLocalChecked()->Uint32Value();
auto imageBuffer = Nan::To<v8::Object>(info[1]).ToLocalChecked()->ToObject();
+
+ char * imageDataBuffer = node::Buffer::Data(imageBuffer);
+ size_t imageLength = node::Buffer::Length(imageBuffer);
- if (node::Buffer::Length(imageBuffer) != imageHeight * imageWidth * 4) {
+ if (imageLength != imageHeight * imageWidth * 4) {
return Nan::ThrowTypeError("Image size does not match buffer size");
}
- std::unique_ptr<uint8_t[]> data = std::make_unique<uint8_t[]>(node::Buffer::Length(imageBuffer));
- std::copy(node::Buffer::Data(imageBuffer), node::Buffer::Data(imageBuffer) + node::Buffer::Length(imageBuffer), data.get());
- mbgl::PremultipliedImage cPremultipliedImage({ imageWidth, imageHeight}, std::move(data));
-
- nodeMap->map->addImage(*Nan::Utf8String(info[0]), std::make_unique<mbgl::SpriteImage>(std::move(cPremultipliedImage), pixelRatio));
+ std::unique_ptr<uint8_t[]> data = std::make_unique<uint8_t[]>(imageLength);
+ std::copy(imageDataBuffer, imageDataBuffer + imageLength, data.get());
+
+ mbgl::UnassociatedImage cImage({ imageWidth, imageHeight}, std::move(data));
+ mbgl::PremultipliedImage cPremultipliedImage = mbgl::util::premultiply(std::move(cImage));
+ nodeMap->map->addImage(std::make_unique<mbgl::style::Image>(*Nan::Utf8String(info[0]), std::move(cPremultipliedImage), pixelRatio));
}
void NodeMap::RemoveImage(const Nan::FunctionCallbackInfo<v8::Value>& info) {
@@ -716,12 +741,7 @@ void NodeMap::SetPaintProperty(const Nan::FunctionCallbackInfo<v8::Value>& info)
return Nan::ThrowTypeError("Second argument must be a string");
}
- mbgl::optional<std::string> klass;
- if (info.Length() == 4 && info[3]->IsString()) {
- klass = std::string(*Nan::Utf8String(info[3]));
- }
-
- mbgl::optional<Error> error = setPaintProperty(*layer, *Nan::Utf8String(info[1]), info[2], klass);
+ mbgl::optional<Error> error = setPaintProperty(*layer, *Nan::Utf8String(info[1]), info[2]);
if (error) {
return Nan::ThrowTypeError(error->message.c_str());
}
@@ -773,9 +793,10 @@ void NodeMap::SetFilter(const Nan::FunctionCallbackInfo<v8::Value>& info) {
Filter filter;
if (!info[1]->IsNull() && !info[1]->IsUndefined()) {
- Result<Filter> converted = convert<Filter>(info[1]);
+ Error error;
+ mbgl::optional<Filter> converted = convert<Filter>(info[1], error);
if (!converted) {
- Nan::ThrowTypeError(converted.error().message.c_str());
+ Nan::ThrowTypeError(error.message.c_str());
return;
}
filter = std::move(*converted);
@@ -899,7 +920,7 @@ void NodeMap::QueryRenderedFeatures(const Nan::FunctionCallbackInfo<v8::Value>&
auto layers = layersOption.As<v8::Array>();
std::vector<std::string> layersVec;
for (uint32_t i=0; i < layers->Length(); i++) {
- layersVec.push_back(*Nan::Utf8String(Nan::Get(layers,i).ToLocalChecked()));
+ layersVec.emplace_back(*Nan::Utf8String(Nan::Get(layers,i).ToLocalChecked()));
}
queryOptions.layerIDs = layersVec;
}
@@ -907,23 +928,24 @@ void NodeMap::QueryRenderedFeatures(const Nan::FunctionCallbackInfo<v8::Value>&
//Check if filter is provided. If set it must be a valid Filter object
if (Nan::Has(options, Nan::New("filter").ToLocalChecked()).FromJust()) {
auto filterOption = Nan::Get(options, Nan::New("filter").ToLocalChecked()).ToLocalChecked();
- Result<Filter> converted = convert<Filter>(filterOption);
+ Error error;
+ mbgl::optional<Filter> converted = convert<Filter>(filterOption, error);
if (!converted) {
- return Nan::ThrowTypeError(converted.error().message.c_str());
+ return Nan::ThrowTypeError(error.message.c_str());
}
queryOptions.filter = std::move(*converted);
}
}
try {
- std::vector<mbgl::Feature> result;
+ std::vector<mbgl::Feature> optional;
if (Nan::Get(posOrBox, 0).ToLocalChecked()->IsArray()) {
auto pos0 = Nan::Get(posOrBox, 0).ToLocalChecked().As<v8::Array>();
auto pos1 = Nan::Get(posOrBox, 1).ToLocalChecked().As<v8::Array>();
- result = nodeMap->map->queryRenderedFeatures(mbgl::ScreenBox {
+ optional = nodeMap->map->queryRenderedFeatures(mbgl::ScreenBox {
{
Nan::Get(pos0, 0).ToLocalChecked()->NumberValue(),
Nan::Get(pos0, 1).ToLocalChecked()->NumberValue()
@@ -934,15 +956,15 @@ void NodeMap::QueryRenderedFeatures(const Nan::FunctionCallbackInfo<v8::Value>&
}, queryOptions);
} else {
- result = nodeMap->map->queryRenderedFeatures(mbgl::ScreenCoordinate {
+ optional = nodeMap->map->queryRenderedFeatures(mbgl::ScreenCoordinate {
Nan::Get(posOrBox, 0).ToLocalChecked()->NumberValue(),
Nan::Get(posOrBox, 1).ToLocalChecked()->NumberValue()
}, queryOptions);
}
auto array = Nan::New<v8::Array>();
- for (unsigned int i = 0; i < result.size(); i++) {
- array->Set(i, toJS(result[i]));
+ for (unsigned int i = 0; i < optional.size(); i++) {
+ array->Set(i, toJS(optional[i]));
}
info.GetReturnValue().Set(array);
} catch (const std::exception &ex) {
@@ -959,7 +981,6 @@ NodeMap::NodeMap(v8::Local<v8::Object> options)
->NumberValue()
: 1.0;
}()),
- backend(sharedDisplay()),
map(std::make_unique<mbgl::Map>(backend,
mbgl::Size{ 256, 256 },
pixelRatio,
@@ -968,14 +989,8 @@ NodeMap::NodeMap(v8::Local<v8::Object> options)
mbgl::MapMode::Still)),
async(new uv_async_t) {
- backend.setMapChangeCallback([&](mbgl::MapChange change) {
- if (change == mbgl::MapChangeDidFailLoadingMap) {
- throw std::runtime_error("Requires a map style to be a valid style JSON");
- }
- });
-
async->data = this;
- uv_async_init(uv_default_loop(), async, [](UV_ASYNC_PARAMS(h)) {
+ uv_async_init(uv_default_loop(), async, [](uv_async_t* h) {
reinterpret_cast<NodeMap *>(h->data)->renderFinished();
});
diff --git a/platform/node/src/node_map.hpp b/platform/node/src/node_map.hpp
index 47a5385ad6..7b81ecd894 100644
--- a/platform/node/src/node_map.hpp
+++ b/platform/node/src/node_map.hpp
@@ -7,6 +7,8 @@
#include <mbgl/gl/headless_backend.hpp>
#include <mbgl/gl/offscreen_view.hpp>
+#include <exception>
+
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wshadow"
@@ -15,6 +17,12 @@
namespace node_mbgl {
+class NodeBackend : public mbgl::HeadlessBackend {
+public:
+ NodeBackend();
+ void onDidFailLoadingMap(std::exception_ptr) final;
+};
+
class NodeMap : public Nan::ObjectWrap,
public mbgl::FileSource {
public:
@@ -33,7 +41,7 @@ public:
static void Loaded(const Nan::FunctionCallbackInfo<v8::Value>&);
static void Render(const Nan::FunctionCallbackInfo<v8::Value>&);
static void Release(const Nan::FunctionCallbackInfo<v8::Value>&);
- static void AddClass(const Nan::FunctionCallbackInfo<v8::Value>&);
+ static void Cancel(const Nan::FunctionCallbackInfo<v8::Value>&);
static void AddSource(const Nan::FunctionCallbackInfo<v8::Value>&);
static void AddLayer(const Nan::FunctionCallbackInfo<v8::Value>&);
static void RemoveLayer(const Nan::FunctionCallbackInfo<v8::Value>&);
@@ -53,13 +61,14 @@ public:
void renderFinished();
void release();
+ void cancel();
static RenderOptions ParseOptions(v8::Local<v8::Object>);
std::unique_ptr<mbgl::AsyncRequest> request(const mbgl::Resource&, mbgl::FileSource::Callback);
const float pixelRatio;
- mbgl::HeadlessBackend backend;
+ NodeBackend backend;
std::unique_ptr<mbgl::OffscreenView> view;
NodeThreadPool threadpool;
std::unique_ptr<mbgl::Map> map;
diff --git a/platform/node/src/node_request.cpp b/platform/node/src/node_request.cpp
index de16710f78..09373b1779 100644
--- a/platform/node/src/node_request.cpp
+++ b/platform/node/src/node_request.cpp
@@ -122,9 +122,19 @@ void NodeRequest::HandleCallback(const Nan::FunctionCallbackInfo<v8::Value>& inf
}
void NodeRequest::Execute() {
+ asyncExecute = std::make_unique<mbgl::util::AsyncTask>([this] { doExecute(); Unref(); });
+ asyncExecute->send();
+
+ Ref();
+}
+
+void NodeRequest::doExecute() {
+ Nan::HandleScope scope;
+
v8::Local<v8::Value> argv[] = { handle() };
Nan::MakeCallback(Nan::To<v8::Object>(target->handle()->GetInternalField(1)).ToLocalChecked(), "request", 1, argv);
+ asyncExecute.reset();
}
NodeRequest::NodeAsyncRequest::NodeAsyncRequest(NodeRequest* request_) : request(request_) {
diff --git a/platform/node/src/node_request.hpp b/platform/node/src/node_request.hpp
index 7d7679a3c7..356566132b 100644
--- a/platform/node/src/node_request.hpp
+++ b/platform/node/src/node_request.hpp
@@ -8,6 +8,9 @@
#include <mbgl/storage/resource.hpp>
#include <mbgl/storage/file_source.hpp>
+#include <mbgl/util/async_task.hpp>
+
+#include <memory>
namespace node_mbgl {
@@ -35,9 +38,12 @@ public:
void Execute();
private:
+ void doExecute();
+
NodeMap* target;
mbgl::FileSource::Callback callback;
NodeAsyncRequest* asyncRequest = nullptr;
+ std::unique_ptr<mbgl::util::AsyncTask> asyncExecute;
};
}
diff --git a/platform/node/src/util/async_queue.hpp b/platform/node/src/util/async_queue.hpp
index 87737437c3..a084b866ae 100644
--- a/platform/node/src/util/async_queue.hpp
+++ b/platform/node/src/util/async_queue.hpp
@@ -8,12 +8,6 @@
#include <queue>
#include <string>
-#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
-#define UV_ASYNC_PARAMS(handle) uv_async_t *handle, int
-#else
-#define UV_ASYNC_PARAMS(handle) uv_async_t *handle
-#endif
-
namespace node_mbgl {
namespace util {
@@ -23,7 +17,7 @@ public:
AsyncQueue(uv_loop_t *loop, std::function<void(T &)> fn) :
callback(fn) {
async.data = this;
- uv_async_init(loop, &async, [](UV_ASYNC_PARAMS(handle)) {
+ uv_async_init(loop, &async, [](uv_async_t* handle) {
auto q = reinterpret_cast<AsyncQueue *>(handle->data);
q->process();
});
diff --git a/platform/node/test/benchmark.js b/platform/node/test/benchmark.js
new file mode 100644
index 0000000000..50f6353bca
--- /dev/null
+++ b/platform/node/test/benchmark.js
@@ -0,0 +1,104 @@
+'use strict';
+
+var mockfs = require('./mockfs');
+var mbgl = require('../index');
+var test = require('tape');
+
+var firstRequest = "mapbox://sprites/mapbox/streets-v9@2x.json";
+
+var params = {
+ mapPoolSize: 10,
+ numRenderings: 1000,
+ failurePercentage: 10,
+ timeoutPercentage: 10,
+ renderingTimeout: 5000,
+ ratio: 2
+};
+
+test('Benchmark', function(t) {
+ console.time('Time');
+
+ var renderCount = 0;
+ var failureCount = 0;
+ var cancelCount = 0;
+
+ var options = {
+ request: function(req, callback) {
+ setTimeout(function() {
+ var num = Math.floor(Math.random() * 100);
+
+ if (req.url == firstRequest && num < params.failurePercentage) {
+ callback(new Error('Failure'));
+ } else if (req.url == firstRequest && num > 99 - params.timeoutPercentage) {
+ setTimeout(function() { callback(new Error('Timeout')); }, params.renderingTimeout * 5);
+ } else {
+ var data = mockfs.dataForRequest(req);
+ callback(null, { data: mockfs.dataForRequest(req) });
+ }
+ }, 0);
+ },
+ ratio: params.ratio,
+ };
+
+ var mapPool = []
+
+ for (var i = 0; i < params.mapPoolSize; ++i) {
+ var map = new mbgl.Map(options);
+ mapPool.push(map);
+ }
+
+ var interval = setInterval(function () {
+ if (mapPool.length == 0 || renderCount == params.numRenderings) {
+ return;
+ }
+
+ var map = mapPool.shift();
+
+ map.load('{ "version": 8, "sources": {}, "layers": [] }');
+ map.load(mockfs.style_vector);
+
+ renderCount += 1;
+
+ if (renderCount % (params.numRenderings / 100) == 0) {
+ // Print some progress, so slow build bots don't timeout.
+ t.comment('Rendering (' + renderCount.toString() +
+ '/' + params.numRenderings.toString() + ')');
+ }
+
+ if (renderCount == params.numRenderings) {
+ clearInterval(interval);
+ t.end();
+ console.timeEnd('Time');
+ console.log('Failures: ' + failureCount);
+ console.log('Canceled: ' + cancelCount);
+
+ return;
+ }
+
+ var mapTimeout = setTimeout(function() {
+ map.cancel();
+ }, params.renderingTimeout);
+
+ map.render({ zoom: 16 }, function(err, pixels) {
+ clearTimeout(mapTimeout);
+
+ if (err) {
+ if (err.message == 'Failure') {
+ failureCount += 1;
+ }
+
+ if (err.message == 'Canceled') {
+ cancelCount += 1;
+ }
+
+ // We cancel the request before it gets a
+ // timeout error from the file source.
+ if (err.message == 'Timeout') {
+ t.fail('should never happen');
+ }
+ }
+
+ mapPool.push(map);
+ });
+ }, 1);
+});
diff --git a/platform/node/test/js/cancel.test.js b/platform/node/test/js/cancel.test.js
new file mode 100644
index 0000000000..17525fb863
--- /dev/null
+++ b/platform/node/test/js/cancel.test.js
@@ -0,0 +1,116 @@
+'use strict';
+
+var mockfs = require('./../mockfs');
+var mbgl = require('../../index');
+var test = require('tape');
+
+var options = {
+ request: function(req, callback) {
+ callback(null, { data: mockfs.dataForRequest(req) });
+ },
+ ratio: 1,
+};
+
+test('Cancel', function(t) {
+ t.test('sanity', function(t) {
+ var renderCount = 0;
+ var cancelCount = 0;
+ var map = new mbgl.Map(options);
+
+ var renderCallback = function(err, pixels) {
+ if (err) {
+ cancelCount++;
+ } else {
+ renderCount++;
+ }
+ };
+
+ map.load(mockfs.style_vector);
+
+ map.render({ zoom: 16 }, renderCallback);
+ map.cancel();
+
+ map.render({ zoom: 16 }, renderCallback);
+ map.cancel();
+
+ map.render({ zoom: 16 }, renderCallback);
+ map.cancel();
+
+ t.equal(renderCount, 0);
+ t.equal(cancelCount, 3);
+
+ t.end();
+ });
+
+ t.test('render after cancel', function(t) {
+ var map = new mbgl.Map(options);
+ var renderCallback = function(err, pixels) { if (!err) t.end(); };
+
+ map.load(mockfs.style_vector);
+
+ map.render({ zoom: 16 }, renderCallback);
+ map.cancel();
+
+ map.render({ zoom: 16 }, renderCallback);
+ });
+
+ t.test('cancel after cancel', function(t) {
+ var cancelCount = 0;
+ var map = new mbgl.Map(options);
+
+ map.load(mockfs.style_vector);
+ map.render({ zoom: 16 }, function(err, pixels) {
+ cancelCount++;
+ });
+
+ map.cancel();
+
+ t.throws(function() {
+ map.cancel();
+ }, 'already canceled');
+
+ t.equal(cancelCount, 1);
+
+ t.end();
+ });
+
+ t.test('cancel without rendering', function(t) {
+ var cancelCount = 0;
+ var map = new mbgl.Map(options);
+
+ map.load(mockfs.style_vector);
+
+ t.throws(function() {
+ map.cancel();
+ }, 'nothing to cancel');
+
+ t.end();
+ });
+
+ t.test('release after cancel', function(t) {
+ var map = new mbgl.Map(options);
+
+ map.load(mockfs.style_vector);
+ map.render({ zoom: 16 }, function(err, pixels) {});
+
+ map.cancel();
+ map.release();
+
+ t.end();
+ });
+
+ t.test('cancel after release', function(t) {
+ var map = new mbgl.Map(options);
+
+ map.load(mockfs.style_vector);
+ map.render({ zoom: 16 }, function(err, pixels) {});
+
+ map.release();
+
+ t.throws(function() {
+ map.cancel();
+ }, 'map resources already released');
+
+ t.end();
+ });
+})
diff --git a/platform/node/test/js/map.test.js b/platform/node/test/js/map.test.js
index 145f62ef5f..04d02d0558 100644
--- a/platform/node/test/js/map.test.js
+++ b/platform/node/test/js/map.test.js
@@ -107,7 +107,7 @@ test('Map', function(t) {
'loaded',
'render',
'release',
- 'addClass',
+ 'cancel',
'addSource',
'addLayer',
'removeLayer',
@@ -311,11 +311,11 @@ test('Map', function(t) {
t.throws(function() {
map.load('foo bar');
- }, /Requires a map style to be a valid style JSON/);
+ }, /Failed to parse style: 1 - Invalid value./);
t.throws(function() {
map.load('""');
- }, /Requires a map style to be a valid style JSON/);
+ }, /Failed to parse style: style must be an object/);
map.release();
t.end();
@@ -335,7 +335,7 @@ test('Map', function(t) {
t.throws(function() {
map.load('invalid');
- }, /Requires a map style to be a valid style JSON/);
+ }, /Failed to parse style: 0 - Invalid value./);
});
t.test('accepts an empty stylesheet string', function(t) {
diff --git a/platform/node/test/js/request_fail.test.js b/platform/node/test/js/request_fail.test.js
new file mode 100644
index 0000000000..fad116a2b8
--- /dev/null
+++ b/platform/node/test/js/request_fail.test.js
@@ -0,0 +1,59 @@
+'use strict';
+
+var mockfs = require('../mockfs');
+var mbgl = require('../../index');
+var test = require('tape');
+
+function asyncReply(callback, data) {
+ setTimeout(function() { callback(null, { data: data }); }, 0);
+};
+
+function asyncFail(callback) {
+ setTimeout(function() { callback(new Error('not found')); }, 0);
+};
+
+function failRequest(t, style, failedResource) {
+ var options = {
+ request: function(req, callback) {
+ var data = mockfs.dataForRequest(req);
+
+ if (failedResource != data) {
+ asyncReply(callback, data);
+ } else {
+ asyncFail(callback);
+ }
+ },
+ ratio: 2,
+ };
+
+ var map = new mbgl.Map(options);
+ map.load(style);
+
+ map.render({ zoom: 16 }, function(err, pixels) {
+ if (err) {
+ t.pass("pass");
+ map.release();
+ }
+ });
+};
+
+test('Vector', function(t) {
+ t.plan(5);
+
+ failRequest(t, mockfs.style_vector, null);
+ failRequest(t, mockfs.style_vector, mockfs.sprite_png);
+ failRequest(t, mockfs.style_vector, mockfs.sprite_json);
+ failRequest(t, mockfs.style_vector, mockfs.source_vector);
+ failRequest(t, mockfs.style_vector, mockfs.tile_vector);
+ failRequest(t, mockfs.style_vector, mockfs.glyph);
+});
+
+test('Raster', function(t) {
+ t.plan(4);
+
+ failRequest(t, mockfs.style_raster, null);
+ failRequest(t, mockfs.style_raster, mockfs.sprite_png);
+ failRequest(t, mockfs.style_raster, mockfs.sprite_json);
+ failRequest(t, mockfs.style_raster, mockfs.source_raster);
+ failRequest(t, mockfs.style_raster, mockfs.tile_raster);
+});
diff --git a/platform/node/test/js/request_notfound.test.js b/platform/node/test/js/request_notfound.test.js
new file mode 100644
index 0000000000..d2d2812784
--- /dev/null
+++ b/platform/node/test/js/request_notfound.test.js
@@ -0,0 +1,74 @@
+'use strict';
+
+var mockfs = require('../mockfs');
+var mbgl = require('../../index');
+var test = require('tape');
+
+function isTile(data) {
+ return data == mockfs.tile_vector || data == mockfs.tile_raster;
+}
+
+function asyncReply(callback, data) {
+ setTimeout(function() { callback(null, { data: data }); }, 0);
+};
+
+function asyncFail(callback, data) {
+ // Do not set an error for tile when not found. A not found
+ // tile is a valid tile.
+ if (isTile(data)) {
+ setTimeout(function() { callback(); }, 0);
+ } else {
+ setTimeout(function() { callback(new Error('not found')); }, 0);
+ }
+};
+
+function notfoundRequest(t, style, notfoundResource) {
+ var options = {
+ request: function(req, callback) {
+ var data = mockfs.dataForRequest(req);
+
+ if (notfoundResource != data) {
+ asyncReply(callback, data);
+ } else {
+ asyncFail(callback, data);
+ }
+ },
+ ratio: 2,
+ };
+
+ var map = new mbgl.Map(options);
+ map.load(style);
+
+ map.render({ zoom: 16 }, function(err, pixels) {
+ if (err && !isTile(notfoundResource)) {
+ t.pass("pass");
+ return;
+ }
+
+ if (!err && isTile(notfoundResource)) {
+ t.pass("pass");
+ return;
+ }
+
+ t.fail("fail");
+ });
+};
+
+test('Vector', function(t) {
+ t.plan(5);
+
+ notfoundRequest(t, mockfs.style_vector, mockfs.sprite_png);
+ notfoundRequest(t, mockfs.style_vector, mockfs.sprite_json);
+ notfoundRequest(t, mockfs.style_vector, mockfs.source_vector);
+ notfoundRequest(t, mockfs.style_vector, mockfs.tile_vector);
+ notfoundRequest(t, mockfs.style_vector, mockfs.glyph);
+});
+
+test('Raster', function(t) {
+ t.plan(4);
+
+ notfoundRequest(t, mockfs.style_raster, mockfs.sprite_png);
+ notfoundRequest(t, mockfs.style_raster, mockfs.sprite_json);
+ notfoundRequest(t, mockfs.style_raster, mockfs.source_raster);
+ notfoundRequest(t, mockfs.style_raster, mockfs.tile_raster);
+});
diff --git a/platform/node/test/memory.test.js b/platform/node/test/memory.test.js
index e23cb60f89..997ccdbbe1 100644
--- a/platform/node/test/memory.test.js
+++ b/platform/node/test/memory.test.js
@@ -1,8 +1,7 @@
'use strict';
-var fs = require('fs');
+var mockfs = require('./mockfs');
var mbgl = require('../index');
-var path = require('path');
var test = require('tape');
var testParams = {
@@ -12,20 +11,6 @@ var testParams = {
ratio: 2
};
-function readFixture(file) {
- return fs.readFileSync(path.join('test/fixtures/resources', file));
-}
-
-var style_raster = readFixture('style_raster.json').toString('utf8');
-var style_vector = readFixture('style_vector.json').toString('utf8');
-var sprite_json = readFixture('sprite.json');
-var sprite_png = readFixture('sprite.png');
-var glyph = readFixture('glyphs.pbf');
-var source_raster = readFixture('source_raster.json');
-var source_vector = readFixture('source_vector.json');
-var tile_raster = readFixture('raster.tile');
-var tile_vector = readFixture('vector.tile');
-
test('Memory', function(t) {
// Trigger garbage collection before starting test, then initialize
// heap size
@@ -34,25 +19,7 @@ test('Memory', function(t) {
var options = {
request: function(req, callback) {
- if (req.url == null) {
- t.fail('invalid file request');
- } else if (req.url.indexOf('sprite') > -1 && req.url.endsWith('json')) {
- callback(null, { data: sprite_json });
- } else if (req.url.indexOf('sprite') > -1 && req.url.endsWith('png')) {
- callback(null, { data: sprite_png });
- } else if (req.url.indexOf('fonts') > -1 && req.url.endsWith('pbf')) {
- callback(null, { data: glyph });
- } else if (req.url.endsWith('mapbox.satellite')) {
- callback(null, { data: source_raster });
- } else if (req.url.indexOf('satellite') > -1 && (req.url.endsWith('png') || req.url.endsWith('webp'))) {
- callback(null, { data: tile_raster });
- } else if (req.url.endsWith('mapbox.mapbox-streets-v7')) {
- callback(null, { data: source_vector });
- } else if (req.url.indexOf('streets') > -1 && req.url.endsWith('pbf')) {
- callback(null, { data: tile_vector });
- } else {
- t.fail('unhandled file request: ' + req.url);
- }
+ callback(null, { data: mockfs.dataForRequest(req) });
},
ratio: testParams.ratio,
};
@@ -75,9 +42,9 @@ test('Memory', function(t) {
var map = mapPool.shift();
if (Math.floor(Math.random() * 2)) {
- map.load(style_raster);
+ map.load(mockfs.style_raster);
} else {
- map.load(style_vector);
+ map.load(mockfs.style_vector);
}
map.render({ zoom: 16 }, function(err, pixels) {
diff --git a/platform/node/test/mockfs.js b/platform/node/test/mockfs.js
new file mode 100644
index 0000000000..dfa5a425e3
--- /dev/null
+++ b/platform/node/test/mockfs.js
@@ -0,0 +1,53 @@
+"use strict";
+
+var fs = require('fs');
+var path = require('path');
+
+function readFixture(file) {
+ return fs.readFileSync(path.join('test/fixtures/resources', file));
+};
+
+var style_raster = readFixture('style_raster.json').toString('utf8');
+var style_vector = readFixture('style_vector.json').toString('utf8');
+var sprite_json = readFixture('sprite.json');
+var sprite_png = readFixture('sprite.png');
+var glyph = readFixture('glyphs.pbf');
+var source_raster = readFixture('source_raster.json');
+var source_vector = readFixture('source_vector.json');
+var tile_raster = readFixture('raster.tile');
+var tile_vector = readFixture('vector.tile');
+
+function dataForRequest(req) {
+ if (req.url == null) {
+ return null;
+ } else if (req.url.indexOf('sprite') > -1 && req.url.endsWith('json')) {
+ return sprite_json;
+ } else if (req.url.indexOf('sprite') > -1 && req.url.endsWith('png')) {
+ return sprite_png;
+ } else if (req.url.indexOf('fonts') > -1 && req.url.endsWith('pbf')) {
+ return glyph;
+ } else if (req.url.endsWith('mapbox.satellite')) {
+ return source_raster;
+ } else if (req.url.indexOf('satellite') > -1 && (req.url.endsWith('png') || req.url.endsWith('webp'))) {
+ return tile_raster;
+ } else if (req.url.endsWith('mapbox.mapbox-streets-v7')) {
+ return source_vector;
+ } else if (req.url.indexOf('streets') > -1 && req.url.endsWith('pbf')) {
+ return tile_vector;
+ } else {
+ return null;
+ }
+};
+
+module.exports = {
+ dataForRequest: dataForRequest,
+ style_raster: style_raster,
+ style_vector: style_vector,
+ sprite_json: sprite_json,
+ sprite_png: sprite_png,
+ glyph: glyph,
+ source_raster: source_raster,
+ source_vector: source_vector,
+ tile_raster: tile_raster,
+ tile_vector: tile_vector
+};
diff --git a/platform/node/test/suite_implementation.js b/platform/node/test/suite_implementation.js
index ef97652893..8ac372b7c3 100644
--- a/platform/node/test/suite_implementation.js
+++ b/platform/node/test/suite_implementation.js
@@ -17,6 +17,8 @@ module.exports = function (style, options, callback) {
request(req.url, {encoding: null}, function (err, response, body) {
if (err) {
callback(err);
+ } else if (response.statusCode == 404) {
+ callback();
} else if (response.statusCode != 200) {
callback(new Error(response.statusMessage));
} else {
@@ -74,7 +76,7 @@ module.exports = function (style, options, callback) {
map.addImage(operation[1], img.data, {
height: img.height,
width: img.width,
- pixelRatio: 1
+ pixelRatio: operation[3] || 1
});
applyOperations(operations.slice(1), callback);
diff --git a/platform/qt/app/mapwindow.cpp b/platform/qt/app/mapwindow.cpp
index e29e62f157..03ca052ec4 100644
--- a/platform/qt/app/mapwindow.cpp
+++ b/platform/qt/app/mapwindow.cpp
@@ -79,8 +79,6 @@ void MapWindow::changeStyle()
void MapWindow::keyPressEvent(QKeyEvent *ev)
{
- static const qint64 transitionDuration = 300;
-
switch (ev->key()) {
case Qt::Key_S:
changeStyle();
@@ -92,6 +90,9 @@ void MapWindow::keyPressEvent(QKeyEvent *ev)
m_sourceAdded = true;
+ // Not in all styles, but will work on streets
+ QString before = "waterway-label";
+
QFile geojson(":source1.geojson");
geojson.open(QIODevice::ReadOnly);
@@ -106,7 +107,7 @@ void MapWindow::keyPressEvent(QKeyEvent *ev)
routeCase["id"] = "routeCase";
routeCase["type"] = "line";
routeCase["source"] = "routeSource";
- m_map->addLayer(routeCase);
+ m_map->addLayer(routeCase, before);
m_map->setPaintProperty("routeCase", "line-color", QColor("white"));
m_map->setPaintProperty("routeCase", "line-width", 20.0);
@@ -118,7 +119,7 @@ void MapWindow::keyPressEvent(QKeyEvent *ev)
route["id"] = "route";
route["type"] = "line";
route["source"] = "routeSource";
- m_map->addLayer(route);
+ m_map->addLayer(route, before);
m_map->setPaintProperty("route", "line-color", QColor("blue"));
m_map->setPaintProperty("route", "line-width", 8.0);
@@ -201,6 +202,40 @@ void MapWindow::keyPressEvent(QKeyEvent *ev)
m_map->setLayoutProperty("road-label-small", "text-pitch-alignment", "viewport");
m_map->setLayoutProperty("road-label-small", "text-size", 30.0);
+
+ // Buildings extrusion
+ QVariantMap buildings;
+ buildings["id"] = "3d-buildings";
+ buildings["source"] = "composite";
+ buildings["source-layer"] = "building";
+ buildings["type"] = "fill-extrusion";
+ buildings["minzoom"] = 15.0;
+ m_map->addLayer(buildings);
+
+ QVariantList buildingsFilterExpression;
+ buildingsFilterExpression.append("==");
+ buildingsFilterExpression.append("extrude");
+ buildingsFilterExpression.append("true");
+
+ QVariantList buildingsFilter;
+ buildingsFilter.append(buildingsFilterExpression);
+
+ m_map->setFilter("3d-buildings", buildingsFilterExpression);
+
+ m_map->setPaintProperty("3d-buildings", "fill-extrusion-color", "#aaa");
+ m_map->setPaintProperty("3d-buildings", "fill-extrusion-opacity", .6);
+
+ QVariantMap extrusionHeight;
+ extrusionHeight["type"] = "identity";
+ extrusionHeight["property"] = "height";
+
+ m_map->setPaintProperty("3d-buildings", "fill-extrusion-height", extrusionHeight);
+
+ QVariantMap extrusionBase;
+ extrusionBase["type"] = "identity";
+ extrusionBase["property"] = "min_height";
+
+ m_map->setPaintProperty("3d-buildings", "fill-extrusion-base", extrusionBase);
}
break;
case Qt::Key_1: {
@@ -243,21 +278,6 @@ void MapWindow::keyPressEvent(QKeyEvent *ev)
}
}
break;
- case Qt::Key_4: {
- if (m_styleSourcedAnnotationId.isNull()) {
- QMapbox::Coordinate topLeft = m_map->coordinateForPixel({ 0, 0 });
- QMapbox::Coordinate topRight = m_map->coordinateForPixel({ 0, qreal(size().height()) });
- QMapbox::Coordinate bottomLeft = m_map->coordinateForPixel({ qreal(size().width()), 0 });
- QMapbox::Coordinate bottomRight = m_map->coordinateForPixel({ qreal(size().width()), qreal(size().height()) });
- QMapbox::CoordinatesCollections geometry { { { bottomLeft, bottomRight, topRight, topLeft, bottomLeft } } };
- QMapbox::StyleSourcedAnnotation styleSourced { { QMapbox::ShapeAnnotationGeometry::PolygonType, geometry }, "water" };
- m_styleSourcedAnnotationId = m_map->addAnnotation(QVariant::fromValue<QMapbox::StyleSourcedAnnotation>(styleSourced));
- } else {
- m_map->removeAnnotation(m_styleSourcedAnnotationId.toUInt());
- m_styleSourcedAnnotationId.clear();
- }
- }
- break;
case Qt::Key_5: {
if (m_map->layerExists("circleLayer")) {
m_map->removeLayer("circleLayer");
@@ -285,14 +305,6 @@ void MapWindow::keyPressEvent(QKeyEvent *ev)
case Qt::Key_Tab:
m_map->cycleDebugOptions();
break;
- case Qt::Key_R: {
- m_map->setTransitionOptions(transitionDuration);
- if (m_map->hasClass("night")) {
- m_map->removeClass("night");
- } else {
- m_map->addClass("night");
- }
- } break;
default:
break;
}
@@ -372,8 +384,6 @@ void MapWindow::wheelEvent(QWheelEvent *ev)
void MapWindow::initializeGL()
{
- QMapbox::initializeGLExtensions();
-
m_map.reset(new QMapboxGL(nullptr, m_settings, size(), pixelRatio()));
connect(m_map.data(), SIGNAL(needsRendering()), this, SLOT(update()));
@@ -399,5 +409,9 @@ void MapWindow::paintGL()
{
m_frameDraws++;
m_map->resize(size(), size() * pixelRatio());
+#if QT_VERSION >= 0x050400
+ // When we're using QOpenGLWidget, we need to tell Mapbox GL about the framebuffer we're using.
+ m_map->setFramebufferObject(defaultFramebufferObject());
+#endif
m_map->render();
}
diff --git a/platform/qt/app/mapwindow.hpp b/platform/qt/app/mapwindow.hpp
index 6b4b7fd1cc..c484114ec0 100644
--- a/platform/qt/app/mapwindow.hpp
+++ b/platform/qt/app/mapwindow.hpp
@@ -64,7 +64,6 @@ private:
QVariant m_symbolAnnotationId;
QVariant m_lineAnnotationId;
QVariant m_fillAnnotationId;
- QVariant m_styleSourcedAnnotationId;
bool m_sourceAdded = false;
};
diff --git a/platform/qt/bitrise-qt4.yml b/platform/qt/bitrise-qt4.yml
index 8b327d0974..d8c7e0788e 100644
--- a/platform/qt/bitrise-qt4.yml
+++ b/platform/qt/bitrise-qt4.yml
@@ -9,22 +9,7 @@ workflows:
primary:
steps:
- script:
- title: Check for skipping CI
- inputs:
- - content: |-
- #!/bin/bash
-
- if [[ -n "$(echo $GIT_CLONE_COMMIT_MESSAGE_SUBJECT | sed -n '/\[skip ci\]/p')" ||
- -n "$(echo $GIT_CLONE_COMMIT_MESSAGE_SUBJECT | sed -n '/\[ci skip\]/p')" ||
- -n "$(echo $GIT_CLONE_COMMIT_MESSAGE_BODY | sed -n 's/\[skip ci\]/p')" ||
- -n "$(echo $GIT_CLONE_COMMIT_MESSAGE_BODY | sed -n 's/\[ci skip\]/p')" ]]; then
- envman add --key SKIPCI --value true
- else
- envman add --key SKIPCI --value false
- fi
- - script:
title: Run build
- run_if: '{{enveq "SKIPCI" "false"}}'
inputs:
- content: |-
#!/bin/bash
@@ -34,13 +19,11 @@ workflows:
brew link qt
brew linkapps qt
export BUILDTYPE=Debug
- export WITH_QT_4=1
make qt-app
make run-qt-test
- is_debug: 'yes'
- slack:
title: Post to Slack
- run_if: '{{enveq "SKIPCI" "false"}}'
inputs:
- webhook_url: "$SLACK_HOOK_URL"
- channel: "#gl-bots"
diff --git a/platform/qt/bitrise-qt5.yml b/platform/qt/bitrise-qt5.yml
index d9b7d4bc69..0ce964e43f 100644
--- a/platform/qt/bitrise-qt5.yml
+++ b/platform/qt/bitrise-qt5.yml
@@ -9,22 +9,7 @@ workflows:
primary:
steps:
- script:
- title: Check for skipping CI
- inputs:
- - content: |-
- #!/bin/bash
-
- if [[ -n "$(echo $GIT_CLONE_COMMIT_MESSAGE_SUBJECT | sed -n '/\[skip ci\]/p')" ||
- -n "$(echo $GIT_CLONE_COMMIT_MESSAGE_SUBJECT | sed -n '/\[ci skip\]/p')" ||
- -n "$(echo $GIT_CLONE_COMMIT_MESSAGE_BODY | sed -n 's/\[skip ci\]/p')" ||
- -n "$(echo $GIT_CLONE_COMMIT_MESSAGE_BODY | sed -n 's/\[ci skip\]/p')" ]]; then
- envman add --key SKIPCI --value true
- else
- envman add --key SKIPCI --value false
- fi
- - script:
title: Run build
- run_if: '{{enveq "SKIPCI" "false"}}'
inputs:
- content: |-
#!/bin/bash
@@ -34,23 +19,22 @@ workflows:
brew install qt
brew link qt --force
brew linkapps qt
+ export HOMEBREW_QT5_CELLAR=$(brew --cellar qt)
export HOMEBREW_QT5_VERSION=$(brew list --versions qt | rev | cut -d' ' -f1 | rev)
- ln -s /usr/local/Cellar/qt/$HOMEBREW_QT5_VERSION/mkspecs /usr/local/mkspecs
- ln -s /usr/local/Cellar/qt/$HOMEBREW_QT5_VERSION/plugins /usr/local/plugins
+ ln -s $HOMEBREW_QT5_CELLAR/$HOMEBREW_QT5_VERSION/mkspecs /usr/local/mkspecs
+ ln -s $HOMEBREW_QT5_CELLAR/$HOMEBREW_QT5_VERSION/plugins /usr/local/plugins
export BUILDTYPE=Debug
make qt-app
make run-qt-test
- is_debug: 'yes'
- deploy-to-bitrise-io:
title: Deploy to Bitrise.io
- run_if: '{{enveq "SKIPCI" "false"}}'
inputs:
- deploy_path: "test/fixtures"
- notify_user_groups: none
- is_compress: 'true'
- slack:
title: Post to Slack
- run_if: '{{enveq "SKIPCI" "false"}}'
inputs:
- webhook_url: "$SLACK_HOOK_URL"
- channel: "#gl-bots"
diff --git a/platform/qt/include/qmapbox.hpp b/platform/qt/include/qmapbox.hpp
index f2d96412a9..1b61d3270f 100644
--- a/platform/qt/include/qmapbox.hpp
+++ b/platform/qt/include/qmapbox.hpp
@@ -62,11 +62,6 @@ struct Q_DECL_EXPORT FillAnnotation {
QVariant outlineColor;
};
-struct Q_DECL_EXPORT StyleSourcedAnnotation {
- ShapeAnnotationGeometry geometry;
- QString layerID;
-};
-
typedef QVariant Annotation;
typedef quint32 AnnotationID;
typedef QList<AnnotationID> AnnotationIDs;
@@ -97,8 +92,6 @@ typedef void (*CustomLayerInitializeFunction)(void* context) ;
typedef void (*CustomLayerRenderFunction)(void* context, const CustomLayerRenderParameters&);
typedef void (*CustomLayerDeinitializeFunction)(void* context);
-Q_DECL_EXPORT void initializeGLExtensions();
-
} // namespace QMapbox
Q_DECLARE_METATYPE(QMapbox::Coordinate);
@@ -111,6 +104,5 @@ Q_DECLARE_METATYPE(QMapbox::SymbolAnnotation);
Q_DECLARE_METATYPE(QMapbox::ShapeAnnotationGeometry);
Q_DECLARE_METATYPE(QMapbox::LineAnnotation);
Q_DECLARE_METATYPE(QMapbox::FillAnnotation);
-Q_DECLARE_METATYPE(QMapbox::StyleSourcedAnnotation);
#endif // QMAPBOX_H
diff --git a/platform/qt/include/qmapboxgl.hpp b/platform/qt/include/qmapboxgl.hpp
index af7ed6275f..e2fb283989 100644
--- a/platform/qt/include/qmapboxgl.hpp
+++ b/platform/qt/include/qmapboxgl.hpp
@@ -94,7 +94,6 @@ class Q_DECL_EXPORT QMapboxGL : public QObject
Q_PROPERTY(QMargins margins READ margins WRITE setMargins)
public:
- // Reflects mbgl::MapChange.
enum MapChange {
MapChangeRegionWillChange = 0,
MapChangeRegionWillChangeAnimated,
@@ -169,12 +168,6 @@ public:
void setGestureInProgress(bool inProgress);
- void addClass(const QString &);
- void removeClass(const QString &);
- bool hasClass(const QString &) const;
- void setClasses(const QStringList &);
- QStringList getClasses() const;
-
void setTransitionOptions(qint64 duration, qint64 delay = 0);
void addAnnotationIcon(const QString &name, const QImage &sprite);
@@ -184,7 +177,7 @@ public:
void removeAnnotation(QMapbox::AnnotationID);
void setLayoutProperty(const QString &layer, const QString &property, const QVariant &value);
- void setPaintProperty(const QString &layer, const QString &property, const QVariant &value, const QString &klass = QString());
+ void setPaintProperty(const QString &layer, const QString &property, const QVariant &value);
bool isFullyLoaded() const;
@@ -193,6 +186,7 @@ public:
void rotateBy(const QPointF &first, const QPointF &second);
void resize(const QSize &size, const QSize &framebufferSize);
+ void setFramebufferObject(quint32 fbo);
double metersPerPixelAtLatitude(double latitude, double zoom) const;
QMapbox::ProjectedMeters projectedMetersForCoordinate(const QMapbox::Coordinate &) const;
@@ -219,8 +213,8 @@ public:
QMapbox::CustomLayerRenderFunction,
QMapbox::CustomLayerDeinitializeFunction,
void* context,
- char* before = NULL);
- void addLayer(const QVariantMap &params);
+ const QString& before = QString());
+ void addLayer(const QVariantMap &params, const QString& before = QString());
bool layerExists(const QString &id);
void removeLayer(const QString &id);
diff --git a/platform/qt/qt4.cmake b/platform/qt/qt4.cmake
index 80fd4f00d3..66aed87c38 100644
--- a/platform/qt/qt4.cmake
+++ b/platform/qt/qt4.cmake
@@ -13,6 +13,10 @@ set(MBGL_QT_TEST_LIBRARIES
PRIVATE Qt4::QtOpenGL
)
+target_compile_options(qmapboxgl
+ PRIVATE -Wno-inconsistent-missing-override
+)
+
target_link_libraries(qmapboxgl
PRIVATE mbgl-core
PRIVATE Qt4::QtCore
diff --git a/platform/qt/resources/common.qrc b/platform/qt/resources/common.qrc
index 4c792b057c..598059d55e 100644
--- a/platform/qt/resources/common.qrc
+++ b/platform/qt/resources/common.qrc
@@ -1,6 +1,6 @@
<RCC>
<qresource prefix="/">
- <file alias="icon.png">../../../common/icon.png</file>
+ <file alias="icon.png">../../../common/mb-icon-blue-square.png</file>
<file alias="default_marker.svg">../../../platform/default/resources/default_marker.svg</file>
<file>source1.geojson</file>
<file>source2.geojson</file>
diff --git a/platform/qt/src/qmapbox.cpp b/platform/qt/src/qmapbox.cpp
index 62bfde4fa8..751b16f9db 100644
--- a/platform/qt/src/qmapbox.cpp
+++ b/platform/qt/src/qmapbox.cpp
@@ -1,7 +1,5 @@
#include "qmapbox.hpp"
-#include <mbgl/gl/extension.hpp>
-#include <mbgl/map/change.hpp>
#include <mbgl/storage/network_status.hpp>
#include <mbgl/util/default_styles.hpp>
#include <mbgl/util/geometry.hpp>
@@ -141,16 +139,6 @@ namespace QMapbox {
*/
/*!
- \class QMapbox::StyleSourcedAnnotation
-
- \inmodule Mapbox Qt SDK
-
- Represents a style sourced annotation object, along with its properties.
-
- A style sourced annotation comprises of its geometry and a layer identifier.
-*/
-
-/*!
\typedef QMapbox::Annotation
Alias for QVariant.
@@ -256,26 +244,4 @@ Q_DECL_EXPORT QList<QPair<QString, QString> >& defaultStyles()
return styles;
}
-/*!
- \fn void QMapbox::initializeGLExtensions()
-
- Initializes the OpenGL extensions such as Vertex Array Objects (VAOs),
- required by Mapbox GL Native engine.
-
- Should be called only once, after an OpenGL context is available.
- Consecutive calls are ignored.
-*/
-Q_DECL_EXPORT void initializeGLExtensions()
-{
- mbgl::gl::InitializeExtensions([](const char* name) {
-#if QT_VERSION >= 0x050000
- QOpenGLContext* thisContext = QOpenGLContext::currentContext();
- return thisContext->getProcAddress(name);
-#else
- const QGLContext* thisContext = QGLContext::currentContext();
- return reinterpret_cast<mbgl::gl::glProc>(thisContext->getProcAddress(name));
-#endif
- });
-}
-
} // namespace QMapbox
diff --git a/platform/qt/src/qmapboxgl.cpp b/platform/qt/src/qmapboxgl.cpp
index 55470a65e1..01471bf733 100644
--- a/platform/qt/src/qmapboxgl.cpp
+++ b/platform/qt/src/qmapboxgl.cpp
@@ -5,22 +5,23 @@
#include "qt_geojson.hpp"
#include <mbgl/annotation/annotation.hpp>
-#include <mbgl/gl/gl.hpp>
-#include <mbgl/gl/context.hpp>
#include <mbgl/map/camera.hpp>
#include <mbgl/map/map.hpp>
+#include <mbgl/map/backend_scope.hpp>
+#include <mbgl/math/minmax.hpp>
#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/layer.hpp>
#include <mbgl/style/conversion/source.hpp>
#include <mbgl/style/layers/custom_layer.hpp>
#include <mbgl/style/sources/geojson_source.hpp>
#include <mbgl/style/transition_options.hpp>
-#include <mbgl/sprite/sprite_image.hpp>
+#include <mbgl/style/image.hpp>
#include <mbgl/storage/network_status.hpp>
#include <mbgl/util/color.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/geo.hpp>
#include <mbgl/util/geometry.hpp>
+#include <mbgl/util/projection.hpp>
#include <mbgl/util/run_loop.hpp>
#include <mbgl/util/shared_thread_pool.hpp>
#include <mbgl/util/traits.hpp>
@@ -31,6 +32,7 @@
#include <QOpenGLContext>
#else
#include <QCoreApplication>
+#include <QGLContext>
#endif
#include <QDebug>
@@ -57,24 +59,6 @@ static_assert(mbgl::underlying_type(QMapboxGLSettings::ConstrainWidthAndHeight)
static_assert(mbgl::underlying_type(QMapboxGLSettings::DefaultViewport) == mbgl::underlying_type(mbgl::ViewportMode::Default), "error");
static_assert(mbgl::underlying_type(QMapboxGLSettings::FlippedYViewport) == mbgl::underlying_type(mbgl::ViewportMode::FlippedY), "error");
-// mbgl::MapChange
-static_assert(mbgl::underlying_type(QMapboxGL::MapChangeRegionWillChange) == mbgl::underlying_type(mbgl::MapChangeRegionWillChange), "error");
-static_assert(mbgl::underlying_type(QMapboxGL::MapChangeRegionWillChangeAnimated) == mbgl::underlying_type(mbgl::MapChangeRegionWillChangeAnimated), "error");
-static_assert(mbgl::underlying_type(QMapboxGL::MapChangeRegionIsChanging) == mbgl::underlying_type(mbgl::MapChangeRegionIsChanging), "error");
-static_assert(mbgl::underlying_type(QMapboxGL::MapChangeRegionDidChange) == mbgl::underlying_type(mbgl::MapChangeRegionDidChange), "error");
-static_assert(mbgl::underlying_type(QMapboxGL::MapChangeRegionDidChangeAnimated) == mbgl::underlying_type(mbgl::MapChangeRegionDidChangeAnimated), "error");
-static_assert(mbgl::underlying_type(QMapboxGL::MapChangeWillStartLoadingMap) == mbgl::underlying_type(mbgl::MapChangeWillStartLoadingMap), "error");
-static_assert(mbgl::underlying_type(QMapboxGL::MapChangeDidFinishLoadingMap) == mbgl::underlying_type(mbgl::MapChangeDidFinishLoadingMap), "error");
-static_assert(mbgl::underlying_type(QMapboxGL::MapChangeDidFailLoadingMap) == mbgl::underlying_type(mbgl::MapChangeDidFailLoadingMap), "error");
-static_assert(mbgl::underlying_type(QMapboxGL::MapChangeWillStartRenderingFrame) == mbgl::underlying_type(mbgl::MapChangeWillStartRenderingFrame), "error");
-static_assert(mbgl::underlying_type(QMapboxGL::MapChangeDidFinishRenderingFrame) == mbgl::underlying_type(mbgl::MapChangeDidFinishRenderingFrame), "error");
-static_assert(mbgl::underlying_type(QMapboxGL::MapChangeDidFinishRenderingFrameFullyRendered) == mbgl::underlying_type(mbgl::MapChangeDidFinishRenderingFrameFullyRendered), "error");
-static_assert(mbgl::underlying_type(QMapboxGL::MapChangeWillStartRenderingMap) == mbgl::underlying_type(mbgl::MapChangeWillStartRenderingMap), "error");
-static_assert(mbgl::underlying_type(QMapboxGL::MapChangeDidFinishRenderingMap) == mbgl::underlying_type(mbgl::MapChangeDidFinishRenderingMap), "error");
-static_assert(mbgl::underlying_type(QMapboxGL::MapChangeDidFinishRenderingMapFullyRendered) == mbgl::underlying_type(mbgl::MapChangeDidFinishRenderingMapFullyRendered), "error");
-static_assert(mbgl::underlying_type(QMapboxGL::MapChangeDidFinishLoadingStyle) == mbgl::underlying_type(mbgl::MapChangeDidFinishLoadingStyle), "error");
-static_assert(mbgl::underlying_type(QMapboxGL::MapChangeSourceDidChange) == mbgl::underlying_type(mbgl::MapChangeSourceDidChange), "error");
-
// mbgl::NorthOrientation
static_assert(mbgl::underlying_type(QMapboxGL::NorthUpwards) == mbgl::underlying_type(mbgl::NorthOrientation::Upwards), "error");
static_assert(mbgl::underlying_type(QMapboxGL::NorthRightwards) == mbgl::underlying_type(mbgl::NorthOrientation::Rightwards), "error");
@@ -87,17 +71,14 @@ QThreadStorage<std::shared_ptr<mbgl::util::RunLoop>> loop;
// Conversion helper functions.
-auto fromQStringList(const QStringList &list)
-{
- std::vector<std::string> strings;
- strings.reserve(list.size());
- for (const QString &string : list) {
- strings.push_back(string.toStdString());
- }
- return strings;
-}
+mbgl::Size sanitizedSize(const QSize& size) {
+ return mbgl::Size {
+ mbgl::util::max(0u, static_cast<uint32_t>(size.width())),
+ mbgl::util::max(0u, static_cast<uint32_t>(size.height())),
+ };
+};
-std::unique_ptr<const mbgl::SpriteImage> toSpriteImage(const QImage &sprite) {
+std::unique_ptr<mbgl::style::Image> toStyleImage(const QString &id, const QImage &sprite) {
const QImage swapped = sprite
.rgbSwapped()
.convertToFormat(QImage::Format_ARGB32_Premultiplied);
@@ -105,7 +86,8 @@ std::unique_ptr<const mbgl::SpriteImage> toSpriteImage(const QImage &sprite) {
auto img = std::make_unique<uint8_t[]>(swapped.byteCount());
memcpy(img.get(), swapped.constBits(), swapped.byteCount());
- return std::make_unique<mbgl::SpriteImage>(
+ return std::make_unique<mbgl::style::Image>(
+ id.toStdString(),
mbgl::PremultipliedImage(
{ static_cast<uint32_t>(swapped.width()), static_cast<uint32_t>(swapped.height()) },
std::move(img)),
@@ -451,6 +433,8 @@ void QMapboxGLSettings::setApiBaseUrl(const QString& url)
QMapboxGL::QMapboxGL(QObject *parent, const QMapboxGLSettings &settings, const QSize& size, qreal pixelRatio)
: QObject(parent)
{
+ assert(!size.isEmpty());
+
// Multiple QMapboxGL running on the same thread
// will share the same mbgl::util::RunLoop
if (!loop.hasLocalData()) {
@@ -532,7 +516,7 @@ void QMapboxGL::setStyleUrl(const QString &url)
*/
double QMapboxGL::latitude() const
{
- return d_ptr->mapObj->getLatLng(d_ptr->margins).latitude;
+ return d_ptr->mapObj->getLatLng(d_ptr->margins).latitude();
}
void QMapboxGL::setLatitude(double latitude_)
@@ -550,7 +534,7 @@ void QMapboxGL::setLatitude(double latitude_)
*/
double QMapboxGL::longitude() const
{
- return d_ptr->mapObj->getLatLng(d_ptr->margins).longitude;
+ return d_ptr->mapObj->getLatLng(d_ptr->margins).longitude();
}
void QMapboxGL::setLongitude(double longitude_)
@@ -573,12 +557,12 @@ void QMapboxGL::setLongitude(double longitude_)
*/
double QMapboxGL::scale() const
{
- return d_ptr->mapObj->getScale();
+ return std::pow(2.0, d_ptr->mapObj->getZoom());
}
void QMapboxGL::setScale(double scale_, const QPointF &center)
{
- d_ptr->mapObj->setScale(scale_, mbgl::ScreenCoordinate { center.x(), center.y() });
+ d_ptr->mapObj->setZoom(std::log2(scale_), mbgl::ScreenCoordinate { center.x(), center.y() });
}
/*!
@@ -632,7 +616,7 @@ double QMapboxGL::maximumZoom() const
Coordinate QMapboxGL::coordinate() const
{
const mbgl::LatLng& latLng = d_ptr->mapObj->getLatLng(d_ptr->margins);
- return Coordinate(latLng.latitude, latLng.longitude);
+ return Coordinate(latLng.latitude(), latLng.longitude());
}
void QMapboxGL::setCoordinate(const QMapbox::Coordinate &coordinate_)
@@ -759,74 +743,8 @@ void QMapboxGL::setGestureInProgress(bool progress)
}
/*!
- Adds an \a className to the list of active classes. Layers tagged with a certain class
- will only be active when the class is added.
-
- This was removed from the \l {https://www.mapbox.com/mapbox-gl-style-spec/#layer-paint.*}
- {Mapbox style specification} and should no longer be used.
-
- \deprecated
- \sa removeClass()
-*/
-void QMapboxGL::addClass(const QString &className)
-{
- d_ptr->mapObj->addClass(className.toStdString());
-}
-
-/*!
- Removes a \a className.
-
- \deprecated
- \sa addClass()
-*/
-void QMapboxGL::removeClass(const QString &className)
-{
- d_ptr->mapObj->removeClass(className.toStdString());
-}
-
-/*!
- Returns true when \a className is active, false otherwise.
-
- \deprecated
- \sa addClass()
-*/
-bool QMapboxGL::hasClass(const QString &className) const
-{
- return d_ptr->mapObj->hasClass(className.toStdString());
-}
-
-/*!
- Bulk adds a list of \a classNames.
-
- \deprecated
- \sa addClass()
-*/
-void QMapboxGL::setClasses(const QStringList &classNames)
-{
- d_ptr->mapObj->setClasses(fromQStringList(classNames));
-}
-
-/*!
- Returns a list of active classes.
-
- \deprecated
- \sa setClasses()
-*/
-QStringList QMapboxGL::getClasses() const
-{
- QStringList classNames;
- for (const std::string &mbglClass : d_ptr->mapObj->getClasses()) {
- classNames << QString::fromStdString(mbglClass);
- }
- return classNames;
-}
-
-/*!
- Sets the \a duration and \a delay of style class transitions. Style property
- values transition to new values with animation when a new class is set.
-
- \deprecated
- \sa addClass()
+ Sets the \a duration and \a delay of style transitions. Style paint property
+ values transition to new values with animation when they are updated.
*/
void QMapboxGL::setTransitionOptions(qint64 duration, qint64 delay) {
static auto convert = [](qint64 value) -> mbgl::optional<mbgl::Duration> {
@@ -873,9 +791,6 @@ mbgl::Annotation asMapboxGLAnnotation(const QMapbox::Annotation & annotation) {
} else {
return mbgl::FillAnnotation { asMapboxGLGeometry(fillAnnotation.geometry), fillAnnotation.opacity, { *color }, {} };
}
- } else if (annotation.canConvert<QMapbox::StyleSourcedAnnotation>()) {
- QMapbox::StyleSourcedAnnotation styleSourcedAnnotation = annotation.value<QMapbox::StyleSourcedAnnotation>();
- return mbgl::StyleSourcedAnnotation { asMapboxGLGeometry(styleSourcedAnnotation.geometry), styleSourcedAnnotation.layerID.toStdString() };
}
qWarning() << "Unable to convert annotation:" << annotation;
@@ -968,9 +883,6 @@ void QMapboxGL::setLayoutProperty(const QString& layer, const QString& property,
as defined by the \l {https://www.mapbox.com/mapbox-gl-style-spec/} {Mapbox style specification}
for paint properties.
- The argument \a styleClass is deprecated and is used for defining the style class for the paint
- property.
-
For paint properties that take a color as \a value, such as \c fill-color, a string such as
\c blue can be passed or a QColor.
@@ -1016,7 +928,7 @@ void QMapboxGL::setLayoutProperty(const QString& layer, const QString& property,
map->setPaintProperty("route","line-dasharray", lineDashArray);
\endcode
*/
-void QMapboxGL::setPaintProperty(const QString& layer, const QString& property, const QVariant& value, const QString& styleClass)
+void QMapboxGL::setPaintProperty(const QString& layer, const QString& property, const QVariant& value)
{
using namespace mbgl::style;
@@ -1026,12 +938,7 @@ void QMapboxGL::setPaintProperty(const QString& layer, const QString& property,
return;
}
- mbgl::optional<std::string> klass;
- if (!styleClass.isEmpty()) {
- klass = styleClass.toStdString();
- }
-
- if (conversion::setPaintProperty(*layer_, property.toStdString(), value, klass)) {
+ if (conversion::setPaintProperty(*layer_, property.toStdString(), value)) {
qWarning() << "Error setting paint property:" << layer << "-" << property;
return;
}
@@ -1063,7 +970,7 @@ void QMapboxGL::moveBy(const QPointF &offset)
can be used for implementing a pinch gesture.
*/
void QMapboxGL::scaleBy(double scale_, const QPointF &center) {
- d_ptr->mapObj->scaleBy(scale_, mbgl::ScreenCoordinate { center.x(), center.y() });
+ d_ptr->mapObj->setZoom(d_ptr->mapObj->getZoom() + std::log2(scale_), mbgl::ScreenCoordinate { center.x(), center.y() });
}
/*!
@@ -1097,8 +1004,15 @@ void QMapboxGL::resize(const QSize& size, const QSize& framebufferSize)
d_ptr->size = size;
d_ptr->fbSize = framebufferSize;
- d_ptr->mapObj->setSize(
- { static_cast<uint32_t>(size.width()), static_cast<uint32_t>(size.height()) });
+ d_ptr->mapObj->setSize(sanitizedSize(size));
+}
+
+/*!
+ If Mapbox GL needs to rebind the default framebuffer, it will use the
+ ID supplied here.
+*/
+void QMapboxGL::setFramebufferObject(quint32 fbo) {
+ d_ptr->fbObject = fbo;
}
/*!
@@ -1114,7 +1028,7 @@ void QMapboxGL::addAnnotationIcon(const QString &name, const QImage &icon)
{
if (icon.isNull()) return;
- d_ptr->mapObj->addAnnotationIcon(name.toStdString(), toSpriteImage(icon));
+ d_ptr->mapObj->addAnnotationImage(toStyleImage(name, icon));
}
/*!
@@ -1122,7 +1036,7 @@ void QMapboxGL::addAnnotationIcon(const QString &name, const QImage &icon)
*/
double QMapboxGL::metersPerPixelAtLatitude(double latitude, double zoom) const
{
- return d_ptr->mapObj->getMetersPerPixelAtLatitude(latitude, zoom);
+ return mbgl::Projection::getMetersPerPixelAtLatitude(latitude, zoom);
}
/*!
@@ -1130,8 +1044,8 @@ double QMapboxGL::metersPerPixelAtLatitude(double latitude, double zoom) const
*/
QMapbox::ProjectedMeters QMapboxGL::projectedMetersForCoordinate(const QMapbox::Coordinate &coordinate_) const
{
- auto projectedMeters = d_ptr->mapObj->projectedMetersForLatLng(mbgl::LatLng { coordinate_.first, coordinate_.second });
- return QMapbox::ProjectedMeters(projectedMeters.northing, projectedMeters.easting);
+ auto projectedMeters = mbgl::Projection::projectedMetersForLatLng(mbgl::LatLng { coordinate_.first, coordinate_.second });
+ return QMapbox::ProjectedMeters(projectedMeters.northing(), projectedMeters.easting());
}
/*!
@@ -1139,8 +1053,8 @@ QMapbox::ProjectedMeters QMapboxGL::projectedMetersForCoordinate(const QMapbox::
*/
QMapbox::Coordinate QMapboxGL::coordinateForProjectedMeters(const QMapbox::ProjectedMeters &projectedMeters) const
{
- auto latLng = d_ptr->mapObj->latLngForProjectedMeters(mbgl::ProjectedMeters { projectedMeters.first, projectedMeters.second });
- return QMapbox::Coordinate(latLng.latitude, latLng.longitude);
+ auto latLng = mbgl::Projection::latLngForProjectedMeters(mbgl::ProjectedMeters { projectedMeters.first, projectedMeters.second });
+ return QMapbox::Coordinate(latLng.latitude(), latLng.longitude());
}
/*!
@@ -1170,7 +1084,7 @@ QMapbox::Coordinate QMapboxGL::coordinateForPixel(const QPointF &pixel) const
const mbgl::LatLng latLng =
d_ptr->mapObj->latLngForPixel(mbgl::ScreenCoordinate { pixel.x(), pixel.y() });
- return Coordinate(latLng.latitude, latLng.longitude);
+ return Coordinate(latLng.latitude(), latLng.longitude());
}
/*!
@@ -1182,7 +1096,7 @@ QMapbox::CoordinateZoom QMapboxGL::coordinateZoomForBounds(const QMapbox::Coordi
auto bounds = mbgl::LatLngBounds::hull(mbgl::LatLng { sw.first, sw.second }, mbgl::LatLng { ne.first, ne.second });
mbgl::CameraOptions camera = d_ptr->mapObj->cameraForLatLngBounds(bounds, d_ptr->margins);
- return {{ (*camera.center).latitude, (*camera.center).longitude }, *camera.zoom };
+ return {{ (*camera.center).latitude(), (*camera.center).longitude() }, *camera.zoom };
}
/*!
@@ -1208,7 +1122,7 @@ QMapbox::CoordinateZoom QMapboxGL::coordinateZoomForBounds(const QMapbox::Coordi
setBearing(currentBearing);
setPitch(currentPitch);
- return {{ (*camera.center).latitude, (*camera.center).longitude }, *camera.zoom };
+ return {{ (*camera.center).latitude(), (*camera.center).longitude() }, *camera.zoom };
}
/*!
@@ -1230,10 +1144,10 @@ void QMapboxGL::setMargins(const QMargins &margins_)
QMargins QMapboxGL::margins() const
{
return QMargins(
- d_ptr->margins.left,
- d_ptr->margins.top,
- d_ptr->margins.right,
- d_ptr->margins.bottom
+ d_ptr->margins.left(),
+ d_ptr->margins.top(),
+ d_ptr->margins.right(),
+ d_ptr->margins.bottom()
);
}
@@ -1260,9 +1174,10 @@ void QMapboxGL::addSource(const QString &id, const QVariantMap &params)
using namespace mbgl::style;
using namespace mbgl::style::conversion;
- Result<std::unique_ptr<Source>> source = convert<std::unique_ptr<Source>>(QVariant(params), id.toStdString());
+ Error error;
+ mbgl::optional<std::unique_ptr<Source>> source = convert<std::unique_ptr<Source>>(QVariant(params), error, id.toStdString());
if (!source) {
- qWarning() << "Unable to add source:" << source.error().message.c_str();
+ qWarning() << "Unable to add source:" << error.message.c_str();
return;
}
@@ -1301,7 +1216,8 @@ void QMapboxGL::updateSource(const QString &id, const QVariantMap &params)
}
if (params.contains("data")) {
- auto result = convertGeoJSON(params["data"]);
+ Error error;
+ auto result = convert<mbgl::GeoJSON>(params["data"], error);
if (result) {
sourceGeoJSON->setGeoJSON(*result);
}
@@ -1335,7 +1251,7 @@ void QMapboxGL::addCustomLayer(const QString &id,
QMapbox::CustomLayerRenderFunction renderFn,
QMapbox::CustomLayerDeinitializeFunction deinitFn,
void *context,
- char *before)
+ const QString& before)
{
d_ptr->mapObj->addLayer(std::make_unique<mbgl::style::CustomLayer>(
id.toStdString(),
@@ -1345,13 +1261,14 @@ void QMapboxGL::addCustomLayer(const QString &id,
(mbgl::style::CustomLayerRenderFunction)renderFn,
reinterpret_cast<mbgl::style::CustomLayerDeinitializeFunction>(deinitFn),
context),
- before ? mbgl::optional<std::string>(before) : mbgl::optional<std::string>());
+ before.isEmpty() ? mbgl::optional<std::string>() : mbgl::optional<std::string>(before.toStdString()));
}
/*!
Adds a style layer to the map as specified by the \l
{https://www.mapbox.com/mapbox-gl-style-spec/#root-layers}{Mapbox style specification} with
- \a params.
+ \a params. The layer will be added under the layer specified by \a before, if specified.
+ Otherwise it will be added as the topmost layer.
This example shows how to add a layer that will be used to show a route line on the map. Note
that nothing will be drawn until we set paint properties using setPaintProperty().
@@ -1367,18 +1284,20 @@ void QMapboxGL::addCustomLayer(const QString &id,
/note The source must exist prior to adding a layer.
*/
-void QMapboxGL::addLayer(const QVariantMap &params)
+void QMapboxGL::addLayer(const QVariantMap &params, const QString& before)
{
using namespace mbgl::style;
using namespace mbgl::style::conversion;
- Result<std::unique_ptr<Layer>> layer = convert<std::unique_ptr<Layer>>(QVariant(params));
+ Error error;
+ mbgl::optional<std::unique_ptr<Layer>> layer = convert<std::unique_ptr<Layer>>(QVariant(params), error);
if (!layer) {
- qWarning() << "Unable to add layer:" << layer.error().message.c_str();
+ qWarning() << "Unable to add layer:" << error.message.c_str();
return;
}
- d_ptr->mapObj->addLayer(std::move(*layer));
+ d_ptr->mapObj->addLayer(std::move(*layer),
+ before.isEmpty() ? mbgl::optional<std::string>() : mbgl::optional<std::string>(before.toStdString()));
}
/*!
@@ -1411,7 +1330,7 @@ void QMapboxGL::addImage(const QString &id, const QImage &image)
{
if (image.isNull()) return;
- d_ptr->mapObj->addImage(id.toStdString(), toSpriteImage(image));
+ d_ptr->mapObj->addImage(toStyleImage(id, image));
}
/*!
@@ -1455,9 +1374,10 @@ void QMapboxGL::setFilter(const QString& layer, const QVariant& filter)
Filter filter_;
- Result<Filter> converted = convert<Filter>(filter);
+ Error error;
+ mbgl::optional<Filter> converted = convert<Filter>(filter, error);
if (!converted) {
- qWarning() << "Error parsing filter:" << converted.error().message.c_str();
+ qWarning() << "Error parsing filter:" << error.message.c_str();
return;
}
filter_ = std::move(*converted);
@@ -1478,6 +1398,10 @@ void QMapboxGL::setFilter(const QString& layer, const QVariant& filter)
layer_->as<CircleLayer>()->setFilter(filter_);
return;
}
+ if (layer_->is<FillExtrusionLayer>()) {
+ layer_->as<FillExtrusionLayer>()->setFilter(filter_);
+ return;
+ }
qWarning() << "Layer doesn't support filters";
}
@@ -1501,6 +1425,9 @@ void QMapboxGL::render()
}
#endif
+ // The OpenGL implementation automatically enables the OpenGL context for us.
+ mbgl::BackendScope scope { *d_ptr, mbgl::BackendScope::ScopeType::Implicit };
+
d_ptr->dirty = false;
d_ptr->mapObj->render(*d_ptr);
}
@@ -1550,14 +1477,15 @@ QMapboxGLPrivate::QMapboxGLPrivate(QMapboxGL *q, const QMapboxGLSettings &settin
settings.assetPath().toStdString(),
settings.cacheDatabaseMaximumSize()))
, threadPool(mbgl::sharedThreadPool())
- , mapObj(std::make_unique<mbgl::Map>(
- *this, mbgl::Size{ static_cast<uint32_t>(size.width()), static_cast<uint32_t>(size.height()) },
- pixelRatio, *fileSourceObj, *threadPool,
- mbgl::MapMode::Continuous,
- static_cast<mbgl::GLContextMode>(settings.contextMode()),
- static_cast<mbgl::ConstrainMode>(settings.constrainMode()),
- static_cast<mbgl::ViewportMode>(settings.viewportMode())))
{
+ mapObj = std::make_unique<mbgl::Map>(
+ *this, sanitizedSize(size),
+ pixelRatio, *fileSourceObj, *threadPool,
+ mbgl::MapMode::Continuous,
+ static_cast<mbgl::GLContextMode>(settings.contextMode()),
+ static_cast<mbgl::ConstrainMode>(settings.constrainMode()),
+ static_cast<mbgl::ViewportMode>(settings.viewportMode()));
+
qRegisterMetaType<QMapboxGL::MapChange>("QMapboxGL::MapChange");
fileSourceObj->setAccessToken(settings.accessToken().toStdString());
@@ -1572,11 +1500,18 @@ QMapboxGLPrivate::~QMapboxGLPrivate()
{
}
+mbgl::Size QMapboxGLPrivate::framebufferSize() const {
+ return sanitizedSize(fbSize);
+}
+
+void QMapboxGLPrivate::updateAssumedState() {
+ assumeFramebufferBinding(fbObject);
+ assumeViewportSize(framebufferSize());
+}
+
void QMapboxGLPrivate::bind() {
- getContext().bindFramebuffer = 0;
- getContext().viewport = {
- 0, 0, { static_cast<uint32_t>(fbSize.width()), static_cast<uint32_t>(fbSize.height()) }
- };
+ setFramebufferBinding(fbObject);
+ setViewportSize(framebufferSize());
}
void QMapboxGLPrivate::invalidate()
@@ -1587,19 +1522,101 @@ void QMapboxGLPrivate::invalidate()
}
}
-void QMapboxGLPrivate::notifyMapChange(mbgl::MapChange change)
+void QMapboxGLPrivate::onCameraWillChange(mbgl::MapObserver::CameraChangeMode mode)
{
- if (change == mbgl::MapChangeSourceDidChange) {
- std::string attribution;
- for (const auto& source : mapObj->getSources()) {
- // Avoid duplicates by using the most complete attribution HTML snippet.
- if (source->getAttribution() && (attribution.size() < source->getAttribution()->size()))
- attribution = *source->getAttribution();
- }
- emit copyrightsChanged(QString::fromStdString(attribution));
+ if (mode == mbgl::MapObserver::CameraChangeMode::Immediate) {
+ emit mapChanged(QMapboxGL::MapChangeRegionWillChange);
+ } else {
+ emit mapChanged(QMapboxGL::MapChangeRegionWillChangeAnimated);
+ }
+}
+
+void QMapboxGLPrivate::onCameraIsChanging()
+{
+ emit mapChanged(QMapboxGL::MapChangeRegionIsChanging);
+}
+
+void QMapboxGLPrivate::onCameraDidChange(mbgl::MapObserver::CameraChangeMode mode)
+{
+ if (mode == mbgl::MapObserver::CameraChangeMode::Immediate) {
+ emit mapChanged(QMapboxGL::MapChangeRegionDidChange);
+ } else {
+ emit mapChanged(QMapboxGL::MapChangeRegionDidChangeAnimated);
+ }
+}
+
+void QMapboxGLPrivate::onWillStartLoadingMap()
+{
+ emit mapChanged(QMapboxGL::MapChangeWillStartLoadingMap);
+}
+
+void QMapboxGLPrivate::onDidFinishLoadingMap()
+{
+ emit mapChanged(QMapboxGL::MapChangeDidFinishLoadingMap);
+}
+
+void QMapboxGLPrivate::onDidFailLoadingMap(std::exception_ptr)
+{
+ emit mapChanged(QMapboxGL::MapChangeDidFailLoadingMap);
+}
+
+void QMapboxGLPrivate::onWillStartRenderingFrame()
+{
+ emit mapChanged(QMapboxGL::MapChangeWillStartRenderingFrame);
+}
+
+void QMapboxGLPrivate::onDidFinishRenderingFrame(mbgl::MapObserver::RenderMode mode)
+{
+ if (mode == mbgl::MapObserver::RenderMode::Partial) {
+ emit mapChanged(QMapboxGL::MapChangeDidFinishRenderingFrame);
+ } else {
+ emit mapChanged(QMapboxGL::MapChangeDidFinishRenderingFrameFullyRendered);
}
+}
+
+void QMapboxGLPrivate::onWillStartRenderingMap()
+{
+ emit mapChanged(QMapboxGL::MapChangeWillStartLoadingMap);
+}
+
+void QMapboxGLPrivate::onDidFinishRenderingMap(mbgl::MapObserver::RenderMode mode)
+{
+ if (mode == mbgl::MapObserver::RenderMode::Partial) {
+ emit mapChanged(QMapboxGL::MapChangeDidFinishRenderingMap);
+ } else {
+ emit mapChanged(QMapboxGL::MapChangeDidFinishRenderingMapFullyRendered);
+ }
+}
- emit mapChanged(static_cast<QMapboxGL::MapChange>(change));
+void QMapboxGLPrivate::onDidFinishLoadingStyle()
+{
+ emit mapChanged(QMapboxGL::MapChangeDidFinishLoadingStyle);
+}
+
+void QMapboxGLPrivate::onSourceChanged(mbgl::style::Source&)
+{
+ std::string attribution;
+ for (const auto& source : mapObj->getSources()) {
+ // Avoid duplicates by using the most complete attribution HTML snippet.
+ if (source->getAttribution() && (attribution.size() < source->getAttribution()->size()))
+ attribution = *source->getAttribution();
+ }
+ emit copyrightsChanged(QString::fromStdString(attribution));
+ emit mapChanged(QMapboxGL::MapChangeSourceDidChange);
+}
+
+/*!
+ Initializes an OpenGL extension function such as Vertex Array Objects (VAOs),
+ required by Mapbox GL Native engine.
+*/
+mbgl::gl::ProcAddress QMapboxGLPrivate::initializeExtension(const char* name) {
+#if QT_VERSION >= 0x050000
+ QOpenGLContext* thisContext = QOpenGLContext::currentContext();
+ return thisContext->getProcAddress(name);
+#else
+ const QGLContext* thisContext = QGLContext::currentContext();
+ return reinterpret_cast<mbgl::gl::ProcAddress>(thisContext->getProcAddress(name));
+#endif
}
void QMapboxGLPrivate::connectionEstablished()
diff --git a/platform/qt/src/qmapboxgl_p.hpp b/platform/qt/src/qmapboxgl_p.hpp
index ee7bff0872..49a7942cce 100644
--- a/platform/qt/src/qmapboxgl_p.hpp
+++ b/platform/qt/src/qmapboxgl_p.hpp
@@ -20,20 +20,35 @@ public:
explicit QMapboxGLPrivate(QMapboxGL *, const QMapboxGLSettings &, const QSize &size, qreal pixelRatio);
virtual ~QMapboxGLPrivate();
+ mbgl::Size framebufferSize() const;
+
// mbgl::View implementation.
- float getPixelRatio() const;
void bind() final;
- std::array<uint16_t, 2> getSize() const;
- std::array<uint16_t, 2> getFramebufferSize() const;
+ // mbgl::Backend implementation.
+ void updateAssumedState() final;
+ void invalidate() final;
void activate() final {}
void deactivate() final {}
- void invalidate() final;
- void notifyMapChange(mbgl::MapChange) final;
+
+ // mbgl::MapObserver implementation.
+ void onCameraWillChange(mbgl::MapObserver::CameraChangeMode) final;
+ void onCameraIsChanging() final;
+ void onCameraDidChange(mbgl::MapObserver::CameraChangeMode) final;
+ void onWillStartLoadingMap() final;
+ void onDidFinishLoadingMap() final;
+ void onDidFailLoadingMap(std::exception_ptr) final;
+ void onWillStartRenderingFrame() final;
+ void onDidFinishRenderingFrame(mbgl::MapObserver::RenderMode) final;
+ void onWillStartRenderingMap() final;
+ void onDidFinishRenderingMap(mbgl::MapObserver::RenderMode) final;
+ void onDidFinishLoadingStyle() final;
+ void onSourceChanged(mbgl::style::Source&) final;
mbgl::EdgeInsets margins;
QSize size { 0, 0 };
QSize fbSize { 0, 0 };
+ quint32 fbObject = 0;
QMapboxGL *q_ptr { nullptr };
@@ -43,6 +58,9 @@ public:
bool dirty { false };
+private:
+ mbgl::gl::ProcAddress initializeExtension(const char*) override;
+
public slots:
void connectionEstablished();
diff --git a/platform/qt/src/qt_geojson.hpp b/platform/qt/src/qt_geojson.hpp
index 038b051941..a6958b7edc 100644
--- a/platform/qt/src/qt_geojson.hpp
+++ b/platform/qt/src/qt_geojson.hpp
@@ -2,7 +2,6 @@
#include <mapbox/geojson.hpp>
#include <mbgl/style/conversion/geojson.hpp>
-#include <mbgl/util/rapidjson.hpp>
#include <QMapbox>
@@ -10,7 +9,6 @@
#include <QDebug>
#include <QVariant>
-#include <sstream>
#include <string>
namespace QMapbox {
@@ -180,44 +178,20 @@ namespace style {
namespace conversion {
template <>
-Result<GeoJSON> convertGeoJSON(const QMapbox::Feature& feature) {
- return Result<GeoJSON> { GeoJSON { asMapboxGLFeature(feature) } };
-}
-
-template <>
-Result<GeoJSON> convertGeoJSON(const QVariant& value) {
+optional<GeoJSON> Converter<GeoJSON>::operator()(const QVariant& value, Error& error) const {
#if QT_VERSION >= 0x050000
if (value.typeName() == QStringLiteral("QMapbox::Feature")) {
#else
if (value.typeName() == QString("QMapbox::Feature")) {
#endif
- return convertGeoJSON(value.value<QMapbox::Feature>());
+ return GeoJSON { asMapboxGLFeature(value.value<QMapbox::Feature>()) };
} else if (value.type() != QVariant::ByteArray) {
- return Error { "JSON data must be in QByteArray" };
- }
-
- auto data = value.toByteArray();
-
- rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::CrtAllocator> d;
- if (data.endsWith(char(0))) {
- d.Parse<0>(value.toByteArray().data());
- } else {
- d.Parse<0>(value.toByteArray().constData());
- }
-
- if (d.HasParseError()) {
- std::stringstream message;
- message << d.GetErrorOffset() << " - " << rapidjson::GetParseError_En(d.GetParseError());
-
- return Error { message.str() };
- }
-
- Result<GeoJSON> geoJSON = convertGeoJSON<JSValue>(d);
- if (!geoJSON) {
- return Error { geoJSON.error().message };
+ error = { "JSON data must be in QByteArray" };
+ return {};
}
- return geoJSON;
+ QByteArray data = value.toByteArray();
+ return convert<GeoJSON>(std::string(data.constData(), data.size()), error);
}
} // namespace conversion
diff --git a/platform/qt/src/sqlite3.cpp b/platform/qt/src/sqlite3.cpp
index 3470c36910..8df279c25d 100644
--- a/platform/qt/src/sqlite3.cpp
+++ b/platform/qt/src/sqlite3.cpp
@@ -130,10 +130,6 @@ Database &Database::operator=(Database &&other) {
Database::~Database() {
}
-Database::operator bool() const {
- return impl.operator bool();
-}
-
void Database::setBusyTimeout(std::chrono::milliseconds timeout) {
assert(impl);
std::string timeoutStr = mbgl::util::toString(timeout.count());
@@ -191,11 +187,6 @@ Statement &Statement::operator=(Statement &&other) {
Statement::~Statement() {
}
-Statement::operator bool() const {
- assert(impl);
- return impl.operator bool();
-}
-
template void Statement::bind(int, int64_t);
template <typename T>
diff --git a/platform/qt/test/headless_backend_qt.cpp b/platform/qt/test/headless_backend_qt.cpp
index 401ce55a7f..5f95b2f96a 100644
--- a/platform/qt/test/headless_backend_qt.cpp
+++ b/platform/qt/test/headless_backend_qt.cpp
@@ -24,13 +24,13 @@ struct QtImpl : public HeadlessBackend::Impl {
QGLWidget widget;
};
-gl::glProc HeadlessBackend::initializeExtension(const char* name) {
+gl::ProcAddress HeadlessBackend::initializeExtension(const char* name) {
#if QT_VERSION >= 0x050000
QOpenGLContext* thisContext = QOpenGLContext::currentContext();
return thisContext->getProcAddress(name);
#else
const QGLContext* thisContext = QGLContext::currentContext();
- return reinterpret_cast<mbgl::gl::glProc>(thisContext->getProcAddress(name));
+ return reinterpret_cast<gl::ProcAddress>(thisContext->getProcAddress(name));
#endif
}
diff --git a/platform/qt/test/qmapboxgl.cpp b/platform/qt/test/qmapboxgl.cpp
index 8b88a4f6f6..453604076e 100644
--- a/platform/qt/test/qmapboxgl.cpp
+++ b/platform/qt/test/qmapboxgl.cpp
@@ -2,24 +2,26 @@
#include <mbgl/util/io.hpp>
#include <QApplication>
-#include <QGLWidget>
#include <QMapbox>
#include <QMapboxGL>
+// We're using QGLFramebufferObject, which is only available in Qt 5 and up.
+#if QT_VERSION >= 0x050000
+
+#include <QGLWidget>
+#include <QGLFramebufferObject>
+
class QMapboxGLTest : public QObject, public ::testing::Test {
Q_OBJECT
public:
- QMapboxGLTest() : map(nullptr, settings) {
+ QMapboxGLTest() : fbo((assert(widget.context()->isValid()), widget.makeCurrent(), QSize(512, 512))), map(nullptr, settings) {
connect(&map, SIGNAL(mapChanged(QMapboxGL::MapChange)),
this, SLOT(onMapChanged(QMapboxGL::MapChange)));
connect(&map, SIGNAL(needsRendering()),
this, SLOT(onNeedsRendering()));
-
- widget.makeCurrent();
- QMapbox::initializeGLExtensions();
-
- map.resize(QSize(512, 512), QSize(512, 512));
+ map.resize(fbo.size(), fbo.size());
+ map.setFramebufferObject(fbo.handle());
map.setCoordinateZoom(QMapbox::Coordinate(60.170448, 24.942046), 14);
}
@@ -36,6 +38,7 @@ public:
private:
QGLWidget widget;
+ QGLFramebufferObject fbo;
protected:
QMapboxGLSettings settings;
@@ -51,6 +54,9 @@ private slots:
};
void onNeedsRendering() {
+ widget.makeCurrent();
+ fbo.bind();
+ glViewport(0, 0, fbo.width(), fbo.height());
map.render();
};
};
@@ -88,3 +94,5 @@ TEST_F(QMapboxGLTest, TEST_DISABLED_ON_CI(styleUrl)) {
}
#include "qmapboxgl.moc"
+
+#endif