summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
authorTim Watson <tewatson89@gmail.com>2019-04-03 14:51:13 -0700
committerGitHub <noreply@github.com>2019-04-03 14:51:13 -0700
commit0ff25060dae4858a1b60e2277dbd8921de7a6785 (patch)
treed29d578b9b9d6cfb0999b7a30819d379b85172b7 /platform
parentba2b7a74c420856401d344ff15b27771175c9819 (diff)
parent0f416fbbde9b146eb28a4bf88586738d12505007 (diff)
downloadqtlocation-mapboxgl-0ff25060dae4858a1b60e2277dbd8921de7a6785.tar.gz
Merge pull request #1 from mapbox/masterupstream/friedbunny-external-pr-14135
Merge Master
Diffstat (limited to 'platform')
-rw-r--r--platform/android/CHANGELOG.md42
-rw-r--r--platform/android/LICENSE.md36
-rw-r--r--platform/android/MapboxGLAndroidSDK/build.gradle12
-rw-r--r--platform/android/MapboxGLAndroidSDK/gradle.properties2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java37
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationCameraController.java6
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java16
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentConstants.java32
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java17
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java8
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java103
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java7
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java2
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java9
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Style.java17
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java49
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/glsurfaceview/GLSurfaceViewMapRenderer.java10
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewRenderThread.java1
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/PerformanceEvent.java94
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/TelemetryImpl.java5
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java5
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java40
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/SymbolLayer.java32
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/types/Formatted.java8
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/types/FormattedSection.java10
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/BitmapUtils.java3
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_internal.xml4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngTest.java11
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationCameraControllerTest.java30
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java40
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.kt150
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/build.gradle2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/assets/streets.json5331
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/InstrumentationApplication.kt10
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/InstrumentationRunner.kt11
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/BaseIntegrationTest.kt39
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/FragmentBackStackTest.kt52
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/GLSurfaceViewReopenTest.kt30
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/GLSurfaceViewReuseTest.kt31
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/OrientationChangeTest.kt34
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/TextureViewReopenTest.kt33
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/TextureViewReuseTest.kt31
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/ViewPagerScrollTest.kt38
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt96
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.kt34
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/GLSurfaceViewReopenTest.kt73
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxTest.java3
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/OrientationTest.java41
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/TextureViewReopenTest.kt77
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/VisibleRegionTest.kt80
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/module/telemetry/PerformanceEventTest.java188
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/OrientationAction.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/OrientationChangeAction.java)18
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/WaitAction.java7
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseTest.java126
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/EspressoTest.java18
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/IconTest.java161
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraForTest.java340
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/fragment/MapDialogFragmentTest.kt4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/geometry/GeoJsonConversionTest.java118
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/StyleLoadTest.kt8
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/AttributionTest.java16
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/CompassViewTest.java3
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/offline/OfflineManagerTest.kt123
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CustomGeometrySourceTest.kt21
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ExpressionTest.java26
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/GeoJsonSourceTests.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ImageTest.java46
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ImageTest.kt75
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleTests.java13
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java28
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/FinishLoadingStyleIdlingResource.java35
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/LoadStyleIdlingResource.java40
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/MapboxIdlingResource.java46
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/OnMapReadyIdlingResource.java60
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml50
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapboxApplication.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/GestureDetectorActivity.java13
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/espresso/PixelTestActivity.kt66
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MapFragmentActivity.java14
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/SupportMapFragmentActivity.java14
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/ViewPagerActivity.java117
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/ViewPagerActivity.kt109
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/SnapshotActivity.java114
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/SnapshotActivity.kt80
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/GLSurfaceRecyclerViewActivity.kt155
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapInDialogActivity.java34
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/RecyclerViewActivity.kt151
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/TextureRecyclerViewActivity.kt15
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/telemetry/PerformanceMeasurementActivity.java187
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_backstack_fragment.xml1
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_pixel_test.xml16
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_snapshot.xml12
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_viewpager.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/item_map_gl.xml10
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/item_map_texture.xml (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/item_map.xml)0
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/categories.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml4
-rw-r--r--platform/android/build.gradle1
-rw-r--r--platform/android/gradle/android-nitpick.gradle10
-rw-r--r--platform/android/gradle/dependencies.gradle6
-rw-r--r--platform/android/gradle/jacoco-report.gradle33
-rw-r--r--platform/android/scripts/exclude-activity-gen.json4
-rwxr-xr-xplatform/android/scripts/generate-style-code.js7
-rwxr-xr-xplatform/android/scripts/parse-jacoco-report.py31
-rw-r--r--platform/android/scripts/validate-license.py17
-rw-r--r--platform/android/src/conversion/constant.hpp11
-rw-r--r--platform/android/src/file_source.cpp27
-rw-r--r--platform/android/src/file_source.hpp6
-rw-r--r--platform/android/src/map_renderer.hpp4
-rwxr-xr-xplatform/android/src/native_map_view.cpp13
-rwxr-xr-xplatform/android/src/native_map_view.hpp1
-rw-r--r--platform/android/src/offline/offline_manager.cpp13
-rw-r--r--platform/android/src/offline/offline_manager.hpp8
-rw-r--r--platform/android/src/offline/offline_region.cpp14
-rw-r--r--platform/android/src/offline/offline_region.hpp2
-rw-r--r--platform/android/src/snapshotter/map_snapshotter.cpp10
-rw-r--r--platform/android/src/style/layers/symbol_layer.cpp12
-rw-r--r--platform/android/src/style/layers/symbol_layer.hpp4
m---------platform/android/vendor/mapbox-events-android0
-rw-r--r--platform/darwin/docs/guides/For Style Authors.md.ejs11
-rw-r--r--platform/darwin/docs/guides/Predicates and Expressions.md8
-rw-r--r--platform/darwin/filesource-files.json1
-rwxr-xr-xplatform/darwin/scripts/generate-style-code.js23
-rw-r--r--platform/darwin/src/MGLAttributedExpression.h55
-rw-r--r--platform/darwin/src/MGLAttributedExpression.m23
-rw-r--r--platform/darwin/src/MGLLoggingConfiguration.h2
-rw-r--r--platform/darwin/src/MGLMapSnapshotter.mm15
-rw-r--r--platform/darwin/src/MGLOfflinePack.mm19
-rw-r--r--platform/darwin/src/MGLOfflinePack_Private.h2
-rw-r--r--platform/darwin/src/MGLOfflineStorage.mm29
-rw-r--r--platform/darwin/src/MGLOfflineStorage_Private.h9
-rw-r--r--platform/darwin/src/MGLRendererConfiguration.h8
-rw-r--r--platform/darwin/src/MGLRendererConfiguration.mm4
-rw-r--r--platform/darwin/src/MGLRendererFrontend.h7
-rw-r--r--platform/darwin/src/MGLStyleValue_Private.h24
-rw-r--r--platform/darwin/src/MGLSymbolStyleLayer.h75
-rw-r--r--platform/darwin/src/MGLSymbolStyleLayer.mm37
-rw-r--r--platform/darwin/src/NSBundle+MGLAdditions.m7
-rw-r--r--platform/darwin/src/NSData+MGLAdditions.h13
-rw-r--r--platform/darwin/src/NSData+MGLAdditions.mm23
-rw-r--r--platform/darwin/src/NSExpression+MGLAdditions.mm51
-rw-r--r--platform/darwin/test/MGLAttributionInfoTests.m15
-rw-r--r--platform/darwin/test/MGLDocumentationExampleTests.swift18
-rw-r--r--platform/darwin/test/MGLExpressionTests.mm92
-rw-r--r--platform/darwin/test/MGLOfflineStorageTests.mm9
-rw-r--r--platform/darwin/test/MGLSymbolStyleLayerTests.mm116
-rw-r--r--platform/default/include/mbgl/map/map_snapshotter.hpp9
-rw-r--r--platform/default/src/mbgl/gl/headless_frontend.cpp8
-rw-r--r--platform/default/src/mbgl/map/map_snapshotter.cpp48
-rw-r--r--platform/default/src/mbgl/storage/default_file_source.cpp4
-rw-r--r--platform/default/src/mbgl/storage/file_source.cpp15
-rw-r--r--platform/glfw/glfw_renderer_frontend.cpp7
-rw-r--r--platform/glfw/glfw_view.cpp2
-rw-r--r--platform/glfw/main.cpp37
-rw-r--r--platform/ios/CHANGELOG.md22
-rw-r--r--platform/ios/Integration Tests/Annotation Tests/MGLAnnotationViewIntegrationTests.m1
-rw-r--r--platform/ios/Integration Tests/MGLCameraTransitionTests.mm2
-rw-r--r--platform/ios/Mapbox-iOS-SDK-snapshot-dynamic.podspec2
-rw-r--r--platform/ios/Mapbox-iOS-SDK-stripped.podspec2
-rw-r--r--platform/ios/Mapbox-iOS-SDK.podspec2
-rw-r--r--platform/ios/app/MBXViewController.m20
-rw-r--r--platform/ios/app/missing_icon.json40
-rw-r--r--platform/ios/docs/guides/For Style Authors.md11
-rw-r--r--platform/ios/ios.xcodeproj/project.pbxproj49
-rwxr-xr-xplatform/ios/scripts/package.sh7
-rw-r--r--platform/ios/sdk-files.json6
-rw-r--r--platform/ios/src/MGLMapView.h27
-rw-r--r--platform/ios/src/MGLMapView.mm197
-rw-r--r--platform/ios/src/MGLMapViewDelegate.h2
-rw-r--r--platform/ios/src/UIColor+MGLAdditions.h1
-rw-r--r--platform/ios/test/MGLMapViewDelegateIntegrationTests.swift2
-rw-r--r--platform/ios/test/MGLNSDataAdditionsTests.m48
m---------platform/ios/vendor/mapbox-events-ios0
-rw-r--r--platform/linux/config.cmake9
-rw-r--r--platform/linux/filesource-files.json10
-rw-r--r--platform/macos/CHANGELOG.md7
-rw-r--r--platform/macos/docs/guides/For Style Authors.md11
-rw-r--r--platform/macos/macos.xcodeproj/project.pbxproj1
-rw-r--r--platform/macos/src/MGLMapView.mm13
-rw-r--r--platform/macos/src/NSColor+MGLAdditions.h1
-rw-r--r--platform/macos/src/NSColor+MGLAdditions.mm6
-rw-r--r--platform/node/src/node_map.cpp51
-rw-r--r--platform/node/src/node_map.hpp24
-rw-r--r--platform/node/test/ignores.json21
-rw-r--r--platform/qt/qt.cmake1
-rw-r--r--platform/qt/src/qmapboxgl.cpp104
-rw-r--r--platform/qt/src/qmapboxgl_p.hpp2
191 files changed, 9016 insertions, 2336 deletions
diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md
index 7a117f4b2a..55cfd1a6cd 100644
--- a/platform/android/CHANGELOG.md
+++ b/platform/android/CHANGELOG.md
@@ -4,6 +4,48 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to
## master
+## 7.4.0-alpha.1 - April 3, 2019
+
+### Bugs
+ - Clean up location permissions annotation [#14311](https://github.com/mapbox/mapbox-gl-native/pull/14311)
+ - Clear camera callbacks' message queue when the map is destroyed [#14292](https://github.com/mapbox/mapbox-gl-native/pull/14292)
+ - Use a valid gestures focal point when resetting a manager [#14284](https://github.com/mapbox/mapbox-gl-native/pull/14284)
+ - Disable move gesture detector foreseeing the quickzoom [#14268](https://github.com/mapbox/mapbox-gl-native/pull/14268)
+ - Remove request render from MapboxMap#onStart [#14245](https://github.com/mapbox/mapbox-gl-native/pull/14245)
+ - Use TurfMeasurement#distance in LatLng#distanceTo [#14220](https://github.com/mapbox/mapbox-gl-native/pull/14220)
+
+### Features
+ - Add pixel dimension annotation to public UiSettings methods [#14281](https://github.com/mapbox/mapbox-gl-native/pull/14281)
+ - Add #toString override for formatted sections [#14247](https://github.com/mapbox/mapbox-gl-native/pull/14247)
+ - Harden fetching camera for bounds when padding is excessive [#14221](https://github.com/mapbox/mapbox-gl-native/pull/14221)
+ - Traverse expression tree when checking for property overrides [#14259](https://github.com/mapbox/mapbox-gl-native/pull/14259)
+ - Variable label placement [#14184](https://github.com/mapbox/mapbox-gl-native/pull/14184)
+
+### Build
+ - Disable binary programs until we fix [#14294]((https://github.com/mapbox/mapbox-gl-native/pull/14298)
+ - Disable leak canary during instrumentation tests [#14296](https://github.com/mapbox/mapbox-gl-native/pull/14296)
+ - Remove Android v7 support library [#14265](https://github.com/mapbox/mapbox-gl-native/pull/14265)
+
+## 7.3.0 - March 28, 2019
+
+### Bugs
+ - Fix MapView reuse issues [#14127](https://github.com/mapbox/mapbox-gl-native/pull/14127)
+ - Don't call OnSurfaceCreated from the main thread [#14244](https://github.com/mapbox/mapbox-gl-native/pull/14244)
+
+## 7.3.0-beta.1 - March 20, 2019
+
+### Features
+ - Expose "text-color" option for formatted sections [#14128](https://github.com/mapbox/mapbox-gl-native/pull/14128)
+ - Expose LocationComponent's layer IDs [#14155](https://github.com/mapbox/mapbox-gl-native/pull/14155)
+
+### Bugs
+ - Cache location layer IDs in a set instead of a list [#14141](https://github.com/mapbox/mapbox-gl-native/pull/14141)
+ - Clear the style object when the map is destroyed [#14171](https://github.com/mapbox/mapbox-gl-native/pull/14171)
+ - Cache source/layer only when successfully added [#14171](https://github.com/mapbox/mapbox-gl-native/pull/14171)
+
+### Build
+ - Bump telemetry version to 4.3.0 [#14140](https://github.com/mapbox/mapbox-gl-native/pull/14140)
+
## 7.3.0-alpha.2 - March 13, 2019
### Features
diff --git a/platform/android/LICENSE.md b/platform/android/LICENSE.md
index f69b393541..d6f4e65302 100644
--- a/platform/android/LICENSE.md
+++ b/platform/android/LICENSE.md
@@ -1,11 +1,5 @@
<!-- This file was generated. Use `make android-license` to update. -->
## Additional Mapbox GL licenses
-Mapbox GL uses portions of the Android AppCompat Library v7.
-URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html)
-License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt)
-
-===========================================================================
-
Mapbox GL uses portions of the Android Arch-Common.
URL: [https://developer.android.com/topic/libraries/architecture/index.html](https://developer.android.com/topic/libraries/architecture/index.html)
License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt)
@@ -18,18 +12,6 @@ License: [The Apache Software License, Version 2.0](http://www.apache.org/licens
===========================================================================
-Mapbox GL uses portions of the Android Lifecycle Extensions.
-URL: [https://developer.android.com/topic/libraries/architecture/index.html](https://developer.android.com/topic/libraries/architecture/index.html)
-License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt)
-
-===========================================================================
-
-Mapbox GL uses portions of the Android Lifecycle LiveData.
-URL: [https://developer.android.com/topic/libraries/architecture/index.html](https://developer.android.com/topic/libraries/architecture/index.html)
-License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt)
-
-===========================================================================
-
Mapbox GL uses portions of the Android Lifecycle LiveData Core.
URL: [https://developer.android.com/topic/libraries/architecture/index.html](https://developer.android.com/topic/libraries/architecture/index.html)
License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt)
@@ -54,12 +36,6 @@ License: [The Apache Software License, Version 2.0](http://www.apache.org/licens
===========================================================================
-Mapbox GL uses portions of the Android Support AnimatedVectorDrawable.
-URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html)
-License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt)
-
-===========================================================================
-
Mapbox GL uses portions of the Android Support Library Annotations.
URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html)
License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt)
@@ -90,12 +66,6 @@ License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.
===========================================================================
-Mapbox GL uses portions of the Android Support VectorDrawable.
-URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html)
-License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt)
-
-===========================================================================
-
Mapbox GL uses portions of the Converter: Gson.
License: [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt)
@@ -157,6 +127,12 @@ License: [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt)
===========================================================================
+Mapbox GL uses portions of the ReLinker.
+URL: [https://github.com/KeepSafe/ReLinker](https://github.com/KeepSafe/ReLinker)
+License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt)
+
+===========================================================================
+
Mapbox GL uses portions of the Retrofit.
License: [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt)
diff --git a/platform/android/MapboxGLAndroidSDK/build.gradle b/platform/android/MapboxGLAndroidSDK/build.gradle
index 89937448e9..74c7c4c465 100644
--- a/platform/android/MapboxGLAndroidSDK/build.gradle
+++ b/platform/android/MapboxGLAndroidSDK/build.gradle
@@ -8,7 +8,6 @@ dependencies {
api dependenciesList.mapboxJavaGeoJSON
api dependenciesList.mapboxAndroidGestures
implementation dependenciesList.mapboxJavaTurf
- implementation dependenciesList.supportAppcompatV7
implementation dependenciesList.supportAnnotations
implementation dependenciesList.supportFragmentV4
implementation dependenciesList.okhttp3
@@ -23,10 +22,6 @@ dependencies {
android {
compileSdkVersion androidVersions.compileSdkVersion
- // Roboelectric 4.0 required config
- // http://robolectric.org/migrating/#migrating-to-40
- testOptions.unitTests.includeAndroidResources = true
-
defaultConfig {
minSdkVersion androidVersions.minSdkVersion
targetSdkVersion androidVersions.targetSdkVersion
@@ -134,12 +129,16 @@ android {
testOptions {
unitTests {
returnDefaultValues true
+
+ // Roboelectric 4.0 required config
+ // http://robolectric.org/migrating/#migrating-to-40
includeAndroidResources = true
}
}
buildTypes {
debug {
+ testCoverageEnabled true
jniDebuggable true
}
}
@@ -169,4 +168,5 @@ apply from: "${rootDir}/gradle/gradle-checkstyle.gradle"
apply from: "${rootDir}/gradle/gradle-dependencies-graph.gradle"
apply from: "${rootDir}/gradle/gradle-update-vendor-modules.gradle"
apply from: "${rootDir}/gradle/android-nitpick.gradle"
-apply from: "${rootDir}/gradle/gradle-bintray.gradle" \ No newline at end of file
+apply from: "${rootDir}/gradle/gradle-bintray.gradle"
+apply from: "${rootDir}/gradle/jacoco-report.gradle" \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/gradle.properties b/platform/android/MapboxGLAndroidSDK/gradle.properties
index be4246a903..5f3ea808fa 100644
--- a/platform/android/MapboxGLAndroidSDK/gradle.properties
+++ b/platform/android/MapboxGLAndroidSDK/gradle.properties
@@ -1,4 +1,4 @@
-VERSION_NAME=7.3.0-SNAPSHOT
+VERSION_NAME=7.4.0-SNAPSHOT
# Only build native dependencies for the current ABI
# See https://code.google.com/p/android/issues/detail?id=221098#c20
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 8ae388549e..ce12489b49 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
@@ -5,10 +5,14 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.FloatRange;
import android.support.annotation.Keep;
-
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+
+import com.mapbox.geojson.Point;
import com.mapbox.mapboxsdk.constants.GeometryConstants;
+import com.mapbox.turf.TurfMeasurement;
+
+import static com.mapbox.turf.TurfConstants.UNIT_METRES;
/**
@@ -209,7 +213,8 @@ public class LatLng implements Parcelable {
@NonNull
public LatLng wrap() {
return new LatLng(latitude, wrap(longitude,
- GeometryConstants.MIN_WRAP_LONGITUDE, GeometryConstants.MAX_WRAP_LONGITUDE));
+ GeometryConstants.MIN_WRAP_LONGITUDE, GeometryConstants.MAX_WRAP_LONGITUDE)
+ );
}
@@ -218,8 +223,10 @@ public class LatLng implements Parcelable {
* <p>
* Same formula as used in Core GL (wrap.hpp)
* std::fmod((std::fmod((value - min), d) + d), d) + min;
- *
+ * </p>
+ * <p>
* Multiples of max value will be wrapped to max.
+ * </p>
*
* @param value Value to wrap
* @param min Minimum value
@@ -318,24 +325,10 @@ public class LatLng implements Parcelable {
* @return distance in meters
*/
public double distanceTo(@NonNull LatLng other) {
- if (latitude == other.latitude && longitude == other.longitude) {
- // return 0.0 to avoid a NaN
- return 0.0;
- }
-
- final double a1 = Math.toRadians(this.latitude);
- final double a2 = Math.toRadians(this.longitude);
- final double b1 = Math.toRadians(other.getLatitude());
- final double b2 = Math.toRadians(other.getLongitude());
-
- final double cosa1 = Math.cos(a1);
- final double cosb1 = Math.cos(b1);
-
- final double t1 = cosa1 * Math.cos(a2) * cosb1 * Math.cos(b2);
- final double t2 = cosa1 * Math.sin(a2) * cosb1 * Math.sin(b2);
- final double t3 = Math.sin(a1) * Math.sin(b1);
- final double tt = Math.acos(t1 + t2 + t3);
-
- return GeometryConstants.RADIUS_EARTH_METERS * tt;
+ return TurfMeasurement.distance(
+ Point.fromLngLat(longitude, latitude),
+ Point.fromLngLat(other.getLongitude(), other.getLatitude()),
+ UNIT_METRES
+ );
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationCameraController.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationCameraController.java
index 4e56c6e9c0..b9aa371a47 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationCameraController.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationCameraController.java
@@ -77,9 +77,11 @@ final class LocationCameraController {
void initializeOptions(LocationComponentOptions options) {
this.options = options;
if (options.trackingGesturesManagement()) {
- mapboxMap.setGesturesManager(internalGesturesManager, true, true);
+ if (mapboxMap.getGesturesManager() != internalGesturesManager) {
+ mapboxMap.setGesturesManager(internalGesturesManager, true, true);
+ }
adjustGesturesThresholds();
- } else {
+ } else if (mapboxMap.getGesturesManager() != initialGesturesManager) {
mapboxMap.setGesturesManager(initialGesturesManager, true, true);
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java
index b97ab75b5e..327ab3c8ed 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java
@@ -220,7 +220,6 @@ public final class LocationComponent {
* @param style the proxy object for current map style. More info at {@link Style}
* @deprecated use {@link LocationComponentActivationOptions.Builder} instead
*/
- @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION})
@Deprecated
public void activateLocationComponent(@NonNull Context context, @NonNull Style style) {
activateLocationComponent(context, style,
@@ -237,7 +236,6 @@ public final class LocationComponent {
* there should be no location engine initialized
* @deprecated use {@link LocationComponentActivationOptions.Builder} instead
*/
- @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION})
@Deprecated
public void activateLocationComponent(@NonNull Context context, @NonNull Style style,
boolean useDefaultLocationEngine) {
@@ -259,7 +257,6 @@ public final class LocationComponent {
* @param locationEngineRequest the location request
* @deprecated use {@link LocationComponentActivationOptions.Builder} instead
*/
- @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION})
@Deprecated
public void activateLocationComponent(@NonNull Context context, @NonNull Style style,
boolean useDefaultLocationEngine,
@@ -284,7 +281,6 @@ public final class LocationComponent {
* @param options the options
* @deprecated use {@link LocationComponentActivationOptions.Builder} instead
*/
- @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION})
@Deprecated
public void activateLocationComponent(@NonNull Context context, @NonNull Style style,
boolean useDefaultLocationEngine,
@@ -309,7 +305,6 @@ public final class LocationComponent {
* @param styleRes the LocationComponent style res
* @deprecated use {@link LocationComponentActivationOptions.Builder} instead
*/
- @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION})
@Deprecated
public void activateLocationComponent(@NonNull Context context, @NonNull Style style, @StyleRes int styleRes) {
activateLocationComponent(context, style, LocationComponentOptions.createFromAttributes(context, styleRes));
@@ -327,7 +322,6 @@ public final class LocationComponent {
* @param options the options
* @deprecated use {@link LocationComponentActivationOptions.Builder} instead
*/
- @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION})
@Deprecated
public void activateLocationComponent(@NonNull Context context, @NonNull Style style,
@NonNull LocationComponentOptions options) {
@@ -346,7 +340,6 @@ public final class LocationComponent {
* @param styleRes the LocationComponent style res
* @deprecated use {@link LocationComponentActivationOptions.Builder} instead
*/
- @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION})
@Deprecated
public void activateLocationComponent(@NonNull Context context, @NonNull Style style,
@Nullable LocationEngine locationEngine, @StyleRes int styleRes) {
@@ -365,7 +358,6 @@ public final class LocationComponent {
* @param styleRes the LocationComponent style res
* @deprecated use {@link LocationComponentActivationOptions.Builder} instead
*/
- @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION})
@Deprecated
public void activateLocationComponent(@NonNull Context context, @NonNull Style style,
@Nullable LocationEngine locationEngine,
@@ -382,7 +374,6 @@ public final class LocationComponent {
* @param locationEngine the engine
* @deprecated use {@link LocationComponentActivationOptions.Builder} instead
*/
- @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION})
@Deprecated
public void activateLocationComponent(@NonNull Context context, @NonNull Style style,
@Nullable LocationEngine locationEngine) {
@@ -398,7 +389,6 @@ public final class LocationComponent {
* @param locationEngineRequest the location request
* @deprecated use {@link LocationComponentActivationOptions.Builder} instead
*/
- @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION})
@Deprecated
public void activateLocationComponent(@NonNull Context context, @NonNull Style style,
@Nullable LocationEngine locationEngine,
@@ -415,7 +405,6 @@ public final class LocationComponent {
* @param options the options
* @deprecated use {@link LocationComponentActivationOptions.Builder} instead
*/
- @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION})
@Deprecated
public void activateLocationComponent(@NonNull Context context, @NonNull Style style,
@Nullable LocationEngine locationEngine,
@@ -453,8 +442,7 @@ public final class LocationComponent {
*
* @param activationOptions a fully built {@link LocationComponentActivationOptions} object
*/
- public void activateLocationComponent(@NonNull LocationComponentActivationOptions
- activationOptions) {
+ public void activateLocationComponent(@NonNull LocationComponentActivationOptions activationOptions) {
LocationComponentOptions options = activationOptions.locationComponentOptions();
if (options == null) {
int styleRes = activationOptions.styleRes();
@@ -496,6 +484,7 @@ public final class LocationComponent {
*
* @param isEnabled true if the plugin should be visible and listen for location updates, false otherwise.
*/
+ @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION})
public void setLocationComponentEnabled(boolean isEnabled) {
checkActivationState();
if (isEnabled) {
@@ -954,7 +943,6 @@ public final class LocationComponent {
* @return the last known location
*/
@Nullable
- @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION})
public Location getLastKnownLocation() {
checkActivationState();
return lastLocation;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentConstants.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentConstants.java
index 093c91e799..c0173cb8e8 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentConstants.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentConstants.java
@@ -1,7 +1,7 @@
package com.mapbox.mapboxsdk.location;
/**
- * Contains all the constants being used for the Location layer.
+ * Contains all the constants being used for the {@link LocationComponent}.
*/
final class LocationComponentConstants {
@@ -49,11 +49,31 @@ final class LocationComponentConstants {
static final String PROPERTY_BEARING_ICON = "mapbox-property-shadow-icon";
// Layers
- static final String SHADOW_LAYER = "mapbox-location-shadow";
- static final String FOREGROUND_LAYER = "mapbox-location-layer";
- static final String BACKGROUND_LAYER = "mapbox-location-stroke-layer";
- static final String ACCURACY_LAYER = "mapbox-location-accuracy-layer";
- static final String BEARING_LAYER = "mapbox-location-bearing-layer";
+
+ /**
+ * Layer ID of the location shadow.
+ */
+ public static final String SHADOW_LAYER = "mapbox-location-shadow-layer";
+
+ /**
+ * Layer ID of the location foreground icon.
+ */
+ public static final String FOREGROUND_LAYER = "mapbox-location-foreground-layer";
+
+ /**
+ * Layer ID of the location background icon.
+ */
+ public static final String BACKGROUND_LAYER = "mapbox-location-background-layer";
+
+ /**
+ * Layer ID of the location accuracy.
+ */
+ public static final String ACCURACY_LAYER = "mapbox-location-accuracy-layer";
+
+ /**
+ * Layer ID of the location bearing icon.
+ */
+ public static final String BEARING_LAYER = "mapbox-location-bearing-layer";
// Icons
static final String FOREGROUND_ICON = "mapbox-location-icon";
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java
index f11acacf31..aa8a82bf6d 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java
@@ -5,6 +5,7 @@ import android.graphics.PointF;
import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
@@ -18,7 +19,6 @@ import com.mapbox.mapboxsdk.style.layers.Layer;
import com.mapbox.mapboxsdk.style.layers.SymbolLayer;
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
-import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -70,7 +70,8 @@ final class LocationLayerController {
private LocationComponentOptions options;
private final OnRenderModeChangedListener internalRenderModeChangedListener;
- private final List<String> layerMap = new ArrayList<>();
+ @VisibleForTesting
+ final Set<String> layerSet = new HashSet<>();
private Feature locationFeature;
private GeoJsonSource locationSource;
@@ -112,7 +113,7 @@ final class LocationLayerController {
removeLayers();
addLayers(newLayerBelowOption);
if (isHidden) {
- for (String layerId : layerMap) {
+ for (String layerId : layerSet) {
setLayerVisibility(layerId, false);
}
}
@@ -193,7 +194,7 @@ final class LocationLayerController {
void hide() {
isHidden = true;
- for (String layerId : layerMap) {
+ for (String layerId : layerSet) {
setLayerVisibility(layerId, false);
}
}
@@ -257,14 +258,14 @@ final class LocationLayerController {
private void addLayerToMap(Layer layer, @NonNull String idBelowLayer) {
style.addLayerBelow(layer, idBelowLayer);
- layerMap.add(layer.getId());
+ layerSet.add(layer.getId());
}
private void removeLayers() {
- for (String layerId : layerMap) {
+ for (String layerId : layerSet) {
style.removeLayer(layerId);
}
- layerMap.clear();
+ layerSet.clear();
}
private void setBearingProperty(@NonNull String propertyId, float bearing) {
@@ -351,7 +352,7 @@ final class LocationLayerController {
}
private void styleScaling(@NonNull LocationComponentOptions options) {
- for (String layerId : layerMap) {
+ for (String layerId : layerSet) {
Layer layer = style.getLayer(layerId);
if (layer instanceof SymbolLayer) {
layer.setProperties(
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java
index b3472ac81e..a1fd4e7e3e 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java
@@ -142,6 +142,14 @@ class CameraChangeDispatcher implements MapboxMap.OnCameraMoveStartedListener, M
}
}
+ void onDestroy() {
+ handler.removeCallbacksAndMessages(null);
+ onCameraMoveStarted.clear();
+ onCameraMoveCanceled.clear();
+ onCameraMove.clear();
+ onCameraIdle.clear();
+ }
+
private static class CameraChangeHandler extends Handler {
private WeakReference<CameraChangeDispatcher> dispatcherWeakReference;
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 c9e6e633aa..9473ea7091 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
@@ -74,7 +74,7 @@ final class MapGestureDetector {
* User-set focal point.
*/
@Nullable
- private PointF focalPoint;
+ private PointF constantFocalPoint;
private AndroidGesturesManager gesturesManager;
@@ -158,7 +158,7 @@ final class MapGestureDetector {
/**
* Set the gesture focal point.
* <p>
- * this is the center point used for calculate transformations from gestures, value is
+ * This is the center point used for calculate transformations from gestures, value is
* overridden if end user provides his own through {@link UiSettings#setFocalPoint(PointF)}.
* </p>
*
@@ -172,22 +172,7 @@ final class MapGestureDetector {
focalPoint = uiSettings.getFocalPoint();
}
}
- this.focalPoint = focalPoint;
- }
-
- /**
- * Get the current active gesture focal point.
- * <p>
- * This could be either the user provided focal point in
- * {@link UiSettings#setFocalPoint(PointF)}or <code>null</code>.
- * If it's <code>null</code>, gestures will use focal pointed returned by the detector.
- * </p>
- *
- * @return the current active gesture focal point.
- */
- @Nullable
- PointF getFocalPoint() {
- return focalPoint;
+ this.constantFocalPoint = focalPoint;
}
/**
@@ -357,18 +342,25 @@ final class MapGestureDetector {
int action = motionEvent.getActionMasked();
if (action == MotionEvent.ACTION_DOWN) {
executeDoubleTap = true;
+
+ // disable the move detector in preparation for the quickzoom,
+ // so that we don't move the map's center slightly before the quickzoom is started (see #14227)
+ gesturesManager.getMoveGestureDetector().setEnabled(false);
}
if (motionEvent.getActionMasked() == MotionEvent.ACTION_UP) {
+ // re-enabled the move detector
+ gesturesManager.getMoveGestureDetector().setEnabled(true);
+
if (!uiSettings.isZoomGesturesEnabled() || !uiSettings.isDoubleTapGesturesEnabled() || !executeDoubleTap) {
return false;
}
PointF zoomFocalPoint;
// Single finger double tap
- if (focalPoint != null) {
+ if (constantFocalPoint != null) {
// User provided focal point
- zoomFocalPoint = focalPoint;
+ zoomFocalPoint = constantFocalPoint;
} else {
// Zoom in on gesture
zoomFocalPoint = new PointF(motionEvent.getX(), motionEvent.getY());
@@ -468,9 +460,6 @@ final class MapGestureDetector {
private final class ScaleGestureListener extends StandardScaleGestureDetector.SimpleStandardOnScaleGestureListener {
private final float minimumVelocity;
-
- @Nullable
- private PointF scaleFocalPoint;
private boolean quickZoom;
ScaleGestureListener(float minimumVelocity) {
@@ -496,8 +485,6 @@ final class MapGestureDetector {
if (!uiSettings.isQuickZoomGesturesEnabled()) {
return false;
}
- // when quickzoom, disable move gesture
- gesturesManager.getMoveGestureDetector().setEnabled(false);
}
cancelTransitionsIfRequired();
@@ -510,10 +497,7 @@ final class MapGestureDetector {
);
}
- // setting focalPoint in #onScaleBegin() as well, because #onScale() might not get called before #onScaleEnd()
- setScaleFocalPoint(detector);
-
- sendTelemetryEvent(TelemetryConstants.PINCH, scaleFocalPoint);
+ sendTelemetryEvent(TelemetryConstants.PINCH, getScaleFocalPoint(detector));
notifyOnScaleBeginListeners(detector);
@@ -525,11 +509,10 @@ final class MapGestureDetector {
// dispatching camera start event only when the movement actually occurred
cameraChangeDispatcher.onCameraMoveStarted(CameraChangeDispatcher.REASON_API_GESTURE);
- setScaleFocalPoint(detector);
-
float scaleFactor = detector.getScaleFactor();
double zoomBy = getNewZoom(scaleFactor, quickZoom);
- transform.zoomBy(zoomBy, scaleFocalPoint);
+ PointF focalPoint = getScaleFocalPoint(detector);
+ transform.zoomBy(zoomBy, focalPoint);
notifyOnScaleListeners(detector);
@@ -538,11 +521,6 @@ final class MapGestureDetector {
@Override
public void onScaleEnd(@NonNull StandardScaleGestureDetector detector, float velocityX, float velocityY) {
- if (quickZoom) {
- //if quickzoom, re-enabling move gesture detector
- gesturesManager.getMoveGestureDetector().setEnabled(true);
- }
-
if (uiSettings.isIncreaseRotateThresholdWhenScaling()) {
// resetting default angle threshold
gesturesManager.getRotateGestureDetector().setAngleThreshold(
@@ -562,21 +540,23 @@ final class MapGestureDetector {
double zoomAddition = calculateScale(velocityXY, detector.isScalingOut());
double currentZoom = transform.getRawZoom();
+ PointF focalPoint = getScaleFocalPoint(detector);
long animationTime = (long) (Math.abs(zoomAddition) * 1000 / 4);
- scaleAnimator = createScaleAnimator(currentZoom, zoomAddition, scaleFocalPoint, animationTime);
+ scaleAnimator = createScaleAnimator(currentZoom, zoomAddition, focalPoint, animationTime);
scheduleAnimator(scaleAnimator);
}
- private void setScaleFocalPoint(@NonNull StandardScaleGestureDetector detector) {
- if (focalPoint != null) {
+ @NonNull
+ private PointF getScaleFocalPoint(@NonNull StandardScaleGestureDetector detector) {
+ if (constantFocalPoint != null) {
// around user provided focal point
- scaleFocalPoint = focalPoint;
+ return constantFocalPoint;
} else if (quickZoom) {
// around center
- scaleFocalPoint = new PointF(uiSettings.getWidth() / 2, uiSettings.getHeight() / 2);
+ return new PointF(uiSettings.getWidth() / 2, uiSettings.getHeight() / 2);
} else {
// around gesture
- scaleFocalPoint = detector.getFocalPoint();
+ return detector.getFocalPoint();
}
}
@@ -603,14 +583,12 @@ final class MapGestureDetector {
}
private final class RotateGestureListener extends RotateGestureDetector.SimpleOnRotateGestureListener {
- @Nullable
- private PointF rotateFocalPoint;
private final float minimumScaleSpanWhenRotating;
private final float minimumAngularVelocity;
private final float defaultSpanSinceStartThreshold;
- public RotateGestureListener(float minimumScaleSpanWhenRotating, float minimumAngularVelocity,
- float defaultSpanSinceStartThreshold) {
+ RotateGestureListener(float minimumScaleSpanWhenRotating, float minimumAngularVelocity,
+ float defaultSpanSinceStartThreshold) {
this.minimumScaleSpanWhenRotating = minimumScaleSpanWhenRotating;
this.minimumAngularVelocity = minimumAngularVelocity;
this.defaultSpanSinceStartThreshold = defaultSpanSinceStartThreshold;
@@ -631,10 +609,7 @@ final class MapGestureDetector {
gesturesManager.getStandardScaleGestureDetector().interrupt();
}
- // setting in #onRotateBegin() as well, because #onRotate() might not get called before #onRotateEnd()
- setRotateFocalPoint(detector);
-
- sendTelemetryEvent(TelemetryConstants.ROTATION, rotateFocalPoint);
+ sendTelemetryEvent(TelemetryConstants.ROTATION, getRotateFocalPoint(detector));
notifyOnRotateBeginListeners(detector);
@@ -647,13 +622,12 @@ final class MapGestureDetector {
// dispatching camera start event only when the movement actually occurred
cameraChangeDispatcher.onCameraMoveStarted(CameraChangeDispatcher.REASON_API_GESTURE);
- setRotateFocalPoint(detector);
-
// Calculate map bearing value
double bearing = transform.getRawBearing() + rotationDegreesSinceLast;
// Rotate the map
- transform.setBearing(bearing, rotateFocalPoint.x, rotateFocalPoint.y);
+ PointF focalPoint = getRotateFocalPoint(detector);
+ transform.setBearing(bearing, focalPoint.x, focalPoint.y);
notifyOnRotateListeners(detector);
@@ -687,21 +661,24 @@ final class MapGestureDetector {
angularVelocity = -angularVelocity;
}
- rotateAnimator = createRotateAnimator(angularVelocity, animationTime);
+ PointF focalPoint = getRotateFocalPoint(detector);
+ rotateAnimator = createRotateAnimator(angularVelocity, animationTime, focalPoint);
scheduleAnimator(rotateAnimator);
}
- private void setRotateFocalPoint(@NonNull RotateGestureDetector detector) {
- if (focalPoint != null) {
+ @NonNull
+ private PointF getRotateFocalPoint(@NonNull RotateGestureDetector detector) {
+ if (constantFocalPoint != null) {
// User provided focal point
- rotateFocalPoint = focalPoint;
+ return constantFocalPoint;
} else {
// around gesture
- rotateFocalPoint = detector.getFocalPoint();
+ return detector.getFocalPoint();
}
}
- private Animator createRotateAnimator(float angularVelocity, long animationTime) {
+ private Animator createRotateAnimator(float angularVelocity, long animationTime,
+ @NonNull final PointF animationFocalPoint) {
ValueAnimator animator = ValueAnimator.ofFloat(angularVelocity, 0f);
animator.setDuration(animationTime);
animator.setInterpolator(new DecelerateInterpolator());
@@ -710,7 +687,7 @@ final class MapGestureDetector {
public void onAnimationUpdate(@NonNull ValueAnimator animation) {
transform.setBearing(
transform.getRawBearing() + (float) animation.getAnimatedValue(),
- rotateFocalPoint.x, rotateFocalPoint.y,
+ animationFocalPoint.x, animationFocalPoint.y,
0L
);
}
@@ -802,9 +779,9 @@ final class MapGestureDetector {
PointF zoomFocalPoint;
// Single finger double tap
- if (focalPoint != null) {
+ if (constantFocalPoint != null) {
// User provided focal point
- zoomFocalPoint = focalPoint;
+ zoomFocalPoint = constantFocalPoint;
} else {
// Zoom in on gesture
zoomFocalPoint = detector.getFocalPoint();
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 f87c6a854a..23ce2bdef0 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
@@ -911,7 +911,7 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback {
/**
* Called when the map has finished rendering.
*
- * @param fully true if map is fully rendered, false if fully rendered
+ * @param fully true if map is fully rendered, false if not fully rendered
*/
void onDidFinishRenderingMap(boolean fully);
}
@@ -1257,4 +1257,4 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback {
public static void setMapStrictModeEnabled(boolean strictModeEnabled) {
MapStrictMode.setStrictModeEnabled(strictModeEnabled);
}
-} \ No newline at end of file
+}
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 f0155bda58..95d5c29b61 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
@@ -128,7 +128,6 @@ public final class MapboxMap {
* Called when the hosting Activity/Fragment onStart() method is called.
*/
void onStart() {
- nativeMapView.update();
locationComponent.onStart();
}
@@ -174,6 +173,10 @@ public final class MapboxMap {
*/
void onDestroy() {
locationComponent.onDestroy();
+ if (style != null) {
+ style.clear();
+ }
+ cameraChangeDispatcher.onDestroy();
}
/**
@@ -813,7 +816,7 @@ public final class MapboxMap {
public void setStyle(Style.Builder builder, final Style.OnStyleLoaded callback) {
locationComponent.onStartLoadingMap();
if (style != null) {
- style.onWillStartLoadingMap();
+ style.clear();
}
if (callback != null) {
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java
index cf5961a313..e49126531a 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java
@@ -29,8 +29,6 @@ interface NativeMap {
// Lifecycle API
//
- void update();
-
void resizeView(int width, int height);
void onLowMemory();
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 10942d521c..a5f8be788c 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
@@ -136,15 +136,6 @@ final class NativeMapView implements NativeMap {
}
@Override
- public void update() {
- if (checkState("update")) {
- return;
- }
-
- mapRenderer.requestRender();
- }
-
- @Override
public void resizeView(int width, int height) {
if (checkState("resizeView")) {
return;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Style.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Style.java
index f14e034816..5c28b55de8 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Style.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Style.java
@@ -100,8 +100,8 @@ public class Style {
*/
public void addSource(@NonNull Source source) {
validateState("addSource");
- sources.put(source.getId(), source);
nativeMap.addSource(source);
+ sources.put(source.getId(), source);
}
/**
@@ -172,8 +172,8 @@ public class Style {
*/
public void addLayer(@NonNull Layer layer) {
validateState("addLayer");
- layers.put(layer.getId(), layer);
nativeMap.addLayer(layer);
+ layers.put(layer.getId(), layer);
}
/**
@@ -184,8 +184,8 @@ public class Style {
*/
public void addLayerBelow(@NonNull Layer layer, @NonNull String below) {
validateState("addLayerBelow");
- layers.put(layer.getId(), layer);
nativeMap.addLayerBelow(layer, below);
+ layers.put(layer.getId(), layer);
}
/**
@@ -196,8 +196,8 @@ public class Style {
*/
public void addLayerAbove(@NonNull Layer layer, @NonNull String above) {
validateState("addLayerAbove");
- layers.put(layer.getId(), layer);
nativeMap.addLayerAbove(layer, above);
+ layers.put(layer.getId(), layer);
}
/**
@@ -209,8 +209,8 @@ public class Style {
*/
public void addLayerAt(@NonNull Layer layer, @IntRange(from = 0) int index) {
validateState("addLayerAbove");
- layers.put(layer.getId(), layer);
nativeMap.addLayerAt(layer, index);
+ layers.put(layer.getId(), layer);
}
/**
@@ -437,10 +437,11 @@ public class Style {
//
/**
- * Called when the underlying map will start loading a new style. This method will clean up this style
- * by setting the java sources and layers in a detached state and removing them from core.
+ * Called when the underlying map will start loading a new style or the map is destroyed.
+ * This method will clean up this style by setting the java sources and layers
+ * in a detached state and removing them from core.
*/
- void onWillStartLoadingMap() {
+ void clear() {
fullyLoaded = false;
for (Source source : sources.values()) {
if (source != null) {
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 034dc63c35..c671146876 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
@@ -10,6 +10,7 @@ import android.os.Bundle;
import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+import android.support.annotation.Px;
import android.support.annotation.UiThread;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.res.ResourcesCompat;
@@ -344,7 +345,7 @@ public final class UiSettings {
}
/**
- * Sets the margins of the compass view. Use this to change the distance of the compass from the
+ * Sets the margins of the compass view in pixels. Use this to change the distance of the compass from the
* map view edge.
*
* @param left The left margin in pixels.
@@ -353,42 +354,46 @@ public final class UiSettings {
* @param bottom The bottom margin in pixels.
*/
@UiThread
- public void setCompassMargins(int left, int top, int right, int bottom) {
+ public void setCompassMargins(@Px int left, @Px int top, @Px int right, @Px int bottom) {
setWidgetMargins(compassView, compassMargins, left, top, right, bottom);
}
/**
- * Returns the left side margin of CompassView
+ * Returns the left side margin of CompassView in pixels.
*
* @return The left margin in pixels
*/
+ @Px
public int getCompassMarginLeft() {
return compassMargins[0];
}
/**
- * Returns the top side margin of CompassView
+ * Returns the top side margin of CompassView in pixels.
*
* @return The top margin in pixels
*/
+ @Px
public int getCompassMarginTop() {
return compassMargins[1];
}
/**
- * Returns the right side margin of CompassView
+ * Returns the right side margin of CompassView in pixels.
*
* @return The right margin in pixels
*/
+ @Px
public int getCompassMarginRight() {
return compassMargins[2];
}
/**
- * Returns the bottom side margin of CompassView
+ * Returns the bottom side margin of CompassView in pixels.
*
* @return The bottom margin in pixels
*/
+ @Px
public int getCompassMarginBottom() {
return compassMargins[3];
}
@@ -456,7 +461,7 @@ public final class UiSettings {
}
/**
- * Sets the margins of the logo view. Use this to change the distance of the Mapbox logo from the
+ * Sets the margins of the logo view in pixels. Use this to change the distance of the Mapbox logo from the
* map view edge.
*
* @param left The left margin in pixels.
@@ -464,42 +469,46 @@ public final class UiSettings {
* @param right The right margin in pixels.
* @param bottom The bottom margin in pixels.
*/
- public void setLogoMargins(int left, int top, int right, int bottom) {
+ public void setLogoMargins(@Px int left, @Px int top, @Px int right, @Px int bottom) {
setWidgetMargins(logoView, logoMargins, left, top, right, bottom);
}
/**
- * Returns the left side margin of the logo
+ * Returns the left side margin of the logo in pixels.
*
* @return The left margin in pixels
*/
+ @Px
public int getLogoMarginLeft() {
return logoMargins[0];
}
/**
- * Returns the top side margin of the logo
+ * Returns the top side margin of the logo in pixels.
*
* @return The top margin in pixels
*/
+ @Px
public int getLogoMarginTop() {
return logoMargins[1];
}
/**
- * Returns the right side margin of the logo
+ * Returns the right side margin of the logo in pixels.
*
* @return The right margin in pixels
*/
+ @Px
public int getLogoMarginRight() {
return logoMargins[2];
}
/**
- * Returns the bottom side margin of the logo
+ * Returns the bottom side margin of the logo in pixels.
*
* @return The bottom margin in pixels
*/
+ @Px
public int getLogoMarginBottom() {
return logoMargins[3];
}
@@ -570,14 +579,14 @@ public final class UiSettings {
}
/**
- * Sets the margins of the attribution view.
+ * Sets the margins of the attribution view in pixels.
*
* @param left The left margin in pixels.
* @param top The top margin in pixels.
* @param right The right margin in pixels.
* @param bottom The bottom margin in pixels.
*/
- public void setAttributionMargins(int left, int top, int right, int bottom) {
+ public void setAttributionMargins(@Px int left, @Px int top, @Px int right, @Px int bottom) {
setWidgetMargins(attributionsView, attributionsMargins, left, top, right, bottom);
}
@@ -599,37 +608,41 @@ public final class UiSettings {
}
/**
- * Returns the left side margin of the attribution view.
+ * Returns the left side margin of the attribution view in pixels.
*
* @return The left margin in pixels
*/
+ @Px
public int getAttributionMarginLeft() {
return attributionsMargins[0];
}
/**
- * Returns the top side margin of the attribution view.
+ * Returns the top side margin of the attribution view in pixels.
*
* @return The top margin in pixels
*/
+ @Px
public int getAttributionMarginTop() {
return attributionsMargins[1];
}
/**
- * Returns the right side margin of the attribution view.
+ * Returns the right side margin of the attribution view in pixels.
*
* @return The right margin in pixels
*/
+ @Px
public int getAttributionMarginRight() {
return attributionsMargins[2];
}
/**
- * Returns the bottom side margin of the logo
+ * Returns the bottom side margin of the logo in pixels.
*
* @return The bottom margin in pixels
*/
+ @Px
public int getAttributionMarginBottom() {
return attributionsMargins[3];
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/glsurfaceview/GLSurfaceViewMapRenderer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/glsurfaceview/GLSurfaceViewMapRenderer.java
index 9d9a7bd2d4..524c1a62ee 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/glsurfaceview/GLSurfaceViewMapRenderer.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/glsurfaceview/GLSurfaceViewMapRenderer.java
@@ -2,10 +2,8 @@ package com.mapbox.mapboxsdk.maps.renderer.glsurfaceview;
import android.content.Context;
import android.opengl.GLSurfaceView;
-
import android.support.annotation.NonNull;
import android.view.SurfaceHolder;
-
import com.mapbox.mapboxsdk.maps.renderer.MapRenderer;
import com.mapbox.mapboxsdk.maps.renderer.egl.EGLConfigChooser;
@@ -25,8 +23,6 @@ public class GLSurfaceViewMapRenderer extends MapRenderer implements GLSurfaceVi
@NonNull
private final GLSurfaceView glSurfaceView;
- private boolean requestDestroy;
-
public GLSurfaceViewMapRenderer(Context context,
GLSurfaceView glSurfaceView,
String localIdeographFontFamily) {
@@ -42,9 +38,8 @@ public class GLSurfaceViewMapRenderer extends MapRenderer implements GLSurfaceVi
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
- requestDestroy = true;
+ onSurfaceDestroyed();
}
-
});
}
@@ -60,9 +55,6 @@ public class GLSurfaceViewMapRenderer extends MapRenderer implements GLSurfaceVi
@Override
public void onDestroy() {
- if (requestDestroy) {
- onSurfaceDestroyed();
- }
super.onDestroy();
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewRenderThread.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewRenderThread.java
index 96d5e9e943..165b15a512 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewRenderThread.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewRenderThread.java
@@ -197,7 +197,6 @@ class TextureViewRenderThread extends Thread implements TextureView.SurfaceTextu
if (destroySurface) {
eglHolder.destroySurface();
destroySurface = false;
- mapRenderer.onSurfaceDestroyed();
break;
}
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 6262418a29..53c0c1c60f 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
@@ -7,10 +7,10 @@ import android.support.annotation.Nullable;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.ViewPropertyAnimatorCompat;
import android.support.v4.view.ViewPropertyAnimatorListenerAdapter;
-import android.support.v7.widget.AppCompatImageView;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.ImageView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
@@ -23,7 +23,7 @@ import com.mapbox.mapboxsdk.maps.MapboxMap;
* use {@link com.mapbox.mapboxsdk.maps.UiSettings}.
* </p>
*/
-public final class CompassView extends AppCompatImageView implements Runnable {
+public final class CompassView extends ImageView implements Runnable {
public static final long TIME_WAIT_IDLE = 500;
public static final long TIME_MAP_NORTH_ANIMATION = 150;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/PerformanceEvent.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/PerformanceEvent.java
index b88e1885ca..12d1fe46cf 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/PerformanceEvent.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/PerformanceEvent.java
@@ -1,20 +1,55 @@
package com.mapbox.mapboxsdk.module.telemetry;
+import com.google.gson.Gson;
+
+import com.google.gson.JsonObject;
+
+import com.google.gson.reflect.TypeToken;
import com.mapbox.android.telemetry.Event;
import android.os.Bundle;
import android.os.Parcel;
+
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
import java.util.Date;
+import java.util.List;
import java.util.Locale;
/**
* Generic Performance Event that can be used for performance measurements.
* Customer measurements can be added to the bundle.
+ *
+ * Bundle is expected to have following properties:
+ * "attributes", "counters", and "metadata" with String values.
+ *
+ * Attributes: a string representing an array of name/string value pair objects.
+ * Counters: a string representing an array of name/number value pair objects.
+ * Metadata is a string representation of a JsonObject with string values.
+ *
+ * Here is an example of a Performance event bundle data:
+ *
+ * "attributes": [{ "name": "style_id", "value": "mapbox://styles/mapbox/streets-v10"}]
+ *
+ * "counters": [{"name": "fps_average", "value": 90.7655486547093},
+ * {"name": "fps_deviation", "value": 29.301809631465574}]
+ * “metadata”: {
+ * “version”: “9”,
+ * “screenSize”: “1080x1794”,
+ * “country”: “US”,
+ * “device”: “Pixel 2”,
+ * “abi”: “arm64-v8a”,
+ * “brand”: “google”,
+ * “ram”: “3834167296”,
+ * “os”: “android”,
+ * “gpu”: “Qualcomm, Adreno (TM) 540, OpenGL ES 3.2 V@313.0 (GIT@7bf2852, Ie32bfa6f6f)“,
+ * “manufacturer”: “Google”
+ * }
*/
public class PerformanceEvent extends Event {
- private static final String PERFORMANCE_TRACE = "performance.trace";
+
+ private static final String PERFORMANCE_TRACE = "mobile.performance_trace";
private final String event;
@@ -22,23 +57,36 @@ public class PerformanceEvent extends Event {
private final String sessionId;
- private final Bundle data;
+ private final List<Attribute<String>> attributes;
+
+ private final List<Attribute<Double>> counters;
+
+ private final JsonObject metadata;
+
private static final SimpleDateFormat DATE_FORMAT =
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US);
- PerformanceEvent(String sessionId, Bundle data) {
+ PerformanceEvent(String sessionId, Bundle bundle) {
+
this.event = PERFORMANCE_TRACE;
this.created = DATE_FORMAT.format(new Date());
this.sessionId = sessionId;
- this.data = data;
+ this.attributes = initList(bundle.getString("attributes"),
+ new TypeToken<ArrayList<Attribute<String>>>() {});
+ this.counters = initList(bundle.getString("counters"),
+ new TypeToken<ArrayList<Attribute<Double>>>() {});
+ this.metadata = initMetaData(bundle.getString("metadata"));
}
private PerformanceEvent(Parcel in) {
this.event = in.readString();
this.created = in.readString();
this.sessionId = in.readString();
- this.data = in.readBundle();
+
+ this.attributes = initList(in.readString(), new TypeToken<ArrayList<Attribute<String>>>() {});
+ this.counters = initList(in.readString(), new TypeToken<ArrayList<Attribute<Double>>>() {});
+ this.metadata = initMetaData(in.readString());
}
@Override
@@ -51,7 +99,30 @@ public class PerformanceEvent extends Event {
parcel.writeString(event);
parcel.writeString(created);
parcel.writeString(sessionId);
- parcel.writeBundle(data);
+
+ Gson gson = new Gson();
+
+ parcel.writeString(gson.toJson(attributes));
+ parcel.writeString(gson.toJson(counters));
+
+ if (metadata != null) {
+ parcel.writeString(metadata.toString());
+ }
+ }
+
+ private <T> ArrayList<Attribute<T>> initList(String fromString, TypeToken typeToken) {
+ if (fromString == null || fromString.isEmpty()) {
+ return new ArrayList<>();
+ }
+ return new Gson().fromJson(fromString, typeToken.getType());
+ }
+
+ private JsonObject initMetaData(String fromString) {
+ if (fromString == null) {
+ return new JsonObject();
+ } else {
+ return new Gson().fromJson(fromString, JsonObject.class);
+ }
}
public static final Creator<PerformanceEvent> CREATOR = new Creator<PerformanceEvent>() {
@@ -65,4 +136,15 @@ public class PerformanceEvent extends Event {
return new PerformanceEvent[size];
}
};
+
+
+ private class Attribute<T> {
+ private final String name;
+ private final T value;
+
+ Attribute(String name, T value) {
+ this.name = name;
+ this.value = value;
+ }
+ }
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/TelemetryImpl.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/TelemetryImpl.java
index 5e021f961e..697a51286f 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/TelemetryImpl.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/TelemetryImpl.java
@@ -111,8 +111,9 @@ public class TelemetryImpl implements TelemetryDefinition {
@Override
public void onPerformanceEvent(Bundle data) {
- if (data != null && !data.isEmpty()) {
- telemetry.push(new PerformanceEvent(UUID.randomUUID().toString(), data));
+ if (data == null) {
+ data = new Bundle();
}
+ telemetry.push(new PerformanceEvent(UUID.randomUUID().toString(), data));
}
} \ No newline at end of file
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 01ac098d16..8684d7c6f1 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
@@ -26,7 +26,11 @@ import java.nio.channels.FileChannel;
/**
* The offline manager is the main entry point for offline-related functionality.
+ * <p>
* It'll help you list and create offline regions.
+ * </p>
+ *
+ * @see <a href="https://docs.mapbox.com/help/troubleshooting/mobile-offline/">Offline Maps Information/</a>
*/
public class OfflineManager {
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 1c87b9004b..57cf6271c9 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
@@ -323,6 +323,10 @@ public final class Property {
// TEXT_JUSTIFY: Text justification options.
/**
+ * The text is aligned towards the anchor position.
+ */
+ public static final String TEXT_JUSTIFY_AUTO = "auto";
+ /**
* The text is aligned to the left.
*/
public static final String TEXT_JUSTIFY_LEFT = "left";
@@ -339,6 +343,7 @@ public final class Property {
* Text justification options.
*/
@StringDef({
+ TEXT_JUSTIFY_AUTO,
TEXT_JUSTIFY_LEFT,
TEXT_JUSTIFY_CENTER,
TEXT_JUSTIFY_RIGHT,
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 3d8b921a79..01908b1b0b 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
@@ -2276,6 +2276,46 @@ public class PropertyFactory {
}
/**
+ * Radial offset of text, in the direction of the symbol's anchor. Useful in combination with {@link PropertyFactory#textVariableAnchor}, which doesn't support the two-dimensional {@link PropertyFactory#textOffset}.
+ *
+ * @param value a Float value
+ * @return property wrapper around Float
+ */
+ public static PropertyValue<Float> textRadialOffset(Float value) {
+ return new LayoutPropertyValue<>("text-radial-offset", value);
+ }
+
+ /**
+ * Radial offset of text, in the direction of the symbol's anchor. Useful in combination with {@link PropertyFactory#textVariableAnchor}, which doesn't support the two-dimensional {@link PropertyFactory#textOffset}.
+ *
+ * @param value a Float value
+ * @return property wrapper around Float
+ */
+ public static PropertyValue<Expression> textRadialOffset(Expression value) {
+ return new LayoutPropertyValue<>("text-radial-offset", value);
+ }
+
+ /**
+ * To increase the chance of placing high-priority labels on the map, you can provide an array of {@link Property.TEXT_ANCHOR} locations: the render will attempt to place the label at each location, in order, before moving onto the next label. Use `text-justify: auto` to choose justification based on anchor position. To apply an offset, use the {@link PropertyFactory#textRadialOffset} instead of the two-dimensional {@link PropertyFactory#textOffset}.
+ *
+ * @param value a String[] value
+ * @return property wrapper around String[]
+ */
+ public static PropertyValue<String[]> textVariableAnchor(String[] value) {
+ return new LayoutPropertyValue<>("text-variable-anchor", value);
+ }
+
+ /**
+ * To increase the chance of placing high-priority labels on the map, you can provide an array of {@link Property.TEXT_ANCHOR} locations: the render will attempt to place the label at each location, in order, before moving onto the next label. Use `text-justify: auto` to choose justification based on anchor position. To apply an offset, use the {@link PropertyFactory#textRadialOffset} instead of the two-dimensional {@link PropertyFactory#textOffset}.
+ *
+ * @param value a String[] value
+ * @return property wrapper around String[]
+ */
+ public static PropertyValue<Expression> textVariableAnchor(Expression value) {
+ return new LayoutPropertyValue<>("text-variable-anchor", value);
+ }
+
+ /**
* Part of the text placed closest to the anchor.
*
* @param value a String value
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 ab45cb04f2..75473f0f30 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
@@ -470,6 +470,30 @@ public class SymbolLayer extends Layer {
}
/**
+ * Get the TextRadialOffset property
+ *
+ * @return property wrapper value around Float
+ */
+ @NonNull
+ @SuppressWarnings("unchecked")
+ public PropertyValue<Float> getTextRadialOffset() {
+ checkThread();
+ return (PropertyValue<Float>) new PropertyValue("text-radial-offset", nativeGetTextRadialOffset());
+ }
+
+ /**
+ * Get the TextVariableAnchor property
+ *
+ * @return property wrapper value around String[]
+ */
+ @NonNull
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String[]> getTextVariableAnchor() {
+ checkThread();
+ return (PropertyValue<String[]>) new PropertyValue("text-variable-anchor", nativeGetTextVariableAnchor());
+ }
+
+ /**
* Get the TextAnchor property
*
* @return property wrapper value around String
@@ -1187,6 +1211,14 @@ public class SymbolLayer extends Layer {
@NonNull
@Keep
+ private native Object nativeGetTextRadialOffset();
+
+ @NonNull
+ @Keep
+ private native Object nativeGetTextVariableAnchor();
+
+ @NonNull
+ @Keep
private native Object nativeGetTextAnchor();
@NonNull
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/types/Formatted.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/types/Formatted.java
index fb2d361bfc..b76e4f4417 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/types/Formatted.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/types/Formatted.java
@@ -58,4 +58,12 @@ public class Formatted {
public int hashCode() {
return Arrays.hashCode(formattedSections);
}
+
+ @Override
+ public String toString() {
+ return "Formatted{"
+ + "formattedSections="
+ + Arrays.toString(formattedSections)
+ + '}';
+ }
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/types/FormattedSection.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/types/FormattedSection.java
index a5b0dfbfe8..859fcff378 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/types/FormattedSection.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/types/FormattedSection.java
@@ -228,4 +228,14 @@ public class FormattedSection {
params.put("text-color", textColor);
return new Object[] {text, params};
}
+
+ @Override
+ public String toString() {
+ return "FormattedSection{"
+ + "text='" + text + '\''
+ + ", fontScale=" + fontScale
+ + ", fontStack=" + Arrays.toString(fontStack)
+ + ", textColor='" + textColor + '\''
+ + '}';
+ }
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/BitmapUtils.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/BitmapUtils.java
index 3ef8e93cae..3570aa2c0b 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/BitmapUtils.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/BitmapUtils.java
@@ -13,7 +13,6 @@ import android.support.annotation.DrawableRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
-import android.support.v7.content.res.AppCompatResources;
import android.view.View;
import java.io.ByteArrayOutputStream;
@@ -152,7 +151,7 @@ public class BitmapUtils {
@Nullable
public static Drawable getDrawableFromRes(@NonNull Context context, @DrawableRes int drawableRes,
@Nullable @ColorInt Integer tintColor) {
- Drawable drawable = AppCompatResources.getDrawable(context, drawableRes);
+ Drawable drawable = context.getResources().getDrawable(drawableRes);
if (drawable == null) {
return null;
}
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 1adbe7e769..e5cde7e441 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
@@ -7,14 +7,14 @@
android:layout_height="wrap_content"
android:contentDescription="@string/mapbox_compassContentDescription"/>
- <android.support.v7.widget.AppCompatImageView
+ <ImageView
android:visibility="gone"
android:id="@+id/logoView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@null"/>
- <android.support.v7.widget.AppCompatImageView
+ <ImageView
android:visibility="gone"
android:id="@+id/attributionView"
android:layout_width="wrap_content"
diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngTest.java
index 8e47f069c3..862c56a526 100644
--- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngTest.java
@@ -175,7 +175,7 @@ public class LatLngTest {
LatLng latLng2 = new LatLng(1.0, 1.0);
assertEquals("distances should match",
latLng1.distanceTo(latLng2),
- 157425.53710839353, DELTA);
+ 157298.7453847275, DELTA);
}
@Test
@@ -186,6 +186,15 @@ public class LatLngTest {
assertEquals("distance should match", 0.0, distance, DELTA);
}
+ // Regression test for #14216
+ @Test
+ public void testDistanceToClosePointNotNaN() {
+ LatLng latLng = new LatLng(40.00599, -105.29261);
+ LatLng other = new LatLng(40.005990000000025, -105.29260999999997);
+ double distance = latLng.distanceTo(other);
+ assertNotEquals(distance, Double.NaN);
+ }
+
@Test
public void testLocationProvider() {
double latitude = 1.2;
diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationCameraControllerTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationCameraControllerTest.java
index 56a8f276a7..a3d54fe221 100644
--- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationCameraControllerTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationCameraControllerTest.java
@@ -408,6 +408,7 @@ public class LocationCameraControllerTest {
MapboxMap mapboxMap = mock(MapboxMap.class);
AndroidGesturesManager initialGesturesManager = mock(AndroidGesturesManager.class);
AndroidGesturesManager internalGesturesManager = mock(AndroidGesturesManager.class);
+ when(mapboxMap.getGesturesManager()).thenReturn(initialGesturesManager);
LocationCameraController camera = buildCamera(mapboxMap, initialGesturesManager, internalGesturesManager);
LocationComponentOptions options = mock(LocationComponentOptions.class);
when(options.trackingGesturesManagement()).thenReturn(true);
@@ -421,6 +422,7 @@ public class LocationCameraControllerTest {
MapboxMap mapboxMap = mock(MapboxMap.class);
AndroidGesturesManager initialGesturesManager = mock(AndroidGesturesManager.class);
AndroidGesturesManager internalGesturesManager = mock(AndroidGesturesManager.class);
+ when(mapboxMap.getGesturesManager()).thenReturn(internalGesturesManager);
LocationCameraController camera = buildCamera(mapboxMap, initialGesturesManager, internalGesturesManager);
LocationComponentOptions options = mock(LocationComponentOptions.class);
when(options.trackingGesturesManagement()).thenReturn(false);
@@ -430,6 +432,34 @@ public class LocationCameraControllerTest {
}
@Test
+ public void gesturesManagement_optionNotChangedInitial() {
+ MapboxMap mapboxMap = mock(MapboxMap.class);
+ AndroidGesturesManager initialGesturesManager = mock(AndroidGesturesManager.class);
+ AndroidGesturesManager internalGesturesManager = mock(AndroidGesturesManager.class);
+ when(mapboxMap.getGesturesManager()).thenReturn(initialGesturesManager);
+ LocationCameraController camera = buildCamera(mapboxMap, initialGesturesManager, internalGesturesManager);
+ LocationComponentOptions options = mock(LocationComponentOptions.class);
+ when(options.trackingGesturesManagement()).thenReturn(false);
+ camera.initializeOptions(options);
+
+ verify(mapboxMap, times(0)).setGesturesManager(initialGesturesManager, true, true);
+ }
+
+ @Test
+ public void gesturesManagement_optionNotChangedInternal() {
+ MapboxMap mapboxMap = mock(MapboxMap.class);
+ AndroidGesturesManager initialGesturesManager = mock(AndroidGesturesManager.class);
+ AndroidGesturesManager internalGesturesManager = mock(AndroidGesturesManager.class);
+ when(mapboxMap.getGesturesManager()).thenReturn(internalGesturesManager);
+ LocationCameraController camera = buildCamera(mapboxMap, initialGesturesManager, internalGesturesManager);
+ LocationComponentOptions options = mock(LocationComponentOptions.class);
+ when(options.trackingGesturesManagement()).thenReturn(true);
+ camera.initializeOptions(options);
+
+ verify(mapboxMap, times(0)).setGesturesManager(internalGesturesManager, true, true);
+ }
+
+ @Test
public void onMove_notCancellingTransitionWhileNone() {
MapboxMap mapboxMap = mock(MapboxMap.class);
when(mapboxMap.getUiSettings()).thenReturn(mock(UiSettings.class));
diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java
index 10553700b3..6a44cf1f79 100644
--- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java
@@ -39,6 +39,7 @@ import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_LAYER_ACCURA
import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_LAYER_COMPASS_BEARING;
import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_LAYER_GPS_BEARING;
import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_LAYER_LATLNG;
+import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
@@ -160,6 +161,24 @@ public class LocationLayerControllerTest {
}
@Test
+ public void onInitialization_numberOfCachedLayerIdsIsConstant() {
+ OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class);
+ LayerSourceProvider sourceProvider = buildLayerProvider();
+ GeoJsonSource locationSource = mock(GeoJsonSource.class);
+ when(sourceProvider.generateSource(any(Feature.class))).thenReturn(locationSource);
+ LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class);
+ LocationComponentOptions options = mock(LocationComponentOptions.class);
+
+ LocationLayerController controller =
+ new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options),
+ bitmapProvider, options, internalRenderModeChangedListener);
+
+ controller.initializeComponents(mapboxMap.getStyle(), options);
+
+ assertEquals(5, controller.layerSet.size());
+ }
+
+ @Test
public void applyStyle_styleShadowWithValidElevation() {
OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class);
LayerSourceProvider sourceProvider = buildLayerProvider();
@@ -300,22 +319,6 @@ public class LocationLayerControllerTest {
LayerSourceProvider sourceProvider = buildLayerProvider();
when(sourceProvider.generateSource(any(Feature.class))).thenReturn(mock(GeoJsonSource.class));
- Layer bearingLayer = mock(Layer.class);
- when(bearingLayer.getId()).thenReturn(BEARING_LAYER);
- when(sourceProvider.generateLayer(BEARING_LAYER)).thenReturn(bearingLayer);
- Layer foregroundLayer = mock(Layer.class);
- when(foregroundLayer.getId()).thenReturn(FOREGROUND_LAYER);
- when(sourceProvider.generateLayer(FOREGROUND_LAYER)).thenReturn(foregroundLayer);
- Layer backgroundLayer = mock(Layer.class);
- when(backgroundLayer.getId()).thenReturn(BACKGROUND_LAYER);
- when(sourceProvider.generateLayer(BACKGROUND_LAYER)).thenReturn(backgroundLayer);
- Layer shadowLayer = mock(Layer.class);
- when(shadowLayer.getId()).thenReturn(SHADOW_LAYER);
- when(sourceProvider.generateLayer(SHADOW_LAYER)).thenReturn(shadowLayer);
- Layer accuracyLayer = mock(Layer.class);
- when(accuracyLayer.getId()).thenReturn(ACCURACY_LAYER);
- when(sourceProvider.generateAccuracyLayer()).thenReturn(accuracyLayer);
-
LocationComponentOptions options = mock(LocationComponentOptions.class);
LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class);
Bitmap bitmap = mock(Bitmap.class);
@@ -606,18 +609,23 @@ public class LocationLayerControllerTest {
LayerSourceProvider layerSourceProvider = mock(LayerSourceProvider.class);
Layer shadowLayer = mock(Layer.class);
+ when(shadowLayer.getId()).thenReturn(SHADOW_LAYER);
when(layerSourceProvider.generateLayer(SHADOW_LAYER)).thenReturn(shadowLayer);
Layer backgroundLayer = mock(Layer.class);
+ when(backgroundLayer.getId()).thenReturn(BACKGROUND_LAYER);
when(layerSourceProvider.generateLayer(BACKGROUND_LAYER)).thenReturn(backgroundLayer);
Layer foregroundLayer = mock(Layer.class);
+ when(foregroundLayer.getId()).thenReturn(FOREGROUND_LAYER);
when(layerSourceProvider.generateLayer(FOREGROUND_LAYER)).thenReturn(foregroundLayer);
Layer bearingLayer = mock(Layer.class);
+ when(bearingLayer.getId()).thenReturn(BEARING_LAYER);
when(layerSourceProvider.generateLayer(BEARING_LAYER)).thenReturn(bearingLayer);
Layer accuracyLayer = mock(Layer.class);
+ when(accuracyLayer.getId()).thenReturn(ACCURACY_LAYER);
when(layerSourceProvider.generateAccuracyLayer()).thenReturn(accuracyLayer);
return layerSourceProvider;
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.kt b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.kt
index a0873e97ff..2d68612c70 100644
--- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.kt
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.kt
@@ -15,31 +15,33 @@ import org.robolectric.RobolectricTestRunner
@RunWith(RobolectricTestRunner::class)
class MapboxMapTest {
- private lateinit var mapboxMap: MapboxMap
-
- private lateinit var nativeMapView: NativeMapView
-
- private lateinit var transform: Transform
-
- @Before
- fun setup() {
- val cameraChangeDispatcher = spyk<CameraChangeDispatcher>()
- nativeMapView = mockk(relaxed = true)
- transform = mockk(relaxed = true)
- mapboxMap = MapboxMap(nativeMapView, transform, mockk(relaxed = true), null, null, cameraChangeDispatcher)
- every { nativeMapView.isDestroyed } returns false
- every { nativeMapView.nativePtr } returns 5
- mapboxMap.injectLocationComponent(spyk())
- mapboxMap.setStyle(Style.MAPBOX_STREETS)
- mapboxMap.onFinishLoadingStyle()
- }
-
- @Test
- fun testTransitionOptions() {
- val expected = TransitionOptions(100, 200)
- mapboxMap.style?.transition = expected
- verify { nativeMapView.transitionOptions = expected }
- }
+ private lateinit var mapboxMap: MapboxMap
+
+ private lateinit var nativeMapView: NativeMapView
+
+ private lateinit var transform: Transform
+
+ private lateinit var cameraChangeDispatcher: CameraChangeDispatcher
+
+ @Before
+ fun setup() {
+ cameraChangeDispatcher = spyk()
+ nativeMapView = mockk(relaxed = true)
+ transform = mockk(relaxed = true)
+ mapboxMap = MapboxMap(nativeMapView, transform, mockk(relaxed = true), null, null, cameraChangeDispatcher)
+ every { nativeMapView.isDestroyed } returns false
+ every { nativeMapView.nativePtr } returns 5
+ mapboxMap.injectLocationComponent(spyk())
+ mapboxMap.setStyle(Style.MAPBOX_STREETS)
+ mapboxMap.onFinishLoadingStyle()
+ }
+
+ @Test
+ fun testTransitionOptions() {
+ val expected = TransitionOptions(100, 200)
+ mapboxMap.style?.transition = expected
+ verify { nativeMapView.transitionOptions = expected }
+ }
@Test
fun testMoveCamera() {
@@ -51,52 +53,52 @@ class MapboxMapTest {
verify { transform.moveCamera(mapboxMap, update, callback) }
}
- @Test
- fun testMinZoom() {
- mapboxMap.setMinZoomPreference(10.0)
- verify { transform.minZoom = 10.0 }
- }
-
- @Test
- fun testMaxZoom() {
- mapboxMap.setMaxZoomPreference(10.0)
- verify { transform.maxZoom = 10.0 }
- }
-
- @Test
- fun testFpsListener() {
- val fpsChangedListener = mockk<MapboxMap.OnFpsChangedListener>()
- mapboxMap.onFpsChangedListener = fpsChangedListener
- assertEquals("Listener should match", fpsChangedListener, mapboxMap.onFpsChangedListener)
- }
-
- @Test
- fun testTilePrefetch() {
- mapboxMap.prefetchesTiles = true
- verify { nativeMapView.prefetchTiles = true }
- }
-
- @Test
- fun testCameraForLatLngBounds() {
- val bounds = LatLngBounds.Builder().include(LatLng()).include(LatLng(1.0, 1.0)).build()
- mapboxMap.setLatLngBoundsForCameraTarget(bounds)
- verify { nativeMapView.setLatLngBounds(bounds) }
- }
-
- @Test(expected = IllegalArgumentException::class)
- fun testAnimateCameraChecksDurationPositive() {
- mapboxMap.animateCamera(CameraUpdateFactory.newLatLng(LatLng(30.0, 30.0)), 0, null)
- }
-
- @Test(expected = IllegalArgumentException::class)
- fun testEaseCameraChecksDurationPositive() {
- mapboxMap.easeCamera(CameraUpdateFactory.newLatLng(LatLng(30.0, 30.0)), 0, null)
- }
-
- @Test
- fun testGetNativeMapPtr() {
- assertEquals(5, mapboxMap.nativeMapPtr)
- }
+ @Test
+ fun testMinZoom() {
+ mapboxMap.setMinZoomPreference(10.0)
+ verify { transform.minZoom = 10.0 }
+ }
+
+ @Test
+ fun testMaxZoom() {
+ mapboxMap.setMaxZoomPreference(10.0)
+ verify { transform.maxZoom = 10.0 }
+ }
+
+ @Test
+ fun testFpsListener() {
+ val fpsChangedListener = mockk<MapboxMap.OnFpsChangedListener>()
+ mapboxMap.onFpsChangedListener = fpsChangedListener
+ assertEquals("Listener should match", fpsChangedListener, mapboxMap.onFpsChangedListener)
+ }
+
+ @Test
+ fun testTilePrefetch() {
+ mapboxMap.prefetchesTiles = true
+ verify { nativeMapView.prefetchTiles = true }
+ }
+
+ @Test
+ fun testCameraForLatLngBounds() {
+ val bounds = LatLngBounds.Builder().include(LatLng()).include(LatLng(1.0, 1.0)).build()
+ mapboxMap.setLatLngBoundsForCameraTarget(bounds)
+ verify { nativeMapView.setLatLngBounds(bounds) }
+ }
+
+ @Test(expected = IllegalArgumentException::class)
+ fun testAnimateCameraChecksDurationPositive() {
+ mapboxMap.animateCamera(CameraUpdateFactory.newLatLng(LatLng(30.0, 30.0)), 0, null)
+ }
+
+ @Test(expected = IllegalArgumentException::class)
+ fun testEaseCameraChecksDurationPositive() {
+ mapboxMap.easeCamera(CameraUpdateFactory.newLatLng(LatLng(30.0, 30.0)), 0, null)
+ }
+
+ @Test
+ fun testGetNativeMapPtr() {
+ assertEquals(5, mapboxMap.nativeMapPtr)
+ }
@Test
fun testNativeMapIsNotCalledOnStateSave() {
@@ -104,4 +106,10 @@ class MapboxMapTest {
mapboxMap.onSaveInstanceState(mockk(relaxed = true))
verify { nativeMapView wasNot Called }
}
+
+ @Test
+ fun testCameraChangeDispatcherCleared() {
+ mapboxMap.onDestroy()
+ verify { cameraChangeDispatcher.onDestroy() }
+ }
} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle
index 22222b0f50..190c279e03 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle
+++ b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle
@@ -9,7 +9,7 @@ android {
targetSdkVersion androidVersions.targetSdkVersion
versionCode 13
versionName "6.0.0"
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ testInstrumentationRunner "com.mapbox.mapboxsdk.InstrumentationRunner"
}
compileOptions {
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/assets/streets.json b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/assets/streets.json
new file mode 100644
index 0000000000..5ab289344a
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/assets/streets.json
@@ -0,0 +1,5331 @@
+{
+ "version": 8,
+ "name": "mapbox-gl-native-test-style",
+ "metadata": {
+ "mapbox:autocomposite": true,
+ "mapbox:type": "default",
+ "mapbox:origin": "streets-v10",
+ "mapbox:groups": {
+ "1444934828655.3389": {"name": "Aeroways", "collapsed": true},
+ "1444933322393.2852": {
+ "name": "POI labels (scalerank 1)",
+ "collapsed": true
+ },
+ "1444855786460.0557": {"name": "Roads", "collapsed": true},
+ "1444933575858.6992": {
+ "name": "Highway shields",
+ "collapsed": true
+ },
+ "1444934295202.7542": {
+ "name": "Admin boundaries",
+ "collapsed": true
+ },
+ "1444856151690.9143": {"name": "State labels", "collapsed": true},
+ "1444933721429.3076": {"name": "Road labels", "collapsed": true},
+ "1444933358918.2366": {
+ "name": "POI labels (scalerank 2)",
+ "collapsed": true
+ },
+ "1444933808272.805": {"name": "Water labels", "collapsed": true},
+ "1444933372896.5967": {
+ "name": "POI labels (scalerank 3)",
+ "collapsed": true
+ },
+ "1444855799204.86": {"name": "Bridges", "collapsed": true},
+ "1444856087950.3635": {"name": "Marine labels", "collapsed": true},
+ "1456969573402.7817": {"name": "Hillshading", "collapsed": true},
+ "1444862510685.128": {"name": "City labels", "collapsed": true},
+ "1444855769305.6016": {"name": "Tunnels", "collapsed": true},
+ "1456970288113.8113": {"name": "Landcover", "collapsed": true},
+ "1444856144497.7825": {"name": "Country labels", "collapsed": true},
+ "1444933456003.5437": {
+ "name": "POI labels (scalerank 4)",
+ "collapsed": true
+ }
+ },
+ "mapbox:sdk-support": {
+ "js": "0.49.0",
+ "android": "6.5.0",
+ "ios": "4.4.0"
+ }
+ },
+ "center": [0.0, 0.0],
+ "zoom": 0,
+ "bearing": 0,
+ "pitch": 0,
+ "sources": {
+ "composite": {
+ "url": "mapbox://mapbox.mapbox-terrain-v2,mapbox.mapbox-streets-v7",
+ "type": "vector"
+ }
+ },
+ "sprite": "mapbox://sprites/lukaspaczos/cjnkdt02b0b2p2ss40skwpvs1",
+ "glyphs": "mapbox://fonts/lukaspaczos/{fontstack}/{range}.pbf",
+ "layers": [
+ {
+ "id": "background",
+ "type": "background",
+ "layout": {},
+ "paint": {
+ "background-color": {
+ "base": 1,
+ "stops": [
+ [11, "hsl(35, 32%, 91%)"],
+ [13, "hsl(35, 12%, 89%)"]
+ ]
+ }
+ }
+ },
+ {
+ "id": "landcover_snow",
+ "type": "fill",
+ "metadata": {"mapbox:group": "1456970288113.8113"},
+ "source": "composite",
+ "source-layer": "landcover",
+ "filter": ["==", "class", "snow"],
+ "layout": {},
+ "paint": {
+ "fill-color": "hsl(0, 0%, 100%)",
+ "fill-opacity": 0.2,
+ "fill-antialias": false
+ }
+ },
+ {
+ "id": "landcover_wood",
+ "type": "fill",
+ "metadata": {"mapbox:group": "1456970288113.8113"},
+ "source": "composite",
+ "source-layer": "landcover",
+ "maxzoom": 14,
+ "filter": ["==", "class", "wood"],
+ "layout": {},
+ "paint": {
+ "fill-color": "hsl(75, 62%, 81%)",
+ "fill-opacity": {"base": 1.5, "stops": [[2, 0.3], [7, 0]]},
+ "fill-antialias": false
+ }
+ },
+ {
+ "id": "landcover_scrub",
+ "type": "fill",
+ "metadata": {"mapbox:group": "1456970288113.8113"},
+ "source": "composite",
+ "source-layer": "landcover",
+ "maxzoom": 14,
+ "filter": ["==", "class", "scrub"],
+ "layout": {},
+ "paint": {
+ "fill-color": "hsl(75, 62%, 81%)",
+ "fill-opacity": {"base": 1.5, "stops": [[2, 0.3], [7, 0]]},
+ "fill-antialias": false
+ }
+ },
+ {
+ "id": "landcover_grass",
+ "type": "fill",
+ "metadata": {"mapbox:group": "1456970288113.8113"},
+ "source": "composite",
+ "source-layer": "landcover",
+ "maxzoom": 14,
+ "filter": ["==", "class", "grass"],
+ "layout": {},
+ "paint": {
+ "fill-color": "hsl(75, 62%, 81%)",
+ "fill-opacity": {"base": 1.5, "stops": [[2, 0.3], [7, 0]]},
+ "fill-antialias": false
+ }
+ },
+ {
+ "id": "landcover_crop",
+ "type": "fill",
+ "metadata": {"mapbox:group": "1456970288113.8113"},
+ "source": "composite",
+ "source-layer": "landcover",
+ "maxzoom": 14,
+ "filter": ["==", "class", "crop"],
+ "layout": {},
+ "paint": {
+ "fill-color": "hsl(75, 62%, 81%)",
+ "fill-opacity": {"base": 1.5, "stops": [[2, 0.3], [7, 0]]},
+ "fill-antialias": false
+ }
+ },
+ {
+ "id": "national_park",
+ "type": "fill",
+ "source": "composite",
+ "source-layer": "landuse_overlay",
+ "filter": ["==", "class", "national_park"],
+ "layout": {},
+ "paint": {
+ "fill-color": "hsl(100, 58%, 76%)",
+ "fill-opacity": {"base": 1, "stops": [[5, 0], [6, 0.5]]}
+ }
+ },
+ {
+ "id": "hospital",
+ "type": "fill",
+ "source": "composite",
+ "source-layer": "landuse",
+ "filter": ["==", "class", "hospital"],
+ "layout": {},
+ "paint": {
+ "fill-color": {
+ "base": 1,
+ "stops": [
+ [15.5, "hsl(340, 37%, 87%)"],
+ [16, "hsl(340, 63%, 89%)"]
+ ]
+ }
+ }
+ },
+ {
+ "id": "school",
+ "type": "fill",
+ "source": "composite",
+ "source-layer": "landuse",
+ "filter": ["==", "class", "school"],
+ "layout": {},
+ "paint": {
+ "fill-color": {
+ "base": 1,
+ "stops": [
+ [15.5, "hsl(50, 47%, 81%)"],
+ [16, "hsl(50, 63%, 84%)"]
+ ]
+ }
+ }
+ },
+ {
+ "id": "park",
+ "type": "fill",
+ "source": "composite",
+ "source-layer": "landuse",
+ "filter": ["==", "class", "park"],
+ "layout": {},
+ "paint": {
+ "fill-color": "hsl(100, 58%, 76%)",
+ "fill-opacity": {"base": 1, "stops": [[5, 0], [6, 1]]}
+ }
+ },
+ {
+ "id": "pitch",
+ "type": "fill",
+ "source": "composite",
+ "source-layer": "landuse",
+ "filter": ["==", "class", "pitch"],
+ "layout": {},
+ "paint": {"fill-color": "hsl(100, 57%, 72%)"}
+ },
+ {
+ "id": "pitch-line",
+ "type": "line",
+ "source": "composite",
+ "source-layer": "landuse",
+ "minzoom": 15,
+ "filter": ["==", "class", "pitch"],
+ "layout": {"line-join": "miter"},
+ "paint": {"line-color": "hsl(75, 57%, 84%)"}
+ },
+ {
+ "id": "cemetery",
+ "type": "fill",
+ "source": "composite",
+ "source-layer": "landuse",
+ "filter": ["==", "class", "cemetery"],
+ "layout": {},
+ "paint": {"fill-color": "hsl(75, 37%, 81%)"}
+ },
+ {
+ "id": "industrial",
+ "type": "fill",
+ "source": "composite",
+ "source-layer": "landuse",
+ "filter": ["==", "class", "industrial"],
+ "layout": {},
+ "paint": {
+ "fill-color": {
+ "base": 1,
+ "stops": [
+ [15.5, "hsl(230, 15%, 86%)"],
+ [16, "hsl(230, 29%, 89%)"]
+ ]
+ }
+ }
+ },
+ {
+ "id": "sand",
+ "type": "fill",
+ "source": "composite",
+ "source-layer": "landuse",
+ "filter": ["==", "class", "sand"],
+ "layout": {},
+ "paint": {"fill-color": "hsl(60, 46%, 87%)"}
+ },
+ {
+ "id": "hillshade_highlight_bright",
+ "type": "fill",
+ "metadata": {"mapbox:group": "1456969573402.7817"},
+ "source": "composite",
+ "source-layer": "hillshade",
+ "maxzoom": 16,
+ "filter": ["==", "level", 94],
+ "layout": {},
+ "paint": {
+ "fill-color": "hsl(0, 0%, 100%)",
+ "fill-opacity": {"stops": [[14, 0.12], [16, 0]]},
+ "fill-antialias": false
+ }
+ },
+ {
+ "id": "hillshade_highlight_med",
+ "type": "fill",
+ "metadata": {"mapbox:group": "1456969573402.7817"},
+ "source": "composite",
+ "source-layer": "hillshade",
+ "maxzoom": 16,
+ "filter": ["==", "level", 90],
+ "layout": {},
+ "paint": {
+ "fill-color": "hsl(0, 0%, 100%)",
+ "fill-opacity": {"stops": [[14, 0.12], [16, 0]]},
+ "fill-antialias": false
+ }
+ },
+ {
+ "id": "hillshade_shadow_faint",
+ "type": "fill",
+ "metadata": {"mapbox:group": "1456969573402.7817"},
+ "source": "composite",
+ "source-layer": "hillshade",
+ "maxzoom": 16,
+ "filter": ["==", "level", 89],
+ "layout": {},
+ "paint": {
+ "fill-color": "hsl(56, 59%, 22%)",
+ "fill-opacity": {"stops": [[14, 0.05], [16, 0]]},
+ "fill-antialias": false
+ }
+ },
+ {
+ "id": "hillshade_shadow_med",
+ "type": "fill",
+ "metadata": {"mapbox:group": "1456969573402.7817"},
+ "source": "composite",
+ "source-layer": "hillshade",
+ "maxzoom": 16,
+ "filter": ["==", "level", 78],
+ "layout": {},
+ "paint": {
+ "fill-color": "hsl(56, 59%, 22%)",
+ "fill-opacity": {"stops": [[14, 0.05], [16, 0]]},
+ "fill-antialias": false
+ }
+ },
+ {
+ "id": "hillshade_shadow_dark",
+ "type": "fill",
+ "metadata": {"mapbox:group": "1456969573402.7817"},
+ "source": "composite",
+ "source-layer": "hillshade",
+ "maxzoom": 16,
+ "filter": ["==", "level", 67],
+ "layout": {},
+ "paint": {
+ "fill-color": "hsl(56, 59%, 22%)",
+ "fill-opacity": {"stops": [[14, 0.06], [16, 0]]},
+ "fill-antialias": false
+ }
+ },
+ {
+ "id": "hillshade_shadow_extreme",
+ "type": "fill",
+ "metadata": {"mapbox:group": "1456969573402.7817"},
+ "source": "composite",
+ "source-layer": "hillshade",
+ "maxzoom": 16,
+ "filter": ["==", "level", 56],
+ "layout": {},
+ "paint": {
+ "fill-color": "hsl(56, 59%, 22%)",
+ "fill-opacity": {"stops": [[14, 0.06], [16, 0]]},
+ "fill-antialias": false
+ }
+ },
+ {
+ "id": "waterway-river-canal",
+ "type": "line",
+ "source": "composite",
+ "source-layer": "waterway",
+ "minzoom": 8,
+ "filter": ["in", "class", "canal", "river"],
+ "layout": {
+ "line-cap": {"base": 1, "stops": [[0, "butt"], [11, "round"]]},
+ "line-join": "round"
+ },
+ "paint": {
+ "line-color": "hsl(205, 87%, 76%)",
+ "line-width": {"base": 1.3, "stops": [[8.5, 0.1], [20, 8]]},
+ "line-opacity": {"base": 1, "stops": [[8, 0], [8.5, 1]]}
+ }
+ },
+ {
+ "id": "waterway-small",
+ "type": "line",
+ "source": "composite",
+ "source-layer": "waterway",
+ "minzoom": 13,
+ "filter": ["!in", "class", "canal", "river"],
+ "layout": {"line-join": "round", "line-cap": "round"},
+ "paint": {
+ "line-color": "hsl(205, 87%, 76%)",
+ "line-width": {"base": 1.35, "stops": [[13.5, 0.1], [20, 3]]},
+ "line-opacity": {"base": 1, "stops": [[13, 0], [13.5, 1]]}
+ }
+ },
+ {
+ "id": "water-shadow",
+ "type": "fill",
+ "source": "composite",
+ "source-layer": "water",
+ "layout": {},
+ "paint": {
+ "fill-color": "hsl(215, 84%, 69%)",
+ "fill-translate": {
+ "base": 1.2,
+ "stops": [[7, [0, 0]], [16, [-1, -1]]]
+ },
+ "fill-translate-anchor": "viewport",
+ "fill-opacity": 1
+ }
+ },
+ {
+ "id": "water",
+ "type": "fill",
+ "source": "composite",
+ "source-layer": "water",
+ "layout": {},
+ "paint": {"fill-color": "hsl(196, 80%, 70%)"}
+ },
+ {
+ "id": "barrier_line-land-polygon",
+ "type": "fill",
+ "source": "composite",
+ "source-layer": "barrier_line",
+ "filter": [
+ "all",
+ ["==", "$type", "Polygon"],
+ ["==", "class", "land"]
+ ],
+ "layout": {},
+ "paint": {"fill-color": "hsl(35, 12%, 89%)"}
+ },
+ {
+ "id": "barrier_line-land-line",
+ "type": "line",
+ "source": "composite",
+ "source-layer": "barrier_line",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ ["==", "class", "land"]
+ ],
+ "layout": {"line-cap": "round"},
+ "paint": {
+ "line-width": {"base": 1.99, "stops": [[14, 0.75], [20, 40]]},
+ "line-color": "hsl(35, 12%, 89%)"
+ }
+ },
+ {
+ "id": "aeroway-polygon",
+ "type": "fill",
+ "metadata": {"mapbox:group": "1444934828655.3389"},
+ "source": "composite",
+ "source-layer": "aeroway",
+ "minzoom": 11,
+ "filter": [
+ "all",
+ ["!=", "type", "apron"],
+ ["==", "$type", "Polygon"]
+ ],
+ "layout": {},
+ "paint": {
+ "fill-color": {
+ "base": 1,
+ "stops": [
+ [15, "hsl(230, 23%, 82%)"],
+ [16, "hsl(230, 37%, 84%)"]
+ ]
+ },
+ "fill-opacity": {"base": 1, "stops": [[11, 0], [11.5, 1]]}
+ }
+ },
+ {
+ "id": "aeroway-runway",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444934828655.3389"},
+ "source": "composite",
+ "source-layer": "aeroway",
+ "minzoom": 9,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ ["==", "type", "runway"]
+ ],
+ "layout": {},
+ "paint": {
+ "line-color": {
+ "base": 1,
+ "stops": [
+ [15, "hsl(230, 23%, 82%)"],
+ [16, "hsl(230, 37%, 84%)"]
+ ]
+ },
+ "line-width": {"base": 1.5, "stops": [[9, 1], [18, 80]]}
+ }
+ },
+ {
+ "id": "aeroway-taxiway",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444934828655.3389"},
+ "source": "composite",
+ "source-layer": "aeroway",
+ "minzoom": 9,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ ["==", "type", "taxiway"]
+ ],
+ "layout": {},
+ "paint": {
+ "line-color": {
+ "base": 1,
+ "stops": [
+ [15, "hsl(230, 23%, 82%)"],
+ [16, "hsl(230, 37%, 84%)"]
+ ]
+ },
+ "line-width": {"base": 1.5, "stops": [[10, 0.5], [18, 20]]}
+ }
+ },
+ {
+ "id": "building-line",
+ "type": "line",
+ "source": "composite",
+ "source-layer": "building",
+ "minzoom": 15,
+ "filter": [
+ "all",
+ ["!=", "type", "building:part"],
+ ["==", "underground", "false"]
+ ],
+ "layout": {},
+ "paint": {
+ "line-color": "hsl(35, 6%, 79%)",
+ "line-width": {"base": 1.5, "stops": [[15, 0.75], [20, 3]]},
+ "line-opacity": {"base": 1, "stops": [[15.5, 0], [16, 1]]}
+ }
+ },
+ {
+ "id": "building",
+ "type": "fill",
+ "source": "composite",
+ "source-layer": "building",
+ "minzoom": 15,
+ "filter": [
+ "all",
+ ["!=", "type", "building:part"],
+ ["==", "underground", "false"]
+ ],
+ "layout": {},
+ "paint": {
+ "fill-color": {
+ "base": 1,
+ "stops": [
+ [15, "hsl(35, 11%, 88%)"],
+ [16, "hsl(35, 8%, 85%)"]
+ ]
+ },
+ "fill-opacity": {"base": 1, "stops": [[15.5, 0], [16, 1]]},
+ "fill-outline-color": "hsl(35, 6%, 79%)"
+ }
+ },
+ {
+ "id": "tunnel-street-low",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855769305.6016"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 11,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "class", "street"],
+ ["==", "structure", "tunnel"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {
+ "base": 1.5,
+ "stops": [[12.5, 0.5], [14, 2], [18, 18]]
+ },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-opacity": {
+ "stops": [[11.5, 0], [12, 1], [14, 1], [14.01, 0]]
+ }
+ }
+ },
+ {
+ "id": "tunnel-street_limited-low",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855769305.6016"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 11,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "class", "street_limited"],
+ ["==", "structure", "tunnel"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {
+ "base": 1.5,
+ "stops": [[12.5, 0.5], [14, 2], [18, 18]]
+ },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-opacity": {
+ "stops": [[11.5, 0], [12, 1], [14, 1], [14.01, 0]]
+ }
+ }
+ },
+ {
+ "id": "tunnel-service-link-track-case",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855769305.6016"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 14,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!=", "type", "trunk_link"],
+ ["==", "structure", "tunnel"],
+ ["in", "class", "link", "service", "track"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]},
+ "line-color": "hsl(230, 19%, 75%)",
+ "line-gap-width": {"base": 1.5, "stops": [[14, 0.5], [18, 12]]},
+ "line-dasharray": [3, 3]
+ }
+ },
+ {
+ "id": "tunnel-street_limited-case",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855769305.6016"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 11,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "class", "street_limited"],
+ ["==", "structure", "tunnel"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]},
+ "line-color": "hsl(230, 19%, 75%)",
+ "line-gap-width": {
+ "base": 1.5,
+ "stops": [[13, 0], [14, 2], [18, 18]]
+ },
+ "line-dasharray": [3, 3],
+ "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]}
+ }
+ },
+ {
+ "id": "tunnel-street-case",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855769305.6016"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 11,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "class", "street"],
+ ["==", "structure", "tunnel"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]},
+ "line-color": "hsl(230, 19%, 75%)",
+ "line-gap-width": {
+ "base": 1.5,
+ "stops": [[13, 0], [14, 2], [18, 18]]
+ },
+ "line-dasharray": [3, 3],
+ "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]}
+ }
+ },
+ {
+ "id": "tunnel-secondary-tertiary-case",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855769305.6016"},
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "structure", "tunnel"],
+ ["in", "class", "secondary", "tertiary"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.2, "stops": [[10, 0.75], [18, 2]]},
+ "line-dasharray": [3, 3],
+ "line-gap-width": {
+ "base": 1.5,
+ "stops": [[8.5, 0.5], [10, 0.75], [18, 26]]
+ },
+ "line-color": "hsl(230, 19%, 75%)"
+ }
+ },
+ {
+ "id": "tunnel-primary-case",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855769305.6016"},
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "class", "primary"],
+ ["==", "structure", "tunnel"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[10, 1], [16, 2]]},
+ "line-dasharray": [3, 3],
+ "line-gap-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]},
+ "line-color": "hsl(230, 19%, 75%)"
+ }
+ },
+ {
+ "id": "tunnel-trunk_link-case",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855769305.6016"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 13,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "structure", "tunnel"],
+ ["==", "type", "trunk_link"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]},
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-gap-width": {
+ "base": 1.5,
+ "stops": [[12, 0.5], [14, 2], [18, 18]]
+ },
+ "line-dasharray": [3, 3]
+ }
+ },
+ {
+ "id": "tunnel-motorway_link-case",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855769305.6016"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 13,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "class", "motorway_link"],
+ ["==", "structure", "tunnel"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]},
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-gap-width": {
+ "base": 1.5,
+ "stops": [[12, 0.5], [14, 2], [18, 18]]
+ },
+ "line-dasharray": [3, 3]
+ }
+ },
+ {
+ "id": "tunnel-trunk-case",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855769305.6016"},
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ ["all", ["==", "structure", "tunnel"], ["==", "type", "trunk"]]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[10, 1], [16, 2]]},
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-gap-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]},
+ "line-opacity": 1,
+ "line-dasharray": [3, 3]
+ }
+ },
+ {
+ "id": "tunnel-motorway-case",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855769305.6016"},
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "class", "motorway"],
+ ["==", "structure", "tunnel"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[10, 1], [16, 2]]},
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-gap-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]},
+ "line-opacity": 1,
+ "line-dasharray": [3, 3]
+ }
+ },
+ {
+ "id": "tunnel-construction",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855769305.6016"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 14,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "class", "construction"],
+ ["==", "structure", "tunnel"]
+ ]
+ ],
+ "layout": {"line-join": "miter"},
+ "paint": {
+ "line-width": {
+ "base": 1.5,
+ "stops": [[12.5, 0.5], [14, 2], [18, 18]]
+ },
+ "line-color": "hsl(230, 24%, 87%)",
+ "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]},
+ "line-dasharray": {
+ "base": 1,
+ "stops": [
+ [14, [0.4, 0.8]],
+ [15, [0.3, 0.6]],
+ [16, [0.2, 0.3]],
+ [17, [0.2, 0.25]],
+ [18, [0.15, 0.15]]
+ ]
+ }
+ }
+ },
+ {
+ "id": "tunnel-path",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855769305.6016"},
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!=", "type", "steps"],
+ ["==", "class", "path"],
+ ["==", "structure", "tunnel"]
+ ]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[15, 1], [18, 4]]},
+ "line-dasharray": {
+ "base": 1,
+ "stops": [
+ [14, [1, 0]],
+ [15, [1.75, 1]],
+ [16, [1, 0.75]],
+ [17, [1, 0.5]]
+ ]
+ },
+ "line-color": "hsl(35, 26%, 95%)",
+ "line-opacity": {"base": 1, "stops": [[14, 0], [14.25, 1]]}
+ }
+ },
+ {
+ "id": "tunnel-steps",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855769305.6016"},
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ ["all", ["==", "structure", "tunnel"], ["==", "type", "steps"]]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-width": {
+ "base": 1.5,
+ "stops": [[15, 1], [16, 1.6], [18, 6]]
+ },
+ "line-color": "hsl(35, 26%, 95%)",
+ "line-dasharray": {
+ "base": 1,
+ "stops": [
+ [14, [1, 0]],
+ [15, [1.75, 1]],
+ [16, [1, 0.75]],
+ [17, [0.3, 0.3]]
+ ]
+ },
+ "line-opacity": {"base": 1, "stops": [[14, 0], [14.25, 1]]}
+ }
+ },
+ {
+ "id": "tunnel-trunk_link",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855769305.6016"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 13,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "structure", "tunnel"],
+ ["==", "type", "trunk_link"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {
+ "base": 1.5,
+ "stops": [[12, 0.5], [14, 2], [18, 18]]
+ },
+ "line-color": "hsl(46, 77%, 78%)",
+ "line-opacity": 1,
+ "line-dasharray": [1, 0]
+ }
+ },
+ {
+ "id": "tunnel-motorway_link",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855769305.6016"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 13,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "class", "motorway_link"],
+ ["==", "structure", "tunnel"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {
+ "base": 1.5,
+ "stops": [[12, 0.5], [14, 2], [18, 18]]
+ },
+ "line-color": "hsl(26, 100%, 78%)",
+ "line-opacity": 1,
+ "line-dasharray": [1, 0]
+ }
+ },
+ {
+ "id": "tunnel-pedestrian",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855769305.6016"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 13,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "class", "pedestrian"],
+ ["==", "structure", "tunnel"]
+ ]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[14, 0.5], [18, 12]]},
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-opacity": 1,
+ "line-dasharray": {
+ "base": 1,
+ "stops": [[14, [1, 0]], [15, [1.5, 0.4]], [16, [1, 0.2]]]
+ }
+ }
+ },
+ {
+ "id": "tunnel-service-link-track",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855769305.6016"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 14,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!=", "type", "trunk_link"],
+ ["==", "structure", "tunnel"],
+ ["in", "class", "link", "service", "track"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[14, 0.5], [18, 12]]},
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-dasharray": [1, 0]
+ }
+ },
+ {
+ "id": "tunnel-street_limited",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855769305.6016"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 11,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "class", "street_limited"],
+ ["==", "structure", "tunnel"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {
+ "base": 1.5,
+ "stops": [[12.5, 0.5], [14, 2], [18, 18]]
+ },
+ "line-color": "hsl(35, 14%, 93%)",
+ "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]}
+ }
+ },
+ {
+ "id": "tunnel-street",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855769305.6016"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 11,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "class", "street"],
+ ["==", "structure", "tunnel"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {
+ "base": 1.5,
+ "stops": [[12.5, 0.5], [14, 2], [18, 18]]
+ },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]}
+ }
+ },
+ {
+ "id": "tunnel-secondary-tertiary",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855769305.6016"},
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "structure", "tunnel"],
+ ["in", "class", "secondary", "tertiary"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {
+ "base": 1.5,
+ "stops": [[8.5, 0.5], [10, 0.75], [18, 26]]
+ },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-opacity": 1,
+ "line-dasharray": [1, 0],
+ "line-blur": 0
+ }
+ },
+ {
+ "id": "tunnel-primary",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855769305.6016"},
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "class", "primary"],
+ ["==", "structure", "tunnel"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]},
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-opacity": 1,
+ "line-dasharray": [1, 0],
+ "line-blur": 0
+ }
+ },
+ {
+ "id": "tunnel-oneway-arrows-blue-minor",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444855769305.6016"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 16,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!=", "type", "trunk_link"],
+ ["==", "oneway", "true"],
+ ["==", "structure", "tunnel"],
+ [
+ "in",
+ "class",
+ "link",
+ "path",
+ "pedestrian",
+ "service",
+ "track"
+ ]
+ ]
+ ],
+ "layout": {
+ "symbol-placement": "line",
+ "icon-image": {
+ "base": 1,
+ "stops": [[17, "oneway-small"], [18, "oneway-large"]]
+ },
+ "symbol-spacing": 200,
+ "icon-padding": 2
+ },
+ "paint": {}
+ },
+ {
+ "id": "tunnel-oneway-arrows-blue-major",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444855769305.6016"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 15,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!=", "type", "trunk_link"],
+ ["==", "oneway", "true"],
+ ["==", "structure", "tunnel"],
+ [
+ "in",
+ "class",
+ "primary",
+ "secondary",
+ "street",
+ "street_limited",
+ "tertiary"
+ ]
+ ]
+ ],
+ "layout": {
+ "symbol-placement": "line",
+ "icon-image": {
+ "base": 1,
+ "stops": [[16, "oneway-small"], [17, "oneway-large"]]
+ },
+ "symbol-spacing": 200,
+ "icon-padding": 2
+ },
+ "paint": {}
+ },
+ {
+ "id": "tunnel-trunk",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855769305.6016"},
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ ["all", ["==", "class", "trunk"], ["==", "structure", "tunnel"]]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]},
+ "line-color": "hsl(46, 77%, 78%)"
+ }
+ },
+ {
+ "id": "tunnel-motorway",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855769305.6016"},
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "class", "motorway"],
+ ["==", "structure", "tunnel"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]},
+ "line-dasharray": [1, 0],
+ "line-opacity": 1,
+ "line-color": "hsl(26, 100%, 78%)",
+ "line-blur": 0
+ }
+ },
+ {
+ "id": "tunnel-oneway-arrows-white",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444855769305.6016"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 16,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ [
+ "!in",
+ "type",
+ "primary_link",
+ "secondary_link",
+ "tertiary_link"
+ ],
+ ["==", "oneway", "true"],
+ ["==", "structure", "tunnel"],
+ [
+ "in",
+ "class",
+ "link",
+ "motorway",
+ "motorway_link",
+ "trunk"
+ ]
+ ]
+ ],
+ "layout": {
+ "symbol-placement": "line",
+ "icon-image": {
+ "base": 1,
+ "stops": [
+ [16, "oneway-white-small"],
+ [17, "oneway-white-large"]
+ ]
+ },
+ "symbol-spacing": 200,
+ "icon-padding": 2
+ },
+ "paint": {}
+ },
+ {
+ "id": "ferry",
+ "type": "line",
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ ["==", "type", "ferry"]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": {
+ "base": 1,
+ "stops": [
+ [15, "hsl(205, 73%, 63%)"],
+ [17, "hsl(230, 73%, 63%)"]
+ ]
+ },
+ "line-opacity": 1,
+ "line-width": {"base": 1.5, "stops": [[14, 0.5], [20, 1]]},
+ "line-dasharray": {
+ "base": 1,
+ "stops": [[12, [1, 0]], [13, [12, 4]]]
+ }
+ }
+ },
+ {
+ "id": "ferry_auto",
+ "type": "line",
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ ["==", "type", "ferry_auto"]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": {
+ "base": 1,
+ "stops": [
+ [15, "hsl(205, 73%, 63%)"],
+ [17, "hsl(230, 73%, 63%)"]
+ ]
+ },
+ "line-opacity": 1,
+ "line-width": {"base": 1.5, "stops": [[14, 0.5], [20, 1]]}
+ }
+ },
+ {
+ "id": "road-path-bg",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!in", "structure", "bridge", "tunnel"],
+ ["!in", "type", "crossing", "sidewalk", "steps"],
+ ["==", "class", "path"]
+ ]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[15, 2], [18, 7]]},
+ "line-dasharray": [1, 0],
+ "line-color": "hsl(230, 17%, 82%)",
+ "line-blur": 0,
+ "line-opacity": {"base": 1, "stops": [[14, 0], [14.25, 0.75]]}
+ }
+ },
+ {
+ "id": "road-steps-bg",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!in", "structure", "bridge", "tunnel"],
+ ["==", "type", "steps"]
+ ]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-width": {
+ "base": 1.5,
+ "stops": [[15, 2], [17, 4.6], [18, 7]]
+ },
+ "line-color": "hsl(230, 17%, 82%)",
+ "line-dasharray": [1, 0],
+ "line-opacity": {"base": 1, "stops": [[14, 0], [14.25, 0.75]]}
+ }
+ },
+ {
+ "id": "road-sidewalk-bg",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 16,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!in", "structure", "bridge", "tunnel"],
+ ["in", "type", "crossing", "sidewalk"]
+ ]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[15, 2], [18, 7]]},
+ "line-dasharray": [1, 0],
+ "line-color": "hsl(230, 17%, 82%)",
+ "line-blur": 0,
+ "line-opacity": {"base": 1, "stops": [[16, 0], [16.25, 0.75]]}
+ }
+ },
+ {
+ "id": "turning-features-outline",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 15,
+ "filter": [
+ "all",
+ ["==", "$type", "Point"],
+ ["in", "class", "turning_circle", "turning_loop"]
+ ],
+ "layout": {
+ "icon-image": "turning-circle-outline",
+ "icon-size": {
+ "base": 1.5,
+ "stops": [[14, 0.122], [18, 0.969], [20, 1]]
+ },
+ "icon-allow-overlap": true,
+ "icon-ignore-placement": true,
+ "icon-padding": 0,
+ "icon-rotation-alignment": "map"
+ },
+ "paint": {}
+ },
+ {
+ "id": "road-pedestrian-case",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 12,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "class", "pedestrian"],
+ ["==", "structure", "none"]
+ ]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[14, 2], [18, 14.5]]},
+ "line-color": "hsl(230, 24%, 87%)",
+ "line-gap-width": 0,
+ "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]}
+ }
+ },
+ {
+ "id": "road-street-low",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 11,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ ["all", ["==", "class", "street"], ["==", "structure", "none"]]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {
+ "base": 1.5,
+ "stops": [[12.5, 0.5], [14, 2], [18, 18]]
+ },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-opacity": {
+ "stops": [[11, 0], [11.25, 1], [14, 1], [14.01, 0]]
+ }
+ }
+ },
+ {
+ "id": "road-street_limited-low",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 11,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "class", "street_limited"],
+ ["==", "structure", "none"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {
+ "base": 1.5,
+ "stops": [[12.5, 0.5], [14, 2], [18, 18]]
+ },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-opacity": {
+ "stops": [[11, 0], [11.25, 1], [14, 1], [14.01, 0]]
+ }
+ }
+ },
+ {
+ "id": "road-service-link-track-case",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 14,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!=", "type", "trunk_link"],
+ ["!in", "structure", "bridge", "tunnel"],
+ ["in", "class", "link", "service", "track"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]},
+ "line-color": "hsl(230, 24%, 87%)",
+ "line-gap-width": {"base": 1.5, "stops": [[14, 0.5], [18, 12]]}
+ }
+ },
+ {
+ "id": "road-street_limited-case",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 11,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "class", "street_limited"],
+ ["==", "structure", "none"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]},
+ "line-color": "hsl(230, 24%, 87%)",
+ "line-gap-width": {
+ "base": 1.5,
+ "stops": [[13, 0], [14, 2], [18, 18]]
+ },
+ "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]}
+ }
+ },
+ {
+ "id": "road-street-case",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 11,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ ["all", ["==", "class", "street"], ["==", "structure", "none"]]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]},
+ "line-color": "hsl(230, 24%, 87%)",
+ "line-gap-width": {
+ "base": 1.5,
+ "stops": [[13, 0], [14, 2], [18, 18]]
+ },
+ "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]}
+ }
+ },
+ {
+ "id": "road-secondary-tertiary-case",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!in", "structure", "bridge", "tunnel"],
+ ["in", "class", "secondary", "tertiary"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.2, "stops": [[10, 0.75], [18, 2]]},
+ "line-color": "hsl(230, 24%, 87%)",
+ "line-gap-width": {
+ "base": 1.5,
+ "stops": [[8.5, 0.5], [10, 0.75], [18, 26]]
+ },
+ "line-opacity": {"base": 1, "stops": [[9.99, 0], [10, 1]]}
+ }
+ },
+ {
+ "id": "road-primary-case",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!in", "structure", "bridge", "tunnel"],
+ ["==", "class", "primary"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[10, 1], [16, 2]]},
+ "line-color": "hsl(230, 24%, 87%)",
+ "line-gap-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]},
+ "line-opacity": {"base": 1, "stops": [[9.99, 0], [10, 1]]}
+ }
+ },
+ {
+ "id": "road-motorway_link-case",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 10,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!in", "structure", "bridge", "tunnel"],
+ ["==", "class", "motorway_link"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]},
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-gap-width": {
+ "base": 1.5,
+ "stops": [[12, 0.5], [14, 2], [18, 18]]
+ },
+ "line-opacity": {"base": 1, "stops": [[10.99, 0], [11, 1]]}
+ }
+ },
+ {
+ "id": "road-trunk_link-case",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 11,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!in", "structure", "bridge", "tunnel"],
+ ["==", "type", "trunk_link"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]},
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-gap-width": {
+ "base": 1.5,
+ "stops": [[12, 0.5], [14, 2], [18, 18]]
+ },
+ "line-opacity": {"base": 1, "stops": [[10.99, 0], [11, 1]]}
+ }
+ },
+ {
+ "id": "road-trunk-case",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!in", "structure", "bridge", "tunnel"],
+ ["==", "class", "trunk"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[10, 1], [16, 2]]},
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-gap-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]},
+ "line-opacity": {"base": 1, "stops": [[6, 0], [6.1, 1]]}
+ }
+ },
+ {
+ "id": "road-motorway-case",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!in", "structure", "bridge", "tunnel"],
+ ["==", "class", "motorway"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[10, 1], [16, 2]]},
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-gap-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]}
+ }
+ },
+ {
+ "id": "road-construction",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 14,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "class", "construction"],
+ ["==", "structure", "none"]
+ ]
+ ],
+ "layout": {"line-join": "miter"},
+ "paint": {
+ "line-width": {
+ "base": 1.5,
+ "stops": [[12.5, 0.5], [14, 2], [18, 18]]
+ },
+ "line-color": "hsl(230, 24%, 87%)",
+ "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]},
+ "line-dasharray": {
+ "base": 1,
+ "stops": [
+ [14, [0.4, 0.8]],
+ [15, [0.3, 0.6]],
+ [16, [0.2, 0.3]],
+ [17, [0.2, 0.25]],
+ [18, [0.15, 0.15]]
+ ]
+ }
+ }
+ },
+ {
+ "id": "road-sidewalks",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 16,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!in", "structure", "bridge", "tunnel"],
+ ["in", "type", "crossing", "sidewalk"]
+ ]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[15, 1], [18, 4]]},
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-dasharray": {
+ "base": 1,
+ "stops": [
+ [14, [1, 0]],
+ [15, [1.75, 1]],
+ [16, [1, 0.75]],
+ [17, [1, 0.5]]
+ ]
+ },
+ "line-opacity": {"base": 1, "stops": [[16, 0], [16.25, 1]]}
+ }
+ },
+ {
+ "id": "road-path",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!in", "structure", "bridge", "tunnel"],
+ ["!in", "type", "crossing", "sidewalk", "steps"],
+ ["==", "class", "path"]
+ ]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[15, 1], [18, 4]]},
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-dasharray": {
+ "base": 1,
+ "stops": [
+ [14, [1, 0]],
+ [15, [1.75, 1]],
+ [16, [1, 0.75]],
+ [17, [1, 0.5]]
+ ]
+ },
+ "line-opacity": {"base": 1, "stops": [[14, 0], [14.25, 1]]}
+ }
+ },
+ {
+ "id": "road-steps",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!in", "structure", "bridge", "tunnel"],
+ ["==", "type", "steps"]
+ ]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-width": {
+ "base": 1.5,
+ "stops": [[15, 1], [16, 1.6], [18, 6]]
+ },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-dasharray": {
+ "base": 1,
+ "stops": [
+ [14, [1, 0]],
+ [15, [1.75, 1]],
+ [16, [1, 0.75]],
+ [17, [0.3, 0.3]]
+ ]
+ },
+ "line-opacity": {"base": 1, "stops": [[14, 0], [14.25, 1]]}
+ }
+ },
+ {
+ "id": "road-trunk_link",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 11,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!in", "structure", "bridge", "tunnel"],
+ ["==", "type", "trunk_link"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {
+ "base": 1.5,
+ "stops": [[12, 0.5], [14, 2], [18, 18]]
+ },
+ "line-color": "hsl(46, 85%, 67%)",
+ "line-opacity": 1
+ }
+ },
+ {
+ "id": "road-motorway_link",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 10,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!in", "structure", "bridge", "tunnel"],
+ ["==", "class", "motorway_link"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {
+ "base": 1.5,
+ "stops": [[12, 0.5], [14, 2], [18, 18]]
+ },
+ "line-color": "hsl(26, 100%, 68%)",
+ "line-opacity": 1
+ }
+ },
+ {
+ "id": "road-pedestrian",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 12,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "class", "pedestrian"],
+ ["==", "structure", "none"]
+ ]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[14, 0.5], [18, 12]]},
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-opacity": 1,
+ "line-dasharray": {
+ "base": 1,
+ "stops": [[14, [1, 0]], [15, [1.5, 0.4]], [16, [1, 0.2]]]
+ }
+ }
+ },
+ {
+ "id": "road-pedestrian-polygon-fill",
+ "type": "fill",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 12,
+ "filter": [
+ "all",
+ ["==", "$type", "Polygon"],
+ [
+ "all",
+ ["==", "structure", "none"],
+ ["in", "class", "path", "pedestrian"]
+ ]
+ ],
+ "layout": {},
+ "paint": {
+ "fill-color": {
+ "base": 1,
+ "stops": [
+ [16, "hsl(230, 16%, 94%)"],
+ [16.25, "hsl(230, 50%, 98%)"]
+ ]
+ },
+ "fill-outline-color": "hsl(230, 26%, 88%)",
+ "fill-opacity": 1
+ }
+ },
+ {
+ "id": "road-pedestrian-polygon-pattern",
+ "type": "fill",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 12,
+ "filter": [
+ "all",
+ ["==", "$type", "Polygon"],
+ [
+ "all",
+ ["==", "structure", "none"],
+ ["in", "class", "path", "pedestrian"]
+ ]
+ ],
+ "layout": {},
+ "paint": {
+ "fill-color": "hsl(0, 0%, 100%)",
+ "fill-outline-color": "hsl(35, 10%, 83%)",
+ "fill-pattern": "pedestrian-polygon",
+ "fill-opacity": {"base": 1, "stops": [[16, 0], [16.25, 1]]}
+ }
+ },
+ {
+ "id": "road-polygon",
+ "type": "fill",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 12,
+ "filter": [
+ "all",
+ ["==", "$type", "Polygon"],
+ [
+ "all",
+ ["!in", "class", "motorway", "path", "pedestrian", "trunk"],
+ ["!in", "structure", "bridge", "tunnel"]
+ ]
+ ],
+ "layout": {},
+ "paint": {
+ "fill-color": "hsl(0, 0%, 100%)",
+ "fill-outline-color": "#d6d9e6"
+ }
+ },
+ {
+ "id": "road-service-link-track",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 14,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!=", "type", "trunk_link"],
+ ["!in", "structure", "bridge", "tunnel"],
+ ["in", "class", "link", "service", "track"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[14, 0.5], [18, 12]]},
+ "line-color": "hsl(0, 0%, 100%)"
+ }
+ },
+ {
+ "id": "road-street_limited",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 11,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "class", "street_limited"],
+ ["==", "structure", "none"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {
+ "base": 1.5,
+ "stops": [[12.5, 0.5], [14, 2], [18, 18]]
+ },
+ "line-color": "hsl(35, 14%, 93%)",
+ "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]}
+ }
+ },
+ {
+ "id": "road-street",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 11,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ ["all", ["==", "class", "street"], ["==", "structure", "none"]]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {
+ "base": 1.5,
+ "stops": [[12.5, 0.5], [14, 2], [18, 18]]
+ },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]}
+ }
+ },
+ {
+ "id": "road-secondary-tertiary",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!in", "structure", "bridge", "tunnel"],
+ ["in", "class", "secondary", "tertiary"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {
+ "base": 1.5,
+ "stops": [[8.5, 0.5], [10, 0.75], [18, 26]]
+ },
+ "line-color": {
+ "base": 1,
+ "stops": [[5, "hsl(35, 32%, 91%)"], [8, "hsl(0, 0%, 100%)"]]
+ },
+ "line-opacity": {"base": 1.2, "stops": [[5, 0], [5.5, 1]]}
+ }
+ },
+ {
+ "id": "road-primary",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!in", "structure", "bridge", "tunnel"],
+ ["==", "class", "primary"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]},
+ "line-color": {
+ "base": 1,
+ "stops": [[5, "hsl(35, 32%, 91%)"], [7, "hsl(0, 0%, 100%)"]]
+ },
+ "line-opacity": 1
+ }
+ },
+ {
+ "id": "road-oneway-arrows-blue-minor",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 16,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!=", "type", "trunk_link"],
+ ["!in", "structure", "bridge", "tunnel"],
+ ["==", "oneway", "true"],
+ [
+ "in",
+ "class",
+ "link",
+ "path",
+ "pedestrian",
+ "service",
+ "track"
+ ]
+ ]
+ ],
+ "layout": {
+ "symbol-placement": "line",
+ "icon-image": {
+ "base": 1,
+ "stops": [[17, "oneway-small"], [18, "oneway-large"]]
+ },
+ "icon-rotation-alignment": "map",
+ "icon-padding": 2,
+ "symbol-spacing": 200
+ },
+ "paint": {}
+ },
+ {
+ "id": "road-oneway-arrows-blue-major",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 15,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!=", "type", "trunk_link"],
+ ["!in", "structure", "bridge", "tunnel"],
+ ["==", "oneway", "true"],
+ [
+ "in",
+ "class",
+ "primary",
+ "secondary",
+ "street",
+ "street_limited",
+ "tertiary"
+ ]
+ ]
+ ],
+ "layout": {
+ "symbol-placement": "line",
+ "icon-image": {
+ "base": 1,
+ "stops": [[16, "oneway-small"], [17, "oneway-large"]]
+ },
+ "icon-rotation-alignment": "map",
+ "icon-padding": 2,
+ "symbol-spacing": 200
+ },
+ "paint": {}
+ },
+ {
+ "id": "road-trunk",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!in", "structure", "bridge", "tunnel"],
+ ["==", "class", "trunk"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]},
+ "line-color": {
+ "base": 1,
+ "stops": [
+ [6, "hsl(0, 0%, 100%)"],
+ [6.1, "hsl(46, 80%, 60%)"],
+ [9, "hsl(46, 85%, 67%)"]
+ ]
+ }
+ }
+ },
+ {
+ "id": "road-motorway",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!in", "structure", "bridge", "tunnel"],
+ ["==", "class", "motorway"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]},
+ "line-color": {
+ "base": 1,
+ "stops": [
+ [8, "hsl(26, 87%, 62%)"],
+ [9, "hsl(26, 100%, 68%)"]
+ ]
+ }
+ }
+ },
+ {
+ "id": "road-rail",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 13,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!in", "structure", "bridge", "tunnel"],
+ ["in", "class", "major_rail", "minor_rail"]
+ ]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": {
+ "stops": [
+ [13, "hsl(50, 17%, 82%)"],
+ [16, "hsl(230, 10%, 74%)"]
+ ]
+ },
+ "line-width": {"base": 1.5, "stops": [[14, 0.5], [20, 1]]}
+ }
+ },
+ {
+ "id": "road-rail-tracks",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 13,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!in", "structure", "bridge", "tunnel"],
+ ["in", "class", "major_rail", "minor_rail"]
+ ]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": {
+ "stops": [
+ [13, "hsl(50, 17%, 82%)"],
+ [16, "hsl(230, 10%, 74%)"]
+ ]
+ },
+ "line-width": {"base": 1.5, "stops": [[14, 4], [20, 8]]},
+ "line-dasharray": [0.1, 15],
+ "line-opacity": {"base": 1, "stops": [[13.75, 0], [14, 1]]}
+ }
+ },
+ {
+ "id": "level-crossings",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 16,
+ "filter": [
+ "all",
+ ["==", "$type", "Point"],
+ ["==", "class", "level_crossing"]
+ ],
+ "layout": {
+ "icon-size": 1,
+ "icon-image": "level-crossing",
+ "icon-allow-overlap": true
+ },
+ "paint": {}
+ },
+ {
+ "id": "road-oneway-arrows-white",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 16,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!in", "structure", "bridge", "tunnel"],
+ [
+ "!in",
+ "type",
+ "primary_link",
+ "secondary_link",
+ "tertiary_link"
+ ],
+ ["==", "oneway", "true"],
+ [
+ "in",
+ "class",
+ "link",
+ "motorway",
+ "motorway_link",
+ "trunk"
+ ]
+ ]
+ ],
+ "layout": {
+ "symbol-placement": "line",
+ "icon-image": {
+ "base": 1,
+ "stops": [
+ [16, "oneway-white-small"],
+ [17, "oneway-white-large"]
+ ]
+ },
+ "icon-padding": 2,
+ "symbol-spacing": 200
+ },
+ "paint": {}
+ },
+ {
+ "id": "turning-features",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444855786460.0557"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 15,
+ "filter": [
+ "all",
+ ["==", "$type", "Point"],
+ ["in", "class", "turning_circle", "turning_loop"]
+ ],
+ "layout": {
+ "icon-image": "turning-circle",
+ "icon-size": {"base": 1.5, "stops": [[14, 0.095], [18, 1]]},
+ "icon-allow-overlap": true,
+ "icon-ignore-placement": true,
+ "icon-padding": 0,
+ "icon-rotation-alignment": "map"
+ },
+ "paint": {}
+ },
+ {
+ "id": "bridge-path-bg",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!=", "type", "steps"],
+ ["==", "class", "path"],
+ ["==", "structure", "bridge"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[15, 2], [18, 7]]},
+ "line-dasharray": [1, 0],
+ "line-color": "hsl(230, 17%, 82%)",
+ "line-blur": 0,
+ "line-opacity": {"base": 1, "stops": [[15, 0], [15.25, 1]]}
+ }
+ },
+ {
+ "id": "bridge-steps-bg",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ ["all", ["==", "structure", "bridge"], ["==", "type", "steps"]]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-width": {
+ "base": 1.5,
+ "stops": [[15, 2], [17, 4.6], [18, 7]]
+ },
+ "line-color": "hsl(230, 17%, 82%)",
+ "line-dasharray": [1, 0],
+ "line-opacity": {"base": 1, "stops": [[14, 0], [14.25, 0.75]]}
+ }
+ },
+ {
+ "id": "bridge-pedestrian-case",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 13,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "class", "pedestrian"],
+ ["==", "structure", "bridge"]
+ ]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[14, 2], [18, 14.5]]},
+ "line-color": "hsl(230, 24%, 87%)",
+ "line-gap-width": 0,
+ "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]}
+ }
+ },
+ {
+ "id": "bridge-street-low",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 11,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "class", "street"],
+ ["==", "structure", "bridge"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {
+ "base": 1.5,
+ "stops": [[12.5, 0.5], [14, 2], [18, 18]]
+ },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-opacity": {
+ "stops": [[11.5, 0], [12, 1], [14, 1], [14.01, 0]]
+ }
+ }
+ },
+ {
+ "id": "bridge-street_limited-low",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 11,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "class", "street_limited"],
+ ["==", "structure", "bridge"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {
+ "base": 1.5,
+ "stops": [[12.5, 0.5], [14, 2], [18, 18]]
+ },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-opacity": {
+ "stops": [[11.5, 0], [12, 1], [14, 1], [14.01, 0]]
+ }
+ }
+ },
+ {
+ "id": "bridge-service-link-track-case",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 14,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!=", "type", "trunk_link"],
+ ["==", "structure", "bridge"],
+ ["in", "class", "link", "service", "track"]
+ ]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]},
+ "line-color": "hsl(230, 24%, 87%)",
+ "line-gap-width": {"base": 1.5, "stops": [[14, 0.5], [18, 12]]}
+ }
+ },
+ {
+ "id": "bridge-street_limited-case",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 11,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "class", "street_limited"],
+ ["==", "structure", "bridge"]
+ ]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]},
+ "line-color": "hsl(230, 24%, 87%)",
+ "line-gap-width": {
+ "base": 1.5,
+ "stops": [[13, 0], [14, 2], [18, 18]]
+ }
+ }
+ },
+ {
+ "id": "bridge-street-case",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 11,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "class", "street"],
+ ["==", "structure", "bridge"]
+ ]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]},
+ "line-color": "hsl(230, 24%, 87%)",
+ "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]},
+ "line-gap-width": {
+ "base": 1.5,
+ "stops": [[13, 0], [14, 2], [18, 18]]
+ }
+ }
+ },
+ {
+ "id": "bridge-secondary-tertiary-case",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "structure", "bridge"],
+ ["in", "class", "secondary", "tertiary"]
+ ]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.2, "stops": [[10, 0.75], [18, 2]]},
+ "line-color": "hsl(230, 24%, 87%)",
+ "line-gap-width": {
+ "base": 1.5,
+ "stops": [[8.5, 0.5], [10, 0.75], [18, 26]]
+ },
+ "line-translate": [0, 0]
+ }
+ },
+ {
+ "id": "bridge-primary-case",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "class", "primary"],
+ ["==", "structure", "bridge"]
+ ]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[10, 1], [16, 2]]},
+ "line-color": "hsl(230, 24%, 87%)",
+ "line-gap-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]},
+ "line-translate": [0, 0]
+ }
+ },
+ {
+ "id": "bridge-trunk_link-case",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 13,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!in", "layer", 2, 3, 4, 5],
+ ["==", "structure", "bridge"],
+ ["==", "type", "trunk_link"]
+ ]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]},
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-gap-width": {
+ "base": 1.5,
+ "stops": [[12, 0.5], [14, 2], [18, 18]]
+ },
+ "line-opacity": {"base": 1, "stops": [[10.99, 0], [11, 1]]}
+ }
+ },
+ {
+ "id": "bridge-motorway_link-case",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 13,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!in", "layer", 2, 3, 4, 5],
+ ["==", "class", "motorway_link"],
+ ["==", "structure", "bridge"]
+ ]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]},
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-gap-width": {
+ "base": 1.5,
+ "stops": [[12, 0.5], [14, 2], [18, 18]]
+ },
+ "line-opacity": 1
+ }
+ },
+ {
+ "id": "bridge-trunk-case",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!in", "layer", 2, 3, 4, 5],
+ ["==", "class", "trunk"],
+ ["==", "structure", "bridge"]
+ ]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[10, 1], [16, 2]]},
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-gap-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]}
+ }
+ },
+ {
+ "id": "bridge-motorway-case",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!in", "layer", 2, 3, 4, 5],
+ ["==", "class", "motorway"],
+ ["==", "structure", "bridge"]
+ ]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[10, 1], [16, 2]]},
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-gap-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]}
+ }
+ },
+ {
+ "id": "bridge-construction",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 14,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "class", "construction"],
+ ["==", "structure", "bridge"]
+ ]
+ ],
+ "layout": {"line-join": "miter"},
+ "paint": {
+ "line-width": {
+ "base": 1.5,
+ "stops": [[12.5, 0.5], [14, 2], [18, 18]]
+ },
+ "line-color": "hsl(230, 24%, 87%)",
+ "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]},
+ "line-dasharray": {
+ "base": 1,
+ "stops": [
+ [14, [0.4, 0.8]],
+ [15, [0.3, 0.6]],
+ [16, [0.2, 0.3]],
+ [17, [0.2, 0.25]],
+ [18, [0.15, 0.15]]
+ ]
+ }
+ }
+ },
+ {
+ "id": "bridge-path",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!=", "type", "steps"],
+ ["==", "class", "path"],
+ ["==", "structure", "bridge"]
+ ]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[15, 1], [18, 4]]},
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-dasharray": {
+ "base": 1,
+ "stops": [
+ [14, [1, 0]],
+ [15, [1.75, 1]],
+ [16, [1, 0.75]],
+ [17, [1, 0.5]]
+ ]
+ },
+ "line-opacity": {"base": 1, "stops": [[14, 0], [14.25, 1]]}
+ }
+ },
+ {
+ "id": "bridge-steps",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ ["all", ["==", "structure", "bridge"], ["==", "type", "steps"]]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-width": {
+ "base": 1.5,
+ "stops": [[15, 1], [16, 1.6], [18, 6]]
+ },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-dasharray": {
+ "base": 1,
+ "stops": [
+ [14, [1, 0]],
+ [15, [1.75, 1]],
+ [16, [1, 0.75]],
+ [17, [0.3, 0.3]]
+ ]
+ },
+ "line-opacity": {"base": 1, "stops": [[14, 0], [14.25, 1]]}
+ }
+ },
+ {
+ "id": "bridge-trunk_link",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 13,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!in", "layer", 2, 3, 4, 5],
+ ["==", "structure", "bridge"],
+ ["==", "type", "trunk_link"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {
+ "base": 1.5,
+ "stops": [[12, 0.5], [14, 2], [18, 18]]
+ },
+ "line-color": "hsl(46, 85%, 67%)"
+ }
+ },
+ {
+ "id": "bridge-motorway_link",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 13,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!in", "layer", 2, 3, 4, 5],
+ ["==", "class", "motorway_link"],
+ ["==", "structure", "bridge"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {
+ "base": 1.5,
+ "stops": [[12, 0.5], [14, 2], [18, 18]]
+ },
+ "line-color": "hsl(26, 100%, 68%)"
+ }
+ },
+ {
+ "id": "bridge-pedestrian",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 13,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "class", "pedestrian"],
+ ["==", "structure", "bridge"]
+ ]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[14, 0.5], [18, 12]]},
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-opacity": 1,
+ "line-dasharray": {
+ "base": 1,
+ "stops": [[14, [1, 0]], [15, [1.5, 0.4]], [16, [1, 0.2]]]
+ }
+ }
+ },
+ {
+ "id": "bridge-service-link-track",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 14,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!=", "type", "trunk_link"],
+ ["==", "structure", "bridge"],
+ ["in", "class", "link", "service", "track"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[14, 0.5], [18, 12]]},
+ "line-color": "hsl(0, 0%, 100%)"
+ }
+ },
+ {
+ "id": "bridge-street_limited",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 11,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "class", "street_limited"],
+ ["==", "structure", "bridge"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {
+ "base": 1.5,
+ "stops": [[12.5, 0.5], [14, 2], [18, 18]]
+ },
+ "line-color": "hsl(35, 14%, 93%)",
+ "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]}
+ }
+ },
+ {
+ "id": "bridge-street",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 11,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "class", "street"],
+ ["==", "structure", "bridge"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {
+ "base": 1.5,
+ "stops": [[12.5, 0.5], [14, 2], [18, 18]]
+ },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]}
+ }
+ },
+ {
+ "id": "bridge-secondary-tertiary",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "structure", "bridge"],
+ ["in", "type", "secondary", "tertiary"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {
+ "base": 1.5,
+ "stops": [[8.5, 0.5], [10, 0.75], [18, 26]]
+ },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-opacity": {"base": 1.2, "stops": [[5, 0], [5.5, 1]]}
+ }
+ },
+ {
+ "id": "bridge-primary",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "structure", "bridge"],
+ ["==", "type", "primary"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]},
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-opacity": 1
+ }
+ },
+ {
+ "id": "bridge-oneway-arrows-blue-minor",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 16,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "oneway", "true"],
+ ["==", "structure", "bridge"],
+ [
+ "in",
+ "class",
+ "link",
+ "path",
+ "pedestrian",
+ "service",
+ "track"
+ ]
+ ]
+ ],
+ "layout": {
+ "symbol-placement": "line",
+ "icon-image": {
+ "base": 1,
+ "stops": [[17, "oneway-small"], [18, "oneway-large"]]
+ },
+ "symbol-spacing": 200,
+ "icon-rotation-alignment": "map",
+ "icon-padding": 2
+ },
+ "paint": {}
+ },
+ {
+ "id": "bridge-oneway-arrows-blue-major",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 15,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "oneway", "true"],
+ ["==", "structure", "bridge"],
+ [
+ "in",
+ "class",
+ "primary",
+ "secondary",
+ "street",
+ "street_limited",
+ "tertiary"
+ ]
+ ]
+ ],
+ "layout": {
+ "symbol-placement": "line",
+ "icon-image": {
+ "base": 1,
+ "stops": [[16, "oneway-small"], [17, "oneway-large"]]
+ },
+ "symbol-spacing": 200,
+ "icon-rotation-alignment": "map",
+ "icon-padding": 2
+ },
+ "paint": {}
+ },
+ {
+ "id": "bridge-trunk",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!in", "layer", 2, 3, 4, 5],
+ ["==", "class", "trunk"],
+ ["==", "structure", "bridge"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]},
+ "line-color": "hsl(46, 85%, 67%)"
+ }
+ },
+ {
+ "id": "bridge-motorway",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["!in", "layer", 2, 3, 4, 5],
+ ["==", "class", "motorway"],
+ ["==", "structure", "bridge"]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]},
+ "line-color": "hsl(26, 100%, 68%)"
+ }
+ },
+ {
+ "id": "bridge-rail",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 13,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "structure", "bridge"],
+ ["in", "class", "major_rail", "minor_rail"]
+ ]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": {
+ "stops": [
+ [13, "hsl(50, 17%, 82%)"],
+ [16, "hsl(230, 10%, 74%)"]
+ ]
+ },
+ "line-width": {"base": 1.5, "stops": [[14, 0.5], [20, 1]]}
+ }
+ },
+ {
+ "id": "bridge-rail-tracks",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 13,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "structure", "bridge"],
+ ["in", "class", "major_rail", "minor_rail"]
+ ]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": {
+ "stops": [
+ [13, "hsl(50, 17%, 82%)"],
+ [16, "hsl(230, 10%, 74%)"]
+ ]
+ },
+ "line-width": {"base": 1.5, "stops": [[14, 4], [20, 8]]},
+ "line-dasharray": [0.1, 15],
+ "line-opacity": {"base": 1, "stops": [[13.75, 0], [20, 1]]}
+ }
+ },
+ {
+ "id": "bridge-trunk_link-2-case",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 13,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "structure", "bridge"],
+ ["==", "type", "trunk_link"],
+ [">=", "layer", 2]
+ ]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]},
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-gap-width": {
+ "base": 1.5,
+ "stops": [[12, 0.5], [14, 2], [18, 18]]
+ },
+ "line-opacity": {"base": 1, "stops": [[10.99, 0], [11, 1]]}
+ }
+ },
+ {
+ "id": "bridge-motorway_link-2-case",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 13,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "class", "motorway_link"],
+ ["==", "structure", "bridge"],
+ [">=", "layer", 2]
+ ]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]},
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-gap-width": {
+ "base": 1.5,
+ "stops": [[12, 0.5], [14, 2], [18, 18]]
+ },
+ "line-opacity": 1
+ }
+ },
+ {
+ "id": "bridge-trunk-2-case",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "class", "trunk"],
+ ["==", "structure", "bridge"],
+ [">=", "layer", 2]
+ ]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[10, 1], [16, 2]]},
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-gap-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]}
+ }
+ },
+ {
+ "id": "bridge-motorway-2-case",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "class", "motorway"],
+ ["==", "structure", "bridge"],
+ [">=", "layer", 2]
+ ]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[10, 1], [16, 2]]},
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-gap-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]}
+ }
+ },
+ {
+ "id": "bridge-trunk_link-2",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 13,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "structure", "bridge"],
+ ["==", "type", "trunk_link"],
+ [">=", "layer", 2]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {
+ "base": 1.5,
+ "stops": [[12, 0.5], [14, 2], [18, 18]]
+ },
+ "line-color": "hsl(46, 85%, 67%)"
+ }
+ },
+ {
+ "id": "bridge-motorway_link-2",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 13,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "class", "motorway_link"],
+ ["==", "structure", "bridge"],
+ [">=", "layer", 2]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {
+ "base": 1.5,
+ "stops": [[12, 0.5], [14, 2], [18, 18]]
+ },
+ "line-color": "hsl(26, 100%, 68%)"
+ }
+ },
+ {
+ "id": "bridge-trunk-2",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "class", "trunk"],
+ ["==", "structure", "bridge"],
+ [">=", "layer", 2]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]},
+ "line-color": "hsl(46, 85%, 67%)"
+ }
+ },
+ {
+ "id": "bridge-motorway-2",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ ["==", "class", "motorway"],
+ ["==", "structure", "bridge"],
+ [">=", "layer", 2]
+ ]
+ ],
+ "layout": {"line-cap": "round", "line-join": "round"},
+ "paint": {
+ "line-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]},
+ "line-color": "hsl(26, 100%, 68%)"
+ }
+ },
+ {
+ "id": "bridge-oneway-arrows-white",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444855799204.86"},
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 16,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "all",
+ [
+ "!in",
+ "type",
+ "primary_link",
+ "secondary_link",
+ "tertiary_link"
+ ],
+ ["==", "oneway", "true"],
+ ["==", "structure", "bridge"],
+ [
+ "in",
+ "class",
+ "link",
+ "motorway",
+ "motorway_link",
+ "trunk"
+ ]
+ ]
+ ],
+ "layout": {
+ "symbol-placement": "line",
+ "icon-image": {
+ "base": 1,
+ "stops": [
+ [16, "oneway-white-small"],
+ [17, "oneway-white-large"]
+ ]
+ },
+ "symbol-spacing": 200,
+ "icon-padding": 2
+ },
+ "paint": {}
+ },
+ {
+ "id": "aerialway",
+ "type": "line",
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 13,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ ["==", "class", "aerialway"]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-color": "hsl(230, 10%, 74%)",
+ "line-width": {"base": 1.5, "stops": [[14, 0.5], [20, 1]]}
+ }
+ },
+ {
+ "id": "admin-3-4-boundaries-bg",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444934295202.7542"},
+ "source": "composite",
+ "source-layer": "admin",
+ "filter": ["all", ["==", "maritime", 0], [">=", "admin_level", 3]],
+ "layout": {"line-join": "bevel"},
+ "paint": {
+ "line-color": {
+ "base": 1,
+ "stops": [
+ [8, "hsl(35, 12%, 89%)"],
+ [16, "hsl(230, 49%, 90%)"]
+ ]
+ },
+ "line-width": {"base": 1, "stops": [[7, 3.75], [12, 5.5]]},
+ "line-opacity": {"base": 1, "stops": [[7, 0], [8, 0.75]]},
+ "line-dasharray": [1, 0],
+ "line-translate": [0, 0],
+ "line-blur": {"base": 1, "stops": [[3, 0], [8, 3]]}
+ }
+ },
+ {
+ "id": "admin-2-boundaries-bg",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444934295202.7542"},
+ "source": "composite",
+ "source-layer": "admin",
+ "minzoom": 1,
+ "filter": ["all", ["==", "admin_level", 2], ["==", "maritime", 0]],
+ "layout": {"line-join": "miter"},
+ "paint": {
+ "line-width": {"base": 1, "stops": [[3, 3.5], [10, 8]]},
+ "line-color": {
+ "base": 1,
+ "stops": [
+ [6, "hsl(35, 12%, 89%)"],
+ [8, "hsl(230, 49%, 90%)"]
+ ]
+ },
+ "line-opacity": {"base": 1, "stops": [[3, 0], [4, 0.5]]},
+ "line-translate": [0, 0],
+ "line-blur": {"base": 1, "stops": [[3, 0], [10, 2]]}
+ }
+ },
+ {
+ "id": "admin-3-4-boundaries",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444934295202.7542"},
+ "source": "composite",
+ "source-layer": "admin",
+ "filter": ["all", ["==", "maritime", 0], [">=", "admin_level", 3]],
+ "layout": {"line-join": "round", "line-cap": "round"},
+ "paint": {
+ "line-dasharray": {
+ "base": 1,
+ "stops": [[6, [2, 0]], [7, [2, 2, 6, 2]]]
+ },
+ "line-width": {"base": 1, "stops": [[7, 0.75], [12, 1.5]]},
+ "line-opacity": {"base": 1, "stops": [[2, 0], [3, 1]]},
+ "line-color": {
+ "base": 1,
+ "stops": [
+ [3, "hsl(230, 14%, 77%)"],
+ [7, "hsl(230, 8%, 62%)"]
+ ]
+ }
+ }
+ },
+ {
+ "id": "admin-2-boundaries",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444934295202.7542"},
+ "source": "composite",
+ "source-layer": "admin",
+ "minzoom": 1,
+ "filter": [
+ "all",
+ ["==", "admin_level", 2],
+ ["==", "disputed", 0],
+ ["==", "maritime", 0]
+ ],
+ "layout": {"line-join": "round", "line-cap": "round"},
+ "paint": {
+ "line-color": "hsl(230, 8%, 51%)",
+ "line-width": {"base": 1, "stops": [[3, 0.5], [10, 2]]}
+ }
+ },
+ {
+ "id": "admin-2-boundaries-dispute",
+ "type": "line",
+ "metadata": {"mapbox:group": "1444934295202.7542"},
+ "source": "composite",
+ "source-layer": "admin",
+ "minzoom": 1,
+ "filter": [
+ "all",
+ ["==", "admin_level", 2],
+ ["==", "disputed", 1],
+ ["==", "maritime", 0]
+ ],
+ "layout": {"line-join": "round"},
+ "paint": {
+ "line-dasharray": [1.5, 1.5],
+ "line-color": "hsl(230, 8%, 51%)",
+ "line-width": {"base": 1, "stops": [[3, 0.5], [10, 2]]}
+ }
+ },
+ {
+ "id": "housenum-label",
+ "type": "symbol",
+ "source": "composite",
+ "source-layer": "housenum_label",
+ "minzoom": 17,
+ "layout": {
+ "text-field": "{house_num}",
+ "text-font": [
+ "DIN Offc Pro Italic",
+ "Arial Unicode MS Regular"
+ ],
+ "text-padding": 4,
+ "text-max-width": 7,
+ "text-size": 9.5
+ },
+ "paint": {
+ "text-color": "hsl(35, 2%, 69%)",
+ "text-halo-color": "hsl(35, 8%, 85%)",
+ "text-halo-width": 0.5,
+ "text-halo-blur": 0
+ }
+ },
+ {
+ "id": "waterway-label",
+ "type": "symbol",
+ "source": "composite",
+ "source-layer": "waterway_label",
+ "minzoom": 12,
+ "filter": ["in", "class", "canal", "river"],
+ "layout": {
+ "text-field": "{name_en}",
+ "text-font": [
+ "DIN Offc Pro Italic",
+ "Arial Unicode MS Regular"
+ ],
+ "symbol-placement": "line",
+ "text-pitch-alignment": "viewport",
+ "text-max-angle": 30,
+ "text-size": {"base": 1, "stops": [[13, 12], [18, 16]]}
+ },
+ "paint": {
+ "text-halo-width": 0.5,
+ "text-halo-color": "hsl(196, 80%, 70%)",
+ "text-color": "hsl(230, 48%, 44%)",
+ "text-halo-blur": 0.5
+ }
+ },
+ {
+ "id": "poi-scalerank4-l15",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444933456003.5437"},
+ "source": "composite",
+ "source-layer": "poi_label",
+ "minzoom": 17,
+ "filter": [
+ "all",
+ [
+ "!in",
+ "maki",
+ "campsite",
+ "cemetery",
+ "dog-park",
+ "garden",
+ "golf",
+ "park",
+ "picnic-site",
+ "playground",
+ "zoo"
+ ],
+ ["==", "scalerank", 4],
+ [">=", "localrank", 15]
+ ],
+ "layout": {
+ "text-line-height": 1.1,
+ "text-size": {"base": 1, "stops": [[16, 11], [20, 13]]},
+ "icon-image": "{maki}-11",
+ "text-max-angle": 38,
+ "symbol-spacing": 250,
+ "text-font": [
+ "DIN Offc Pro Medium",
+ "Arial Unicode MS Regular"
+ ],
+ "text-padding": 2,
+ "text-offset": [0, 0.65],
+ "text-rotation-alignment": "viewport",
+ "text-anchor": "top",
+ "text-field": "{name_en}",
+ "text-letter-spacing": 0.01,
+ "text-max-width": 8
+ },
+ "paint": {
+ "text-color": "hsl(26, 25%, 32%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 0.5,
+ "text-halo-blur": 0.5
+ }
+ },
+ {
+ "id": "poi-scalerank4-l1",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444933456003.5437"},
+ "source": "composite",
+ "source-layer": "poi_label",
+ "minzoom": 15,
+ "filter": [
+ "all",
+ [
+ "!in",
+ "maki",
+ "campsite",
+ "cemetery",
+ "dog-park",
+ "garden",
+ "golf",
+ "park",
+ "picnic-site",
+ "playground",
+ "zoo"
+ ],
+ ["<=", "localrank", 14],
+ ["==", "scalerank", 4]
+ ],
+ "layout": {
+ "text-line-height": 1.1,
+ "text-size": {"base": 1, "stops": [[16, 11], [20, 13]]},
+ "icon-image": "{maki}-11",
+ "text-max-angle": 38,
+ "symbol-spacing": 250,
+ "text-font": [
+ "DIN Offc Pro Medium",
+ "Arial Unicode MS Regular"
+ ],
+ "text-padding": 1,
+ "text-offset": [0, 0.65],
+ "text-rotation-alignment": "viewport",
+ "text-anchor": "top",
+ "text-field": "{name_en}",
+ "text-letter-spacing": 0.01,
+ "text-max-width": 8
+ },
+ "paint": {
+ "text-color": "hsl(26, 25%, 32%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 0.5,
+ "text-halo-blur": 0.5
+ }
+ },
+ {
+ "id": "poi-parks_scalerank4",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444933456003.5437"},
+ "source": "composite",
+ "source-layer": "poi_label",
+ "minzoom": 15,
+ "filter": [
+ "all",
+ ["==", "scalerank", 4],
+ [
+ "in",
+ "maki",
+ "campsite",
+ "cemetery",
+ "dog-park",
+ "garden",
+ "golf",
+ "park",
+ "picnic-site",
+ "playground",
+ "zoo"
+ ]
+ ],
+ "layout": {
+ "text-line-height": 1.1,
+ "text-size": {"base": 1, "stops": [[16, 11], [20, 13]]},
+ "icon-image": "{maki}-11",
+ "text-max-angle": 38,
+ "symbol-spacing": 250,
+ "text-font": [
+ "DIN Offc Pro Medium",
+ "Arial Unicode MS Regular"
+ ],
+ "text-padding": 1,
+ "text-offset": [0, 0.65],
+ "text-rotation-alignment": "viewport",
+ "text-anchor": "top",
+ "text-field": "{name_en}",
+ "text-letter-spacing": 0.01,
+ "text-max-width": 8
+ },
+ "paint": {
+ "text-color": "hsl(100, 100%, 20%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 0.5,
+ "text-halo-blur": 0.5
+ }
+ },
+ {
+ "id": "poi-scalerank3",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444933372896.5967"},
+ "source": "composite",
+ "source-layer": "poi_label",
+ "filter": [
+ "all",
+ [
+ "!in",
+ "maki",
+ "campsite",
+ "cemetery",
+ "dog-park",
+ "garden",
+ "golf",
+ "park",
+ "picnic-site",
+ "playground",
+ "zoo"
+ ],
+ ["==", "scalerank", 3]
+ ],
+ "layout": {
+ "text-line-height": 1.1,
+ "text-size": {"base": 1, "stops": [[16, 11], [20, 13]]},
+ "icon-image": "{maki}-11",
+ "text-max-angle": 38,
+ "symbol-spacing": 250,
+ "text-font": [
+ "DIN Offc Pro Medium",
+ "Arial Unicode MS Regular"
+ ],
+ "text-padding": 1,
+ "text-offset": [0, 0.65],
+ "text-rotation-alignment": "viewport",
+ "text-anchor": "top",
+ "text-field": "{name_en}",
+ "text-letter-spacing": 0.01,
+ "text-max-width": 8
+ },
+ "paint": {
+ "text-color": "hsl(26, 25%, 32%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 0.5,
+ "text-halo-blur": 0.5
+ }
+ },
+ {
+ "id": "poi-parks-scalerank3",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444933372896.5967"},
+ "source": "composite",
+ "source-layer": "poi_label",
+ "filter": [
+ "all",
+ ["==", "scalerank", 3],
+ [
+ "in",
+ "maki",
+ "campsite",
+ "cemetery",
+ "dog-park",
+ "garden",
+ "golf",
+ "park",
+ "picnic-site",
+ "playground",
+ "zoo"
+ ]
+ ],
+ "layout": {
+ "text-line-height": 1.1,
+ "text-size": {"base": 1, "stops": [[16, 11], [20, 13]]},
+ "icon-image": "{maki}-11",
+ "text-max-angle": 38,
+ "symbol-spacing": 250,
+ "text-font": [
+ "DIN Offc Pro Medium",
+ "Arial Unicode MS Regular"
+ ],
+ "text-padding": 2,
+ "text-offset": [0, 0.65],
+ "text-rotation-alignment": "viewport",
+ "text-anchor": "top",
+ "text-field": "{name_en}",
+ "text-letter-spacing": 0.01,
+ "text-max-width": 8
+ },
+ "paint": {
+ "text-color": "hsl(100, 100%, 20%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 0.5,
+ "text-halo-blur": 0.5
+ }
+ },
+ {
+ "id": "road-label-small",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444933721429.3076"},
+ "source": "composite",
+ "source-layer": "road_label",
+ "minzoom": 15,
+ "filter": [
+ "all",
+ [
+ "!in",
+ "class",
+ "golf",
+ "link",
+ "motorway",
+ "pedestrian",
+ "primary",
+ "secondary",
+ "street",
+ "street_limited",
+ "tertiary",
+ "trunk"
+ ],
+ ["==", "$type", "LineString"]
+ ],
+ "layout": {
+ "text-size": {"base": 1, "stops": [[15, 10], [20, 13]]},
+ "text-max-angle": 30,
+ "symbol-spacing": 250,
+ "text-font": [
+ "DIN Offc Pro Regular",
+ "Arial Unicode MS Regular"
+ ],
+ "symbol-placement": "line",
+ "text-padding": 1,
+ "text-rotation-alignment": "map",
+ "text-pitch-alignment": "viewport",
+ "text-field": "{name_en}",
+ "text-letter-spacing": 0.01
+ },
+ "paint": {
+ "text-color": "hsl(0, 0%, 0%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 1.25,
+ "text-halo-blur": 1
+ }
+ },
+ {
+ "id": "road-label-medium",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444933721429.3076"},
+ "source": "composite",
+ "source-layer": "road_label",
+ "minzoom": 11,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [
+ "in",
+ "class",
+ "link",
+ "pedestrian",
+ "street",
+ "street_limited"
+ ]
+ ],
+ "layout": {
+ "text-size": {"base": 1, "stops": [[11, 10], [20, 14]]},
+ "text-max-angle": 30,
+ "symbol-spacing": 250,
+ "text-font": [
+ "DIN Offc Pro Regular",
+ "Arial Unicode MS Regular"
+ ],
+ "symbol-placement": "line",
+ "text-padding": 1,
+ "text-rotation-alignment": "map",
+ "text-pitch-alignment": "viewport",
+ "text-field": "{name_en}",
+ "text-letter-spacing": 0.01
+ },
+ "paint": {
+ "text-color": "hsl(0, 0%, 0%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 1
+ }
+ },
+ {
+ "id": "road-label-large",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444933721429.3076"},
+ "source": "composite",
+ "source-layer": "road_label",
+ "filter": [
+ "in",
+ "class",
+ "motorway",
+ "primary",
+ "secondary",
+ "tertiary",
+ "trunk"
+ ],
+ "layout": {
+ "text-size": {"base": 1, "stops": [[9, 10], [20, 16]]},
+ "text-max-angle": 30,
+ "symbol-spacing": 250,
+ "text-font": [
+ "DIN Offc Pro Regular",
+ "Arial Unicode MS Regular"
+ ],
+ "symbol-placement": "line",
+ "text-padding": 1,
+ "text-rotation-alignment": "map",
+ "text-pitch-alignment": "viewport",
+ "text-field": "{name_en}",
+ "text-letter-spacing": 0.01
+ },
+ "paint": {
+ "text-color": "hsl(0, 0%, 0%)",
+ "text-halo-color": "hsla(0, 0%, 100%, 0.75)",
+ "text-halo-width": 1,
+ "text-halo-blur": 1
+ }
+ },
+ {
+ "id": "road-shields-black",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444933575858.6992"},
+ "source": "composite",
+ "source-layer": "road_label",
+ "filter": [
+ "all",
+ [
+ "!in",
+ "shield",
+ "at-expressway",
+ "at-motorway",
+ "at-state-b",
+ "bg-motorway",
+ "bg-national",
+ "ch-main",
+ "ch-motorway",
+ "cz-motorway",
+ "cz-road",
+ "de-motorway",
+ "e-road",
+ "fi-main",
+ "gr-motorway",
+ "gr-national",
+ "hr-motorway",
+ "hr-state",
+ "hu-main",
+ "hu-motorway",
+ "nz-state",
+ "pl-expressway",
+ "pl-motorway",
+ "pl-national",
+ "ro-county",
+ "ro-motorway",
+ "ro-national",
+ "rs-motorway",
+ "rs-state-1b",
+ "se-main",
+ "si-expressway",
+ "si-motorway",
+ "sk-highway",
+ "sk-road",
+ "us-interstate",
+ "us-interstate-business",
+ "us-interstate-duplex",
+ "us-interstate-truck",
+ "za-metropolitan",
+ "za-national",
+ "za-provincial",
+ "za-regional"
+ ],
+ ["<=", "reflen", 6]
+ ],
+ "layout": {
+ "text-size": 9,
+ "icon-image": "{shield}-{reflen}",
+ "icon-rotation-alignment": "viewport",
+ "text-max-angle": 38,
+ "symbol-spacing": {"base": 1, "stops": [[11, 150], [14, 200]]},
+ "text-font": ["DIN Offc Pro Bold", "Arial Unicode MS Bold"],
+ "symbol-placement": {
+ "base": 1,
+ "stops": [[10, "point"], [11, "line"]]
+ },
+ "text-padding": 2,
+ "text-rotation-alignment": "viewport",
+ "text-field": "{ref}",
+ "text-letter-spacing": 0.05,
+ "icon-padding": 2
+ },
+ "paint": {
+ "text-color": "hsl(0, 0%, 7%)",
+ "icon-halo-color": "rgba(0, 0, 0, 1)",
+ "icon-halo-width": 1,
+ "text-opacity": 1,
+ "icon-color": "white",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 0
+ }
+ },
+ {
+ "id": "road-shields-white",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444933575858.6992"},
+ "source": "composite",
+ "source-layer": "road_label",
+ "filter": [
+ "all",
+ ["<=", "reflen", 6],
+ [
+ "in",
+ "shield",
+ "at-expressway",
+ "at-motorway",
+ "at-state-b",
+ "bg-motorway",
+ "bg-national",
+ "ch-main",
+ "ch-motorway",
+ "cz-motorway",
+ "cz-road",
+ "de-motorway",
+ "e-road",
+ "fi-main",
+ "gr-motorway",
+ "gr-national",
+ "hr-motorway",
+ "hr-state",
+ "hu-main",
+ "hu-motorway",
+ "nz-state",
+ "pl-expressway",
+ "pl-motorway",
+ "pl-national",
+ "ro-county",
+ "ro-motorway",
+ "ro-national",
+ "rs-motorway",
+ "rs-state-1b",
+ "se-main",
+ "si-expressway",
+ "si-motorway",
+ "sk-highway",
+ "sk-road",
+ "us-interstate",
+ "us-interstate-business",
+ "us-interstate-duplex",
+ "us-interstate-truck",
+ "za-metropolitan",
+ "za-national",
+ "za-provincial",
+ "za-regional"
+ ]
+ ],
+ "layout": {
+ "text-size": 9,
+ "icon-image": "{shield}-{reflen}",
+ "icon-rotation-alignment": "viewport",
+ "text-max-angle": 38,
+ "symbol-spacing": {"base": 1, "stops": [[11, 150], [14, 200]]},
+ "text-font": ["DIN Offc Pro Bold", "Arial Unicode MS Bold"],
+ "symbol-placement": {
+ "base": 1,
+ "stops": [[10, "point"], [11, "line"]]
+ },
+ "text-padding": 2,
+ "text-rotation-alignment": "viewport",
+ "text-field": "{ref}",
+ "text-letter-spacing": 0.05,
+ "icon-padding": 2
+ },
+ "paint": {
+ "text-color": "hsl(0, 0%, 100%)",
+ "icon-halo-color": "rgba(0, 0, 0, 1)",
+ "icon-halo-width": 1,
+ "text-opacity": 1,
+ "icon-color": "white",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 0
+ }
+ },
+ {
+ "id": "motorway-junction",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444933575858.6992"},
+ "source": "composite",
+ "source-layer": "motorway_junction",
+ "minzoom": 14,
+ "filter": ["all", ["<=", "reflen", 9], [">", "reflen", 0]],
+ "layout": {
+ "text-field": "{ref}",
+ "text-size": 9,
+ "icon-image": "motorway-exit-{reflen}",
+ "text-font": ["DIN Offc Pro Bold", "Arial Unicode MS Bold"]
+ },
+ "paint": {
+ "text-color": "hsl(0, 0%, 100%)",
+ "text-translate": [0, 0]
+ }
+ },
+ {
+ "id": "poi-scalerank2",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444933358918.2366"},
+ "source": "composite",
+ "source-layer": "poi_label",
+ "filter": [
+ "all",
+ [
+ "!in",
+ "maki",
+ "campsite",
+ "cemetery",
+ "dog-park",
+ "garden",
+ "golf",
+ "park",
+ "picnic-site",
+ "playground",
+ "zoo"
+ ],
+ ["==", "scalerank", 2]
+ ],
+ "layout": {
+ "text-line-height": 1.1,
+ "text-size": {"base": 1, "stops": [[14, 11], [20, 14]]},
+ "icon-image": {"stops": [[14, "{maki}-11"], [15, "{maki}-15"]]},
+ "text-max-angle": 38,
+ "symbol-spacing": 250,
+ "text-font": [
+ "DIN Offc Pro Medium",
+ "Arial Unicode MS Regular"
+ ],
+ "text-padding": 2,
+ "text-offset": [0, 0.65],
+ "text-rotation-alignment": "viewport",
+ "text-anchor": "top",
+ "text-field": "{name_en}",
+ "text-letter-spacing": 0.01,
+ "text-max-width": 8
+ },
+ "paint": {
+ "text-color": "hsl(26, 25%, 32%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 0.5,
+ "text-halo-blur": 0.5
+ }
+ },
+ {
+ "id": "poi-parks-scalerank2",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444933358918.2366"},
+ "source": "composite",
+ "source-layer": "poi_label",
+ "filter": [
+ "all",
+ ["==", "scalerank", 2],
+ [
+ "in",
+ "maki",
+ "campsite",
+ "cemetery",
+ "dog-park",
+ "garden",
+ "golf",
+ "park",
+ "picnic-site",
+ "playground",
+ "zoo"
+ ]
+ ],
+ "layout": {
+ "text-line-height": 1.1,
+ "text-size": {"base": 1, "stops": [[14, 11], [20, 14]]},
+ "icon-image": {"stops": [[14, "{maki}-11"], [15, "{maki}-15"]]},
+ "text-max-angle": 38,
+ "symbol-spacing": 250,
+ "text-font": [
+ "DIN Offc Pro Medium",
+ "Arial Unicode MS Regular"
+ ],
+ "text-padding": 2,
+ "text-offset": [0, 0.65],
+ "text-rotation-alignment": "viewport",
+ "text-anchor": "top",
+ "text-field": "{name_en}",
+ "text-letter-spacing": 0.01,
+ "text-max-width": 8
+ },
+ "paint": {
+ "text-color": "hsl(100, 100%, 20%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 0.5,
+ "text-halo-blur": 0.5
+ }
+ },
+ {
+ "id": "rail-label",
+ "type": "symbol",
+ "source": "composite",
+ "source-layer": "rail_station_label",
+ "minzoom": 12,
+ "filter": ["!=", "maki", "entrance"],
+ "layout": {
+ "text-line-height": 1.1,
+ "text-size": {"base": 1, "stops": [[16, 11], [20, 13]]},
+ "icon-image": "{network}",
+ "symbol-spacing": 250,
+ "text-font": [
+ "DIN Offc Pro Medium",
+ "Arial Unicode MS Regular"
+ ],
+ "text-offset": [0, 0.85],
+ "text-rotation-alignment": "viewport",
+ "text-anchor": "top",
+ "text-field": {
+ "base": 1,
+ "stops": [[0, ""], [13, "{name_en}"]]
+ },
+ "text-letter-spacing": 0.01,
+ "icon-padding": 0,
+ "text-max-width": 7
+ },
+ "paint": {
+ "text-color": "hsl(230, 48%, 44%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 0.5,
+ "icon-halo-width": 4,
+ "icon-halo-color": "#fff",
+ "text-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]},
+ "text-halo-blur": 0.5
+ }
+ },
+ {
+ "id": "water-label-sm",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444933808272.805"},
+ "source": "composite",
+ "source-layer": "water_label",
+ "minzoom": 15,
+ "filter": ["<=", "area", 10000],
+ "layout": {
+ "text-field": "{name_en}",
+ "text-font": [
+ "DIN Offc Pro Italic",
+ "Arial Unicode MS Regular"
+ ],
+ "text-max-width": 7,
+ "text-size": {"base": 1, "stops": [[16, 13], [20, 16]]}
+ },
+ "paint": {"text-color": "hsl(230, 48%, 44%)"}
+ },
+ {
+ "id": "water-label",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444933808272.805"},
+ "source": "composite",
+ "source-layer": "water_label",
+ "minzoom": 5,
+ "filter": [">", "area", 10000],
+ "layout": {
+ "text-field": "{name_en}",
+ "text-font": [
+ "DIN Offc Pro Italic",
+ "Arial Unicode MS Regular"
+ ],
+ "text-max-width": 7,
+ "text-size": {"base": 1, "stops": [[13, 13], [18, 18]]}
+ },
+ "paint": {"text-color": "hsl(230, 48%, 44%)"}
+ },
+ {
+ "id": "place-residential",
+ "type": "symbol",
+ "source": "composite",
+ "source-layer": "place_label",
+ "maxzoom": 18,
+ "filter": [
+ "all",
+ ["all", ["<=", "localrank", 10], ["==", "type", "residential"]],
+ ["in", "$type", "LineString", "Point", "Polygon"]
+ ],
+ "layout": {
+ "text-line-height": 1.2,
+ "text-size": {"base": 1, "stops": [[10, 11], [18, 14]]},
+ "text-max-angle": 38,
+ "symbol-spacing": 250,
+ "text-font": [
+ "DIN Offc Pro Regular",
+ "Arial Unicode MS Regular"
+ ],
+ "text-padding": 2,
+ "text-offset": [0, 0],
+ "text-rotation-alignment": "viewport",
+ "text-field": "{name_en}",
+ "text-max-width": 7
+ },
+ "paint": {
+ "text-color": "hsl(26, 25%, 32%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 1,
+ "text-halo-blur": 0.5
+ }
+ },
+ {
+ "id": "poi-parks-scalerank1",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444933322393.2852"},
+ "source": "composite",
+ "source-layer": "poi_label",
+ "filter": [
+ "all",
+ ["<=", "scalerank", 1],
+ [
+ "in",
+ "maki",
+ "campsite",
+ "cemetery",
+ "dog-park",
+ "garden",
+ "golf",
+ "park",
+ "picnic-site",
+ "playground",
+ "zoo"
+ ]
+ ],
+ "layout": {
+ "text-line-height": 1.1,
+ "text-size": {"base": 1, "stops": [[10, 11], [18, 14]]},
+ "icon-image": {"stops": [[13, "{maki}-11"], [14, "{maki}-15"]]},
+ "text-max-angle": 38,
+ "symbol-spacing": 250,
+ "text-font": [
+ "DIN Offc Pro Medium",
+ "Arial Unicode MS Regular"
+ ],
+ "text-padding": 2,
+ "text-offset": [0, 0.65],
+ "text-rotation-alignment": "viewport",
+ "text-anchor": "top",
+ "text-field": "{name_en}",
+ "text-letter-spacing": 0.01,
+ "text-max-width": 8
+ },
+ "paint": {
+ "text-color": "hsl(100, 100%, 20%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 0.5,
+ "text-halo-blur": 0.5
+ }
+ },
+ {
+ "id": "poi-scalerank1",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444933322393.2852"},
+ "source": "composite",
+ "source-layer": "poi_label",
+ "filter": [
+ "all",
+ [
+ "!in",
+ "maki",
+ "campsite",
+ "cemetery",
+ "dog-park",
+ "garden",
+ "golf",
+ "park",
+ "picnic-site",
+ "playground",
+ "zoo"
+ ],
+ ["<=", "scalerank", 1]
+ ],
+ "layout": {
+ "text-line-height": 1.1,
+ "text-size": {"base": 1, "stops": [[10, 11], [18, 14]]},
+ "icon-image": {"stops": [[13, "{maki}-11"], [14, "{maki}-15"]]},
+ "text-max-angle": 38,
+ "symbol-spacing": 250,
+ "text-font": [
+ "DIN Offc Pro Medium",
+ "Arial Unicode MS Regular"
+ ],
+ "text-padding": 2,
+ "text-offset": [0, 0.65],
+ "text-rotation-alignment": "viewport",
+ "text-anchor": "top",
+ "text-field": "{name_en}",
+ "text-letter-spacing": 0.01,
+ "text-max-width": 8
+ },
+ "paint": {
+ "text-color": "hsl(26, 25%, 32%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 0.5,
+ "text-halo-blur": 0.5
+ }
+ },
+ {
+ "id": "airport-label",
+ "type": "symbol",
+ "source": "composite",
+ "source-layer": "airport_label",
+ "minzoom": 9,
+ "filter": ["<=", "scalerank", 2],
+ "layout": {
+ "text-line-height": 1.1,
+ "text-size": {"base": 1, "stops": [[10, 12], [18, 18]]},
+ "icon-image": {"stops": [[12, "{maki}-11"], [13, "{maki}-15"]]},
+ "symbol-spacing": 250,
+ "text-font": [
+ "DIN Offc Pro Medium",
+ "Arial Unicode MS Regular"
+ ],
+ "text-padding": 2,
+ "text-offset": [0, 0.75],
+ "text-rotation-alignment": "viewport",
+ "text-anchor": "top",
+ "text-field": {"stops": [[11, "{ref}"], [12, "{name_en}"]]},
+ "text-letter-spacing": 0.01,
+ "text-max-width": 9
+ },
+ "paint": {
+ "text-color": "hsl(230, 48%, 44%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 0.5,
+ "text-halo-blur": 0.5
+ }
+ },
+ {
+ "id": "place-islet-archipelago-aboriginal",
+ "type": "symbol",
+ "source": "composite",
+ "source-layer": "place_label",
+ "maxzoom": 16,
+ "filter": [
+ "in",
+ "type",
+ "aboriginal_lands",
+ "archipelago",
+ "islet"
+ ],
+ "layout": {
+ "text-line-height": 1.2,
+ "text-size": {"base": 1, "stops": [[10, 11], [18, 16]]},
+ "text-max-angle": 38,
+ "symbol-spacing": 250,
+ "text-font": [
+ "DIN Offc Pro Regular",
+ "Arial Unicode MS Regular"
+ ],
+ "text-padding": 2,
+ "text-offset": [0, 0],
+ "text-rotation-alignment": "viewport",
+ "text-field": "{name_en}",
+ "text-letter-spacing": 0.01,
+ "text-max-width": 8
+ },
+ "paint": {
+ "text-color": "hsl(230, 29%, 35%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 1
+ }
+ },
+ {
+ "id": "place-neighbourhood",
+ "type": "symbol",
+ "source": "composite",
+ "source-layer": "place_label",
+ "minzoom": 10,
+ "maxzoom": 16,
+ "filter": ["==", "type", "neighbourhood"],
+ "layout": {
+ "text-field": "{name_en}",
+ "text-transform": "uppercase",
+ "text-letter-spacing": 0.1,
+ "text-max-width": 7,
+ "text-font": [
+ "DIN Offc Pro Regular",
+ "Arial Unicode MS Regular"
+ ],
+ "text-padding": 3,
+ "text-size": {"base": 1, "stops": [[12, 11], [16, 16]]}
+ },
+ "paint": {
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 1,
+ "text-color": "hsl(230, 29%, 35%)",
+ "text-halo-blur": 0.5
+ }
+ },
+ {
+ "id": "place-suburb",
+ "type": "symbol",
+ "source": "composite",
+ "source-layer": "place_label",
+ "minzoom": 10,
+ "maxzoom": 16,
+ "filter": ["==", "type", "suburb"],
+ "layout": {
+ "text-field": "{name_en}",
+ "text-transform": "uppercase",
+ "text-font": [
+ "DIN Offc Pro Regular",
+ "Arial Unicode MS Regular"
+ ],
+ "text-letter-spacing": 0.15,
+ "text-max-width": 7,
+ "text-padding": 3,
+ "text-size": {"base": 1, "stops": [[11, 11], [15, 18]]}
+ },
+ "paint": {
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 1,
+ "text-color": "hsl(230, 29%, 35%)",
+ "text-halo-blur": 0.5
+ }
+ },
+ {
+ "id": "place-hamlet",
+ "type": "symbol",
+ "source": "composite",
+ "source-layer": "place_label",
+ "minzoom": 10,
+ "maxzoom": 16,
+ "filter": ["==", "type", "hamlet"],
+ "layout": {
+ "text-field": "{name_en}",
+ "text-font": [
+ "DIN Offc Pro Regular",
+ "Arial Unicode MS Regular"
+ ],
+ "text-size": {"base": 1, "stops": [[12, 11.5], [15, 16]]}
+ },
+ "paint": {
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 1.25,
+ "text-color": "hsl(0, 0%, 0%)"
+ }
+ },
+ {
+ "id": "place-village",
+ "type": "symbol",
+ "source": "composite",
+ "source-layer": "place_label",
+ "minzoom": 8,
+ "maxzoom": 15,
+ "filter": ["==", "type", "village"],
+ "layout": {
+ "text-field": "{name_en}",
+ "text-font": [
+ "DIN Offc Pro Regular",
+ "Arial Unicode MS Regular"
+ ],
+ "text-max-width": 7,
+ "text-size": {"base": 1, "stops": [[10, 11.5], [16, 18]]}
+ },
+ "paint": {
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 1.25,
+ "text-color": "hsl(0, 0%, 0%)"
+ }
+ },
+ {
+ "id": "place-town",
+ "type": "symbol",
+ "source": "composite",
+ "source-layer": "place_label",
+ "minzoom": 6,
+ "maxzoom": 15,
+ "filter": ["==", "type", "town"],
+ "layout": {
+ "icon-image": "dot-9",
+ "text-font": {
+ "base": 1,
+ "stops": [
+ [
+ 11,
+ ["DIN Offc Pro Regular", "Arial Unicode MS Regular"]
+ ],
+ [
+ 12,
+ ["DIN Offc Pro Medium", "Arial Unicode MS Regular"]
+ ]
+ ]
+ },
+ "text-offset": {
+ "base": 1,
+ "stops": [[7, [0, -0.15]], [8, [0, 0]]]
+ },
+ "text-anchor": {
+ "base": 1,
+ "stops": [[7, "bottom"], [8, "center"]]
+ },
+ "text-field": "{name_en}",
+ "text-max-width": 7,
+ "text-size": {"base": 1, "stops": [[7, 11.5], [15, 20]]}
+ },
+ "paint": {
+ "text-color": "hsl(0, 0%, 0%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 1.25,
+ "icon-opacity": {"base": 1, "stops": [[7.99, 1], [8, 0]]}
+ }
+ },
+ {
+ "id": "place-island",
+ "type": "symbol",
+ "source": "composite",
+ "source-layer": "place_label",
+ "maxzoom": 16,
+ "filter": ["==", "type", "island"],
+ "layout": {
+ "text-line-height": 1.2,
+ "text-size": {"base": 1, "stops": [[10, 11], [18, 16]]},
+ "text-max-angle": 38,
+ "symbol-spacing": 250,
+ "text-font": [
+ "DIN Offc Pro Regular",
+ "Arial Unicode MS Regular"
+ ],
+ "text-padding": 2,
+ "text-offset": [0, 0],
+ "text-rotation-alignment": "viewport",
+ "text-field": "{name_en}",
+ "text-letter-spacing": 0.01,
+ "text-max-width": 7
+ },
+ "paint": {
+ "text-color": "hsl(230, 29%, 35%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 1
+ }
+ },
+ {
+ "id": "place-city-sm",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444862510685.128"},
+ "source": "composite",
+ "source-layer": "place_label",
+ "maxzoom": 14,
+ "filter": [
+ "all",
+ ["!in", "scalerank", 0, 1, 2, 3, 4, 5],
+ ["==", "type", "city"]
+ ],
+ "layout": {
+ "text-size": {"base": 1, "stops": [[6, 12], [14, 22]]},
+ "icon-image": "dot-9",
+ "text-font": {
+ "base": 1,
+ "stops": [
+ [
+ 7,
+ ["DIN Offc Pro Regular", "Arial Unicode MS Regular"]
+ ],
+ [8, ["DIN Offc Pro Medium", "Arial Unicode MS Regular"]]
+ ]
+ },
+ "text-offset": {
+ "base": 1,
+ "stops": [[7.99, [0, -0.2]], [8, [0, 0]]]
+ },
+ "text-anchor": {
+ "base": 1,
+ "stops": [[7, "bottom"], [8, "center"]]
+ },
+ "text-field": "{name_en}",
+ "text-max-width": 7
+ },
+ "paint": {
+ "text-color": "hsl(0, 0%, 0%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 1.25,
+ "icon-opacity": {"base": 1, "stops": [[7.99, 1], [8, 0]]}
+ }
+ },
+ {
+ "id": "place-city-md-s",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444862510685.128"},
+ "source": "composite",
+ "source-layer": "place_label",
+ "maxzoom": 14,
+ "filter": [
+ "all",
+ ["==", "type", "city"],
+ ["in", "ldir", "E", "S", "SE", "SW"],
+ ["in", "scalerank", 3, 4, 5]
+ ],
+ "layout": {
+ "text-field": "{name_en}",
+ "icon-image": "dot-10",
+ "text-anchor": {
+ "base": 1,
+ "stops": [[7, "top"], [8, "center"]]
+ },
+ "text-offset": {
+ "base": 1,
+ "stops": [[7.99, [0, 0.1]], [8, [0, 0]]]
+ },
+ "text-font": {
+ "base": 1,
+ "stops": [
+ [
+ 7,
+ ["DIN Offc Pro Regular", "Arial Unicode MS Regular"]
+ ],
+ [8, ["DIN Offc Pro Medium", "Arial Unicode MS Regular"]]
+ ]
+ },
+ "text-size": {"base": 0.9, "stops": [[5, 12], [12, 22]]}
+ },
+ "paint": {
+ "text-halo-width": 1,
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-color": "hsl(0, 0%, 0%)",
+ "text-halo-blur": 1,
+ "icon-opacity": {"base": 1, "stops": [[7.99, 1], [8, 0]]}
+ }
+ },
+ {
+ "id": "place-city-md-n",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444862510685.128"},
+ "source": "composite",
+ "source-layer": "place_label",
+ "maxzoom": 14,
+ "filter": [
+ "all",
+ ["==", "type", "city"],
+ ["in", "ldir", "N", "NE", "NW", "W"],
+ ["in", "scalerank", 3, 4, 5]
+ ],
+ "layout": {
+ "icon-image": "dot-10",
+ "text-font": {
+ "base": 1,
+ "stops": [
+ [
+ 7,
+ ["DIN Offc Pro Regular", "Arial Unicode MS Regular"]
+ ],
+ [8, ["DIN Offc Pro Medium", "Arial Unicode MS Regular"]]
+ ]
+ },
+ "text-offset": {
+ "base": 1,
+ "stops": [[7.99, [0, -0.25]], [8, [0, 0]]]
+ },
+ "text-anchor": {
+ "base": 1,
+ "stops": [[7, "bottom"], [8, "center"]]
+ },
+ "text-field": "{name_en}",
+ "text-max-width": 7,
+ "text-size": {"base": 0.9, "stops": [[5, 12], [12, 22]]}
+ },
+ "paint": {
+ "text-color": "hsl(0, 0%, 0%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 1,
+ "icon-opacity": {"base": 1, "stops": [[7.99, 1], [8, 0]]},
+ "text-halo-blur": 1
+ }
+ },
+ {
+ "id": "place-city-lg-s",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444862510685.128"},
+ "source": "composite",
+ "source-layer": "place_label",
+ "minzoom": 1,
+ "maxzoom": 14,
+ "filter": [
+ "all",
+ ["<=", "scalerank", 2],
+ ["==", "type", "city"],
+ ["in", "ldir", "E", "S", "SE", "SW"]
+ ],
+ "layout": {
+ "icon-image": "dot-11",
+ "text-font": {
+ "base": 1,
+ "stops": [
+ [
+ 7,
+ ["DIN Offc Pro Regular", "Arial Unicode MS Regular"]
+ ],
+ [8, ["DIN Offc Pro Medium", "Arial Unicode MS Regular"]]
+ ]
+ },
+ "text-offset": {
+ "base": 1,
+ "stops": [[7.99, [0, 0.15]], [8, [0, 0]]]
+ },
+ "text-anchor": {
+ "base": 1,
+ "stops": [[7, "top"], [8, "center"]]
+ },
+ "text-field": "{name_en}",
+ "text-max-width": 7,
+ "text-size": {"base": 0.9, "stops": [[4, 12], [10, 22]]}
+ },
+ "paint": {
+ "text-color": "hsl(0, 0%, 0%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 1,
+ "icon-opacity": {"base": 1, "stops": [[7.99, 1], [8, 0]]},
+ "text-halo-blur": 1
+ }
+ },
+ {
+ "id": "place-city-lg-n",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444862510685.128"},
+ "source": "composite",
+ "source-layer": "place_label",
+ "minzoom": 1,
+ "maxzoom": 14,
+ "filter": [
+ "all",
+ ["<=", "scalerank", 2],
+ ["==", "type", "city"],
+ ["in", "ldir", "N", "NE", "NW", "W"]
+ ],
+ "layout": {
+ "icon-image": "dot-11",
+ "text-font": {
+ "base": 1,
+ "stops": [
+ [
+ 7,
+ ["DIN Offc Pro Regular", "Arial Unicode MS Regular"]
+ ],
+ [8, ["DIN Offc Pro Medium", "Arial Unicode MS Regular"]]
+ ]
+ },
+ "text-offset": {
+ "base": 1,
+ "stops": [[7.99, [0, -0.25]], [8, [0, 0]]]
+ },
+ "text-anchor": {
+ "base": 1,
+ "stops": [[7, "bottom"], [8, "center"]]
+ },
+ "text-field": "{name_en}",
+ "text-max-width": 7,
+ "text-size": {"base": 0.9, "stops": [[4, 12], [10, 22]]}
+ },
+ "paint": {
+ "text-color": "hsl(0, 0%, 0%)",
+ "text-opacity": 1,
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 1,
+ "icon-opacity": {"base": 1, "stops": [[7.99, 1], [8, 0]]},
+ "text-halo-blur": 1
+ }
+ },
+ {
+ "id": "marine-label-sm-ln",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444856087950.3635"},
+ "source": "composite",
+ "source-layer": "marine_label",
+ "minzoom": 3,
+ "maxzoom": 10,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ [">=", "labelrank", 4]
+ ],
+ "layout": {
+ "text-line-height": 1.1,
+ "text-size": {"base": 1, "stops": [[3, 12], [6, 16]]},
+ "symbol-spacing": {"base": 1, "stops": [[4, 100], [6, 400]]},
+ "text-font": [
+ "DIN Offc Pro Italic",
+ "Arial Unicode MS Regular"
+ ],
+ "symbol-placement": "line",
+ "text-pitch-alignment": "viewport",
+ "text-field": "{name_en}",
+ "text-letter-spacing": 0.1,
+ "text-max-width": 5
+ },
+ "paint": {"text-color": "hsl(205, 83%, 88%)"}
+ },
+ {
+ "id": "marine-label-sm-pt",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444856087950.3635"},
+ "source": "composite",
+ "source-layer": "marine_label",
+ "minzoom": 3,
+ "maxzoom": 10,
+ "filter": ["all", ["==", "$type", "Point"], [">=", "labelrank", 4]],
+ "layout": {
+ "text-field": "{name_en}",
+ "text-max-width": 5,
+ "text-letter-spacing": 0.1,
+ "text-line-height": 1.5,
+ "text-font": [
+ "DIN Offc Pro Italic",
+ "Arial Unicode MS Regular"
+ ],
+ "text-size": {"base": 1, "stops": [[3, 12], [6, 16]]}
+ },
+ "paint": {"text-color": "hsl(205, 83%, 88%)"}
+ },
+ {
+ "id": "marine-label-md-ln",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444856087950.3635"},
+ "source": "composite",
+ "source-layer": "marine_label",
+ "minzoom": 2,
+ "maxzoom": 8,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ ["in", "labelrank", 2, 3]
+ ],
+ "layout": {
+ "text-line-height": 1.1,
+ "text-size": {"base": 1.1, "stops": [[2, 12], [5, 20]]},
+ "symbol-spacing": 250,
+ "text-font": [
+ "DIN Offc Pro Italic",
+ "Arial Unicode MS Regular"
+ ],
+ "symbol-placement": "line",
+ "text-pitch-alignment": "viewport",
+ "text-field": "{name_en}",
+ "text-letter-spacing": 0.15,
+ "text-max-width": 5
+ },
+ "paint": {"text-color": "hsl(205, 83%, 88%)"}
+ },
+ {
+ "id": "marine-label-md-pt",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444856087950.3635"},
+ "source": "composite",
+ "source-layer": "marine_label",
+ "minzoom": 2,
+ "maxzoom": 8,
+ "filter": [
+ "all",
+ ["==", "$type", "Point"],
+ ["in", "labelrank", 2, 3]
+ ],
+ "layout": {
+ "text-field": "{name_en}",
+ "text-max-width": 5,
+ "text-letter-spacing": 0.15,
+ "text-line-height": 1.5,
+ "text-font": [
+ "DIN Offc Pro Italic",
+ "Arial Unicode MS Regular"
+ ],
+ "text-size": {"base": 1.1, "stops": [[2, 14], [5, 20]]}
+ },
+ "paint": {"text-color": "hsl(205, 83%, 88%)"}
+ },
+ {
+ "id": "marine-label-lg-ln",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444856087950.3635"},
+ "source": "composite",
+ "source-layer": "marine_label",
+ "minzoom": 1,
+ "maxzoom": 4,
+ "filter": [
+ "all",
+ ["==", "$type", "LineString"],
+ ["==", "labelrank", 1]
+ ],
+ "layout": {
+ "text-field": "{name_en}",
+ "text-max-width": 4,
+ "text-letter-spacing": 0.25,
+ "text-line-height": 1.1,
+ "symbol-placement": "line",
+ "text-pitch-alignment": "viewport",
+ "text-font": [
+ "DIN Offc Pro Italic",
+ "Arial Unicode MS Regular"
+ ],
+ "text-size": {"base": 1, "stops": [[1, 14], [4, 30]]}
+ },
+ "paint": {"text-color": "hsl(205, 83%, 88%)"}
+ },
+ {
+ "id": "marine-label-lg-pt",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444856087950.3635"},
+ "source": "composite",
+ "source-layer": "marine_label",
+ "minzoom": 1,
+ "maxzoom": 4,
+ "filter": ["all", ["==", "$type", "Point"], ["==", "labelrank", 1]],
+ "layout": {
+ "text-field": "{name_en}",
+ "text-max-width": 4,
+ "text-letter-spacing": 0.25,
+ "text-line-height": 1.5,
+ "text-font": [
+ "DIN Offc Pro Italic",
+ "Arial Unicode MS Regular"
+ ],
+ "text-size": {"base": 1, "stops": [[1, 14], [4, 30]]}
+ },
+ "paint": {"text-color": "hsl(205, 83%, 88%)"}
+ },
+ {
+ "id": "state-label-sm",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444856151690.9143"},
+ "source": "composite",
+ "source-layer": "state_label",
+ "minzoom": 3,
+ "maxzoom": 9,
+ "filter": ["<", "area", 20000],
+ "layout": {
+ "text-size": {"base": 1, "stops": [[6, 10], [9, 14]]},
+ "text-transform": "uppercase",
+ "text-font": ["DIN Offc Pro Bold", "Arial Unicode MS Bold"],
+ "text-field": {
+ "base": 1,
+ "stops": [[0, "{abbr}"], [6, "{name_en}"]]
+ },
+ "text-letter-spacing": 0.15,
+ "text-max-width": 5
+ },
+ "paint": {
+ "text-opacity": 1,
+ "text-color": "hsl(0, 0%, 0%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 1
+ }
+ },
+ {
+ "id": "state-label-md",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444856151690.9143"},
+ "source": "composite",
+ "source-layer": "state_label",
+ "minzoom": 3,
+ "maxzoom": 8,
+ "filter": ["all", ["<", "area", 80000], [">=", "area", 20000]],
+ "layout": {
+ "text-size": {"base": 1, "stops": [[5, 10], [8, 16]]},
+ "text-transform": "uppercase",
+ "text-font": ["DIN Offc Pro Bold", "Arial Unicode MS Bold"],
+ "text-field": {
+ "base": 1,
+ "stops": [[0, "{abbr}"], [5, "{name_en}"]]
+ },
+ "text-letter-spacing": 0.15,
+ "text-max-width": 6
+ },
+ "paint": {
+ "text-opacity": 1,
+ "text-color": "hsl(0, 0%, 0%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 1
+ }
+ },
+ {
+ "id": "state-label-lg",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444856151690.9143"},
+ "source": "composite",
+ "source-layer": "state_label",
+ "minzoom": 3,
+ "maxzoom": 7,
+ "filter": [">=", "area", 80000],
+ "layout": {
+ "text-size": {"base": 1, "stops": [[4, 10], [7, 18]]},
+ "text-transform": "uppercase",
+ "text-font": ["DIN Offc Pro Bold", "Arial Unicode MS Bold"],
+ "text-padding": 1,
+ "text-field": {
+ "base": 1,
+ "stops": [[0, "{abbr}"], [4, "{name_en}"]]
+ },
+ "text-letter-spacing": 0.15,
+ "text-max-width": 6
+ },
+ "paint": {
+ "text-opacity": 1,
+ "text-color": "hsl(0, 0%, 0%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 1
+ }
+ },
+ {
+ "id": "country-label-sm",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444856144497.7825"},
+ "source": "composite",
+ "source-layer": "country_label",
+ "minzoom": 1,
+ "maxzoom": 10,
+ "filter": [">=", "scalerank", 5],
+ "layout": {
+ "text-field": "{name_en}",
+ "text-max-width": 6,
+ "text-font": [
+ "DIN Offc Pro Medium",
+ "Arial Unicode MS Regular"
+ ],
+ "text-size": {"base": 0.9, "stops": [[5, 14], [9, 22]]}
+ },
+ "paint": {
+ "text-color": "hsl(0, 0%, 0%)",
+ "text-halo-color": {
+ "base": 1,
+ "stops": [
+ [2, "rgba(255,255,255,0.75)"],
+ [3, "hsl(0, 0%, 100%)"]
+ ]
+ },
+ "text-halo-width": 1.25
+ }
+ },
+ {
+ "id": "country-label-md",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444856144497.7825"},
+ "source": "composite",
+ "source-layer": "country_label",
+ "minzoom": 1,
+ "maxzoom": 8,
+ "filter": ["in", "scalerank", 3, 4],
+ "layout": {
+ "text-field": {
+ "base": 1,
+ "stops": [[0, "{code}"], [2, "{name_en}"]]
+ },
+ "text-max-width": 6,
+ "text-font": [
+ "DIN Offc Pro Medium",
+ "Arial Unicode MS Regular"
+ ],
+ "text-size": {"base": 1, "stops": [[3, 10], [8, 24]]}
+ },
+ "paint": {
+ "text-color": "hsl(0, 0%, 0%)",
+ "text-halo-color": {
+ "base": 1,
+ "stops": [
+ [2, "rgba(255,255,255,0.75)"],
+ [3, "hsl(0, 0%, 100%)"]
+ ]
+ },
+ "text-halo-width": 1.25
+ }
+ },
+ {
+ "id": "country-label-lg",
+ "type": "symbol",
+ "metadata": {"mapbox:group": "1444856144497.7825"},
+ "source": "composite",
+ "source-layer": "country_label",
+ "minzoom": 1,
+ "maxzoom": 7,
+ "filter": ["in", "scalerank", 1, 2],
+ "layout": {
+ "text-field": "{name_en}",
+ "text-max-width": {"base": 1, "stops": [[0, 5], [3, 6]]},
+ "text-font": [
+ "DIN Offc Pro Medium",
+ "Arial Unicode MS Regular"
+ ],
+ "text-size": {"base": 1, "stops": [[1, 10], [6, 24]]}
+ },
+ "paint": {
+ "text-color": "hsl(0, 0%, 0%)",
+ "text-halo-color": {
+ "base": 1,
+ "stops": [
+ [2, "rgba(255,255,255,0.75)"],
+ [3, "hsl(0, 0%, 100%)"]
+ ]
+ },
+ "text-halo-width": 1.25
+ }
+ }
+ ],
+ "created": "2018-10-22T14:13:43.210Z",
+ "id": "cjnkdt02b0b2p2ss40skwpvs1",
+ "modified": "2018-10-22T14:14:35.211Z",
+ "owner": "lukaspaczos",
+ "visibility": "public",
+ "draft": false
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/InstrumentationApplication.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/InstrumentationApplication.kt
new file mode 100644
index 0000000000..ea48bdc00f
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/InstrumentationApplication.kt
@@ -0,0 +1,10 @@
+package com.mapbox.mapboxsdk
+
+import com.mapbox.mapboxsdk.testapp.MapboxApplication
+
+class InstrumentationApplication : MapboxApplication() {
+ override fun initializeLeakCanary(): Boolean {
+ // do not initialize leak canary during instrumentation tests
+ return true
+ }
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/InstrumentationRunner.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/InstrumentationRunner.kt
new file mode 100644
index 0000000000..6873b33262
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/InstrumentationRunner.kt
@@ -0,0 +1,11 @@
+package com.mapbox.mapboxsdk
+
+import android.app.Application
+import android.content.Context
+import android.support.test.runner.AndroidJUnitRunner
+
+class InstrumentationRunner : AndroidJUnitRunner() {
+ override fun newApplication(cl: ClassLoader?, className: String?, context: Context?): Application {
+ return super.newApplication(cl, InstrumentationApplication::class.java.name, context)
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/BaseIntegrationTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/BaseIntegrationTest.kt
new file mode 100644
index 0000000000..aeb8863790
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/BaseIntegrationTest.kt
@@ -0,0 +1,39 @@
+package com.mapbox.mapboxsdk.integration
+
+import android.content.Context
+import android.content.Intent
+import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
+import android.support.test.InstrumentationRegistry
+import android.support.test.uiautomator.*
+import org.junit.Before
+
+const val TIMEOUT_UI_SEARCH_WAIT = 5000L
+
+abstract class BaseIntegrationTest {
+
+ protected lateinit var device: UiDevice
+
+ @Before
+ open fun beforeTest() {
+ device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
+ }
+}
+
+/**
+ * Launches an activity with FLAG_ACTIVITY_NEW_TASK.
+ * <p>
+ * To resume an activity, you need to add a single instance launchmode to your manifest configuration.
+ * <p>
+ */
+fun UiDevice.launchActivity(context: Context, clazz: Class<*>) {
+ val applicationPackage = InstrumentationRegistry.getTargetContext().packageName
+ val intent = Intent(context, clazz)
+ intent.addFlags(FLAG_ACTIVITY_NEW_TASK)
+ InstrumentationRegistry.getContext().startActivity(intent)
+ wait(Until.hasObject(By.pkg(applicationPackage).depth(0)), TIMEOUT_UI_SEARCH_WAIT)
+}
+
+fun UiDevice.scrollRecyclerViewTo(recycleItem: String) {
+ val appView = UiScrollable(UiSelector().scrollable(true))
+ appView.scrollIntoView(UiSelector().text(recycleItem))
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/FragmentBackStackTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/FragmentBackStackTest.kt
new file mode 100644
index 0000000000..b0f6436bdd
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/FragmentBackStackTest.kt
@@ -0,0 +1,52 @@
+package com.mapbox.mapboxsdk.integration
+
+import android.support.test.filters.LargeTest
+import android.support.test.rule.ActivityTestRule
+import android.support.test.runner.AndroidJUnit4
+import android.support.test.uiautomator.By
+import android.support.test.uiautomator.SearchCondition
+import android.support.test.uiautomator.UiSelector
+import android.support.test.uiautomator.Until
+import com.mapbox.mapboxsdk.testapp.R
+import com.mapbox.mapboxsdk.testapp.activity.fragment.FragmentBackStackActivity
+import com.mapbox.mapboxsdk.testapp.activity.maplayout.SimpleMapActivity
+import kotlinx.android.synthetic.main.activity_backstack_fragment.view.*
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Regression test that validates MapFragment integration on the backstack
+ */
+@RunWith(AndroidJUnit4::class)
+class FragmentBackStackTest : BaseIntegrationTest() {
+
+ @get:Rule
+ var activityRule: ActivityTestRule<FragmentBackStackActivity> = ActivityTestRule(FragmentBackStackActivity::class.java)
+
+ @Test
+ @LargeTest
+ fun backPressedOnBackStackResumed() {
+ device.waitForIdle()
+ clickReplaceFragmentButton()
+ device.pressHome()
+ device.waitForIdle()
+ device.launchActivity(activityRule.activity.applicationContext, FragmentBackStackActivity::class.java)
+ backPressBackStack()
+ device.waitForIdle()
+ }
+
+ private fun clickReplaceFragmentButton() {
+ device.findObject(UiSelector().description(textDescription)).click()
+ }
+
+ private fun backPressBackStack() {
+ device.pressBack() // pops fragment, showing map
+ device.pressBack() // finish activity
+ }
+
+ private companion object {
+ const val textDescription = "btn_change_fragment"
+ }
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/GLSurfaceViewReopenTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/GLSurfaceViewReopenTest.kt
new file mode 100644
index 0000000000..f22b5f7c9d
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/GLSurfaceViewReopenTest.kt
@@ -0,0 +1,30 @@
+package com.mapbox.mapboxsdk.integration
+
+import android.support.test.filters.LargeTest
+import android.support.test.rule.ActivityTestRule
+import android.support.test.runner.AndroidJUnit4
+import com.mapbox.mapboxsdk.testapp.activity.maplayout.SimpleMapActivity
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+
+/**
+ * Regression test that validates reopening an Activity with a GLSurfaceView
+ */
+@RunWith(AndroidJUnit4::class)
+class GLSurfaceViewReopenTest : BaseIntegrationTest() {
+
+ @get:Rule
+ var activityRule: ActivityTestRule<SimpleMapActivity> = ActivityTestRule(SimpleMapActivity::class.java)
+
+ @Test
+ @LargeTest
+ fun reopenSimpleMapActivity() {
+ device.waitForIdle()
+ device.pressHome()
+ device.waitForIdle()
+ device.launchActivity(activityRule.activity, SimpleMapActivity::class.java)
+ device.waitForIdle()
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/GLSurfaceViewReuseTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/GLSurfaceViewReuseTest.kt
new file mode 100644
index 0000000000..945fac677e
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/GLSurfaceViewReuseTest.kt
@@ -0,0 +1,31 @@
+package com.mapbox.mapboxsdk.integration
+
+import android.support.test.filters.LargeTest
+import android.support.test.rule.ActivityTestRule
+import android.support.test.runner.AndroidJUnit4
+import com.mapbox.mapboxsdk.testapp.activity.maplayout.GLSurfaceRecyclerViewActivity
+import com.mapbox.mapboxsdk.testapp.activity.maplayout.SimpleMapActivity
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Regression test that validates if a GLSurfaceView surface can be recreated without crashing.
+ */
+@RunWith(AndroidJUnit4::class)
+class GLSurfaceViewReuseTest : BaseIntegrationTest() {
+
+ @get:Rule
+ var activityRule: ActivityTestRule<GLSurfaceRecyclerViewActivity> = ActivityTestRule(GLSurfaceRecyclerViewActivity::class.java)
+
+ @Test
+ @LargeTest
+ fun scrollRecyclerView() {
+ device.waitForIdle()
+ device.scrollRecyclerViewTo("Twenty-one")
+ device.waitForIdle()
+ device.scrollRecyclerViewTo("One")
+ device.waitForIdle()
+ }
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/OrientationChangeTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/OrientationChangeTest.kt
new file mode 100644
index 0000000000..941b7ea8dc
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/OrientationChangeTest.kt
@@ -0,0 +1,34 @@
+package com.mapbox.mapboxsdk.integration
+
+import android.support.test.filters.LargeTest
+import android.support.test.rule.ActivityTestRule
+import android.support.test.runner.AndroidJUnit4
+import com.mapbox.mapboxsdk.testapp.activity.maplayout.GLSurfaceRecyclerViewActivity
+import com.mapbox.mapboxsdk.testapp.activity.maplayout.SimpleMapActivity
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class OrientationChangeTest : BaseIntegrationTest() {
+
+ @get:Rule
+ var activityRule: ActivityTestRule<SimpleMapActivity> = ActivityTestRule(SimpleMapActivity::class.java)
+
+ @Test
+ @LargeTest
+ fun rotateSimpleMap() {
+ device.setOrientationLeft()
+ device.waitForIdle()
+ device.setOrientationNatural()
+ device.waitForIdle()
+ device.setOrientationRight()
+ device.waitForIdle()
+ device.setOrientationNatural()
+ device.setOrientationLeft()
+ device.setOrientationNatural()
+ device.setOrientationRight()
+ device.setOrientationNatural()
+ }
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/TextureViewReopenTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/TextureViewReopenTest.kt
new file mode 100644
index 0000000000..44da557904
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/TextureViewReopenTest.kt
@@ -0,0 +1,33 @@
+package com.mapbox.mapboxsdk.integration
+
+import android.support.test.filters.LargeTest
+import android.support.test.rule.ActivityTestRule
+import android.support.test.runner.AndroidJUnit4
+import com.mapbox.mapboxsdk.testapp.activity.maplayout.GLSurfaceRecyclerViewActivity
+import com.mapbox.mapboxsdk.testapp.activity.maplayout.SimpleMapActivity
+import com.mapbox.mapboxsdk.testapp.activity.textureview.TextureViewDebugModeActivity
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import java.lang.Thread.sleep
+
+/**
+ * Regression test that validates reopening an Activity with a TextureView
+ */
+@RunWith(AndroidJUnit4::class)
+class TextureViewReopenTest : BaseIntegrationTest() {
+
+ @get:Rule
+ var activityRule: ActivityTestRule<TextureViewDebugModeActivity> = ActivityTestRule(TextureViewDebugModeActivity::class.java)
+
+ @Test
+ @LargeTest
+ fun reopenTextureViewDebugActivity() {
+ device.waitForIdle()
+ device.pressHome()
+ device.waitForIdle()
+ device.launchActivity(activityRule.activity, TextureViewDebugModeActivity::class.java)
+ device.waitForIdle()
+ }
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/TextureViewReuseTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/TextureViewReuseTest.kt
new file mode 100644
index 0000000000..5c3d66c462
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/TextureViewReuseTest.kt
@@ -0,0 +1,31 @@
+package com.mapbox.mapboxsdk.integration
+
+import android.support.test.filters.LargeTest
+import android.support.test.rule.ActivityTestRule
+import android.support.test.runner.AndroidJUnit4
+import com.mapbox.mapboxsdk.testapp.activity.maplayout.GLSurfaceRecyclerViewActivity
+import com.mapbox.mapboxsdk.testapp.activity.maplayout.TextureRecyclerViewActivity
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Regression test that validates if a GLSurfaceView surface can be recreated without crashing.
+ */
+@RunWith(AndroidJUnit4::class)
+class TextureViewReuseTest : BaseIntegrationTest() {
+
+ @get:Rule
+ var activityRule: ActivityTestRule<TextureRecyclerViewActivity> = ActivityTestRule(TextureRecyclerViewActivity::class.java)
+
+ @Test
+ @LargeTest
+ fun scrollRecyclerView() {
+ device.waitForIdle()
+ device.scrollRecyclerViewTo("Twenty-one")
+ device.waitForIdle()
+ device.scrollRecyclerViewTo("One")
+ device.waitForIdle()
+ }
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/ViewPagerScrollTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/ViewPagerScrollTest.kt
new file mode 100644
index 0000000000..b918801296
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/ViewPagerScrollTest.kt
@@ -0,0 +1,38 @@
+package com.mapbox.mapboxsdk.integration
+
+import android.support.test.filters.LargeTest
+import android.support.test.rule.ActivityTestRule
+import android.support.test.runner.AndroidJUnit4
+import android.support.test.uiautomator.UiSelector
+import com.mapbox.mapboxsdk.testapp.activity.fragment.ViewPagerActivity
+import com.mapbox.mapboxsdk.testapp.activity.maplayout.GLSurfaceRecyclerViewActivity
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Regression test that validates MapFragment integration with a ViewPager
+ */
+@RunWith(AndroidJUnit4::class)
+class ViewPagerScrollTest : BaseIntegrationTest() {
+
+ @get:Rule
+ var activityRule: ActivityTestRule<ViewPagerActivity> = ActivityTestRule(ViewPagerActivity::class.java)
+
+ @Test
+ @LargeTest
+ fun scrollViewPager() {
+ for (i in 1..4) {
+ clickTab(i)
+ }
+
+ for (i in 3 downTo 0) {
+ clickTab(i)
+ }
+ }
+
+ private fun clickTab(index: Int) {
+ device.findObject(UiSelector().text("Page $index")).click()
+ }
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt
index dde03d8a14..f9827c767e 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt
@@ -82,7 +82,7 @@ class LocationComponentTest : EspressoTest() {
val locationEngine = component.locationEngine
assertThat(locationEngine, notNullValue())
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
}
}
@@ -118,7 +118,7 @@ class LocationComponentTest : EspressoTest() {
assertThat(locationEngine, notNullValue())
assertThat(componentOptions, notNullValue())
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
assertThat(componentOptions?.accuracyAlpha(), `is`(.5f))
assertThat(componentOptions?.accuracyColor(), `is`(Color.BLUE))
}
@@ -157,7 +157,7 @@ class LocationComponentTest : EspressoTest() {
assertThat(locationEngine, nullValue())
assertThat(componentOptions, notNullValue())
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
assertThat(componentOptions?.accuracyAlpha(), `is`(.5f))
assertThat(componentOptions?.accuracyColor(), `is`(Color.BLUE))
}
@@ -205,7 +205,7 @@ class LocationComponentTest : EspressoTest() {
// Force the first location update
component.forceLocationUpdate(location)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
// Check if the puck is visible
assertThat(mapboxMap.queryRenderedFeatures(location, FOREGROUND_LAYER).isEmpty(), `is`(false))
@@ -240,7 +240,7 @@ class LocationComponentTest : EspressoTest() {
component.isLocationComponentEnabled = true
component.forceLocationUpdate(location)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
uiController.loopMainThreadForAtLeast(300) // waiting for stale state
mapboxMap.querySourceFeatures(LOCATION_SOURCE).also { feature ->
@@ -287,7 +287,7 @@ class LocationComponentTest : EspressoTest() {
}
component.forceLocationUpdate(location)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
val feature = mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0]
assertThat(mapboxMap.queryRenderedFeatures(location, FOREGROUND_LAYER).isEmpty(), `is`(false))
@@ -329,7 +329,7 @@ class LocationComponentTest : EspressoTest() {
mapboxMap.addImageFromDrawable("custom-foreground-bitmap", it)
mapboxMap.addImageFromDrawable("custom-gps-bitmap", it)
}
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
val foregroundId = mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getStringProperty(PROPERTY_FOREGROUND_ICON)
assertThat(foregroundId, `is`(equalTo("custom-gps-bitmap")))
@@ -360,13 +360,13 @@ class LocationComponentTest : EspressoTest() {
component.renderMode = RenderMode.GPS
component.forceLocationUpdate(location)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
val foregroundId = mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getStringProperty(PROPERTY_FOREGROUND_ICON)
assertThat(foregroundId, `is`(equalTo("custom-gps-bitmap")))
component.applyStyle(LocationComponentOptions.builder(context).build())
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
assertEquals(FOREGROUND_ICON, mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getStringProperty(PROPERTY_FOREGROUND_ICON))
}
@@ -395,13 +395,13 @@ class LocationComponentTest : EspressoTest() {
component.renderMode = RenderMode.GPS
component.forceLocationUpdate(location)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
val foregroundId = mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getStringProperty(PROPERTY_FOREGROUND_ICON)
assertThat(foregroundId, `is`(equalTo("custom-gps-bitmap")))
component.renderMode = RenderMode.NORMAL
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
assertEquals(FOREGROUND_ICON, mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getStringProperty(PROPERTY_FOREGROUND_ICON))
}
@@ -430,14 +430,14 @@ class LocationComponentTest : EspressoTest() {
component.isLocationComponentEnabled = true
component.forceLocationUpdate(location)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
uiController.loopMainThreadForAtLeast(250) // engaging stale state
assertThat(mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getBooleanProperty(PROPERTY_LOCATION_STALE), `is`(true))
component.onStop()
component.onStart()
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
assertThat(mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getBooleanProperty(PROPERTY_LOCATION_STALE), `is`(true))
assertThat(mapboxMap.isLayerVisible(ACCURACY_LAYER), `is`(false))
@@ -461,13 +461,13 @@ class LocationComponentTest : EspressoTest() {
component.isLocationComponentEnabled = true
component.forceLocationUpdate(location)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
assertThat(mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getBooleanProperty(PROPERTY_LOCATION_STALE), `is`(false))
component.onStop()
component.onStart()
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
assertThat(mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getBooleanProperty(PROPERTY_LOCATION_STALE), `is`(false))
assertThat(mapboxMap.isLayerVisible(ACCURACY_LAYER), `is`(true))
@@ -499,7 +499,7 @@ class LocationComponentTest : EspressoTest() {
component.isLocationComponentEnabled = true
component.forceLocationUpdate(location)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
mapboxMap.querySourceFeatures(LOCATION_SOURCE).also { feature ->
feature.forEach {
@@ -526,7 +526,7 @@ class LocationComponentTest : EspressoTest() {
component.isLocationComponentEnabled = true
component.forceLocationUpdate(location)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
val point: Point = mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].geometry() as Point
assertThat(component.locationEngine, nullValue())
@@ -550,14 +550,14 @@ class LocationComponentTest : EspressoTest() {
.build())
component.isLocationComponentEnabled = true
component.forceLocationUpdate(location)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
val point: Point = mapboxMap.queryRenderedFeatures(location, FOREGROUND_LAYER)[0].geometry() as Point
assertEquals(point.latitude(), location.latitude, 0.1)
assertEquals(point.longitude(), location.longitude, 0.1)
component.isLocationComponentEnabled = false
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
assertThat(mapboxMap.queryRenderedFeatures(location, FOREGROUND_LAYER).isEmpty(), `is`(true))
}
}
@@ -580,7 +580,7 @@ class LocationComponentTest : EspressoTest() {
component.isLocationComponentEnabled = false
mapboxMap.setStyle(Style.Builder().fromUrl(Style.LIGHT))
component.isLocationComponentEnabled = true
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
assertThat(mapboxMap.isLayerVisible(FOREGROUND_LAYER), `is`(true))
}
@@ -675,7 +675,7 @@ class LocationComponentTest : EspressoTest() {
component.onStart()
mapboxMap.setStyle(Style.Builder().fromUrl(Style.DARK))
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
}
}
executeComponentTest(componentAction)
@@ -695,7 +695,7 @@ class LocationComponentTest : EspressoTest() {
mapboxMap.setStyle(Style.Builder().fromUrl(Style.DARK))
component.onStop()
component.onStart()
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
}
}
executeComponentTest(componentAction)
@@ -714,7 +714,7 @@ class LocationComponentTest : EspressoTest() {
component.isLocationComponentEnabled = true
component.onStop()
component.forceLocationUpdate(location)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
assertThat(mapboxMap.querySourceFeatures(LOCATION_SOURCE).isEmpty(), `is`(true))
}
@@ -736,7 +736,7 @@ class LocationComponentTest : EspressoTest() {
component.onStop()
component.forceLocationUpdate(location)
component.onStart()
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
val point: Point = mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].geometry() as Point
assertEquals(point.latitude(), location.latitude, 0.1)
@@ -760,9 +760,9 @@ class LocationComponentTest : EspressoTest() {
component.forceLocationUpdate(location)
mapboxMap.setStyle(Style.Builder().fromUrl(Style.LIGHT))
component.onStop()
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
component.onStart()
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
val point: Point = mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].geometry() as Point
assertEquals(point.latitude(), location.latitude, 0.1)
@@ -797,7 +797,7 @@ class LocationComponentTest : EspressoTest() {
component.applyStyle(options)
}
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
}
}
executeComponentTest(componentAction)
@@ -823,7 +823,7 @@ class LocationComponentTest : EspressoTest() {
component.forceLocationUpdate(location)
}
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
}
}
executeComponentTest(componentAction)
@@ -839,7 +839,7 @@ class LocationComponentTest : EspressoTest() {
override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap,
style: Style, uiController: UiController, context: Context) {
styleChangeIdlingResource.waitForStyle(mapboxMap, MAPBOX_HEAVY_STYLE)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
locationComponentActivationOptions = LocationComponentActivationOptions
.builder(context, mapboxMap.style!!)
@@ -878,13 +878,13 @@ class LocationComponentTest : EspressoTest() {
component.renderMode = RenderMode.GPS
location.bearing = 77f
component.forceLocationUpdate(location)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
uiController.loopMainThreadForAtLeast(MAX_ANIMATION_DURATION_MS)
assertEquals(77f, mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getNumberProperty(PROPERTY_GPS_BEARING).toFloat(), 0.1f)
location.bearing = 92f
component.forceLocationUpdate(location)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
uiController.loopMainThreadForAtLeast(MAX_ANIMATION_DURATION_MS) // Waiting for the animation to finish
assertEquals(92.0f, mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getNumberProperty(PROPERTY_GPS_BEARING).toFloat(), 0.1f)
}
@@ -906,7 +906,7 @@ class LocationComponentTest : EspressoTest() {
component.cameraMode = CameraMode.TRACKING_GPS
location.bearing = 77f
component.forceLocationUpdate(location)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
uiController.loopMainThreadForAtLeast(MAX_ANIMATION_DURATION_MS)
assertEquals(77.0, mapboxMap.cameraPosition.bearing, 0.1)
@@ -917,7 +917,7 @@ class LocationComponentTest : EspressoTest() {
location.latitude = 30.0
location.longitude = 35.0
component.forceLocationUpdate(location)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
uiController.loopMainThreadForAtLeast(MAX_ANIMATION_DURATION_MS) // Waiting for the animation to finish
assertEquals(92.0, mapboxMap.cameraPosition.bearing, 0.1)
@@ -945,7 +945,7 @@ class LocationComponentTest : EspressoTest() {
location.bearing = 77f
component.forceLocationUpdate(location)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
uiController.loopMainThreadForAtLeast(MAX_ANIMATION_DURATION_MS)
assertEquals(77.0, mapboxMap.cameraPosition.bearing, 0.1)
@@ -956,7 +956,7 @@ class LocationComponentTest : EspressoTest() {
location.latitude = 30.0
location.longitude = 35.0
component.forceLocationUpdate(location)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
uiController.loopMainThreadForAtLeast(MAX_ANIMATION_DURATION_MS)
assertEquals(92.0, mapboxMap.cameraPosition.bearing, 0.1)
@@ -985,7 +985,7 @@ class LocationComponentTest : EspressoTest() {
location.bearing = 77f
component.forceLocationUpdate(location)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
uiController.loopMainThreadForAtLeast(MAX_ANIMATION_DURATION_MS)
assertEquals(bearing, mapboxMap.cameraPosition.bearing, 0.1)
@@ -996,7 +996,7 @@ class LocationComponentTest : EspressoTest() {
location.latitude = 30.0
location.longitude = 35.0
component.forceLocationUpdate(location)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
uiController.loopMainThreadForAtLeast(MAX_ANIMATION_DURATION_MS)
assertEquals(bearing, mapboxMap.cameraPosition.bearing, 0.1)
@@ -1021,7 +1021,7 @@ class LocationComponentTest : EspressoTest() {
component.cameraMode = CameraMode.TRACKING
component.cameraMode = CameraMode.NONE
component.forceLocationUpdate(location)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
assertThat(mapboxMap.uiSettings.focalPoint, nullValue())
}
@@ -1044,7 +1044,7 @@ class LocationComponentTest : EspressoTest() {
val zoom = mapboxMap.cameraPosition.zoom
component.zoomWhileTracking(10.0)
uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_ZOOM_ANIM_DURATION)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
assertEquals(zoom, mapboxMap.cameraPosition.zoom, 0.1)
}
@@ -1066,7 +1066,7 @@ class LocationComponentTest : EspressoTest() {
component.cameraMode = CameraMode.TRACKING
component.zoomWhileTracking(10.0)
uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_ZOOM_ANIM_DURATION)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
assertEquals(10.0, mapboxMap.cameraPosition.zoom, 0.1)
}
@@ -1091,7 +1091,7 @@ class LocationComponentTest : EspressoTest() {
uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_ZOOM_ANIM_DURATION / 2)
component.cameraMode = CameraMode.NONE
uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_ZOOM_ANIM_DURATION / 2)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
assertEquals(15.0 / 2.0, mapboxMap.cameraPosition.zoom, 3.0)
}
@@ -1117,7 +1117,7 @@ class LocationComponentTest : EspressoTest() {
component.onStop()
component.zoomWhileTracking(10.0)
uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_ZOOM_ANIM_DURATION)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
assertEquals(zoom, mapboxMap.cameraPosition.zoom, 0.1)
}
@@ -1142,7 +1142,7 @@ class LocationComponentTest : EspressoTest() {
uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_ZOOM_ANIM_DURATION / 2)
component.cancelZoomWhileTrackingAnimation()
uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_ZOOM_ANIM_DURATION / 2)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
assertEquals(15.0 / 2.0, mapboxMap.cameraPosition.zoom, 3.0)
}
@@ -1165,7 +1165,7 @@ class LocationComponentTest : EspressoTest() {
val tilt = mapboxMap.cameraPosition.tilt
component.tiltWhileTracking(30.0)
uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_TILT_ANIM_DURATION)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
assertEquals(tilt, mapboxMap.cameraPosition.tilt, 0.1)
}
@@ -1187,7 +1187,7 @@ class LocationComponentTest : EspressoTest() {
component.cameraMode = CameraMode.TRACKING
component.tiltWhileTracking(30.0)
uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_TILT_ANIM_DURATION)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
assertEquals(30.0, mapboxMap.cameraPosition.tilt, 0.1)
}
@@ -1212,7 +1212,7 @@ class LocationComponentTest : EspressoTest() {
uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_TILT_ANIM_DURATION / 2)
component.cameraMode = CameraMode.NONE
uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_TILT_ANIM_DURATION / 2)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
assertEquals(30.0 / 2.0, mapboxMap.cameraPosition.tilt, 3.0)
}
@@ -1237,7 +1237,7 @@ class LocationComponentTest : EspressoTest() {
component.onStop()
component.tiltWhileTracking(30.0)
uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_TILT_ANIM_DURATION)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
assertEquals(tilt, mapboxMap.cameraPosition.tilt, 0.1)
}
@@ -1286,7 +1286,7 @@ class LocationComponentTest : EspressoTest() {
mapboxMap.moveCamera(CameraUpdateFactory.newLatLng(LatLng(51.0, 17.0)))
mapboxMap.moveCamera(CameraUpdateFactory.bearingTo(90.0))
component.isLocationComponentEnabled = true
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
uiController.loopMainThreadForAtLeast(MAX_ANIMATION_DURATION_MS)
assertEquals(location.bearing.toDouble(), mapboxMap.cameraPosition.bearing, 0.1)
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.kt
index 37b3e8b802..fb450de527 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.kt
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.kt
@@ -75,7 +75,7 @@ class LocationLayerControllerTest : EspressoTest() {
.build())
component.isLocationComponentEnabled = true
component.renderMode = RenderMode.NORMAL
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
assertThat(style.getSource(LOCATION_SOURCE), notNullValue())
}
@@ -99,7 +99,7 @@ class LocationLayerControllerTest : EspressoTest() {
component.isLocationComponentEnabled = true
component.renderMode = RenderMode.NORMAL
component.forceLocationUpdate(location)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
assertThat(mapboxMap.isLayerVisible(FOREGROUND_LAYER), `is`(true))
assertThat(mapboxMap.isLayerVisible(BACKGROUND_LAYER), `is`(true))
@@ -123,7 +123,7 @@ class LocationLayerControllerTest : EspressoTest() {
component.isLocationComponentEnabled = true
component.renderMode = RenderMode.COMPASS
component.forceLocationUpdate(location)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
assertThat(mapboxMap.isLayerVisible(FOREGROUND_LAYER), `is`(true))
assertThat(mapboxMap.isLayerVisible(BACKGROUND_LAYER), `is`(true))
@@ -147,7 +147,7 @@ class LocationLayerControllerTest : EspressoTest() {
component.isLocationComponentEnabled = true
component.renderMode = RenderMode.GPS
component.forceLocationUpdate(location)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
assertThat(mapboxMap.isLayerVisible(FOREGROUND_LAYER), `is`(true))
assertThat(mapboxMap.isLayerVisible(BACKGROUND_LAYER), `is`(true))
@@ -171,7 +171,7 @@ class LocationLayerControllerTest : EspressoTest() {
component.isLocationComponentEnabled = true
component.forceLocationUpdate(location)
component.isLocationComponentEnabled = false
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
component.renderMode = RenderMode.GPS
assertThat(mapboxMap.isLayerVisible(FOREGROUND_LAYER), `is`(false))
@@ -197,7 +197,7 @@ class LocationLayerControllerTest : EspressoTest() {
component.renderMode = RenderMode.NORMAL
component.forceLocationUpdate(location)
component.isLocationComponentEnabled = false
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
// Check that all layers visibilities are set to none
assertThat(mapboxMap.isLayerVisible(FOREGROUND_LAYER), `is`(false))
@@ -223,7 +223,7 @@ class LocationLayerControllerTest : EspressoTest() {
component.renderMode = RenderMode.NORMAL
component.forceLocationUpdate(location)
styleChangeIdlingResource.waitForStyle(mapboxMap, Style.LIGHT)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
assertThat(component.renderMode, `is`(equalTo(RenderMode.NORMAL)))
@@ -254,13 +254,13 @@ class LocationLayerControllerTest : EspressoTest() {
component.isLocationComponentEnabled = true
component.applyStyle(LocationComponentOptions.builder(context).staleStateTimeout(100).build())
component.forceLocationUpdate(location)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
uiController.loopMainThreadForAtLeast(150)
assertThat(mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getBooleanProperty(PROPERTY_LOCATION_STALE), `is`(true))
mapboxMap.setStyle(Style.Builder().fromUrl(Style.LIGHT))
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
assertThat(mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getBooleanProperty(PROPERTY_LOCATION_STALE), `is`(true))
}
@@ -279,9 +279,9 @@ class LocationLayerControllerTest : EspressoTest() {
.build())
component.isLocationComponentEnabled = true
component.forceLocationUpdate(location)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
component.isLocationComponentEnabled = false
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
assertThat(mapboxMap.queryRenderedFeatures(location, FOREGROUND_LAYER).isEmpty(), `is`(true))
val options =
@@ -291,7 +291,7 @@ class LocationLayerControllerTest : EspressoTest() {
.build()
component.applyStyle(options)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
assertThat(mapboxMap.queryRenderedFeatures(location, FOREGROUND_LAYER).isEmpty(), `is`(true))
}
}
@@ -338,7 +338,7 @@ class LocationLayerControllerTest : EspressoTest() {
show = !show
}
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
}
}
executeComponentTest(componentAction)
@@ -359,7 +359,7 @@ class LocationLayerControllerTest : EspressoTest() {
component.isLocationComponentEnabled = true
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(location), 16.0))
component.forceLocationUpdate(location)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
uiController.loopMainThreadForAtLeast(ACCURACY_RADIUS_ANIMATION_DURATION)
assertEquals(Utils.calculateZoomLevelRadius(mapboxMap, location) /*meters projected to radius on zoom 16*/,
@@ -386,7 +386,7 @@ class LocationLayerControllerTest : EspressoTest() {
val zoom = 16.0
mapboxMap.easeCamera(CameraUpdateFactory.newLatLngZoom(target, zoom), 300)
uiController.loopMainThreadForAtLeast(300)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
assertThat(Math.abs(zoom - mapboxMap.cameraPosition.zoom) < 0.1
@@ -418,7 +418,7 @@ class LocationLayerControllerTest : EspressoTest() {
val target = LatLng(location)
val zoom = 16.0
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(target, zoom))
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
assertThat(Math.abs(zoom - mapboxMap.cameraPosition.zoom) < 0.1
&& Math.abs(target.latitude - mapboxMap.cameraPosition.target.latitude) < 0.1
@@ -445,7 +445,7 @@ class LocationLayerControllerTest : EspressoTest() {
.build())
component.isLocationComponentEnabled = true
component.forceLocationUpdate(location)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
component.applyStyle(LocationComponentOptions.builder(context).layerBelow("road-label").build())
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/GLSurfaceViewReopenTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/GLSurfaceViewReopenTest.kt
deleted file mode 100644
index 98b251027f..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/GLSurfaceViewReopenTest.kt
+++ /dev/null
@@ -1,73 +0,0 @@
-package com.mapbox.mapboxsdk.maps
-
-import android.content.Intent
-import android.support.test.InstrumentationRegistry
-import android.support.test.filters.SdkSuppress
-import android.support.test.runner.AndroidJUnit4
-import android.support.test.uiautomator.*
-import org.hamcrest.CoreMatchers.notNullValue
-import org.hamcrest.MatcherAssert.assertThat
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import java.lang.Thread.sleep
-
-private const val BASIC_SAMPLE_PACKAGE = "com.mapbox.mapboxsdk.testapp"
-private const val LAUNCH_TIMEOUT = 5000L
-
-@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = 18)
-class GLSurfaceViewReopenTest {
-
- private lateinit var device: UiDevice
-
- @Before
- fun startSimpleMapActivityFromHomeScreen() {
- // Initialize UiDevice instance
- device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
-
- // Start from the home screen
- device.pressHome()
-
- // Wait for launcher
- val launcherPackage: String = device.launcherPackageName
- assertThat(launcherPackage, notNullValue())
- device.wait(Until.hasObject(By.pkg(launcherPackage).depth(0)), LAUNCH_TIMEOUT)
-
- // Launch the app
- val context = InstrumentationRegistry.getInstrumentation().context
- val intent = context.packageManager.getLaunchIntentForPackage(BASIC_SAMPLE_PACKAGE).apply {
- // Clear out any previous instances
- addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
- }
- context.startActivity(intent)
-
- // Wait for the app to appear
- device.wait(
- Until.hasObject(By.pkg(BASIC_SAMPLE_PACKAGE).depth(0)),
- LAUNCH_TIMEOUT
- )
-
- // open SimpleMapActivity
- device.findObject(UiSelector().text("Simple Map")).clickAndWaitForNewWindow()
-
- // wait for idle
- device.waitForIdle(LAUNCH_TIMEOUT)
- }
-
- @Test
- fun reopenSimpleMapActivity() {
- // return to home screen
- device.pressHome()
-
- // press recents apps button
- device.pressRecentApps()
-
- // click to reopen app
- device.findObject(UiSelector().description("Mapbox Android SDK TestApp")).click()
-
- // wait for idle
- device.waitForIdle(LAUNCH_TIMEOUT)
- sleep(LAUNCH_TIMEOUT)
- }
-} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxTest.java
index b56d267b81..c8737e2802 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxTest.java
@@ -1,5 +1,6 @@
package com.mapbox.mapboxsdk.maps;
+import android.support.test.annotation.UiThreadTest;
import android.support.test.runner.AndroidJUnit4;
import com.mapbox.mapboxsdk.Mapbox;
import org.junit.Test;
@@ -16,6 +17,7 @@ public class MapboxTest {
private static final String ACCESS_TOKEN_2 = "pk.0000000002";
@Test
+ @UiThreadTest
public void testConnected() {
assertTrue(Mapbox.isConnected());
@@ -31,6 +33,7 @@ public class MapboxTest {
}
@Test
+ @UiThreadTest
public void setAccessToken() {
String realToken = Mapbox.getAccessToken();
Mapbox.setAccessToken(ACCESS_TOKEN);
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/OrientationTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/OrientationTest.java
deleted file mode 100644
index 14a2c3bdbf..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/OrientationTest.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.mapbox.mapboxsdk.maps;
-
-import com.mapbox.mapboxsdk.testapp.activity.BaseTest;
-import com.mapbox.mapboxsdk.testapp.activity.camera.CameraAnimationTypeActivity;
-import org.junit.Test;
-
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.matcher.ViewMatchers.isRoot;
-import static com.mapbox.mapboxsdk.testapp.action.OrientationChangeAction.orientationLandscape;
-import static com.mapbox.mapboxsdk.testapp.action.OrientationChangeAction.orientationLandscapeReverse;
-import static com.mapbox.mapboxsdk.testapp.action.OrientationChangeAction.orientationPortrait;
-import static com.mapbox.mapboxsdk.testapp.action.OrientationChangeAction.orientationPortraitReverse;
-
-public class OrientationTest extends BaseTest {
-
- @Test
- public void testChangeDeviceOrientation() {
- onView(isRoot()).perform(orientationLandscape());
- waitAction(2200);
- onView(isRoot()).perform(orientationPortrait());
- waitAction(2500);
- onView(isRoot()).perform(orientationLandscapeReverse());
- waitAction(500);
- onView(isRoot()).perform(orientationPortraitReverse());
- waitAction(1250);
- onView(isRoot()).perform(orientationLandscape());
- waitAction(750);
- onView(isRoot()).perform(orientationPortrait());
- waitAction(950);
- onView(isRoot()).perform(orientationLandscapeReverse());
- onView(isRoot()).perform(orientationPortraitReverse());
- onView(isRoot()).perform(orientationLandscape());
- onView(isRoot()).perform(orientationPortrait());
- }
-
- @Override
- protected Class getActivityClass() {
- return CameraAnimationTypeActivity.class;
- }
-
-}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/TextureViewReopenTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/TextureViewReopenTest.kt
deleted file mode 100644
index cd139ccc40..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/TextureViewReopenTest.kt
+++ /dev/null
@@ -1,77 +0,0 @@
-package com.mapbox.mapboxsdk.maps
-
-import android.content.Intent
-import android.support.test.InstrumentationRegistry
-import android.support.test.filters.SdkSuppress
-import android.support.test.runner.AndroidJUnit4
-import android.support.test.uiautomator.*
-import org.hamcrest.CoreMatchers.notNullValue
-import org.hamcrest.MatcherAssert.assertThat
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import java.lang.Thread.sleep
-import android.support.test.uiautomator.UiSelector
-import android.support.test.uiautomator.UiScrollable
-
-private const val BASIC_SAMPLE_PACKAGE = "com.mapbox.mapboxsdk.testapp"
-private const val LAUNCH_TIMEOUT = 5000L
-
-@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = 18)
-class TextureViewReopenTest {
-
- private lateinit var device: UiDevice
-
- @Before
- fun startSimpleMapActivityFromHomeScreen() {
- // Initialize UiDevice instance
- device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
-
- // Start from the home screen
- device.pressHome()
-
- // Wait for launcher
- val launcherPackage: String = device.launcherPackageName
- assertThat(launcherPackage, notNullValue())
- device.wait(Until.hasObject(By.pkg(launcherPackage).depth(0)), LAUNCH_TIMEOUT)
-
- // Launch the app
- val context = InstrumentationRegistry.getInstrumentation().context
- val intent = context.packageManager.getLaunchIntentForPackage(BASIC_SAMPLE_PACKAGE).apply {
- // Clear out any previous instances
- addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
- }
- context.startActivity(intent)
-
- // Wait for the app to appear
- device.wait(
- Until.hasObject(By.pkg(BASIC_SAMPLE_PACKAGE).depth(0)),
- LAUNCH_TIMEOUT
- )
-
- // open TextureView debug activity
- val appView = UiScrollable(UiSelector().scrollable(true))
- appView.scrollIntoView(UiSelector().text("TextureView debug"))
- device.findObject(UiSelector().text("TextureView debug")).clickAndWaitForNewWindow()
-
- // wait for idle
- device.waitForIdle(LAUNCH_TIMEOUT)
- }
-
- @Test
- fun reopenTextureViewDebugActivity() {
- // return to home screen
- device.pressHome()
-
- // press recent apps button
- device.pressRecentApps()
-
- // click to reopen app
- device.findObject(UiSelector().description("Mapbox Android SDK TestApp")).click()
-
- // wait for idle
- device.waitForIdle(LAUNCH_TIMEOUT)
- sleep(LAUNCH_TIMEOUT)
- }
-} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/VisibleRegionTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/VisibleRegionTest.kt
index 4866812e67..139695461d 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/VisibleRegionTest.kt
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/VisibleRegionTest.kt
@@ -1,25 +1,27 @@
-package com.mapbox.mapboxsdk.testapp.maps
+package com.mapbox.mapboxsdk.maps
import android.graphics.PointF
import android.support.test.espresso.UiController
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.testapp.action.MapboxMapAction.invoke
-import com.mapbox.mapboxsdk.testapp.activity.EspressoTest
-import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity
+
+import com.mapbox.mapboxsdk.testapp.activity.BaseTest
+import com.mapbox.mapboxsdk.testapp.activity.espresso.PixelTestActivity
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
-class VisibleRegionTest : EspressoTest() {
+class VisibleRegionTest : BaseTest() {
- private lateinit var mapView: MapView
+ override fun getActivityClass(): Class<*> {
+ return PixelTestActivity::class.java
+ }
- override fun beforeTest() {
+ override
+ fun beforeTest() {
super.beforeTest()
- mapView = (rule.activity as EspressoTestActivity).mapView
+ mapView = (rule.activity as PixelTestActivity).mapView
}
@Test
@@ -263,9 +265,9 @@ class VisibleRegionTest : EspressoTest() {
@Test
fun paddedTopVisibleRegionOverDatelineTest() {
validateTestSetup()
- invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
+ invoke(mapboxMap) { ui: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0))
-
+ ui.loopMainThreadForAtLeast(5000)
val latLngs = listOf(
mapboxMap.getLatLngFromScreenCoords(0f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
@@ -299,7 +301,7 @@ class VisibleRegionTest : EspressoTest() {
mapboxMap.getLatLngFromScreenCoords(0f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f)
- .also { it.longitude += 360 },
+ .also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f)
.also { it.longitude += 360 },
mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat())
@@ -355,11 +357,11 @@ class VisibleRegionTest : EspressoTest() {
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 0.0), 8.0))
val d = Math.min(mapboxMap.width, mapboxMap.height) / 4;
val latLngs = listOf(
- mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f - d / 2f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f + d / 2f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f - d / 2f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f + d / 2f)
+ mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f),
+ mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f - d / 2f, mapView.height / 2f),
+ mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f + d / 2f, mapView.height / 2f),
+ mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f - d / 2f),
+ mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f + d / 2f)
)
@@ -371,29 +373,29 @@ class VisibleRegionTest : EspressoTest() {
}
}
- @Test
- fun visibleRotatedRegionOverDatelineTest() {
- validateTestSetup()
- invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
- mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0))
- val d = Math.min(mapboxMap.width, mapboxMap.height) / 4;
- val latLngs = listOf(
- mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f - d / 2f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f + d / 2f, mapView.height / 2f)
- .also { it.longitude += 360 },
- mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f - d / 2f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f + d / 2f)
- )
-
-
- for (bearing in 45 until 360 step 45) {
- mapboxMap.moveCamera(CameraUpdateFactory.bearingTo(bearing.toDouble()));
- val visibleRegion = mapboxMap.projection.visibleRegion
- assertTrue(latLngs.all { visibleRegion.latLngBounds.contains(it) })
- }
- }
+ @Test
+ fun visibleRotatedRegionOverDatelineTest() {
+ validateTestSetup()
+ invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap ->
+ mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0))
+ val d = Math.min(mapboxMap.width, mapboxMap.height) / 4;
+ val latLngs = listOf(
+ mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f),
+ mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f - d / 2f, mapView.height / 2f),
+ mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f + d / 2f, mapView.height / 2f)
+ .also { it.longitude += 360 },
+ mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f - d / 2f),
+ mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f + d / 2f)
+ )
+
+
+ for (bearing in 45 until 360 step 45) {
+ mapboxMap.moveCamera(CameraUpdateFactory.bearingTo(bearing.toDouble()));
+ val visibleRegion = mapboxMap.projection.visibleRegion
+ assertTrue(latLngs.all { visibleRegion.latLngBounds.contains(it) })
+ }
}
+ }
private fun MapboxMap.getLatLngFromScreenCoords(x: Float, y: Float): LatLng {
return this.projection.fromScreenLocation(PointF(x, y))
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/module/telemetry/PerformanceEventTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/module/telemetry/PerformanceEventTest.java
new file mode 100644
index 0000000000..6f256b4e56
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/module/telemetry/PerformanceEventTest.java
@@ -0,0 +1,188 @@
+package com.mapbox.mapboxsdk.module.telemetry;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.DisplayMetrics;
+import android.view.Display;
+import android.view.WindowManager;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import com.mapbox.mapboxsdk.Mapbox;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.UUID;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+@RunWith(AndroidJUnit4.class)
+public class PerformanceEventTest {
+
+ @Test
+ public void checksPerformanceEventWithMetaData() throws Exception {
+ PerformanceEvent event = obtainPerformanceEvent();
+ assertNotNull(event);
+
+ Parcel parcel = Parcel.obtain();
+
+ event.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+
+ PerformanceEvent newPerfEvent = PerformanceEvent.CREATOR.createFromParcel(parcel);
+ assertNotNull(newPerfEvent);
+
+ compare(event, newPerfEvent, "attributes", "style_id");
+ compare(event, newPerfEvent, "counters", "int_value");
+ compare(event, newPerfEvent, "counters", "long_value");
+ compare(event, newPerfEvent, "counters", "double_value");
+ assertEquals(getMetadata(event), getMetadata(newPerfEvent));
+ }
+
+ @Test
+ public void checksPerformanceEventOnlyRequiredData() throws Exception {
+ Bundle bundle = new Bundle();
+ bundle.putString("property ignored", "value will be ignored");
+ PerformanceEvent event = new PerformanceEvent(UUID.randomUUID().toString(), bundle);
+ assertNotNull(event);
+
+ Parcel parcel = Parcel.obtain();
+ event.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+
+ PerformanceEvent newPerfEvent = PerformanceEvent.CREATOR.createFromParcel(parcel);
+ assertNotNull(newPerfEvent);
+
+ assertEquals(getAttributes(event).size(), 0);
+ assertEquals(getCounters(event).size(), 0);
+ assertEquals(getAttributes(newPerfEvent).size(), 0);
+ assertEquals(getCounters(newPerfEvent).size(), 0);
+ assertEquals(getMetadata(event), getMetadata(newPerfEvent));
+ }
+
+
+ private PerformanceEvent obtainPerformanceEvent() {
+ String styleStr = "mapbox://styles/mapbox/streets-v11";
+ boolean testPerfEvent = true;
+ Double doubleValue = 40.5;
+ Long longValue = 40L;
+ Integer intValue = 40;
+
+ List<Attribute<String>> attributes = new ArrayList<>();
+ attributes.add(
+ new Attribute<>("style_id", styleStr));
+ attributes.add(
+ new Attribute<>("test_perf_event", String.valueOf(testPerfEvent)));
+
+ List<Attribute<? extends Number>> counters = new ArrayList();
+ counters.add(new Attribute<>("long_value", longValue));
+ counters.add(new Attribute<>("double_value", doubleValue));
+ counters.add(new Attribute<>("int_value", intValue));
+
+ Gson gson = new Gson();
+
+ Bundle bundle = new Bundle();
+ bundle.putString("attributes", gson.toJson(attributes));
+ bundle.putString("counters", gson.toJson(counters));
+
+ JsonObject metaData = new JsonObject();
+ metaData.addProperty("os", "android");
+ metaData.addProperty("manufacturer", Build.MANUFACTURER);
+ metaData.addProperty("brand", Build.BRAND);
+ metaData.addProperty("device", Build.MODEL);
+ metaData.addProperty("version", Build.VERSION.RELEASE);
+ metaData.addProperty("abi", Build.CPU_ABI);
+ metaData.addProperty("country", Locale.getDefault().getISO3Country());
+ metaData.addProperty("ram", getRam());
+ metaData.addProperty("screenSize", getWindowSize());
+ bundle.putString("metadata", metaData.toString());
+
+ return new PerformanceEvent(UUID.randomUUID().toString(), bundle);
+ }
+
+ private void compare(PerformanceEvent event1, PerformanceEvent event2, String listFieldName, String name)
+ throws NoSuchFieldException, IllegalAccessException {
+ Object value1 = getValue(event1, listFieldName, name);
+ Object value2 = getValue(event2, listFieldName, name);
+
+ if (value1 instanceof Double && value2 instanceof Double) {
+ assertEquals((Double)value1, (Double)value2, 0.00006);
+ } else {
+ assertEquals(value1, value2);
+ }
+ }
+
+ private Object getPrivateFieldValue(Object object, String fieldName)
+ throws NoSuchFieldException, IllegalAccessException {
+ Field field = object.getClass().getDeclaredField(fieldName);
+ field.setAccessible(true);
+ return field.get(object);
+ }
+
+ private Object getValue(PerformanceEvent event, String listFieldName, String name)
+ throws NoSuchFieldException, IllegalAccessException {
+ ArrayList list = (ArrayList)getPrivateFieldValue(event, listFieldName);
+ for (Object element : list) {
+ Object elementName = getPrivateFieldValue(element, "name");
+ if (elementName != null && elementName.equals((String)name)) {
+ return getPrivateFieldValue(element, "value");
+ }
+ }
+ return null;
+ }
+
+ private JsonObject getMetadata(PerformanceEvent event)
+ throws NoSuchFieldException, IllegalAccessException {
+ return (JsonObject)getPrivateFieldValue(event, "metadata");
+ }
+
+ private ArrayList getAttributes(PerformanceEvent event)
+ throws NoSuchFieldException, IllegalAccessException {
+ return (ArrayList)getPrivateFieldValue(event, "attributes");
+ }
+
+ private ArrayList getCounters(PerformanceEvent event)
+ throws NoSuchFieldException, IllegalAccessException {
+ return (ArrayList)getPrivateFieldValue(event, "counters");
+ }
+
+ private static String getRam() {
+ ActivityManager actManager =
+ (ActivityManager) Mapbox.getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
+ ActivityManager.MemoryInfo memInfo = new ActivityManager.MemoryInfo();
+ actManager.getMemoryInfo(memInfo);
+ return String.valueOf(memInfo.totalMem);
+ }
+
+ private static String getWindowSize() {
+ WindowManager windowManager =
+ (WindowManager) Mapbox.getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
+ Display display = windowManager.getDefaultDisplay();
+ DisplayMetrics metrics = new DisplayMetrics();
+ display.getMetrics(metrics);
+ int width = metrics.widthPixels;
+ int height = metrics.heightPixels;
+
+ return "{" + width + "," + height + "}";
+ }
+
+ private class Attribute<T> {
+ private String name;
+ private T value;
+
+ Attribute(String name, T value) {
+ this.name = name;
+ this.value = value;
+ }
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/OrientationChangeAction.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/OrientationAction.java
index 7f73d6a7f3..1bf5a87970 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/OrientationChangeAction.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/OrientationAction.java
@@ -1,6 +1,5 @@
package com.mapbox.mapboxsdk.testapp.action;
-
import android.app.Activity;
import android.content.Context;
import android.content.ContextWrapper;
@@ -11,30 +10,31 @@ import android.view.View;
import android.view.ViewGroup;
import org.hamcrest.Matcher;
+import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.matcher.ViewMatchers.isRoot;
-public class OrientationChangeAction implements ViewAction {
+public class OrientationAction implements ViewAction {
private final int orientation;
- private OrientationChangeAction(int orientation) {
+ private OrientationAction(int orientation) {
this.orientation = orientation;
}
public static ViewAction orientationLandscape() {
- return new OrientationChangeAction(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
+ return new OrientationAction(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
public static ViewAction orientationPortrait() {
- return new OrientationChangeAction(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+ return new OrientationAction(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
public static ViewAction orientationLandscapeReverse() {
- return new OrientationChangeAction(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
+ return new OrientationAction(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
}
public static ViewAction orientationPortraitReverse() {
- return new OrientationChangeAction(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
+ return new OrientationAction(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
}
@Override
@@ -61,6 +61,10 @@ public class OrientationChangeAction implements ViewAction {
activity.setRequestedOrientation(orientation);
}
+ public static void invoke(ViewAction action) {
+ onView(isRoot()).perform(action);
+ }
+
private Activity getActivity(Context context) {
while (context instanceof ContextWrapper) {
if (context instanceof Activity) {
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/WaitAction.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/WaitAction.java
index 5d98ccb7f8..e3741f3d42 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/WaitAction.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/WaitAction.java
@@ -3,10 +3,11 @@ package com.mapbox.mapboxsdk.testapp.action;
import android.support.test.espresso.UiController;
import android.support.test.espresso.ViewAction;
import android.view.View;
-
import org.hamcrest.Matcher;
+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.isRoot;
public final class WaitAction implements ViewAction {
@@ -30,5 +31,9 @@ public final class WaitAction implements ViewAction {
public void perform(UiController uiController, View view) {
uiController.loopMainThreadForAtLeast(loopTime);
}
+
+ public static void invoke(long loopTime) {
+ onView(isRoot()).perform(new WaitAction(loopTime));
+ }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseTest.java
index ea69f8adae..c91afe9b60 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseTest.java
@@ -1,116 +1,96 @@
package com.mapbox.mapboxsdk.testapp.activity;
-import android.app.Activity;
-import android.support.test.espresso.Espresso;
-import android.support.test.espresso.IdlingRegistry;
-import android.support.test.espresso.IdlingResource;
-import android.support.test.espresso.IdlingResourceTimeoutException;
-import android.support.test.espresso.ViewInteraction;
+import android.support.annotation.CallSuper;
+import android.support.annotation.UiThread;
import android.support.test.rule.ActivityTestRule;
-
import com.mapbox.mapboxsdk.Mapbox;
+import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.testapp.R;
-import com.mapbox.mapboxsdk.testapp.action.MapboxMapAction;
-import com.mapbox.mapboxsdk.testapp.action.WaitAction;
-import com.mapbox.mapboxsdk.testapp.utils.FinishLoadingStyleIdlingResource;
-
-import com.mapbox.mapboxsdk.testapp.utils.MapboxIdlingResource;
-import junit.framework.Assert;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.rules.TestName;
-
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;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import static junit.framework.TestCase.assertNotNull;
+import static junit.framework.TestCase.assertTrue;
/**
* Base class for all Activity test hooking into an existing Activity that will load style.
*/
public abstract class BaseTest {
+ private static final int WAIT_TIMEOUT = 30; //seconds
+
@Rule
- public ActivityTestRule<Activity> rule = new ActivityTestRule<>(getActivityClass());
+ public ActivityTestRule rule = new ActivityTestRule<>(getActivityClass());
@Rule
- public TestName testNameRule = new TestName();
+ public TestName testName = new TestName();
protected MapboxMap mapboxMap;
- protected MapboxIdlingResource idlingResource;
+ protected MapView mapView;
+ private final CountDownLatch latch = new CountDownLatch(1);
@Before
+ @CallSuper
public void beforeTest() {
- try {
- Timber.e(String.format(
- "%s - %s - %s",
- getClass().getSimpleName(),
- testNameRule.getMethodName(),
- "@Before test: register idle resource"
- ));
- idlingResource = (MapboxIdlingResource) generateIdlingResource();
- IdlingRegistry.getInstance().register(idlingResource);
- Espresso.onIdle();
- mapboxMap = idlingResource.getMapboxMap();
- } catch (IdlingResourceTimeoutException idlingResourceTimeoutException) {
- throw new RuntimeException(
- String.format(
- "Could not start %s test for %s.",
- testNameRule.getMethodName(),
- getActivityClass().getSimpleName()
- )
- );
- }
+ initialiseMap();
+ holdTestRunnerForStyleLoad();
}
- protected IdlingResource generateIdlingResource() {
- return new FinishLoadingStyleIdlingResource(rule.getActivity());
+ @After
+ @CallSuper
+ public void afterTest() {
+ // override to add logic
+ }
+
+ @UiThread
+ @CallSuper
+ protected void initMap(MapboxMap mapboxMap) {
+ this.mapboxMap = mapboxMap;
+ mapboxMap.getStyle(style -> latch.countDown());
}
protected void validateTestSetup() {
if (!Mapbox.isConnected()) {
Timber.e("Not connected to the internet while running test");
}
-
- checkViewIsDisplayed(R.id.mapView);
- Assert.assertNotNull(mapboxMap);
- }
-
- protected MapboxMap getMapboxMap() {
- return mapboxMap;
+ assertNotNull("MapView isn't initialised", mapView);
+ assertNotNull("MapboxMap isn't initialised", mapboxMap);
+ assertNotNull("Style isn't initialised", mapboxMap.getStyle());
+ assertTrue("Style isn't fully loaded", mapboxMap.getStyle().isFullyLoaded());
}
protected abstract Class getActivityClass();
- protected void checkViewIsDisplayed(int id) {
- onView(withId(id)).check(matches(isDisplayed()));
- }
-
- protected void waitAction() {
- waitAction(500);
- }
-
- protected void waitAction(long waitTime) {
- onView(withId(R.id.mapView)).perform(new WaitAction(waitTime));
- }
-
- protected ViewInteraction onMapView() {
- return onView(withId(R.id.mapView));
+ private void initialiseMap() {
+ try {
+ rule.runOnUiThread(() -> {
+ mapView = rule.getActivity().findViewById(R.id.mapView);
+ mapView.getMapAsync(this::initMap);
+ });
+ } catch (Throwable throwable) {
+ throwable.printStackTrace();
+ }
}
- protected MapboxMapAction getMapboxMapAction(MapboxMapAction.OnInvokeActionListener onInvokeActionListener) {
- return new MapboxMapAction(onInvokeActionListener, mapboxMap);
- }
+ private void holdTestRunnerForStyleLoad() {
+ boolean interrupted;
+ try {
+ interrupted = latch.await(WAIT_TIMEOUT, TimeUnit.SECONDS);
+ } catch (InterruptedException ignore) {
+ interrupted = true;
+ }
- @After
- public void afterTest() {
- Timber.e(String.format("%s - %s", testNameRule.getMethodName(), "@After test: unregister idle resource"));
- IdlingRegistry.getInstance().unregister(idlingResource);
+ if (!interrupted) {
+ Timber.e("Timeout occurred for %s", testName.getMethodName());
+ validateTestSetup();
+ }
}
-}
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/EspressoTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/EspressoTest.java
index dfb4a46180..97a73ba1cb 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/EspressoTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/EspressoTest.java
@@ -1,24 +1,28 @@
package com.mapbox.mapboxsdk.testapp.activity;
-import android.support.test.espresso.IdlingResource;
+import android.support.annotation.UiThread;
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity;
-import com.mapbox.mapboxsdk.testapp.utils.LoadStyleIdlingResource;
+
/**
* Base class for all tests using EspressoTestActivity as wrapper.
* <p>
- * Uses {@link LoadStyleIdlingResource} to load "assets/streets.json" as style.
+ * Loads "assets/streets.json" as style.
* </p>
*/
public class EspressoTest extends BaseTest {
@Override
- protected IdlingResource generateIdlingResource() {
- return new LoadStyleIdlingResource(rule.getActivity());
+ protected final Class getActivityClass() {
+ return EspressoTestActivity.class;
}
+ @UiThread
@Override
- protected final Class getActivityClass() {
- return EspressoTestActivity.class;
+ protected void initMap(MapboxMap mapboxMap) {
+ mapboxMap.setStyle(new Style.Builder().fromUrl("asset://streets.json"));
+ super.initMap(mapboxMap);
}
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/IconTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/IconTest.java
index 9fb823a377..559213af3d 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/IconTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/IconTest.java
@@ -1,6 +1,7 @@
package com.mapbox.mapboxsdk.testapp.annotations;
import android.app.Activity;
+import android.support.test.annotation.UiThreadTest;
import android.support.v4.content.res.ResourcesCompat;
import com.mapbox.mapboxsdk.annotations.Icon;
import com.mapbox.mapboxsdk.annotations.IconFactory;
@@ -31,117 +32,107 @@ public class IconTest extends EspressoTest {
@Before
public void beforeTest() {
super.beforeTest();
- iconMap = new IconManagerResolver(getMapboxMap()).getIconMap();
- }
-
- @Test
- public void testEmpty() {
- assertTrue(iconMap.isEmpty());
+ iconMap = new IconManagerResolver(mapboxMap).getIconMap();
}
@Test
+ @UiThreadTest
public void testAddSameIconMarker() {
validateTestSetup();
- onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> {
- Icon defaultMarker = IconFactory.getInstance(rule.getActivity()).defaultMarker();
- mapboxMap.addMarker(new MarkerOptions().position(new LatLng()));
- mapboxMap.addMarker(new MarkerOptions().position(new LatLng(1, 1)));
- assertEquals(1, iconMap.size());
- assertEquals(2, iconMap.get(defaultMarker), 0);
- }));
+ Icon defaultMarker = IconFactory.getInstance(rule.getActivity()).defaultMarker();
+ mapboxMap.addMarker(new MarkerOptions().position(new LatLng()));
+ mapboxMap.addMarker(new MarkerOptions().position(new LatLng(1, 1)));
+ assertEquals(1, iconMap.size());
+ assertEquals(2, iconMap.get(defaultMarker), 0);
}
@Test
+ @UiThreadTest
public void testAddDifferentIconMarker() {
validateTestSetup();
- onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> {
- Icon icon = IconFactory.getInstance(rule.getActivity()).fromResource(R.drawable.mapbox_logo_icon);
- getMapboxMap().addMarker(new MarkerOptions().icon(icon).position(new LatLng()));
- getMapboxMap().addMarker(new MarkerOptions().position(new LatLng(1, 1)));
- assertEquals(iconMap.size(), 2);
- assertTrue(iconMap.containsKey(icon));
- assertTrue(iconMap.get(icon) == 1);
- }));
+ Icon icon = IconFactory.getInstance(rule.getActivity()).fromResource(R.drawable.mapbox_logo_icon);
+ mapboxMap.addMarker(new MarkerOptions().icon(icon).position(new LatLng()));
+ mapboxMap.addMarker(new MarkerOptions().position(new LatLng(1, 1)));
+ assertEquals(iconMap.size(), 2);
+ assertTrue(iconMap.containsKey(icon));
+ assertTrue(iconMap.get(icon) == 1);
}
@Test
+ @UiThreadTest
public void testAddRemoveIconMarker() {
validateTestSetup();
- onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> {
- Icon icon = IconFactory.getInstance(rule.getActivity()).fromResource(R.drawable.mapbox_logo_icon);
- Marker marker = mapboxMap.addMarker(new MarkerOptions().icon(icon).position(new LatLng()));
- mapboxMap.addMarker(new MarkerOptions().position(new LatLng(1, 1)));
- assertEquals(iconMap.size(), 2);
- assertTrue(iconMap.containsKey(icon));
- assertTrue(iconMap.get(icon) == 1);
-
- mapboxMap.removeMarker(marker);
- assertEquals(iconMap.size(), 1);
- assertFalse(iconMap.containsKey(icon));
- }));
+ Icon icon = IconFactory.getInstance(rule.getActivity()).fromResource(R.drawable.mapbox_logo_icon);
+ Marker marker = mapboxMap.addMarker(new MarkerOptions().icon(icon).position(new LatLng()));
+ mapboxMap.addMarker(new MarkerOptions().position(new LatLng(1, 1)));
+ assertEquals(iconMap.size(), 2);
+ assertTrue(iconMap.containsKey(icon));
+ assertTrue(iconMap.get(icon) == 1);
+
+ mapboxMap.removeMarker(marker);
+ assertEquals(iconMap.size(), 1);
+ assertFalse(iconMap.containsKey(icon));
}
@Test
+ @UiThreadTest
public void testAddRemoveDefaultMarker() {
validateTestSetup();
- onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> {
- Marker marker = mapboxMap.addMarker(new MarkerOptions().position(new LatLng(1, 1)));
- assertEquals(iconMap.size(), 1);
+ Marker marker = mapboxMap.addMarker(new MarkerOptions().position(new LatLng(1, 1)));
+ assertEquals(iconMap.size(), 1);
- mapboxMap.removeMarker(marker);
- assertEquals(iconMap.size(), 0);
+ mapboxMap.removeMarker(marker);
+ assertEquals(iconMap.size(), 0);
- mapboxMap.addMarker(new MarkerOptions().position(new LatLng()));
- assertEquals(iconMap.size(), 1);
- }));
+ mapboxMap.addMarker(new MarkerOptions().position(new LatLng()));
+ assertEquals(iconMap.size(), 1);
}
@Test
+ @UiThreadTest
public void testAddRemoveMany() {
validateTestSetup();
- onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> {
- Activity activity = rule.getActivity();
- IconFactory iconFactory = IconFactory.getInstance(activity);
-
- // add 2 default icon markers
- Marker defaultMarkerOne = mapboxMap.addMarker(new MarkerOptions().position(new LatLng(1, 1)));
- Marker defaultMarkerTwo = mapboxMap.addMarker(new MarkerOptions().position(new LatLng(2, 1)));
-
- // add 4 unique icon markers
- mapboxMap.addMarker(new MarkerOptions()
- .icon(iconFactory.fromResource(R.drawable.mapbox_logo_icon))
- .position(new LatLng(3, 1))
- );
- mapboxMap.addMarker(new MarkerOptions()
- .icon(iconFactory.fromResource(R.drawable.mapbox_compass_icon))
- .position(new LatLng(4, 1))
- );
- mapboxMap.addMarker(new MarkerOptions()
- .icon(IconUtils.drawableToIcon(activity, R.drawable.ic_stars,
- ResourcesCompat.getColor(activity.getResources(),
- R.color.blueAccent, activity.getTheme())))
- .position(new LatLng(5, 1))
- );
- mapboxMap.addMarker(new MarkerOptions()
- .icon(iconFactory.fromResource(R.drawable.ic_android))
- .position(new LatLng(6, 1))
- );
-
- assertEquals("Amount of icons should match 5", 5, iconMap.size());
- assertEquals("Refcounter of default marker should match 2", 2, iconMap.get(iconFactory.defaultMarker()), 0);
-
- mapboxMap.removeMarker(defaultMarkerOne);
-
- assertEquals("Amount of icons should match 5", 5, iconMap.size());
- assertEquals("Refcounter of default marker should match 1", 1, iconMap.get(iconFactory.defaultMarker()), 0);
-
- mapboxMap.removeMarker(defaultMarkerTwo);
-
- assertEquals("Amount of icons should match 4", 4, iconMap.size());
- assertNull("DefaultMarker shouldn't exist anymore", iconMap.get(iconFactory.defaultMarker()));
-
- mapboxMap.clear();
- assertEquals("Amount of icons should match 0", 0, iconMap.size());
- }));
+ Activity activity = rule.getActivity();
+ IconFactory iconFactory = IconFactory.getInstance(activity);
+
+ // add 2 default icon markers
+ Marker defaultMarkerOne = mapboxMap.addMarker(new MarkerOptions().position(new LatLng(1, 1)));
+ Marker defaultMarkerTwo = mapboxMap.addMarker(new MarkerOptions().position(new LatLng(2, 1)));
+
+ // add 4 unique icon markers
+ mapboxMap.addMarker(new MarkerOptions()
+ .icon(iconFactory.fromResource(R.drawable.mapbox_logo_icon))
+ .position(new LatLng(3, 1))
+ );
+ mapboxMap.addMarker(new MarkerOptions()
+ .icon(iconFactory.fromResource(R.drawable.mapbox_compass_icon))
+ .position(new LatLng(4, 1))
+ );
+ mapboxMap.addMarker(new MarkerOptions()
+ .icon(IconUtils.drawableToIcon(activity, R.drawable.ic_stars,
+ ResourcesCompat.getColor(activity.getResources(),
+ R.color.blueAccent, activity.getTheme())))
+ .position(new LatLng(5, 1))
+ );
+ mapboxMap.addMarker(new MarkerOptions()
+ .icon(iconFactory.fromResource(R.drawable.ic_android))
+ .position(new LatLng(6, 1))
+ );
+
+ assertEquals("Amount of icons should match 5", 5, iconMap.size());
+ assertEquals("Refcounter of default marker should match 2", 2, iconMap.get(iconFactory.defaultMarker()), 0);
+
+ mapboxMap.removeMarker(defaultMarkerOne);
+
+ assertEquals("Amount of icons should match 5", 5, iconMap.size());
+ assertEquals("Refcounter of default marker should match 1", 1, iconMap.get(iconFactory.defaultMarker()), 0);
+
+ mapboxMap.removeMarker(defaultMarkerTwo);
+
+ assertEquals("Amount of icons should match 4", 4, iconMap.size());
+ assertNull("DefaultMarker shouldn't exist anymore", iconMap.get(iconFactory.defaultMarker()));
+
+ mapboxMap.clear();
+ assertEquals("Amount of icons should match 0", 0, iconMap.size());
}
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraForTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraForTest.java
index eb38bddf84..4365ea95ff 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraForTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraForTest.java
@@ -1,6 +1,7 @@
package com.mapbox.mapboxsdk.testapp.camera;
import android.support.annotation.NonNull;
+import android.support.test.annotation.UiThreadTest;
import com.mapbox.geojson.Point;
import com.mapbox.geojson.Polygon;
import com.mapbox.mapboxsdk.camera.CameraPosition;
@@ -18,123 +19,117 @@ import static org.junit.Assert.assertEquals;
public class CameraForTest extends BaseTest {
@Test
+ @UiThreadTest
public void testGetCameraForLatLngBounds() {
validateTestSetup();
- onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> {
- CameraPosition actualPosition = mapboxMap.getCameraForLatLngBounds(
- LatLngBounds.from(10, 10, -10, -10));
- CameraPosition expectedPosition = new CameraPosition.Builder()
- .target(new LatLng()).zoom(4.16).tilt(0).bearing(0).build();
- assertEquals("Latitude should match",
- expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f);
- assertEquals("Longitude should match",
- expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f);
- assertEquals("Bearing should match",
- expectedPosition.zoom, actualPosition.zoom, 0.01f);
- assertEquals("Tilt should match", expectedPosition.tilt, actualPosition.tilt, 0.01f);
- }));
+ CameraPosition actualPosition = mapboxMap.getCameraForLatLngBounds(
+ LatLngBounds.from(10, 10, -10, -10));
+ CameraPosition expectedPosition = new CameraPosition.Builder()
+ .target(new LatLng()).zoom(4.16).tilt(0).bearing(0).build();
+ assertEquals("Latitude should match",
+ expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f);
+ assertEquals("Longitude should match",
+ expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f);
+ assertEquals("Bearing should match",
+ expectedPosition.zoom, actualPosition.zoom, 0.01f);
+ assertEquals("Tilt should match", expectedPosition.tilt, actualPosition.tilt, 0.01f);
}
@Test
+ @UiThreadTest
public void testGetCameraForLatLngBoundsPadding() {
validateTestSetup();
- onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> {
- CameraPosition actualPosition = mapboxMap.getCameraForLatLngBounds(
- LatLngBounds.from(10, 10, -10, -10), new int[] {5, 5, 5, 5});
- CameraPosition expectedPosition = new CameraPosition.Builder()
- .target(new LatLng()).zoom(4.13).tilt(0).bearing(0).build();
- assertEquals("Latitude should match",
- expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f);
- assertEquals("Longitude should match",
- expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f);
- assertEquals("Zoom should match",
- expectedPosition.zoom, actualPosition.zoom, 0.01f);
- assertEquals("Tilt should match",
- expectedPosition.tilt, actualPosition.tilt, 0.01f);
- assertEquals("Bearing should match",
- expectedPosition.bearing, actualPosition.bearing, 0.01f);
- }));
+ CameraPosition actualPosition = mapboxMap.getCameraForLatLngBounds(
+ LatLngBounds.from(10, 10, -10, -10), new int[] {5, 5, 5, 5});
+ CameraPosition expectedPosition = new CameraPosition.Builder()
+ .target(new LatLng()).zoom(4.13).tilt(0).bearing(0).build();
+ assertEquals("Latitude should match",
+ expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f);
+ assertEquals("Longitude should match",
+ expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f);
+ assertEquals("Zoom should match",
+ expectedPosition.zoom, actualPosition.zoom, 0.01f);
+ assertEquals("Tilt should match",
+ expectedPosition.tilt, actualPosition.tilt, 0.01f);
+ assertEquals("Bearing should match",
+ expectedPosition.bearing, actualPosition.bearing, 0.01f);
}
@Test
+ @UiThreadTest
public void testGetCameraForLatLngBoundsBearing() {
validateTestSetup();
- onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> {
- CameraPosition actualPosition = mapboxMap.getCameraForLatLngBounds(
- LatLngBounds.from(10, 10, -10, -10), 45, 0);
- CameraPosition expectedPosition = new CameraPosition.Builder()
- .target(new LatLng()).zoom(3.66).tilt(0).bearing(45).build();
- assertEquals("Latitude should match",
- expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f);
- assertEquals("Longitude should match",
- expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f);
- assertEquals("Zoom should match",
- expectedPosition.zoom, actualPosition.zoom, 0.01f);
- assertEquals("Tilt should match",
- expectedPosition.tilt, actualPosition.tilt, 0.01f);
- assertEquals("Bearing should match",
- expectedPosition.bearing, actualPosition.bearing, 0.01f);
- }));
+ CameraPosition actualPosition = mapboxMap.getCameraForLatLngBounds(
+ LatLngBounds.from(10, 10, -10, -10), 45, 0);
+ CameraPosition expectedPosition = new CameraPosition.Builder()
+ .target(new LatLng()).zoom(3.66).tilt(0).bearing(45).build();
+ assertEquals("Latitude should match",
+ expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f);
+ assertEquals("Longitude should match",
+ expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f);
+ assertEquals("Zoom should match",
+ expectedPosition.zoom, actualPosition.zoom, 0.01f);
+ assertEquals("Tilt should match",
+ expectedPosition.tilt, actualPosition.tilt, 0.01f);
+ assertEquals("Bearing should match",
+ expectedPosition.bearing, actualPosition.bearing, 0.01f);
}
@Test
+ @UiThreadTest
public void testGetCameraForLatLngBoundsTilt() {
validateTestSetup();
- onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> {
- CameraPosition actualPosition = mapboxMap.getCameraForLatLngBounds(
- LatLngBounds.from(10, 10, -10, -10), 0, 45);
- CameraPosition expectedPosition = new CameraPosition.Builder()
- .target(new LatLng(-0.264576975267, 0)).zoom(4.13).tilt(45).bearing(0).build();
- assertEquals("Latitude should match",
- expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f);
- assertEquals("Longitude should match",
- expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f);
- assertEquals("Zoom should match",
- expectedPosition.zoom, actualPosition.zoom, 0.01f);
- assertEquals("Tilt should match",
- expectedPosition.tilt, actualPosition.tilt, 0.01f);
- assertEquals("Bearing should match",
- expectedPosition.bearing, actualPosition.bearing, 0.01f);
- }));
+ CameraPosition actualPosition = mapboxMap.getCameraForLatLngBounds(
+ LatLngBounds.from(10, 10, -10, -10), 0, 45);
+ CameraPosition expectedPosition = new CameraPosition.Builder()
+ .target(new LatLng(-0.264576975267, 0)).zoom(4.13).tilt(45).bearing(0).build();
+ assertEquals("Latitude should match",
+ expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f);
+ assertEquals("Longitude should match",
+ expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f);
+ assertEquals("Zoom should match",
+ expectedPosition.zoom, actualPosition.zoom, 0.01f);
+ assertEquals("Tilt should match",
+ expectedPosition.tilt, actualPosition.tilt, 0.01f);
+ assertEquals("Bearing should match",
+ expectedPosition.bearing, actualPosition.bearing, 0.01f);
}
@Test
+ @UiThreadTest
public void testGetCameraForLatLngBoundsAll() {
validateTestSetup();
- onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> {
- CameraPosition actualPosition = mapboxMap.getCameraForLatLngBounds(
- LatLngBounds.from(10, 10, -10, -10), new int[] {5, 5, 5, 5}, 45, 45);
- CameraPosition expectedPosition = new CameraPosition.Builder()
- .target(new LatLng(-0.3732134634, -0.3713191053)).zoom(3.63).tilt(45).bearing(45).build();
- assertEquals("Latitude should match",
- expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f);
- assertEquals("Longitude should match",
- expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f);
- assertEquals("Zoom should match",
- expectedPosition.zoom, actualPosition.zoom, 0.01f);
- assertEquals("Tilt should match",
- expectedPosition.tilt, actualPosition.tilt, 0.01f);
- assertEquals("Bearing should match",
- expectedPosition.bearing, actualPosition.bearing, 0.01f);
- }));
+ CameraPosition actualPosition = mapboxMap.getCameraForLatLngBounds(
+ LatLngBounds.from(10, 10, -10, -10), new int[] {5, 5, 5, 5}, 45, 45);
+ CameraPosition expectedPosition = new CameraPosition.Builder()
+ .target(new LatLng(-0.3732134634, -0.3713191053)).zoom(3.63).tilt(45).bearing(45).build();
+ assertEquals("Latitude should match",
+ expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f);
+ assertEquals("Longitude should match",
+ expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f);
+ assertEquals("Zoom should match",
+ expectedPosition.zoom, actualPosition.zoom, 0.01f);
+ assertEquals("Tilt should match",
+ expectedPosition.tilt, actualPosition.tilt, 0.01f);
+ assertEquals("Bearing should match",
+ expectedPosition.bearing, actualPosition.bearing, 0.01f);
}
@Test
+ @UiThreadTest
public void testGetCameraForGeometry() {
validateTestSetup();
- onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> {
- List<List<Point>> polygonDefinition = getPolygonDefinition();
- CameraPosition actualPosition = mapboxMap.getCameraForGeometry(Polygon.fromLngLats(polygonDefinition));
- CameraPosition expectedPosition = new CameraPosition.Builder()
- .target(new LatLng()).zoom(4.16).tilt(0).bearing(0).build();
- assertEquals("Latitude should match",
- expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f);
- assertEquals("Longitude should match",
- expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f);
- assertEquals("Bearing should match",
- expectedPosition.zoom, actualPosition.zoom, 0.01f);
- assertEquals("Tilt should match", expectedPosition.tilt, actualPosition.tilt, 0.01f);
- }));
+ List<List<Point>> polygonDefinition = getPolygonDefinition();
+ CameraPosition actualPosition = mapboxMap.getCameraForGeometry(Polygon.fromLngLats(polygonDefinition));
+ CameraPosition expectedPosition = new CameraPosition.Builder()
+ .target(new LatLng()).zoom(4.16).tilt(0).bearing(0).build();
+ assertEquals("Latitude should match",
+ expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f);
+ assertEquals("Longitude should match",
+ expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f);
+ assertEquals("Bearing should match",
+ expectedPosition.zoom, actualPosition.zoom, 0.01f);
+ assertEquals("Tilt should match", expectedPosition.tilt, actualPosition.tilt, 0.01f);
}
@NonNull
@@ -154,113 +149,108 @@ public class CameraForTest extends BaseTest {
}
@Test
+ @UiThreadTest
public void testGetCameraForGeometryPadding() {
validateTestSetup();
- onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> {
- List<List<Point>> polygonDefinition = getPolygonDefinition();
- CameraPosition actualPosition = mapboxMap.getCameraForGeometry(Polygon.fromLngLats(polygonDefinition),
- new int[] {5, 5, 5, 5});
- CameraPosition expectedPosition = new CameraPosition.Builder()
- .target(new LatLng()).zoom(4.13).tilt(0).bearing(0).build();
- assertEquals("Latitude should match",
- expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f);
- assertEquals("Longitude should match",
- expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f);
- assertEquals("Zoom should match",
- expectedPosition.zoom, actualPosition.zoom, 0.01f);
- assertEquals("Tilt should match",
- expectedPosition.tilt, actualPosition.tilt, 0.01f);
- assertEquals("Bearing should match",
- expectedPosition.bearing, actualPosition.bearing, 0.01f);
- }));
+ List<List<Point>> polygonDefinition = getPolygonDefinition();
+ CameraPosition actualPosition = mapboxMap.getCameraForGeometry(Polygon.fromLngLats(polygonDefinition),
+ new int[] {5, 5, 5, 5});
+ CameraPosition expectedPosition = new CameraPosition.Builder()
+ .target(new LatLng()).zoom(4.13).tilt(0).bearing(0).build();
+ assertEquals("Latitude should match",
+ expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f);
+ assertEquals("Longitude should match",
+ expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f);
+ assertEquals("Zoom should match",
+ expectedPosition.zoom, actualPosition.zoom, 0.01f);
+ assertEquals("Tilt should match",
+ expectedPosition.tilt, actualPosition.tilt, 0.01f);
+ assertEquals("Bearing should match",
+ expectedPosition.bearing, actualPosition.bearing, 0.01f);
}
@Test
+ @UiThreadTest
public void testGetCameraForGeometryBearing() {
validateTestSetup();
- onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> {
- List<List<Point>> polygonDefinition = getPolygonDefinition();
- CameraPosition actualPosition = mapboxMap.getCameraForGeometry(Polygon.fromLngLats(polygonDefinition), 45, 0);
- CameraPosition expectedPosition = new CameraPosition.Builder()
- .target(new LatLng()).zoom(3.66).tilt(0).bearing(45).build();
- assertEquals("Latitude should match",
- expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f);
- assertEquals("Longitude should match",
- expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f);
- assertEquals("Zoom should match",
- expectedPosition.zoom, actualPosition.zoom, 0.01f);
- assertEquals("Tilt should match",
- expectedPosition.tilt, actualPosition.tilt, 0.01f);
- assertEquals("Bearing should match",
- expectedPosition.bearing, actualPosition.bearing, 0.01f);
- }));
+ List<List<Point>> polygonDefinition = getPolygonDefinition();
+ CameraPosition actualPosition = mapboxMap.getCameraForGeometry(Polygon.fromLngLats(polygonDefinition), 45, 0);
+ CameraPosition expectedPosition = new CameraPosition.Builder()
+ .target(new LatLng()).zoom(3.66).tilt(0).bearing(45).build();
+ assertEquals("Latitude should match",
+ expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f);
+ assertEquals("Longitude should match",
+ expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f);
+ assertEquals("Zoom should match",
+ expectedPosition.zoom, actualPosition.zoom, 0.01f);
+ assertEquals("Tilt should match",
+ expectedPosition.tilt, actualPosition.tilt, 0.01f);
+ assertEquals("Bearing should match",
+ expectedPosition.bearing, actualPosition.bearing, 0.01f);
}
@Test
+ @UiThreadTest
public void testGetCameraForGeometryTilt() {
validateTestSetup();
- onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> {
- List<List<Point>> polygonDefinition = getPolygonDefinition();
- CameraPosition actualPosition = mapboxMap.getCameraForGeometry(Polygon.fromLngLats(polygonDefinition), 0, 45);
- CameraPosition expectedPosition = new CameraPosition.Builder()
- .target(new LatLng(-0.2645769752, 0)).zoom(4.13).tilt(45).bearing(0).build();
- assertEquals("Latitude should match",
- expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f);
- assertEquals("Longitude should match",
- expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f);
- assertEquals("Zoom should match",
- expectedPosition.zoom, actualPosition.zoom, 0.01f);
- assertEquals("Tilt should match",
- expectedPosition.tilt, actualPosition.tilt, 0.01f);
- assertEquals("Bearing should match",
- expectedPosition.bearing, actualPosition.bearing, 0.01f);
- }));
+ List<List<Point>> polygonDefinition = getPolygonDefinition();
+ CameraPosition actualPosition = mapboxMap.getCameraForGeometry(Polygon.fromLngLats(polygonDefinition), 0, 45);
+ CameraPosition expectedPosition = new CameraPosition.Builder()
+ .target(new LatLng(-0.2645769752, 0)).zoom(4.13).tilt(45).bearing(0).build();
+ assertEquals("Latitude should match",
+ expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f);
+ assertEquals("Longitude should match",
+ expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f);
+ assertEquals("Zoom should match",
+ expectedPosition.zoom, actualPosition.zoom, 0.01f);
+ assertEquals("Tilt should match",
+ expectedPosition.tilt, actualPosition.tilt, 0.01f);
+ assertEquals("Bearing should match",
+ expectedPosition.bearing, actualPosition.bearing, 0.01f);
}
@Test
+ @UiThreadTest
public void testGetCameraForGeometryAll() {
validateTestSetup();
- onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> {
- List<List<Point>> polygonDefinition = getPolygonDefinition();
- CameraPosition actualPosition = mapboxMap.getCameraForGeometry(Polygon.fromLngLats(polygonDefinition),
- new int[] {5, 5, 5, 5}, 45, 45);
- CameraPosition expectedPosition = new CameraPosition.Builder()
- .target(new LatLng(-0.373213463, -0.37131910534)).zoom(3.63).tilt(45).bearing(45).build();
- assertEquals("Latitude should match",
- expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f);
- assertEquals("Longitude should match",
- expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f);
- assertEquals("Zoom should match",
- expectedPosition.zoom, actualPosition.zoom, 0.01f);
- assertEquals("Tilt should match",
- expectedPosition.tilt, actualPosition.tilt, 0.01f);
- assertEquals("Bearing should match",
- expectedPosition.bearing, actualPosition.bearing, 0.01f);
- }));
+ List<List<Point>> polygonDefinition = getPolygonDefinition();
+ CameraPosition actualPosition = mapboxMap.getCameraForGeometry(Polygon.fromLngLats(polygonDefinition),
+ new int[] {5, 5, 5, 5}, 45, 45);
+ CameraPosition expectedPosition = new CameraPosition.Builder()
+ .target(new LatLng(-0.373213463, -0.37131910534)).zoom(3.63).tilt(45).bearing(45).build();
+ assertEquals("Latitude should match",
+ expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f);
+ assertEquals("Longitude should match",
+ expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f);
+ assertEquals("Zoom should match",
+ expectedPosition.zoom, actualPosition.zoom, 0.01f);
+ assertEquals("Tilt should match",
+ expectedPosition.tilt, actualPosition.tilt, 0.01f);
+ assertEquals("Bearing should match",
+ expectedPosition.bearing, actualPosition.bearing, 0.01f);
}
@Test
+ @UiThreadTest
public void testGetCameraForGeometryDeprecatedApi() {
validateTestSetup();
- onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> {
- List<List<Point>> polygonDefinition = getPolygonDefinition();
- CameraPosition actualPosition = mapboxMap.getCameraForGeometry(
- Polygon.fromLngLats(polygonDefinition),
- new int[] {5, 5, 5, 5},
- 45, 0);
- CameraPosition expectedPosition = new CameraPosition.Builder()
- .target(new LatLng()).zoom(3.63).tilt(0).bearing(45).build();
- assertEquals("Latitude should match",
- expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f);
- assertEquals("Longitude should match",
- expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f);
- assertEquals("Zoom should match",
- expectedPosition.zoom, actualPosition.zoom, 0.01f);
- assertEquals("Tilt should match",
- expectedPosition.tilt, actualPosition.tilt, 0.01f);
- assertEquals("Bearing should match",
- expectedPosition.bearing, actualPosition.bearing, 0.01f);
- }));
+ List<List<Point>> polygonDefinition = getPolygonDefinition();
+ CameraPosition actualPosition = mapboxMap.getCameraForGeometry(
+ Polygon.fromLngLats(polygonDefinition),
+ new int[] {5, 5, 5, 5},
+ 45, 0);
+ CameraPosition expectedPosition = new CameraPosition.Builder()
+ .target(new LatLng()).zoom(3.63).tilt(0).bearing(45).build();
+ assertEquals("Latitude should match",
+ expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f);
+ assertEquals("Longitude should match",
+ expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f);
+ assertEquals("Zoom should match",
+ expectedPosition.zoom, actualPosition.zoom, 0.01f);
+ assertEquals("Tilt should match",
+ expectedPosition.tilt, actualPosition.tilt, 0.01f);
+ assertEquals("Bearing should match",
+ expectedPosition.bearing, actualPosition.bearing, 0.01f);
}
@Override
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/fragment/MapDialogFragmentTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/fragment/MapDialogFragmentTest.kt
index 418191e91a..2731b20db7 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/fragment/MapDialogFragmentTest.kt
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/fragment/MapDialogFragmentTest.kt
@@ -10,6 +10,7 @@ import android.support.test.runner.AndroidJUnit4
import com.mapbox.mapboxsdk.testapp.R
import com.mapbox.mapboxsdk.testapp.action.WaitAction
import com.mapbox.mapboxsdk.testapp.activity.maplayout.MapInDialogActivity
+import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -25,9 +26,10 @@ class MapDialogFragmentTest {
var activityRule: ActivityTestRule<MapInDialogActivity> = ActivityTestRule(MapInDialogActivity::class.java)
@Test
+ @Ignore
fun openCloseDialog() {
onView(withId(R.id.button_open_dialog)).perform(click())
- onView(withId(R.id.mapView)).perform(WaitAction(2500))
+ Thread.sleep(2500)
Espresso.pressBack()
}
} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/geometry/GeoJsonConversionTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/geometry/GeoJsonConversionTest.java
index c34e76a6e5..f30b3aa8cf 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/geometry/GeoJsonConversionTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/geometry/GeoJsonConversionTest.java
@@ -1,5 +1,6 @@
package com.mapbox.mapboxsdk.testapp.geometry;
+import android.support.test.annotation.UiThreadTest;
import com.google.gson.JsonArray;
import com.mapbox.geojson.Feature;
import com.mapbox.geojson.FeatureCollection;
@@ -13,11 +14,13 @@ import com.mapbox.mapboxsdk.style.layers.SymbolLayer;
import com.mapbox.mapboxsdk.style.sources.CustomGeometrySource;
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
import com.mapbox.mapboxsdk.style.sources.GeometryTileProvider;
+import com.mapbox.mapboxsdk.testapp.action.MapboxMapAction;
import com.mapbox.mapboxsdk.testapp.activity.EspressoTest;
import com.mapbox.mapboxsdk.testapp.utils.TestingAsyncUtils;
-
import org.junit.Test;
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.matcher.ViewMatchers.isRoot;
import static com.mapbox.geojson.Feature.fromGeometry;
import static com.mapbox.geojson.FeatureCollection.fromFeatures;
import static com.mapbox.geojson.GeometryCollection.fromGeometries;
@@ -35,101 +38,94 @@ public class GeoJsonConversionTest extends EspressoTest {
// Regression test for #12343
@Test
+ @UiThreadTest
public void testEmptyFeatureCollection() {
validateTestSetup();
- onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> {
- mapboxMap.getStyle().addSource(
- new CustomGeometrySource("test-id",
- new CustomProvider(fromFeatures(singletonList(fromGeometry(fromGeometries(emptyList())))))
- )
- );
- mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id"));
- }));
+ mapboxMap.getStyle().addSource(
+ new CustomGeometrySource("test-id",
+ new CustomProvider(fromFeatures(singletonList(fromGeometry(fromGeometries(emptyList())))))
+ )
+ );
+ mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id"));
}
@Test
+ @UiThreadTest
public void testPointFeatureCollection() {
validateTestSetup();
- onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> {
- mapboxMap.getStyle().addSource(
- new CustomGeometrySource("test-id",
- new CustomProvider(fromFeatures(singletonList(fromGeometry(Point.fromLngLat(0.0, 0.0)))))
- )
- );
- mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id"));
- }));
+ mapboxMap.getStyle().addSource(
+ new CustomGeometrySource("test-id",
+ new CustomProvider(fromFeatures(singletonList(fromGeometry(Point.fromLngLat(0.0, 0.0)))))
+ )
+ );
+ mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id"));
}
@Test
+ @UiThreadTest
public void testMultiPointFeatureCollection() {
validateTestSetup();
- onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> {
- mapboxMap.getStyle().addSource(
- new CustomGeometrySource("test-id",
- new CustomProvider(fromFeatures(singletonList(fromGeometry(fromLngLats(emptyList())))))
- )
- );
- mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id"));
- }));
+ mapboxMap.getStyle().addSource(
+ new CustomGeometrySource("test-id",
+ new CustomProvider(fromFeatures(singletonList(fromGeometry(fromLngLats(emptyList())))))
+ )
+ );
+ mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id"));
}
-
@Test
+ @UiThreadTest
public void testPolygonFeatureCollection() {
validateTestSetup();
- onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> {
- mapboxMap.getStyle().addSource(
- new CustomGeometrySource("test-id",
- new CustomProvider(fromFeatures(singletonList(fromGeometry(Polygon.fromLngLats(emptyList())))))
- )
- );
- mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id"));
- }));
+ mapboxMap.getStyle().addSource(
+ new CustomGeometrySource("test-id",
+ new CustomProvider(fromFeatures(singletonList(fromGeometry(Polygon.fromLngLats(emptyList())))))
+ )
+ );
+ mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id"));
}
@Test
+ @UiThreadTest
public void testMultiPolygonFeatureCollection() {
validateTestSetup();
- onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> {
- mapboxMap.getStyle().addSource(
- new CustomGeometrySource("test-id",
- new CustomProvider(fromFeatures(singletonList(fromGeometry(fromPolygon(Polygon.fromLngLats(emptyList()))))))
- )
- );
- mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id"));
- }));
+ mapboxMap.getStyle().addSource(
+ new CustomGeometrySource("test-id",
+ new CustomProvider(fromFeatures(singletonList(fromGeometry(fromPolygon(Polygon.fromLngLats(emptyList()))))))
+ )
+ );
+ mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id"));
}
@Test
+ @UiThreadTest
public void testLineStringFeatureCollection() {
validateTestSetup();
- onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> {
- mapboxMap.getStyle().addSource(
- new CustomGeometrySource("test-id",
- new CustomProvider(fromFeatures(singletonList(fromGeometry(fromLngLats(emptyList())))))
- )
- );
- mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id"));
- }));
+ mapboxMap.getStyle().addSource(
+ new CustomGeometrySource("test-id",
+ new CustomProvider(fromFeatures(singletonList(fromGeometry(fromLngLats(emptyList())))))
+ )
+ );
+ mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id"));
}
@Test
+ @UiThreadTest
public void testMultiLineStringFeatureCollection() {
validateTestSetup();
- onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> {
- mapboxMap.getStyle().addSource(
- new CustomGeometrySource("test-id",
- new CustomProvider(fromFeatures(singletonList(fromGeometry(fromLineString(fromLngLats(emptyList()))))))
- )
- );
- mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id"));
- }));
+ mapboxMap.getStyle().addSource(
+ new CustomGeometrySource("test-id",
+ new CustomProvider(fromFeatures(singletonList(fromGeometry(fromLineString(fromLngLats(emptyList()))))))
+ )
+ );
+ mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id"));
}
+
@Test
public void testNegativeNumberPropertyConversion() {
validateTestSetup();
- onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> {
+ onView(isRoot()).perform(new MapboxMapAction((uiController, mapboxMap) -> {
LatLng latLng = new LatLng();
Feature feature = Feature.fromGeometry(Point.fromLngLat(latLng.getLongitude(), latLng.getLatitude()));
@@ -148,10 +144,10 @@ public class GeoJsonConversionTest extends EspressoTest {
);
mapboxMap.getStyle().addLayer(layer);
- TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView());
+ TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng)).isEmpty());
- }));
+ }, mapboxMap));
}
class CustomProvider implements GeometryTileProvider {
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/StyleLoadTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/StyleLoadTest.kt
index 84af279bd0..ac73b028f3 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/StyleLoadTest.kt
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/StyleLoadTest.kt
@@ -18,14 +18,6 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class StyleLoadTest : EspressoTest() {
- private lateinit var mapView: MapView
-
- @Before
- override fun beforeTest() {
- super.beforeTest()
- mapView = (rule.activity as EspressoTestActivity).mapView
- }
-
@Test
fun updateSourceAfterStyleLoad() {
validateTestSetup()
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 0fadd33325..ca5c9adc1f 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,6 +3,7 @@ package com.mapbox.mapboxsdk.testapp.maps.widgets;
import android.app.Instrumentation;
import android.content.Intent;
import android.net.Uri;
+import android.os.Build;
import android.support.test.espresso.UiController;
import android.support.test.espresso.ViewAction;
import android.support.test.espresso.intent.Intents;
@@ -31,12 +32,14 @@ import static android.support.test.espresso.intent.Intents.intended;
import static android.support.test.espresso.intent.Intents.intending;
import static android.support.test.espresso.intent.matcher.IntentMatchers.hasAction;
import static android.support.test.espresso.intent.matcher.IntentMatchers.hasData;
+import static android.support.test.espresso.matcher.RootMatchers.isDialog;
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.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.anything;
import static org.hamcrest.core.IsNot.not;
+import static org.junit.Assume.assumeTrue;
public class AttributionTest extends EspressoTest {
@@ -126,15 +129,20 @@ public class AttributionTest extends EspressoTest {
@Test
public void testTelemetryDialog() {
+ assumeTrue(
+ "Can only run on API Level 23 or newer because of instability",
+ Build.VERSION.SDK_INT >= 23
+ );
+
validateTestSetup();
// click on View to open dialog
onView(withId(R.id.attributionView)).perform(click());
- onView(withText(R.string.mapbox_attributionsDialogTitle)).check(matches(isDisplayed()));
+ onView(withText(R.string.mapbox_attributionsDialogTitle)).inRoot(isDialog()).check(matches(isDisplayed()));
// click on item to open second dialog
- onView(withText(R.string.mapbox_telemetrySettings)).perform(click());
- onView(withText(R.string.mapbox_attributionTelemetryTitle)).check(matches(isDisplayed()));
+ onView(withText(R.string.mapbox_telemetrySettings)).inRoot(isDialog()).perform(click());
+ onView(withText(R.string.mapbox_attributionTelemetryTitle)).inRoot(isDialog()).check(matches(isDisplayed()));
}
@After
@@ -206,4 +214,4 @@ public class AttributionTest extends EspressoTest {
interface InvokeViewAction {
void onViewAction(UiController uiController, View view);
}
-}
+} \ No newline at end of file
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 1cdf1423a3..8b62ee7612 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
@@ -4,6 +4,7 @@ import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.action.WaitAction;
import com.mapbox.mapboxsdk.testapp.activity.EspressoTest;
import com.mapbox.mapboxsdk.testapp.utils.TestConstants;
import org.junit.Ignore;
@@ -55,7 +56,7 @@ public class CompassViewTest extends EspressoTest {
.build()
)));
onView(withId(R.id.compassView)).perform(click());
- waitAction();
+ WaitAction.invoke(500);
onView(withId(R.id.compassView)).check(matches(not(isDisplayed())));
invoke(mapboxMap, (uiController, mapboxMap) -> {
CameraPosition cameraPosition = mapboxMap.getCameraPosition();
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/offline/OfflineManagerTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/offline/OfflineManagerTest.kt
index 144d67feee..8e5f3f7c5f 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/offline/OfflineManagerTest.kt
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/offline/OfflineManagerTest.kt
@@ -1,59 +1,43 @@
package com.mapbox.mapboxsdk.testapp.offline
import android.content.Context
-import android.support.test.espresso.Espresso
-import android.support.test.espresso.IdlingRegistry
-import android.support.test.espresso.UiController
-import android.support.test.espresso.idling.CountingIdlingResource
+import android.support.test.rule.ActivityTestRule
import android.support.test.runner.AndroidJUnit4
-import com.mapbox.mapboxsdk.maps.MapboxMap
import com.mapbox.mapboxsdk.offline.OfflineManager
import com.mapbox.mapboxsdk.offline.OfflineRegion
import com.mapbox.mapboxsdk.storage.FileSource
-import com.mapbox.mapboxsdk.testapp.action.MapboxMapAction.invoke
-import com.mapbox.mapboxsdk.testapp.activity.EspressoTest
+import com.mapbox.mapboxsdk.testapp.activity.FeatureOverviewActivity
import com.mapbox.mapboxsdk.testapp.utils.FileUtils
+import org.junit.FixMethodOrder
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
import java.io.IOException
+import java.util.concurrent.CountDownLatch
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@RunWith(AndroidJUnit4::class)
-class OfflineManagerTest : EspressoTest() {
+class OfflineManagerTest {
companion object {
private const val TEST_DB_FILE_NAME = "offline_test.db"
+ private lateinit var mergedRegion: OfflineRegion
}
- private val context: Context by lazy { rule.activity }
-
- private lateinit var offlineIdlingResource: CountingIdlingResource
-
- override fun beforeTest() {
- super.beforeTest()
- offlineIdlingResource = CountingIdlingResource("idling_resource")
- IdlingRegistry.getInstance().register(offlineIdlingResource)
- }
+ @Rule
+ @JvmField
+ var rule = ActivityTestRule(FeatureOverviewActivity::class.java)
- @Test
- fun offlineMergeListDeleteTest() {
- validateTestSetup()
+ private val context: Context by lazy { rule.activity }
- invoke(mapboxMap) { _: UiController, _: MapboxMap ->
- offlineIdlingResource.increment()
+ @Test(timeout = 30_000)
+ fun a_copyFileFromAssets() {
+ val latch = CountDownLatch(1)
+ rule.runOnUiThread {
FileUtils.CopyFileFromAssetsTask(rule.activity, object : FileUtils.OnFileCopiedFromAssetsListener {
override fun onFileCopiedFromAssets() {
- OfflineManager.getInstance(context).mergeOfflineRegions(
- FileSource.getResourcesCachePath(rule.activity) + "/" + TEST_DB_FILE_NAME,
- object : OfflineManager.MergeOfflineRegionsCallback {
- override fun onMerge(offlineRegions: Array<out OfflineRegion>?) {
- assert(offlineRegions?.size == 1)
- offlineIdlingResource.decrement()
- }
-
- override fun onError(error: String?) {
- throw RuntimeException("Unable to merge external offline database. $error")
- }
- })
+ latch.countDown()
}
override fun onError() {
@@ -61,43 +45,62 @@ class OfflineManagerTest : EspressoTest() {
}
}).execute(TEST_DB_FILE_NAME, FileSource.getResourcesCachePath(rule.activity))
}
+ latch.await()
+ }
+
+ @Test(timeout = 30_000)
+ fun b_mergeRegion() {
+ val latch = CountDownLatch(1)
+ rule.runOnUiThread {
+ OfflineManager.getInstance(context).mergeOfflineRegions(
+ FileSource.getResourcesCachePath(rule.activity) + "/" + TEST_DB_FILE_NAME,
+ object : OfflineManager.MergeOfflineRegionsCallback {
+ override fun onMerge(offlineRegions: Array<out OfflineRegion>?) {
+ assert(offlineRegions?.size == 1)
+ latch.countDown()
+ }
+
+ override fun onError(error: String?) {
+ throw RuntimeException("Unable to merge external offline database. $error")
+ }
+ })
+ }
+ latch.await()
+ }
- invoke(mapboxMap) { _: UiController, _: MapboxMap ->
- offlineIdlingResource.increment()
+ @Test(timeout = 30_000)
+ fun c_listRegion() {
+ val latch = CountDownLatch(1)
+ rule.runOnUiThread {
OfflineManager.getInstance(context).listOfflineRegions(object : OfflineManager.ListOfflineRegionsCallback {
override fun onList(offlineRegions: Array<out OfflineRegion>?) {
assert(offlineRegions?.size == 1)
- if (offlineRegions != null) {
- for (region in offlineRegions) {
- offlineIdlingResource.increment()
- region.delete(object : OfflineRegion.OfflineRegionDeleteCallback {
- override fun onDelete() {
- offlineIdlingResource.decrement()
- }
-
- override fun onError(error: String?) {
- throw RuntimeException("Unable to delete region with ID: ${region.id}. $error")
- }
- })
- }
- } else {
- throw RuntimeException("Unable to find merged region.")
- }
- offlineIdlingResource.decrement()
+ mergedRegion = offlineRegions!![0]
+ latch.countDown()
}
override fun onError(error: String?) {
- throw RuntimeException("Unable to obtain offline regions list. $error")
+ throw RuntimeException("Unable to merge external offline database. $error")
}
})
}
-
- // waiting for offline idling resource
- Espresso.onIdle()
+ latch.await()
}
- override fun afterTest() {
- super.afterTest()
- IdlingRegistry.getInstance().unregister(offlineIdlingResource)
+ @Test(timeout = 30_000)
+ fun d_deleteRegion() {
+ val latch = CountDownLatch(1)
+ rule.runOnUiThread {
+ mergedRegion.delete(object : OfflineRegion.OfflineRegionDeleteCallback {
+ override fun onDelete() {
+ latch.countDown()
+ }
+
+ override fun onError(error: String?) {
+ throw RuntimeException("Unable to delete region")
+ }
+ })
+ }
+ latch.await()
}
} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CustomGeometrySourceTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CustomGeometrySourceTest.kt
index eb458ab8f5..a6238ebf14 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CustomGeometrySourceTest.kt
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CustomGeometrySourceTest.kt
@@ -6,8 +6,9 @@ import com.mapbox.mapboxsdk.style.sources.CustomGeometrySource
import com.mapbox.mapboxsdk.style.sources.CustomGeometrySource.THREAD_POOL_LIMIT
import com.mapbox.mapboxsdk.style.sources.CustomGeometrySource.THREAD_PREFIX
import com.mapbox.mapboxsdk.testapp.action.MapboxMapAction.invoke
-import com.mapbox.mapboxsdk.testapp.action.OrientationChangeAction.orientationLandscape
-import com.mapbox.mapboxsdk.testapp.action.OrientationChangeAction.orientationPortrait
+import com.mapbox.mapboxsdk.testapp.action.OrientationAction.orientationLandscape
+import com.mapbox.mapboxsdk.testapp.action.OrientationAction.orientationPortrait
+import com.mapbox.mapboxsdk.testapp.action.WaitAction
import com.mapbox.mapboxsdk.testapp.activity.BaseTest
import com.mapbox.mapboxsdk.testapp.activity.style.GridSourceActivity
import com.mapbox.mapboxsdk.testapp.activity.style.GridSourceActivity.ID_GRID_LAYER
@@ -25,11 +26,11 @@ class CustomGeometrySourceTest : BaseTest() {
@Ignore
fun sourceNotLeakingThreadsTest() {
validateTestSetup()
- waitAction(4000)
+ WaitAction.invoke(4000)
onView(isRoot()).perform(orientationLandscape())
- waitAction(2000)
+ WaitAction.invoke(2000)
onView(isRoot()).perform(orientationPortrait())
- waitAction(2000)
+ WaitAction.invoke(2000)
Assert.assertFalse("Threads should be shutdown when the source is destroyed.",
Thread.getAllStackTraces().keys.filter {
it.name.startsWith(THREAD_PREFIX)
@@ -42,9 +43,9 @@ class CustomGeometrySourceTest : BaseTest() {
validateTestSetup()
invoke(mapboxMap) { uiController, mapboxMap ->
mapboxMap.style!!.removeLayer(ID_GRID_LAYER)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
mapboxMap.style!!.removeSource(ID_GRID_SOURCE)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
Assert.assertTrue("There should be no threads running when the source is removed.",
Thread.getAllStackTraces().keys.filter {
it.name.startsWith(CustomGeometrySource.THREAD_PREFIX)
@@ -58,12 +59,12 @@ class CustomGeometrySourceTest : BaseTest() {
validateTestSetup()
invoke(mapboxMap) { uiController, mapboxMap ->
mapboxMap.style!!.removeLayer((rule.activity as GridSourceActivity).layer)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
mapboxMap.style!!.removeSource(ID_GRID_SOURCE)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
mapboxMap.style!!.addSource((rule.activity as GridSourceActivity).source)
mapboxMap.style!!.addLayer((rule.activity as GridSourceActivity).layer)
- TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView)
+ TestingAsyncUtils.waitForLayer(uiController, mapView)
Assert.assertTrue("Threads should be restarted when the source is re-added to the map.",
Thread.getAllStackTraces().keys.filter {
it.name.startsWith(CustomGeometrySource.THREAD_PREFIX)
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ExpressionTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ExpressionTest.java
index 75dcbf1209..ff3b2a9d6d 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ExpressionTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ExpressionTest.java
@@ -252,7 +252,7 @@ public class ExpressionTest extends EspressoTest {
)
));
mapboxMap.getStyle().addLayer(layer);
- TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView());
+ TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer")
.isEmpty());
@@ -262,7 +262,7 @@ public class ExpressionTest extends EspressoTest {
literal(ColorUtils.colorToRgbaString(Color.RED))
)
));
- TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView());
+ TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer")
.isEmpty());
@@ -272,7 +272,7 @@ public class ExpressionTest extends EspressoTest {
literal(ColorUtils.colorToRgbaString(Color.RED))
)
));
- TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView());
+ TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer")
.isEmpty());
});
@@ -292,7 +292,7 @@ public class ExpressionTest extends EspressoTest {
formatEntry("test")
);
layer.setProperties(textField(expression));
- TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView());
+ TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer")
.isEmpty());
@@ -315,7 +315,7 @@ public class ExpressionTest extends EspressoTest {
formatEntry("test", formatFontScale(1.75))
);
layer.setProperties(textField(expression));
- TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView());
+ TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer")
.isEmpty());
@@ -341,7 +341,7 @@ public class ExpressionTest extends EspressoTest {
)
);
layer.setProperties(textField(expression));
- TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView());
+ TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
assertFalse(
mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer").isEmpty()
@@ -371,7 +371,7 @@ public class ExpressionTest extends EspressoTest {
)
);
layer.setProperties(textField(expression));
- TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView());
+ TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
assertFalse(
mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer").isEmpty()
@@ -402,7 +402,7 @@ public class ExpressionTest extends EspressoTest {
)
);
layer.setProperties(textField(expression));
- TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView());
+ TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
assertFalse(
mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer").isEmpty()
@@ -436,7 +436,7 @@ public class ExpressionTest extends EspressoTest {
formatEntry("\ntest2", formatFontScale(2), formatTextColor(Color.BLUE))
);
layer.setProperties(textField(expression));
- TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView());
+ TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
assertFalse(
mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer").isEmpty()
@@ -472,7 +472,7 @@ public class ExpressionTest extends EspressoTest {
)
);
layer.setProperties(textField(expression));
- TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView());
+ TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer")
.isEmpty());
@@ -504,7 +504,7 @@ public class ExpressionTest extends EspressoTest {
formatEntry("\ntest2", formatFontScale(2))
);
layer.setProperties(textField(expression), textColor("rgba(128, 0, 0, 1)"));
- TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView());
+ TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer")
.isEmpty());
@@ -524,7 +524,7 @@ public class ExpressionTest extends EspressoTest {
mapboxMap.getStyle().addLayer(layer);
layer.setProperties(textField("test"));
- TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView());
+ TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer")
.isEmpty());
@@ -550,7 +550,7 @@ public class ExpressionTest extends EspressoTest {
new FormattedSection("test", null, null, "rgba(0, 255, 0, 1)")
);
layer.setProperties(textField(formatted), textColor("rgba(128, 0, 0, 1)"));
- TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView());
+ TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer")
.isEmpty());
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
index 92d060fee4..99e0ae4016 100644
--- 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
@@ -94,7 +94,7 @@ public class GeoJsonSourceTests extends EspressoTest {
}
source.setGeoJson(Point.fromLngLat(20, 55));
- TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView());
+ TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
assertEquals(1, mapboxMap.queryRenderedFeatures(
mapboxMap.getProjection().toScreenLocation(
new LatLng(55, 20)), "layer").size());
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ImageTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ImageTest.java
deleted file mode 100644
index 0e4c8f3f2e..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ImageTest.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.mapbox.mapboxsdk.testapp.style;
-
-import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.support.test.runner.AndroidJUnit4;
-
-import com.mapbox.mapboxsdk.testapp.R;
-import com.mapbox.mapboxsdk.testapp.action.MapboxMapAction;
-
-import com.mapbox.mapboxsdk.testapp.activity.EspressoTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-/**
- * CRUD tests around Image
- */
-@RunWith(AndroidJUnit4.class)
-public class ImageTest extends EspressoTest {
-
- private static final String IMAGE_ID = "test.image";
-
- @Test
- public void testAddGetImage() {
- validateTestSetup();
- MapboxMapAction.invoke(mapboxMap, (uiController, mapboxMap) -> {
- Drawable drawable = rule.getActivity().getResources().getDrawable(R.drawable.ic_launcher_round);
- assertTrue(drawable instanceof BitmapDrawable);
-
- Bitmap bitmapSet = ((BitmapDrawable) drawable).getBitmap();
- mapboxMap.getStyle().addImage(IMAGE_ID, bitmapSet);
-
- // adding an image requires converting the image with an asynctask
- uiController.loopMainThreadForAtLeast(200);
-
- Bitmap bitmapGet = mapboxMap.getStyle().getImage(IMAGE_ID);
- assertTrue(bitmapGet.sameAs(bitmapSet));
-
- mapboxMap.getStyle().removeImage(IMAGE_ID);
- assertNull(mapboxMap.getStyle().getImage(IMAGE_ID));
- });
- }
-}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ImageTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ImageTest.kt
new file mode 100644
index 0000000000..9cef677e7c
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ImageTest.kt
@@ -0,0 +1,75 @@
+package com.mapbox.mapboxsdk.testapp.style
+
+import android.graphics.Bitmap
+import android.graphics.drawable.BitmapDrawable
+import android.support.test.runner.AndroidJUnit4
+import com.mapbox.mapboxsdk.testapp.R
+import com.mapbox.mapboxsdk.testapp.action.MapboxMapAction
+import com.mapbox.mapboxsdk.testapp.activity.EspressoTest
+import org.junit.Assert.assertNull
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+import java.util.*
+
+/**
+ * CRUD tests around Image
+ */
+@RunWith(AndroidJUnit4::class)
+class ImageTest : EspressoTest() {
+
+ companion object {
+ private const val IMAGE_ID = "test.image"
+ }
+
+ @Test
+ fun testAddGetImage() {
+ validateTestSetup()
+ MapboxMapAction.invoke(mapboxMap) { uiController, mapboxMap ->
+ val drawable = rule.activity.resources.getDrawable(R.drawable.ic_launcher_round)
+ assertTrue(drawable is BitmapDrawable)
+
+ val bitmapSet = (drawable as BitmapDrawable).bitmap
+ mapboxMap.style!!.addImage(IMAGE_ID, bitmapSet)
+
+ // adding an image requires converting the image with an asynctask
+ uiController.loopMainThreadForAtLeast(200)
+
+ val bitmapGet = mapboxMap.style!!.getImage(IMAGE_ID)
+ assertTrue(bitmapGet!!.similarTo(bitmapSet))
+
+ mapboxMap.style!!.removeImage(IMAGE_ID)
+ assertNull(mapboxMap.style!!.getImage(IMAGE_ID))
+ }
+ }
+}
+
+/**
+ * Alternative implementation of Bitmap.sameAs #14060
+ */
+fun Bitmap.similarTo(other: Bitmap): Boolean {
+ if (invalidConfig(other)) {
+ return false
+ }
+
+ // Allocate arrays
+ val argb = IntArray(width * height)
+ val argbOther = IntArray(other.width * other.height)
+ getPixels(argb, 0, width, 0, 0, width, height)
+ other.getPixels(argbOther, 0, width, 0, 0, width, height)
+
+ // Alpha channel special check
+ if (config == Bitmap.Config.ALPHA_8) {
+ // in this case we have to manually compare the alpha channel as the rest is garbage.
+ val length = width * height
+ for (i in 0 until length) {
+ if (argb[i] and -0x1000000 != argbOther[i] and -0x1000000) {
+ return false
+ }
+ }
+ return true
+ }
+ return Arrays.equals(argb, argbOther)
+}
+
+fun Bitmap.invalidConfig(other: Bitmap): Boolean = this.config != other.config || this.width != other.width || this.height != other.height \ No newline at end of file
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 ed39f36e32..a4a34e752e 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
@@ -2,12 +2,10 @@ package com.mapbox.mapboxsdk.testapp.style;
import android.graphics.Color;
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.runner.AndroidJUnit4;
import android.view.View;
-
import com.mapbox.mapboxsdk.style.layers.CannotAddLayerException;
import com.mapbox.mapboxsdk.style.layers.CircleLayer;
import com.mapbox.mapboxsdk.style.layers.FillLayer;
@@ -22,20 +20,16 @@ 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.EspressoTest;
-
import junit.framework.Assert;
-
import org.hamcrest.Matcher;
-import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
+import timber.log.Timber;
import java.net.MalformedURLException;
import java.net.URL;
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;
@@ -366,11 +360,6 @@ public class RuntimeStyleTests extends EspressoTest {
}
}
- @After
- public void unregisterIntentServiceIdlingResource() {
- Espresso.unregisterIdlingResources(idlingResource);
- }
-
public abstract class BaseViewAction implements ViewAction {
@Override
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 149064d684..ae2c6d98f6 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
@@ -559,7 +559,7 @@ public class SymbolLayerTest extends BaseLayerTest {
assertNull(layer.getTextJustify().getValue());
// Set and Get
- String propertyValue = TEXT_JUSTIFY_LEFT;
+ String propertyValue = TEXT_JUSTIFY_AUTO;
layer.setProperties(textJustify(propertyValue));
assertEquals(layer.getTextJustify().getValue(), propertyValue);
}
@@ -579,6 +579,32 @@ public class SymbolLayerTest extends BaseLayerTest {
@Test
@UiThreadTest
+ public void testTextRadialOffsetAsConstant() {
+ Timber.i("text-radial-offset");
+ assertNotNull(layer);
+ assertNull(layer.getTextRadialOffset().getValue());
+
+ // Set and Get
+ Float propertyValue = 0.3f;
+ layer.setProperties(textRadialOffset(propertyValue));
+ assertEquals(layer.getTextRadialOffset().getValue(), propertyValue);
+ }
+
+ @Test
+ @UiThreadTest
+ public void testTextVariableAnchorAsConstant() {
+ Timber.i("text-variable-anchor");
+ assertNotNull(layer);
+ assertNull(layer.getTextVariableAnchor().getValue());
+
+ // Set and Get
+ String[] propertyValue = new String[0];
+ layer.setProperties(textVariableAnchor(propertyValue));
+ assertEquals(layer.getTextVariableAnchor().getValue(), propertyValue);
+ }
+
+ @Test
+ @UiThreadTest
public void testTextAnchorAsConstant() {
Timber.i("text-anchor");
assertNotNull(layer);
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/FinishLoadingStyleIdlingResource.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/FinishLoadingStyleIdlingResource.java
deleted file mode 100644
index 323d2c0f15..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/FinishLoadingStyleIdlingResource.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.mapbox.mapboxsdk.testapp.utils;
-
-import android.app.Activity;
-import android.os.Handler;
-import android.os.Looper;
-import android.support.annotation.WorkerThread;
-import com.mapbox.mapboxsdk.maps.MapboxMap;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-public class FinishLoadingStyleIdlingResource extends MapboxIdlingResource {
-
- @WorkerThread
- public FinishLoadingStyleIdlingResource(final Activity activity) {
- new Handler(Looper.getMainLooper()).post(() -> inflateMap(activity));
- }
-
- @Override
- public void initMap(MapboxMap mapboxMap) {
- super.initMap(mapboxMap);
- mapboxMap.getStyle(style -> {
- assertNotNull(style);
- assertTrue(style.isFullyLoaded());
- if (resourceCallback != null) {
- resourceCallback.onTransitionToIdle();
- }
- });
- }
-
- @Override
- public boolean isIdleNow() {
- return getMapboxMap() != null && getMapboxMap().getStyle() != null;
- }
-} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/LoadStyleIdlingResource.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/LoadStyleIdlingResource.java
deleted file mode 100644
index 5dead21fbb..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/LoadStyleIdlingResource.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package com.mapbox.mapboxsdk.testapp.utils;
-
-import android.app.Activity;
-import android.os.Handler;
-import android.os.Looper;
-import android.support.annotation.UiThread;
-import android.support.annotation.WorkerThread;
-import com.mapbox.mapboxsdk.maps.MapboxMap;
-import com.mapbox.mapboxsdk.maps.Style;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-public class LoadStyleIdlingResource extends MapboxIdlingResource {
-
- private Style style;
-
- @WorkerThread
- public LoadStyleIdlingResource(final Activity activity) {
- new Handler(Looper.getMainLooper()).post(() -> inflateMap(activity));
- }
-
- @UiThread
- public void initMap(MapboxMap mapboxMap) {
- super.initMap(mapboxMap);
- mapboxMap.setStyle("asset://streets.json", style -> {
- assertNotNull(style);
- assertTrue(style.isFullyLoaded());
- this.style = style;
- if (resourceCallback != null) {
- resourceCallback.onTransitionToIdle();
- }
- });
- }
-
- @Override
- public boolean isIdleNow() {
- return style != null;
- }
-} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/MapboxIdlingResource.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/MapboxIdlingResource.java
deleted file mode 100644
index a05221d618..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/MapboxIdlingResource.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.mapbox.mapboxsdk.testapp.utils;
-
-import android.app.Activity;
-import android.support.annotation.UiThread;
-import android.support.test.espresso.IdlingResource;
-import com.mapbox.mapboxsdk.maps.MapView;
-import com.mapbox.mapboxsdk.maps.MapboxMap;
-import com.mapbox.mapboxsdk.testapp.R;
-
-public abstract class MapboxIdlingResource implements IdlingResource {
-
- private MapView mapView;
- private MapboxMap mapboxMap;
- IdlingResource.ResourceCallback resourceCallback;
-
- @UiThread
- void inflateMap(Activity activity) {
- mapView = activity.findViewById(R.id.mapView);
- if (mapView != null) {
- mapView.getMapAsync(this::initMap);
- }
- }
-
- @UiThread
- protected void initMap(MapboxMap mapboxMap) {
- this.mapboxMap = mapboxMap;
- }
-
- @Override
- public String getName() {
- return getClass().getSimpleName();
- }
-
- @Override
- public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
- this.resourceCallback = resourceCallback;
- }
-
- public MapboxMap getMapboxMap() {
- return mapboxMap;
- }
-
- public MapView getMapView() {
- return mapView;
- }
-} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/OnMapReadyIdlingResource.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/OnMapReadyIdlingResource.java
deleted file mode 100644
index 7696447289..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/OnMapReadyIdlingResource.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package com.mapbox.mapboxsdk.testapp.utils;
-
-import android.app.Activity;
-import android.os.Handler;
-import android.os.Looper;
-import android.support.annotation.WorkerThread;
-import android.support.test.espresso.IdlingResource;
-
-import com.mapbox.mapboxsdk.maps.MapView;
-import com.mapbox.mapboxsdk.maps.MapboxMap;
-import com.mapbox.mapboxsdk.maps.Style;
-import com.mapbox.mapboxsdk.testapp.R;
-
-public class OnMapReadyIdlingResource implements IdlingResource {
-
- private boolean styleLoaded;
- private MapboxMap mapboxMap;
- private IdlingResource.ResourceCallback resourceCallback;
-
- @WorkerThread
- public OnMapReadyIdlingResource(final Activity activity) {
- Handler handler = new Handler(Looper.getMainLooper());
- handler.post(() -> {
- MapView mapView = activity.findViewById(R.id.mapView);
- if (mapView != null) {
- mapView.addOnDidFinishLoadingStyleListener(() -> {
- styleLoaded = true;
- if (resourceCallback != null) {
- resourceCallback.onTransitionToIdle();
- }
- });
- mapView.getMapAsync(this::initMap);
- }
- });
- }
-
- private void initMap(MapboxMap mapboxMap) {
- this.mapboxMap = mapboxMap;
- mapboxMap.setStyle(new Style.Builder().fromUrl("asset://streets.json"));
- }
-
- @Override
- public String getName() {
- return getClass().getSimpleName();
- }
-
- @Override
- public boolean isIdleNow() {
- return styleLoaded;
- }
-
- @Override
- public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
- this.resourceCallback = resourceCallback;
- }
-
- public MapboxMap getMapboxMap() {
- return mapboxMap;
- }
-} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
index 2fa26f822a..017fe3ddca 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
@@ -173,10 +173,11 @@
<activity
android:name=".activity.fragment.FragmentBackStackActivity"
android:description="@string/description_map_fragment_backstack"
- android:label="@string/activity_map_fragment_backstack">
+ android:label="@string/activity_map_fragment_backstack"
+ android:launchMode="singleInstance">
<meta-data
android:name="@string/category"
- android:value="@string/category_fragment" />
+ android:value="@string/category_integration" />
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".activity.FeatureOverviewActivity" />
@@ -399,7 +400,7 @@
android:label="@string/activity_viewpager">
<meta-data
android:name="@string/category"
- android:value="@string/category_fragment" />
+ android:value="@string/category_integration" />
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".activity.FeatureOverviewActivity" />
@@ -407,7 +408,8 @@
<activity
android:name=".activity.maplayout.SimpleMapActivity"
android:description="@string/description_simple_map"
- android:label="@string/activity_simple_map">
+ android:label="@string/activity_simple_map"
+ android:launchMode="singleInstance">
<meta-data
android:name="@string/category"
android:value="@string/category_basic" />
@@ -720,7 +722,8 @@
<activity
android:name=".activity.textureview.TextureViewDebugModeActivity"
android:description="@string/description_textureview_debug"
- android:label="@string/activity_textureview_debug">
+ android:label="@string/activity_textureview_debug"
+ android:launchMode="singleInstance">
<meta-data
android:name="@string/category"
android:value="@string/category_basic" />
@@ -895,27 +898,49 @@
android:value=".activity.FeatureOverviewActivity" />
</activity>
<activity
- android:name=".activity.maplayout.RecyclerViewActivity"
- android:description="@string/description_recyclerview"
- android:label="@string/activity_recyclerview">
+ android:name=".activity.maplayout.TextureRecyclerViewActivity"
+ android:description="@string/description_recyclerview_textureview"
+ android:label="@string/activity_recyclerview_textureview">
<meta-data
android:name="@string/category"
- android:value="@string/category_maplayout" />
+ android:value="@string/category_integration" />
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity" />
+ </activity>
+ <activity
+ android:name=".activity.maplayout.GLSurfaceRecyclerViewActivity"
+ android:description="@string/description_recyclerview_glsurfaceview"
+ android:label="@string/activity_recyclerview_glsurfaceview">
+ <meta-data
+ android:name="@string/category"
+ android:value="@string/category_integration" />
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".activity.FeatureOverviewActivity" />
</activity>
<activity
android:name=".activity.fragment.NestedViewPagerActivity"
- android:description="@string/description_recyclerview"
+ android:description="@string/description_nested_viewpager"
android:label="@string/activity_nested_viewpager">
<meta-data
android:name="@string/category"
- android:value="@string/category_fragment" />
+ android:value="@string/category_integration" />
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".activity.FeatureOverviewActivity" />
</activity>
+ <activity
+ android:name=".activity.telemetry.PerformanceMeasurementActivity"
+ android:description="@string/description_performance_measurement"
+ android:label="@string/activity_performance_measurement">
+ <meta-data
+ android:name="@string/category"
+ android:value="@string/category_telemetry" />
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity" />
+ </activity>
<!-- For Instrumentation tests -->
<activity
android:name=".activity.style.RuntimeStyleTimingTestActivity"
@@ -924,6 +949,9 @@
android:name=".activity.espresso.EspressoTestActivity"
android:screenOrientation="portrait" />
<activity
+ android:name=".activity.espresso.PixelTestActivity"
+ android:screenOrientation="portrait" />
+ <activity
android:name=".activity.espresso.DeviceIndependentTestActivity"
android:screenOrientation="portrait" />
<activity
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 9ade97f91e..d5cff301db 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
@@ -40,7 +40,7 @@ public class MapboxApplication extends Application {
initializeMapbox();
}
- private boolean initializeLeakCanary() {
+ protected boolean initializeLeakCanary() {
if (LeakCanary.isInAnalyzerProcess(this)) {
// This process is dedicated to LeakCanary for heap analysis.
// You should not init your app in this process.
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/GestureDetectorActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/GestureDetectorActivity.java
index f4639b0f1a..ed5364655e 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/GestureDetectorActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/GestureDetectorActivity.java
@@ -267,7 +267,18 @@ public class GestureDetectorActivity extends AppCompatActivity {
if (enabled) {
focalPointLatLng = new LatLng(51.50325, -0.12968);
marker = mapboxMap.addMarker(new MarkerOptions().position(focalPointLatLng));
- mapboxMap.easeCamera(CameraUpdateFactory.newLatLngZoom(focalPointLatLng, 16));
+ mapboxMap.easeCamera(CameraUpdateFactory.newLatLngZoom(focalPointLatLng, 16),
+ new MapboxMap.CancelableCallback() {
+ @Override
+ public void onCancel() {
+ recalculateFocalPoint();
+ }
+
+ @Override
+ public void onFinish() {
+ recalculateFocalPoint();
+ }
+ });
} else {
if (marker != null) {
mapboxMap.removeMarker(marker);
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/espresso/PixelTestActivity.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/espresso/PixelTestActivity.kt
new file mode 100644
index 0000000000..b69d1ee5ed
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/espresso/PixelTestActivity.kt
@@ -0,0 +1,66 @@
+package com.mapbox.mapboxsdk.testapp.activity.espresso
+
+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.maps.Style
+import com.mapbox.mapboxsdk.testapp.R
+
+/**
+ * Test activity used for instrumentation tests that require a specific device size.
+ */
+class PixelTestActivity : AppCompatActivity(), OnMapReadyCallback {
+
+ lateinit var mapView: MapView
+ lateinit var mapboxMap: MapboxMap
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_pixel_test)
+ mapView = findViewById(R.id.mapView)
+ mapView.onCreate(savedInstanceState)
+ mapView.getMapAsync(this)
+ }
+
+ override fun onMapReady(map: MapboxMap) {
+ mapboxMap = map
+ mapboxMap.setStyle(Style.MAPBOX_STREETS)
+ }
+
+ public override fun onResume() {
+ super.onResume()
+ mapView.onResume()
+ }
+
+ override fun onStart() {
+ super.onStart()
+ mapView.onStart()
+ }
+
+ public override fun onPause() {
+ super.onPause()
+ mapView.onPause()
+ }
+
+ override fun onStop() {
+ super.onStop()
+ mapView.onStop()
+ }
+
+ override fun onSaveInstanceState(outState: Bundle) {
+ super.onSaveInstanceState(outState)
+ mapView.onSaveInstanceState(outState)
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ mapView.onDestroy()
+ }
+
+ override fun onLowMemory() {
+ super.onLowMemory()
+ mapView.onLowMemory()
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MapFragmentActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MapFragmentActivity.java
index 472b9b7d57..c7f530b123 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MapFragmentActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MapFragmentActivity.java
@@ -3,16 +3,15 @@ package com.mapbox.mapboxsdk.testapp.activity.fragment;
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.maps.Style;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapFragment;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.MapboxMapOptions;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
+import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.testapp.R;
/**
@@ -24,6 +23,7 @@ import com.mapbox.mapboxsdk.testapp.R;
public class MapFragmentActivity extends AppCompatActivity implements MapFragment.OnMapViewReadyCallback,
OnMapReadyCallback, MapView.OnDidFinishRenderingFrameListener {
+ private static final String TAG = "com.mapbox.map";
private MapboxMap mapboxMap;
private MapView mapView;
private boolean initialCameraAnimation = true;
@@ -32,14 +32,18 @@ public class MapFragmentActivity extends AppCompatActivity implements MapFragmen
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map_fragment);
+
+ MapFragment mapFragment;
if (savedInstanceState == null) {
- MapFragment mapFragment = MapFragment.newInstance(createFragmentOptions());
+ mapFragment = MapFragment.newInstance(createFragmentOptions());
getFragmentManager()
.beginTransaction()
- .add(R.id.fragment_container, mapFragment, "com.mapbox.map")
+ .add(R.id.fragment_container, mapFragment, TAG)
.commit();
- mapFragment.getMapAsync(this);
+ } else {
+ mapFragment = (MapFragment) getFragmentManager().findFragmentByTag(TAG);
}
+ mapFragment.getMapAsync(this);
}
private MapboxMapOptions createFragmentOptions() {
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/SupportMapFragmentActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/SupportMapFragmentActivity.java
index 4baf40d51b..7fd84bcd25 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/SupportMapFragmentActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/SupportMapFragmentActivity.java
@@ -3,16 +3,15 @@ package com.mapbox.mapboxsdk.testapp.activity.fragment;
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.maps.Style;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapFragment;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.MapboxMapOptions;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
+import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.maps.SupportMapFragment;
import com.mapbox.mapboxsdk.testapp.R;
@@ -25,6 +24,7 @@ import com.mapbox.mapboxsdk.testapp.R;
public class SupportMapFragmentActivity extends AppCompatActivity implements MapFragment.OnMapViewReadyCallback,
OnMapReadyCallback, MapView.OnDidFinishRenderingFrameListener {
+ private static final String TAG = "com.mapbox.map";
private MapboxMap mapboxMap;
private MapView mapView;
private boolean initialCameraAnimation = true;
@@ -33,14 +33,18 @@ public class SupportMapFragmentActivity extends AppCompatActivity implements Map
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map_fragment);
+ SupportMapFragment mapFragment;
if (savedInstanceState == null) {
- SupportMapFragment mapFragment = SupportMapFragment.newInstance(createFragmentOptions());
+ mapFragment = SupportMapFragment.newInstance(createFragmentOptions());
getSupportFragmentManager()
.beginTransaction()
- .add(R.id.fragment_container, mapFragment, "com.mapbox.map")
+ .add(R.id.fragment_container, mapFragment, TAG)
.commit();
- mapFragment.getMapAsync(this);
+ } else {
+ mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentByTag(TAG);
}
+ mapFragment.getMapAsync(this);
+
}
private MapboxMapOptions createFragmentOptions() {
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/ViewPagerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/ViewPagerActivity.java
deleted file mode 100644
index c494842b14..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/ViewPagerActivity.java
+++ /dev/null
@@ -1,117 +0,0 @@
-package com.mapbox.mapboxsdk.testapp.activity.fragment;
-
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentStatePagerAdapter;
-import android.support.v4.view.ViewPager;
-import android.support.v7.app.AppCompatActivity;
-
-import com.mapbox.mapboxsdk.camera.CameraPosition;
-import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.maps.MapboxMapOptions;
-import com.mapbox.mapboxsdk.maps.Style;
-import com.mapbox.mapboxsdk.maps.SupportMapFragment;
-import com.mapbox.mapboxsdk.testapp.R;
-
-/**
- * Test activity showcasing using the Android SDK ViewPager API to show MapFragments.
- */
-public class ViewPagerActivity extends AppCompatActivity {
-
- private ViewPager viewPager;
- private MapFragmentAdapter adapter;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_viewpager);
-
- viewPager = (ViewPager) findViewById(R.id.viewpager);
- if (viewPager != null) {
- adapter = new MapFragmentAdapter(getSupportFragmentManager());
- viewPager.setAdapter(adapter);
- }
- }
-
- @Override
- protected void onRestoreInstanceState(Bundle savedInstanceState) {
- super.onRestoreInstanceState(savedInstanceState);
-
- int currentPosition = viewPager.getCurrentItem();
- SupportMapFragment mapFragment;
-
- if (Math.abs(0 - currentPosition) <= 1) {
- mapFragment = (SupportMapFragment) adapter.instantiateItem(viewPager, 0);
- mapFragment.getMapAsync(mapboxMap -> {
- mapboxMap.setStyle(Style.MAPBOX_STREETS);
- });
- }
-
- if (Math.abs(1 - currentPosition) <= 1) {
- mapFragment = (SupportMapFragment) adapter.instantiateItem(viewPager, 1);
- mapFragment.getMapAsync(mapboxMap -> {
- mapboxMap.setStyle(Style.DARK);
- });
- }
-
- if (Math.abs(2 - currentPosition) <= 1) {
- mapFragment = (SupportMapFragment) adapter.instantiateItem(viewPager, 2);
- mapFragment.getMapAsync(mapboxMap -> {
- mapboxMap.setStyle(Style.SATELLITE);
- });
- }
- }
-
- static class MapFragmentAdapter extends FragmentStatePagerAdapter {
-
- private static int NUM_ITEMS = 3;
-
- MapFragmentAdapter(FragmentManager fragmentManager) {
- super(fragmentManager);
- }
-
- @Override
- public int getCount() {
- return NUM_ITEMS;
- }
-
- @Override
- public Fragment getItem(int position) {
- SupportMapFragment fragment = null;
- MapboxMapOptions options = new MapboxMapOptions();
- options.textureMode(true);
-
- switch (position) {
- case 0:
- options.camera(new CameraPosition.Builder().target(new LatLng(34.920526, 102.634774)).zoom(3).build());
- fragment = SupportMapFragment.newInstance(options);
- fragment.getMapAsync(mapboxMap -> {
- mapboxMap.setStyle(Style.MAPBOX_STREETS);
- });
- break;
- case 1:
- options.camera(new CameraPosition.Builder().target(new LatLng(62.326440, 92.764913)).zoom(3).build());
- fragment = SupportMapFragment.newInstance(options);
- fragment.getMapAsync(mapboxMap -> {
- mapboxMap.setStyle(Style.DARK);
- });
- break;
- case 2:
- options.camera(new CameraPosition.Builder().target(new LatLng(-25.007786, 133.623852)).zoom(3).build());
- fragment = SupportMapFragment.newInstance(options);
- fragment.getMapAsync(mapboxMap -> {
- mapboxMap.setStyle(Style.SATELLITE);
- });
- break;
- }
- return fragment;
- }
-
- @Override
- public CharSequence getPageTitle(int position) {
- return "Page " + position;
- }
- }
-}
-
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/ViewPagerActivity.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/ViewPagerActivity.kt
new file mode 100644
index 0000000000..77e2e1370d
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/ViewPagerActivity.kt
@@ -0,0 +1,109 @@
+package com.mapbox.mapboxsdk.testapp.activity.fragment
+
+import android.os.Bundle
+import android.support.v4.app.Fragment
+import android.support.v4.app.FragmentManager
+import android.support.v4.app.FragmentStatePagerAdapter
+import android.support.v7.app.AppCompatActivity
+import com.mapbox.mapboxsdk.camera.CameraPosition
+import com.mapbox.mapboxsdk.geometry.LatLng
+import com.mapbox.mapboxsdk.maps.MapboxMapOptions
+import com.mapbox.mapboxsdk.maps.Style
+import com.mapbox.mapboxsdk.maps.SupportMapFragment
+import com.mapbox.mapboxsdk.testapp.R
+import kotlinx.android.synthetic.main.activity_viewpager.*
+
+/**
+ * Test activity showcasing using the Android SDK ViewPager API to show MapFragments.
+ */
+class ViewPagerActivity : AppCompatActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_viewpager)
+ viewPager.adapter = MapFragmentAdapter(supportFragmentManager)
+ }
+
+ override fun onRestoreInstanceState(savedInstanceState: Bundle) {
+ super.onRestoreInstanceState(savedInstanceState)
+
+ val currentPosition = viewPager.currentItem
+ var mapFragment: SupportMapFragment
+
+ if (Math.abs(0 - currentPosition) <= 1) {
+ mapFragment = viewPager.adapter?.instantiateItem(viewPager, 0) as SupportMapFragment
+ mapFragment.getMapAsync { mapboxMap -> mapboxMap.setStyle(Style.MAPBOX_STREETS) }
+ }
+
+ if (Math.abs(1 - currentPosition) <= 1) {
+ mapFragment = viewPager.adapter?.instantiateItem(viewPager, 1) as SupportMapFragment
+ mapFragment.getMapAsync { mapboxMap -> mapboxMap.setStyle(Style.DARK) }
+ }
+
+ if (Math.abs(2 - currentPosition) <= 1) {
+ mapFragment = viewPager.adapter?.instantiateItem(viewPager, 2) as SupportMapFragment
+ mapFragment.getMapAsync { mapboxMap -> mapboxMap.setStyle(Style.SATELLITE) }
+ }
+
+ if (Math.abs(3 - currentPosition) <= 1) {
+ mapFragment = viewPager.adapter?.instantiateItem(viewPager, 3) as SupportMapFragment
+ mapFragment.getMapAsync { mapboxMap -> mapboxMap.setStyle(Style.SATELLITE) }
+ }
+
+ if (Math.abs(4 - currentPosition) <= 1) {
+ mapFragment = viewPager.adapter?.instantiateItem(viewPager, 4) as SupportMapFragment
+ mapFragment.getMapAsync { mapboxMap -> mapboxMap.setStyle(Style.SATELLITE) }
+ }
+ }
+
+ internal class MapFragmentAdapter(fragmentManager: FragmentManager) : FragmentStatePagerAdapter(fragmentManager) {
+
+ override fun getCount(): Int {
+ return NUM_ITEMS
+ }
+
+ override fun getItem(position: Int): Fragment? {
+ var fragment: SupportMapFragment? = null
+ val options = MapboxMapOptions()
+ options.textureMode(true)
+
+ when (position) {
+ 0 -> {
+ options.camera(CameraPosition.Builder().target(LatLng(34.920526, 102.634774)).zoom(3.0).build())
+ fragment = SupportMapFragment.newInstance(options)
+ fragment.getMapAsync { mapboxMap -> mapboxMap.setStyle(Style.MAPBOX_STREETS) }
+ }
+ 1 -> {
+ options.camera(CameraPosition.Builder().target(LatLng(62.326440, 92.764913)).zoom(3.0).build())
+ fragment = SupportMapFragment.newInstance(options)
+ fragment.getMapAsync { mapboxMap -> mapboxMap.setStyle(Style.DARK) }
+ }
+ 2 -> {
+ options.camera(CameraPosition.Builder().target(LatLng(-25.007786, 133.623852)).zoom(3.0).build())
+ fragment = SupportMapFragment.newInstance(options)
+ fragment.getMapAsync { mapboxMap -> mapboxMap.setStyle(Style.SATELLITE) }
+ }
+ 3 -> {
+ options.camera(CameraPosition.Builder().target(LatLng(62.326440, 92.764913)).zoom(3.0).build())
+ fragment = SupportMapFragment.newInstance(options)
+ fragment.getMapAsync { mapboxMap -> mapboxMap.setStyle(Style.LIGHT) }
+ }
+ 4 -> {
+ options.camera(CameraPosition.Builder().target(LatLng(34.920526, 102.634774)).zoom(3.0).build())
+ fragment = SupportMapFragment.newInstance(options)
+ fragment.getMapAsync { mapboxMap -> mapboxMap.setStyle(Style.TRAFFIC_NIGHT) }
+ }
+ }
+ return fragment
+ }
+
+ override fun getPageTitle(position: Int): CharSequence? {
+ return "Page $position"
+ }
+
+ companion object {
+
+ private val NUM_ITEMS = 5
+ }
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/SnapshotActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/SnapshotActivity.java
deleted file mode 100644
index c1697ab960..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/SnapshotActivity.java
+++ /dev/null
@@ -1,114 +0,0 @@
-package com.mapbox.mapboxsdk.testapp.activity.imagegenerator;
-
-import android.graphics.Bitmap;
-import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.design.widget.FloatingActionButton;
-import android.support.v4.content.ContextCompat;
-import android.support.v7.app.AppCompatActivity;
-import android.view.View;
-import android.widget.ImageView;
-import android.widget.Toast;
-
-import com.mapbox.mapboxsdk.maps.Style;
-import com.mapbox.mapboxsdk.maps.MapView;
-import com.mapbox.mapboxsdk.maps.MapboxMap;
-import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
-import com.mapbox.mapboxsdk.testapp.R;
-
-import java.util.Locale;
-
-import timber.log.Timber;
-
-/**
- * Test activity showcasing the Snapshot API to create and display a bitmap of the current shown Map.
- */
-public class SnapshotActivity extends AppCompatActivity implements OnMapReadyCallback, View.OnClickListener {
-
- private MapView mapView;
- private MapboxMap mapboxMap;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_snapshot);
-
- mapView = (MapView) findViewById(R.id.mapView);
- mapView.onCreate(savedInstanceState);
- mapView.getMapAsync(this);
- }
-
- @Override
- public void onMapReady(@NonNull MapboxMap map) {
- mapboxMap = map;
- mapboxMap.setStyle(new Style.Builder().fromUrl(Style.OUTDOORS));
- FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
- if (fab != null) {
- fab.setColorFilter(ContextCompat.getColor(SnapshotActivity.this, R.color.primary));
- fab.setOnClickListener(this);
- }
- }
-
- @Override
- public void onClick(View view) {
- final long startTime = System.nanoTime();
- mapboxMap.snapshot(snapshot -> {
- long endTime = System.nanoTime();
- long duration = (long) ((endTime - startTime) / 1e6);
- ImageView snapshotView = (ImageView) findViewById(R.id.imageView);
- snapshotView.setImageBitmap(snapshot);
- Toast.makeText(
- SnapshotActivity.this,
- String.format(Locale.getDefault(), "Snapshot taken in %d ms", duration),
- Toast.LENGTH_LONG).show();
- });
- }
-
- @Override
- protected void onStart() {
- super.onStart();
- mapView.onStart();
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- mapView.onResume();
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- mapboxMap.snapshot(new MapboxMap.SnapshotReadyCallback() {
- @Override
- public void onSnapshotReady(Bitmap snapshot) {
- Timber.e("Regression test for https://github.com/mapbox/mapbox-gl-native/pull/11358");
- }
- });
- 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/imagegenerator/SnapshotActivity.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/SnapshotActivity.kt
new file mode 100644
index 0000000000..51b1c08ba5
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/SnapshotActivity.kt
@@ -0,0 +1,80 @@
+package com.mapbox.mapboxsdk.testapp.activity.imagegenerator
+
+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.maps.Style
+import com.mapbox.mapboxsdk.testapp.R
+import kotlinx.android.synthetic.main.activity_snapshot.*
+import timber.log.Timber
+
+/**
+ * Test activity showcasing the Snapshot API to create and display a bitmap of the current shown Map.
+ */
+class SnapshotActivity : AppCompatActivity(), OnMapReadyCallback {
+
+ private lateinit var mapboxMap: MapboxMap
+
+ private val idleListener = object : MapView.OnDidBecomeIdleListener {
+ override fun onDidBecomeIdle() {
+ mapView.removeOnDidBecomeIdleListener(this)
+ mapboxMap.snapshot { snapshot ->
+ imageView.setImageBitmap(snapshot)
+ mapView.addOnDidBecomeIdleListener(this)
+ }
+ }
+ }
+
+ public override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_snapshot)
+ mapView.onCreate(savedInstanceState)
+ mapView.getMapAsync(this)
+ }
+
+ override fun onMapReady(map: MapboxMap) {
+ mapboxMap = map
+ mapboxMap.setStyle(Style.Builder().fromUrl(Style.OUTDOORS)) { mapView.addOnDidBecomeIdleListener(idleListener) }
+ }
+
+ override fun onStart() {
+ super.onStart()
+ mapView.onStart()
+ }
+
+ override fun onResume() {
+ super.onResume()
+ mapView.onResume()
+ }
+
+ override fun onPause() {
+ super.onPause()
+ mapboxMap.snapshot {
+ Timber.e("Regression test for https://github.com/mapbox/mapbox-gl-native/pull/11358")
+ }
+ mapView.onPause()
+ }
+
+ override fun onStop() {
+ super.onStop()
+ mapView.onStop()
+ }
+
+ public override fun onSaveInstanceState(outState: Bundle) {
+ super.onSaveInstanceState(outState)
+ mapView.onSaveInstanceState(outState)
+ }
+
+ override fun onLowMemory() {
+ super.onLowMemory()
+ mapView.onLowMemory()
+ }
+
+ public override fun onDestroy() {
+ super.onDestroy()
+ mapView.removeOnDidBecomeIdleListener(idleListener)
+ mapView.onDestroy()
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/GLSurfaceRecyclerViewActivity.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/GLSurfaceRecyclerViewActivity.kt
new file mode 100644
index 0000000000..5acf356696
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/GLSurfaceRecyclerViewActivity.kt
@@ -0,0 +1,155 @@
+package com.mapbox.mapboxsdk.testapp.activity.maplayout
+
+import android.annotation.SuppressLint
+import android.os.Bundle
+import android.support.v7.app.AppCompatActivity
+import android.support.v7.widget.LinearLayoutManager
+import android.support.v7.widget.RecyclerView
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import android.widget.TextView
+import com.mapbox.mapboxsdk.maps.MapView
+import com.mapbox.mapboxsdk.maps.Style
+import com.mapbox.mapboxsdk.testapp.R
+import kotlinx.android.synthetic.main.activity_recyclerview.*
+
+/**
+ * TestActivity showcasing how to integrate a GLSurfaceView MapView in a RecyclerView.
+ * <p>
+ * It requires calling the correct lifecycle methods when detaching and attaching the View to
+ * the RecyclerView with onViewAttachedToWindow and onViewDetachedFromWindow.
+ * </p>
+ */
+@SuppressLint("ClickableViewAccessibility")
+open class GLSurfaceRecyclerViewActivity : AppCompatActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_recyclerview)
+ recyclerView.layoutManager = LinearLayoutManager(this)
+ recyclerView.adapter = ItemAdapter(this, LayoutInflater.from(this), savedInstanceState)
+ }
+
+ override fun onSaveInstanceState(outState: Bundle?) {
+ super.onSaveInstanceState(outState)
+ // to save state, we need to call MapView#onSaveInstanceState
+ (recyclerView.adapter as ItemAdapter).onSaveInstanceState(outState)
+ }
+
+ override fun onLowMemory() {
+ super.onLowMemory()
+ // to release memory, we need to call MapView#onLowMemory
+ (recyclerView.adapter as ItemAdapter).onLowMemory()
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ // to perform cleanup, we need to call MapView#onDestroy
+ (recyclerView.adapter as ItemAdapter).onDestroy()
+ }
+
+ open fun getMapItemLayoutId(): Int {
+ return R.layout.item_map_gl
+ }
+
+ class ItemAdapter(private val activity: GLSurfaceRecyclerViewActivity, private val inflater: LayoutInflater, val savedInstanceState: Bundle?) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
+
+ private val items = listOf(
+ "one", "two", "three", MapItem(), "four", "five", "six", "seven", "eight", "nine", "ten",
+ "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen",
+ "nineteen", "twenty", "twenty-one"
+ )
+
+ private var mapHolder: MapHolder? = null
+
+ companion object {
+ const val TYPE_MAP = 0
+ const val TYPE_TEXT = 1
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
+ return if (viewType == TYPE_MAP) {
+ val mapView = inflater.inflate(activity.getMapItemLayoutId(), parent, false) as MapView
+ mapView.getMapAsync { mapboxMap -> mapboxMap.setStyle(Style.MAPBOX_STREETS) }
+ mapHolder = MapHolder(mapView, savedInstanceState)
+ return mapHolder as MapHolder
+ } else {
+ TextHolder(inflater.inflate(android.R.layout.simple_list_item_1, parent, false) as TextView)
+ }
+ }
+
+ override fun onViewAttachedToWindow(holder: RecyclerView.ViewHolder) {
+ super.onViewAttachedToWindow(holder)
+ if (holder is MapHolder) {
+ val mapView = holder.mapView
+ mapView.onStart()
+ mapView.onResume()
+ }
+ }
+
+ override fun onViewDetachedFromWindow(holder: RecyclerView.ViewHolder) {
+ super.onViewDetachedFromWindow(holder)
+ if (holder is MapHolder) {
+ val mapView = holder.mapView
+ mapView.onPause()
+ mapView.onStop()
+ }
+ }
+
+ override fun getItemCount(): Int {
+ return items.count()
+ }
+
+ override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
+ if (holder.itemViewType == TYPE_TEXT) {
+ val textHolder = holder as TextHolder
+ textHolder.bind(items[position] as String)
+ }
+ }
+
+ override fun getItemViewType(position: Int): Int {
+ return if (items[position] is MapItem) {
+ TYPE_MAP
+ } else {
+ TYPE_TEXT
+ }
+ }
+
+ fun onSaveInstanceState(savedInstanceState: Bundle?) {
+ savedInstanceState?.let {
+ mapHolder?.mapView?.onSaveInstanceState(it)
+ }
+ }
+
+ fun onLowMemory() {
+ mapHolder?.mapView?.onLowMemory()
+ }
+
+ fun onDestroy() {
+ mapHolder?.mapView?.let {
+ it.onPause()
+ it.onStop()
+ it.onDestroy()
+ }
+ }
+
+ class MapItem
+ class MapHolder(val mapView: MapView, bundle: Bundle?) : RecyclerView.ViewHolder(mapView) {
+ init {
+ mapView.onCreate(bundle)
+ mapView.setOnTouchListener { view, motionEvent ->
+ // Disallow the touch request for recyclerView scroll
+ view.parent.requestDisallowInterceptTouchEvent(true)
+ mapView.onTouchEvent(motionEvent)
+ true
+ }
+ }
+ }
+
+ class TextHolder(val textView: TextView) : RecyclerView.ViewHolder(textView) {
+ fun bind(item: String) {
+ textView.text = item
+ }
+ }
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapInDialogActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapInDialogActivity.java
index c9a9377885..18092ce372 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapInDialogActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapInDialogActivity.java
@@ -1,6 +1,5 @@
package com.mapbox.mapboxsdk.testapp.activity.maplayout;
-import android.app.Dialog;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@@ -17,9 +16,6 @@ import com.mapbox.mapboxsdk.testapp.R;
/**
* Test activity showcasing showing a Map inside of a DialogFragment.
- * <p>
- * Uses the deprecated TextureView API to workaround the issue of seeing a grey background before the gl surface.
- * </p>
*/
public class MapInDialogActivity extends AppCompatActivity {
@@ -64,23 +60,6 @@ public class MapInDialogActivity extends AppCompatActivity {
mapView.getMapAsync(mapboxMap -> mapboxMap.setStyle(Style.OUTDOORS));
}
- @NonNull
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- return new Dialog(getActivity(), getTheme()) {
- @Override
- public void dismiss() {
- if (mapView != null && !mapView.isDestroyed()) {
- mapView.onPause();
- mapView.onStop();
- mapView.onDestroy();
- mapView = null;
- }
- super.dismiss();
- }
- };
- }
-
@Override
public void onStart() {
super.onStart();
@@ -96,25 +75,20 @@ public class MapInDialogActivity extends AppCompatActivity {
@Override
public void onPause() {
super.onPause();
- if (mapView != null) {
- mapView.onPause();
- }
+ mapView.onPause();
}
@Override
public void onStop() {
super.onStop();
- if (mapView != null) {
- mapView.onStop();
- }
+ mapView.onStop();
}
@Override
public void onDestroyView() {
super.onDestroyView();
- if (mapView != null) {
- mapView.onDestroy();
- }
+ mapView.onDestroy();
+ mapView = null;
}
@Override
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/RecyclerViewActivity.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/RecyclerViewActivity.kt
deleted file mode 100644
index 9989d1b137..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/RecyclerViewActivity.kt
+++ /dev/null
@@ -1,151 +0,0 @@
-package com.mapbox.mapboxsdk.testapp.activity.maplayout
-
-import android.annotation.SuppressLint
-import android.os.Bundle
-import android.support.v7.app.AppCompatActivity
-import android.support.v7.widget.LinearLayoutManager
-import android.support.v7.widget.RecyclerView
-import android.view.LayoutInflater
-import android.view.ViewGroup
-import android.widget.TextView
-import com.mapbox.mapboxsdk.maps.MapView
-import com.mapbox.mapboxsdk.maps.OnMapReadyCallback
-import com.mapbox.mapboxsdk.maps.Style
-import com.mapbox.mapboxsdk.testapp.R
-import kotlinx.android.synthetic.main.activity_recyclerview.*
-
-/**
- * TestActivity showcasing how to integrate a MapView in a RecyclerView.
- * <p>
- * It requires calling the correct lifecycle methods when detaching and attaching the View to
- * the RecyclerView with onViewAttachedToWindow and onViewDetachedFromWindow.
- * </p>
- */
-@SuppressLint("ClickableViewAccessibility")
-class RecyclerViewActivity : AppCompatActivity() {
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_recyclerview)
- recyclerView.layoutManager = LinearLayoutManager(this)
- recyclerView.adapter = ItemAdapter(LayoutInflater.from(this), savedInstanceState)
- }
-
- override fun onSaveInstanceState(outState: Bundle?) {
- super.onSaveInstanceState(outState)
- // to save state, we need to call MapView#onSaveInstanceState
- (recyclerView.adapter as ItemAdapter).onSaveInstanceState(outState)
- }
-
- override fun onLowMemory() {
- super.onLowMemory()
- // to release memory, we need to call MapView#onLowMemory
- (recyclerView.adapter as ItemAdapter).onLowMemory()
- }
-
- override fun onDestroy() {
- super.onDestroy()
- // to perform cleanup, we need to call MapView#onDestroy
- (recyclerView.adapter as ItemAdapter).onDestroy()
- }
-
- class ItemAdapter(private val inflater: LayoutInflater, val savedInstanceState: Bundle?) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
-
- private val items = listOf(
- "one", "two", "three", MapItem(), "four", "five", "six", "seven", "eight", "nine", "ten",
- "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen",
- "nineteen", "twenty", "twenty-one"
- )
-
- private var mapHolder: MapHolder? = null
-
- companion object {
- const val TYPE_MAP = 0
- const val TYPE_TEXT = 1
- }
-
- override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
- return if (viewType == TYPE_MAP) {
- val mapView = inflater.inflate(R.layout.item_map, parent, false) as MapView
- mapView.getMapAsync { mapboxMap -> mapboxMap.setStyle(Style.MAPBOX_STREETS) }
- mapHolder = MapHolder(mapView, savedInstanceState)
- return mapHolder as MapHolder
- } else {
- TextHolder(inflater.inflate(android.R.layout.simple_list_item_1, parent, false) as TextView)
- }
- }
-
- override fun onViewAttachedToWindow(holder: RecyclerView.ViewHolder) {
- super.onViewAttachedToWindow(holder)
- if (holder is MapHolder) {
- val mapView = holder.mapView
- mapView.onStart()
- mapView.onResume()
- }
- }
-
- override fun onViewDetachedFromWindow(holder: RecyclerView.ViewHolder) {
- super.onViewDetachedFromWindow(holder)
- if (holder is MapHolder) {
- val mapView = holder.mapView
- mapView.onPause()
- mapView.onStop()
- }
- }
-
- override fun getItemCount(): Int {
- return items.count()
- }
-
- override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
- if (holder.itemViewType == TYPE_TEXT) {
- val textHolder = holder as TextHolder
- textHolder.bind(items[position] as String)
- }
- }
-
- override fun getItemViewType(position: Int): Int {
- return if (items[position] is MapItem) {
- TYPE_MAP
- } else {
- TYPE_TEXT
- }
- }
-
- fun onSaveInstanceState(savedInstanceState: Bundle?){
- savedInstanceState?.let {
- mapHolder?.mapView?.onSaveInstanceState(it)
- }
- }
-
- fun onLowMemory() {
- mapHolder?.mapView?.onLowMemory()
- }
-
- fun onDestroy() {
- mapHolder?.mapView?.let {
- it.onPause()
- it.onStop()
- it.onDestroy()
- }
- }
-
- class MapItem
- class MapHolder(val mapView: MapView, bundle: Bundle?) : RecyclerView.ViewHolder(mapView) {
- init {
- mapView.onCreate(bundle)
- mapView.setOnTouchListener { view, motionEvent ->
- // Disallow the touch request for recyclerView scroll
- view.parent.requestDisallowInterceptTouchEvent(true)
- mapView.onTouchEvent(motionEvent)
- true
- }
- }
- }
- class TextHolder(val textView: TextView) : RecyclerView.ViewHolder(textView) {
- fun bind(item: String) {
- textView.text = item
- }
- }
- }
-}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/TextureRecyclerViewActivity.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/TextureRecyclerViewActivity.kt
new file mode 100644
index 0000000000..895389bc1e
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/TextureRecyclerViewActivity.kt
@@ -0,0 +1,15 @@
+package com.mapbox.mapboxsdk.testapp.activity.maplayout
+
+import android.annotation.SuppressLint
+import com.mapbox.mapboxsdk.testapp.R
+
+/**
+ * TestActivity showcasing how to integrate a TexureView MapView in a RecyclerView.
+ */
+@SuppressLint("ClickableViewAccessibility")
+class TextureRecyclerViewActivity : GLSurfaceRecyclerViewActivity() {
+
+ override fun getMapItemLayoutId() : Int{
+ return R.layout.item_map_texture
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/telemetry/PerformanceMeasurementActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/telemetry/PerformanceMeasurementActivity.java
new file mode 100644
index 0000000000..285d7bc6c8
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/telemetry/PerformanceMeasurementActivity.java
@@ -0,0 +1,187 @@
+package com.mapbox.mapboxsdk.testapp.activity.telemetry;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.util.DisplayMetrics;
+import android.view.Display;
+import android.view.WindowManager;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import com.mapbox.mapboxsdk.Mapbox;
+import com.mapbox.mapboxsdk.maps.MapView;
+import com.mapbox.mapboxsdk.maps.Style;
+import com.mapbox.mapboxsdk.module.http.HttpRequestUtil;
+import com.mapbox.mapboxsdk.testapp.R;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import okhttp3.Call;
+import okhttp3.EventListener;
+import okhttp3.OkHttpClient;
+import timber.log.Timber;
+
+/**
+ * Test activity showcasing gathering performance measurement data.
+ */
+public class PerformanceMeasurementActivity extends AppCompatActivity {
+
+ private MapView mapView;
+
+ private Map<String, Long> startTimes = new HashMap<>();
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_map_simple);
+ mapView = findViewById(R.id.mapView);
+ mapView.onCreate(savedInstanceState);
+
+
+ OkHttpClient.Builder builder = new OkHttpClient.Builder();
+ builder.eventListener(new EventListener() {
+
+ @Override
+ public void callStart(Call call) {
+ String url = call.request().url().toString();
+ startTimes.put(url, System.nanoTime());
+ super.callStart(call);
+ Timber.e("callStart: %s", url);
+ }
+
+ @Override
+ public void callEnd(Call call) {
+ String url = call.request().url().toString();
+ Timber.e("callEnd: %s", url);
+ Long start = startTimes.get(url);
+ if (start != null) {
+ long elapsed = System.nanoTime() - start;
+ triggerPerformanceEvent(url.substring(0, url.indexOf('?')), elapsed);
+ startTimes.remove(start);
+ Timber.e("callEnd: %s took %d", url, elapsed);
+ }
+ super.callEnd(call);
+ }
+ });
+ HttpRequestUtil.setOkHttpClient(builder.build());
+
+ mapView.getMapAsync(mapboxMap -> mapboxMap.setStyle(
+ new Style.Builder().fromUrl(Style.MAPBOX_STREETS)));
+ }
+
+
+ @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 onLowMemory() {
+ super.onLowMemory();
+ mapView.onLowMemory();
+ }
+
+ @Override
+ protected void onDestroy() {
+
+ startTimes.clear();
+
+ super.onDestroy();
+ mapView.onDestroy();
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ mapView.onSaveInstanceState(outState);
+ }
+
+ private void triggerPerformanceEvent(String style, long elapsed) {
+
+ List<Attribute<String>> attributes = new ArrayList<>();
+ attributes.add(
+ new Attribute<>("style_id", style));
+ attributes.add(
+ new Attribute<>("test_perf_event", "true"));
+
+ List<Attribute<Long>> counters = new ArrayList();
+ counters.add(new Attribute<>("elapsed", elapsed));
+
+
+ JsonObject metaData = new JsonObject();
+ metaData.addProperty("os", "android");
+ metaData.addProperty("manufacturer", Build.MANUFACTURER);
+ metaData.addProperty("brand", Build.BRAND);
+ metaData.addProperty("device", Build.MODEL);
+ metaData.addProperty("version", Build.VERSION.RELEASE);
+ metaData.addProperty("abi", Build.CPU_ABI);
+ metaData.addProperty("country", Locale.getDefault().getISO3Country());
+ metaData.addProperty("ram", getRam());
+ metaData.addProperty("screenSize", getWindowSize());
+
+ Gson gson = new Gson();
+
+ Bundle bundle = new Bundle();
+ bundle.putString("attributes", gson.toJson(attributes));
+ bundle.putString("counters", gson.toJson(counters));
+ bundle.putString("metadata", metaData.toString());
+
+ Mapbox.getTelemetry().onPerformanceEvent(bundle);
+ }
+
+ private static String getRam() {
+ ActivityManager actManager =
+ (ActivityManager) Mapbox.getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
+ ActivityManager.MemoryInfo memInfo = new ActivityManager.MemoryInfo();
+ actManager.getMemoryInfo(memInfo);
+ return String.valueOf(memInfo.totalMem);
+ }
+
+ private static String getWindowSize() {
+ WindowManager windowManager =
+ (WindowManager) Mapbox.getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
+ Display display = windowManager.getDefaultDisplay();
+ DisplayMetrics metrics = new DisplayMetrics();
+ display.getMetrics(metrics);
+ int width = metrics.widthPixels;
+ int height = metrics.heightPixels;
+
+ return "{" + width + "," + height + "}";
+ }
+
+ private class Attribute<T> {
+ private String name;
+ private T value;
+
+ Attribute(String name, T value) {
+ this.name = name;
+ this.value = value;
+ }
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_backstack_fragment.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_backstack_fragment.xml
index b6b672cf73..10c11a9320 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_backstack_fragment.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_backstack_fragment.xml
@@ -10,6 +10,7 @@
<Button android:layout_width="match_parent"
android:layout_height="58dp"
android:id="@+id/button"
+ android:contentDescription="btn_change_fragment"
android:text="Replace with empty fragment"/>
</FrameLayout> \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_pixel_test.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_pixel_test.xml
new file mode 100644
index 0000000000..4c88a87703
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_pixel_test.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout
+ 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">
+
+ <com.mapbox.mapboxsdk.maps.MapView
+ android:layout_gravity="center"
+ android:id="@id/mapView"
+ app:mapbox_cameraZoom="1"
+ android:layout_width="1080px"
+ android:layout_height="1920px"
+ app:mapbox_pixelRatio="1"/>
+
+</FrameLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_snapshot.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_snapshot.xml
index 53345571b4..f0787ecad9 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_snapshot.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_snapshot.xml
@@ -1,7 +1,6 @@
<?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">
@@ -27,15 +26,4 @@
</LinearLayout>
- <android.support.design.widget.FloatingActionButton
- android:id="@id/fab"
- 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:src="@drawable/ic_add_a_photo_black"
- app:backgroundTint="@android:color/white"/>
-
</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_viewpager.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_viewpager.xml
index 3edaff6985..516bf60b6b 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_viewpager.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_viewpager.xml
@@ -5,7 +5,7 @@
android:layout_height="match_parent">
<com.mapbox.mapboxsdk.testapp.view.MapViewPager
- android:id="@+id/viewpager"
+ android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent">
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/item_map_gl.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/item_map_gl.xml
new file mode 100644
index 0000000000..850399e355
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/item_map_gl.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<com.mapbox.mapboxsdk.maps.MapView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@id/mapView"
+ android:layout_width="match_parent"
+ android:layout_height="256dp"
+ app:mapbox_cameraTargetLat="45.38301927899065"
+ app:mapbox_cameraTargetLng="8.63525390625"
+ app:mapbox_cameraZoom="7"/>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/item_map.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/item_map_texture.xml
index 3224b73477..3224b73477 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/item_map.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/item_map_texture.xml
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/categories.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/categories.xml
index a4403a34f7..2c34a59327 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/categories.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/categories.xml
@@ -15,4 +15,6 @@
<string name="category_storage">Storage</string>
<string name="category_textureview">Texture View</string>
<string name="category_location">Location</string>
+ <string name="category_integration">_Integration</string>
+ <string name="category_telemetry">Telemetry</string>
</resources> \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml
index 21ebeaabd5..778805b3b3 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml
@@ -78,6 +78,8 @@
<string name="description_location_fragment">Uses LocationComponent in a Fragment</string>
<string name="description_location_manual">Force location updates and don\'t rely on the engine</string>
<string name="description_location_activation_builder">Use LocationComponentActivationOptions to set options</string>
- <string name="description_recyclerview">Show a MapView as a recyclerView item</string>
+ <string name="description_recyclerview_textureview">Show a TextureView MapView as a recyclerView item</string>
+ <string name="description_recyclerview_glsurfaceview">Show a GLSurfaceView MapView as a recyclerView item</string>
<string name="description_nested_viewpager">Show a MapView inside a viewpager inside a recyclerView</string>
+ <string name="description_performance_measurement">Show the use PerformanceEvent for performance measurements</string>
</resources>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml
index 26f56f29b1..12c82bf21a 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml
@@ -78,6 +78,8 @@
<string name="activity_location_fragment">Location Fragment</string>
<string name="activity_location_manual">Manual Location updates</string>
<string name="activity_location_activation_builder">Build Location Activation</string>
- <string name="activity_recyclerview">RecyclerView</string>
+ <string name="activity_recyclerview_textureview">RecyclerView TextureView</string>
+ <string name="activity_recyclerview_glsurfaceview">RecyclerView GLSurfaceView</string>
<string name="activity_nested_viewpager">Nested ViewPager</string>
+ <string name="activity_performance_measurement">Performance Measurement</string>
</resources> \ No newline at end of file
diff --git a/platform/android/build.gradle b/platform/android/build.gradle
index 5334c93ce9..97f3037afb 100644
--- a/platform/android/build.gradle
+++ b/platform/android/build.gradle
@@ -12,6 +12,7 @@ buildscript {
classpath dependenciesList.bintrayPlugin
classpath dependenciesList.artifactoryPlugin
classpath dependenciesList.androidPublishPlugin
+ classpath dependenciesList.jacocoPlugin
}
}
diff --git a/platform/android/gradle/android-nitpick.gradle b/platform/android/gradle/android-nitpick.gradle
index f8e4a47b0b..32539270f5 100644
--- a/platform/android/gradle/android-nitpick.gradle
+++ b/platform/android/gradle/android-nitpick.gradle
@@ -17,6 +17,8 @@ task androidNitpick {
verifyVendorSubmodulePin(MAPBOX_JAVA_DIR, MAPBOX_JAVA_TAG_PREFIX, versions.mapboxServices)
verifyVendorSubmodulePin(MAPBOX_TELEMETRY_DIR, MAPBOX_TELEMETRY_TAG_PREFIX, versions.mapboxTelemetry)
verifyVendorSubmodulePin(MAPBOX_GESTURES_DIR, MAPBOX_GESTURES_TAG_PREFIX, versions.mapboxGestures)
+
+ verifyLicenseGeneration()
}
}
@@ -51,4 +53,12 @@ private def verifyVendorSubmodulePin(def dir, def prefix, def version) {
"If you've bumped the pin, make sure to verify the version tag prefix in the android-nitpick.gradle file.")
}
output.close()
+}
+
+private def verifyLicenseGeneration() {
+ println "Verify license generation with git diff..."
+ exec {
+ workingDir = "${rootDir}"
+ commandLine "python", "scripts/validate-license.py"
+ }
} \ No newline at end of file
diff --git a/platform/android/gradle/dependencies.gradle b/platform/android/gradle/dependencies.gradle
index 600901ca76..1d17e7f83d 100644
--- a/platform/android/gradle/dependencies.gradle
+++ b/platform/android/gradle/dependencies.gradle
@@ -8,7 +8,7 @@ ext {
versions = [
mapboxServices : '4.3.0',
- mapboxTelemetry : '4.2.0',
+ mapboxTelemetry : '4.3.0',
mapboxGestures : '0.4.0',
supportLib : '27.1.1',
constraintLayout: '1.1.2',
@@ -29,7 +29,8 @@ ext {
androidPublish : '3.6.2',
lint : '26.1.4',
gms : '16.0.0',
- reLinker : '1.3.1'
+ reLinker : '1.3.1',
+ jacoco : '0.8.3'
]
dependenciesList = [
@@ -72,6 +73,7 @@ ext {
bintrayPlugin : "com.jfrog.bintray.gradle:gradle-bintray-plugin:${versions.bintray}",
artifactoryPlugin : "org.jfrog.buildinfo:build-info-extractor-gradle:${versions.artifactory}",
androidPublishPlugin : "digital.wup:android-maven-publish:${versions.androidPublish}",
+ jacocoPlugin : "org.jacoco:org.jacoco.core:${versions.jacoco}",
lint : "com.android.tools.lint:lint:${versions.lint}",
lintApi : "com.android.tools.lint:lint-api:${versions.lint}",
diff --git a/platform/android/gradle/jacoco-report.gradle b/platform/android/gradle/jacoco-report.gradle
new file mode 100644
index 0000000000..e50facb683
--- /dev/null
+++ b/platform/android/gradle/jacoco-report.gradle
@@ -0,0 +1,33 @@
+apply plugin: 'jacoco'
+apply from: "${rootDir}/gradle/dependencies.gradle"
+
+jacoco {
+ toolVersion = versions.jacoco
+}
+
+task jacocoTestReport(type: JacocoReport, dependsOn: ['testDebugUnitTest']) {
+ group = "Reporting"
+ description = "Combine code coverage to unified report."
+
+ reports {
+ xml.enabled = true
+ html.enabled = true
+ }
+
+ def fileExcludes = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*', '**/*Test*.*', 'android/**/*.*']
+ def debugTree = fileTree(dir: "${project.buildDir}/intermediates/javac/debug/compileDebugJavaWithJavac/classes", excludes: fileExcludes)
+ def mainSrc = "${project.projectDir}/src/main/java"
+ println(mainSrc)
+ def ecSrc = fileTree(dir: "$project.buildDir", include: "**/*.ec")
+ def execSrc = fileTree(dir: "$project.buildDir", include: "**/*.exec")
+
+ doFirst {
+ def files = files([ecSrc, execSrc]).files
+ println "Creating Jacoco Report for ${files.size()} coverage files"
+ files.each { file -> println file }
+ }
+
+ sourceDirectories = files([mainSrc])
+ classDirectories = files([debugTree])
+ executionData = files([ecSrc, execSrc])
+} \ No newline at end of file
diff --git a/platform/android/scripts/exclude-activity-gen.json b/platform/android/scripts/exclude-activity-gen.json
index 9e0a1d154f..a6070edccf 100644
--- a/platform/android/scripts/exclude-activity-gen.json
+++ b/platform/android/scripts/exclude-activity-gen.json
@@ -48,5 +48,7 @@
"EspressoTestActivity",
"ChangeResourcesCachePathActivity",
"EspressoTestActivity",
- "FragmentBackStackActivity"
+ "FragmentBackStackActivity",
+ "ChildFragmentMapInDialogActivity",
+ "PerformanceMeasurementActivity"
]
diff --git a/platform/android/scripts/generate-style-code.js b/platform/android/scripts/generate-style-code.js
index 56e7511362..688a3aa527 100755
--- a/platform/android/scripts/generate-style-code.js
+++ b/platform/android/scripts/generate-style-code.js
@@ -197,7 +197,12 @@ global.defaultValueJava = function(property) {
case 'array':
switch (property.value) {
case 'string':
- return '[' + property['default'] + "]";
+ case 'enum':
+ if (property['default'] !== undefined) {
+ return '[' + property['default'] + ']';
+ } else {
+ return 'new String[0]';
+ }
case 'number':
var result ='new Float[] {';
for (var i = 0; i < property.length; i++) {
diff --git a/platform/android/scripts/parse-jacoco-report.py b/platform/android/scripts/parse-jacoco-report.py
new file mode 100755
index 0000000000..4d06fda6cc
--- /dev/null
+++ b/platform/android/scripts/parse-jacoco-report.py
@@ -0,0 +1,31 @@
+#!/usr/bin/python
+
+import os
+import re
+from io import open
+
+reportPath = os.getcwd() + "/platform/android/MapboxGLAndroidSDK/build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml"
+with open(reportPath, 'r', encoding='utf-8') as jacocoReport:
+ line = jacocoReport.readline().strip()
+
+ # find the last INSTRUCTION coverage report which is a sum of all separate ones
+ instructionIndex = line.rfind('type="INSTRUCTION"')
+ startIndex = line.find('missed', instructionIndex)
+ endIndex = line.find('/>', startIndex)
+
+ # find the missed and covered lines counts
+ numbers = re.match(r'missed="(\d+)" covered="(\d+)"', line[startIndex:endIndex])
+ missed = int(numbers.group(1))
+ covered = int(numbers.group(2))
+
+ # calculate the code coverage percentage
+ percentage = round(covered * 100.0 / (missed + covered), 2)
+ print("Android tests code coverage: %s%%" % (str(percentage)))
+
+ # invoke the script that send the data to s3
+ testEnvironment = "LOCAL"
+ if os.environ.get('IS_LOCAL_DEVELOPMENT').lower()=='false':
+ testEnvironment = "CI"
+
+ cmd = os.getcwd() + ("/scripts/code-coverage.sh %.2f %s %s" % (percentage, "Android", testEnvironment))
+ os.system(cmd)
diff --git a/platform/android/scripts/validate-license.py b/platform/android/scripts/validate-license.py
new file mode 100644
index 0000000000..365d7ac265
--- /dev/null
+++ b/platform/android/scripts/validate-license.py
@@ -0,0 +1,17 @@
+#!/usr/bin/python
+
+from subprocess import call
+from subprocess import Popen, PIPE
+import sys
+
+## Run license generation
+call('cd ../../ && make android-license', shell=True)
+
+## Git diff changes
+p = Popen(['git', 'diff', '--name-only', 'LICENSE.md'], stdin=PIPE, stdout=PIPE, stderr=PIPE)
+output, err = p.communicate(b"input data that is passed to subprocess' stdin")
+if "platform/android/LICENSE.md" in output:
+ raise ValueError("""An error ocurred while validating the license generation.
+ Changes were detected to the license generation output
+ but weren't commited. Run make android-license and
+ commit the changeset to make this validation pass.""") \ No newline at end of file
diff --git a/platform/android/src/conversion/constant.hpp b/platform/android/src/conversion/constant.hpp
index 4def670f3c..839e6e84dc 100644
--- a/platform/android/src/conversion/constant.hpp
+++ b/platform/android/src/conversion/constant.hpp
@@ -88,6 +88,17 @@ struct Converter<jni::Local<jni::Object<>>, T, typename std::enable_if_t<std::is
}
};
+template <class T>
+struct Converter<jni::Local<jni::Object<>>, std::vector<T>, typename std::enable_if_t<std::is_enum<T>::value>> {
+ Result<jni::Local<jni::Object<>>> operator()(jni::JNIEnv& env, const std::vector<T>& value) const {
+ auto result = jni::Array<jni::String>::New(env, value.size());
+ for (std::size_t i = 0; i < value.size(); ++i) {
+ result.Set(env, i, jni::Make<jni::String>(env, Enum<T>::toString(value.at(i))));
+ }
+ return result;
+ }
+};
+
} // namespace conversion
} // namespace android
} // namespace mbgl
diff --git a/platform/android/src/file_source.cpp b/platform/android/src/file_source.cpp
index 4cfb545b84..41081cd0fb 100644
--- a/platform/android/src/file_source.cpp
+++ b/platform/android/src/file_source.cpp
@@ -3,6 +3,7 @@
#include <mbgl/actor/actor.hpp>
#include <mbgl/actor/scheduler.hpp>
+#include <mbgl/storage/resource_options.hpp>
#include <mbgl/storage/resource_transform.hpp>
#include <mbgl/util/logging.hpp>
@@ -11,6 +12,14 @@
#include "asset_manager_file_source.hpp"
namespace mbgl {
+
+std::shared_ptr<FileSource> FileSource::createPlatformFileSource(const ResourceOptions& options) {
+ auto* assetFileSource = reinterpret_cast<AssetManagerFileSource*>(options.platformContext());
+ auto fileSource = std::make_shared<DefaultFileSource>(options.cachePath(), std::unique_ptr<AssetManagerFileSource>(assetFileSource));
+ fileSource->setAccessToken(options.accessToken());
+ return fileSource;
+}
+
namespace android {
// FileSource //
@@ -22,15 +31,13 @@ FileSource::FileSource(jni::JNIEnv& _env,
std::string path = jni::Make<std::string>(_env, _cachePath);
mapbox::sqlite::setTempPath(path);
- // Create a core default file source
- fileSource = std::make_unique<mbgl::DefaultFileSource>(
- path + DATABASE_FILE,
- std::make_unique<AssetManagerFileSource>(_env, assetManager));
+ resourceOptions
+ .withAccessToken(accessToken ? jni::Make<std::string>(_env, accessToken) : "")
+ .withCachePath(path + DATABASE_FILE)
+ .withPlatformContext(reinterpret_cast<void*>(new AssetManagerFileSource(_env, assetManager)));
- // Set access token
- if (accessToken) {
- fileSource->setAccessToken(jni::Make<std::string>(_env, accessToken));
- }
+ // Create a core default file source
+ fileSource = std::static_pointer_cast<mbgl::DefaultFileSource>(mbgl::FileSource::getSharedFileSource(resourceOptions));
}
FileSource::~FileSource() {
@@ -110,10 +117,10 @@ FileSource* FileSource::getNativePeer(jni::JNIEnv& env, const jni::Object<FileSo
return reinterpret_cast<FileSource *>(jFileSource.Get(env, field));
}
-mbgl::DefaultFileSource& FileSource::getDefaultFileSource(jni::JNIEnv& env, const jni::Object<FileSource>& jFileSource) {
+mbgl::ResourceOptions FileSource::getSharedResourceOptions(jni::JNIEnv& env, const jni::Object<FileSource>& jFileSource) {
FileSource* fileSource = FileSource::getNativePeer(env, jFileSource);
assert(fileSource != nullptr);
- return *fileSource->fileSource;
+ return fileSource->resourceOptions.clone();
}
void FileSource::registerNative(jni::JNIEnv& env) {
diff --git a/platform/android/src/file_source.hpp b/platform/android/src/file_source.hpp
index 575702120e..3001a5e0f0 100644
--- a/platform/android/src/file_source.hpp
+++ b/platform/android/src/file_source.hpp
@@ -1,6 +1,7 @@
#pragma once
#include <mbgl/storage/default_file_source.hpp>
+#include <mbgl/storage/resource_options.hpp>
#include "asset_manager.hpp"
@@ -49,15 +50,16 @@ public:
static FileSource* getNativePeer(jni::JNIEnv&, const jni::Object<FileSource>&);
- static mbgl::DefaultFileSource& getDefaultFileSource(jni::JNIEnv&, const jni::Object<FileSource>&);
+ static mbgl::ResourceOptions getSharedResourceOptions(jni::JNIEnv&, const jni::Object<FileSource>&);
static void registerNative(jni::JNIEnv&);
private:
const std::string DATABASE_FILE = "/mbgl-offline.db";
optional<int> activationCounter;
+ mbgl::ResourceOptions resourceOptions;
std::unique_ptr<Actor<ResourceTransform>> resourceTransform;
- std::unique_ptr<mbgl::DefaultFileSource> fileSource;
+ std::shared_ptr<mbgl::DefaultFileSource> fileSource;
};
diff --git a/platform/android/src/map_renderer.hpp b/platform/android/src/map_renderer.hpp
index 3e5b99605e..57265cebb1 100644
--- a/platform/android/src/map_renderer.hpp
+++ b/platform/android/src/map_renderer.hpp
@@ -1,13 +1,15 @@
#pragma once
+#include <mbgl/actor/actor_ref.hpp>
#include <mbgl/actor/scheduler.hpp>
#include <mbgl/util/image.hpp>
+#include <mbgl/util/optional.hpp>
#include <memory>
+#include <mutex>
#include <utility>
#include <jni/jni.hpp>
-#include <mbgl/storage/default_file_source.hpp>
namespace mbgl {
diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp
index 3a4e2014ba..e74e4c3bbc 100755
--- a/platform/android/src/native_map_view.cpp
+++ b/platform/android/src/native_map_view.cpp
@@ -13,6 +13,7 @@
#include <jni/jni.hpp>
+#include <mbgl/map/map.hpp>
#include <mbgl/map/map_options.hpp>
#include <mbgl/math/minmax.hpp>
#include <mbgl/util/constants.hpp>
@@ -74,24 +75,22 @@ NativeMapView::NativeMapView(jni::JNIEnv& _env,
return;
}
- // Get native peer for file source
- mbgl::FileSource& fileSource = mbgl::android::FileSource::getDefaultFileSource(_env, jFileSource);
-
// Create a renderer frontend
rendererFrontend = std::make_unique<AndroidRendererFrontend>(mapRenderer);
// Create Map options
MapOptions options;
options.withMapMode(MapMode::Continuous)
+ .withSize(mbgl::Size{ static_cast<uint32_t>(width), static_cast<uint32_t>(height) })
+ .withPixelRatio(pixelRatio)
.withConstrainMode(ConstrainMode::HeightOnly)
.withViewportMode(ViewportMode::Default)
.withCrossSourceCollisions(_crossSourceCollisions);
// Create the core map
- map = std::make_unique<mbgl::Map>(*rendererFrontend, *this,
- mbgl::Size{ static_cast<uint32_t>(width),
- static_cast<uint32_t>(height) }, pixelRatio,
- fileSource, *threadPool, options);
+ map = std::make_unique<mbgl::Map>(
+ *rendererFrontend, *this, *threadPool, options,
+ mbgl::android::FileSource::getSharedResourceOptions(_env, jFileSource));
}
/**
diff --git a/platform/android/src/native_map_view.hpp b/platform/android/src/native_map_view.hpp
index d695a91ce0..903543e5d1 100755
--- a/platform/android/src/native_map_view.hpp
+++ b/platform/android/src/native_map_view.hpp
@@ -6,7 +6,6 @@
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/default_thread_pool.hpp>
#include <mbgl/util/run_loop.hpp>
-#include <mbgl/storage/default_file_source.hpp>
#include <mbgl/storage/network_status.hpp>
#include "annotation/marker.hpp"
diff --git a/platform/android/src/offline/offline_manager.cpp b/platform/android/src/offline/offline_manager.cpp
index 968c33b644..54b1142845 100644
--- a/platform/android/src/offline/offline_manager.cpp
+++ b/platform/android/src/offline/offline_manager.cpp
@@ -10,20 +10,19 @@ namespace android {
// OfflineManager //
OfflineManager::OfflineManager(jni::JNIEnv& env, const jni::Object<FileSource>& jFileSource)
- : fileSource(mbgl::android::FileSource::getDefaultFileSource(env, jFileSource)) {
-}
+ : fileSource(std::static_pointer_cast<DefaultFileSource>(mbgl::FileSource::getSharedFileSource(FileSource::getSharedResourceOptions(env, jFileSource)))) {}
OfflineManager::~OfflineManager() {}
void OfflineManager::setOfflineMapboxTileCountLimit(jni::JNIEnv&, jni::jlong limit) {
- fileSource.setOfflineMapboxTileCountLimit(limit);
+ fileSource->setOfflineMapboxTileCountLimit(limit);
}
void OfflineManager::listOfflineRegions(jni::JNIEnv& env_, const jni::Object<FileSource>& jFileSource_, const jni::Object<ListOfflineRegionsCallback>& callback_) {
auto globalCallback = jni::NewGlobal<jni::EnvAttachingDeleter>(env_, callback_);
auto globalFilesource = jni::NewGlobal<jni::EnvAttachingDeleter>(env_, jFileSource_);
- fileSource.listOfflineRegions([
+ fileSource->listOfflineRegions([
//Keep a shared ptr to a global reference of the callback and file source so they are not GC'd in the meanwhile
callback = std::make_shared<decltype(globalCallback)>(std::move(globalCallback)),
jFileSource = std::make_shared<decltype(globalFilesource)>(std::move(globalFilesource))
@@ -59,7 +58,7 @@ void OfflineManager::createOfflineRegion(jni::JNIEnv& env_,
auto globalFilesource = jni::NewGlobal<jni::EnvAttachingDeleter>(env_, jFileSource_);
// Create region
- fileSource.createOfflineRegion(definition, metadata, [
+ fileSource->createOfflineRegion(definition, metadata, [
//Keep a shared ptr to a global reference of the callback and file source so they are not GC'd in the meanwhile
callback = std::make_shared<decltype(globalCallback)>(std::move(globalCallback)),
jFileSource = std::make_shared<decltype(globalFilesource)>(std::move(globalFilesource))
@@ -86,7 +85,7 @@ void OfflineManager::mergeOfflineRegions(jni::JNIEnv& env_, const jni::Object<Fi
auto globalFilesource = jni::NewGlobal<jni::EnvAttachingDeleter>(env_, jFileSource_);
auto path = jni::Make<std::string>(env_, jString_);
- fileSource.mergeOfflineRegions(path, [
+ fileSource->mergeOfflineRegions(path, [
//Keep a shared ptr to a global reference of the callback and file source so they are not GC'd in the meanwhile
callback = std::make_shared<decltype(globalCallback)>(std::move(globalCallback)),
jFileSource = std::make_shared<decltype(globalFilesource)>(std::move(globalFilesource))
@@ -226,7 +225,7 @@ void OfflineManager::putResourceWithUrl(jni::JNIEnv& env,
response.expires = Timestamp(mbgl::Seconds(expires));
}
- fileSource.put(resource, response);
+ fileSource->put(resource, response);
}
} // namespace android
diff --git a/platform/android/src/offline/offline_manager.hpp b/platform/android/src/offline/offline_manager.hpp
index f8d57b88da..d0b637b900 100644
--- a/platform/android/src/offline/offline_manager.hpp
+++ b/platform/android/src/offline/offline_manager.hpp
@@ -1,7 +1,5 @@
#pragma once
-
-#include <mbgl/storage/default_file_source.hpp>
#include <mbgl/storage/offline.hpp>
#include <jni/jni.hpp>
@@ -10,8 +8,12 @@
#include "offline_region_definition.hpp"
#include "../java_types.hpp"
+#include <memory>
namespace mbgl {
+
+class DefaultFileSource;
+
namespace android {
class OfflineManager {
@@ -85,7 +87,7 @@ public:
private:
- mbgl::DefaultFileSource& fileSource;
+ std::shared_ptr<mbgl::DefaultFileSource> fileSource;
};
} // namespace android
diff --git a/platform/android/src/offline/offline_region.cpp b/platform/android/src/offline/offline_region.cpp
index 1cd73a7c76..e0f28631b4 100644
--- a/platform/android/src/offline/offline_region.cpp
+++ b/platform/android/src/offline/offline_region.cpp
@@ -14,8 +14,8 @@ namespace android {
// OfflineRegion //
OfflineRegion::OfflineRegion(jni::JNIEnv& env, jni::jlong offlineRegionPtr, const jni::Object<FileSource>& jFileSource)
- : region(reinterpret_cast<mbgl::OfflineRegion *>(offlineRegionPtr)),
- fileSource(mbgl::android::FileSource::getDefaultFileSource(env, jFileSource)) {}
+ : region(reinterpret_cast<mbgl::OfflineRegion *>(offlineRegionPtr))
+ , fileSource(std::static_pointer_cast<DefaultFileSource>(mbgl::FileSource::getSharedFileSource(FileSource::getSharedResourceOptions(env, jFileSource)))) {}
OfflineRegion::~OfflineRegion() {}
@@ -62,7 +62,7 @@ void OfflineRegion::setOfflineRegionObserver(jni::JNIEnv& env_, const jni::Objec
};
// Set the observer
- fileSource.setOfflineRegionObserver(*region, std::make_unique<Observer>(jni::NewGlobal<jni::EnvAttachingDeleter>(env_, callback)));
+ fileSource->setOfflineRegionObserver(*region, std::make_unique<Observer>(jni::NewGlobal<jni::EnvAttachingDeleter>(env_, callback)));
}
void OfflineRegion::setOfflineRegionDownloadState(jni::JNIEnv&, jni::jint jState) {
@@ -80,13 +80,13 @@ void OfflineRegion::setOfflineRegionDownloadState(jni::JNIEnv&, jni::jint jState
return;
}
- fileSource.setOfflineRegionDownloadState(*region, state);
+ fileSource->setOfflineRegionDownloadState(*region, state);
}
void OfflineRegion::getOfflineRegionStatus(jni::JNIEnv& env_, const jni::Object<OfflineRegionStatusCallback>& callback_) {
auto globalCallback = jni::NewGlobal<jni::EnvAttachingDeleter>(env_, callback_);
- fileSource.getOfflineRegionStatus(*region, [
+ fileSource->getOfflineRegionStatus(*region, [
//Ensure the object is not gc'd in the meanwhile
callback = std::make_shared<decltype(globalCallback)>(std::move(globalCallback))
](mbgl::expected<mbgl::OfflineRegionStatus, std::exception_ptr> status) mutable {
@@ -104,7 +104,7 @@ void OfflineRegion::getOfflineRegionStatus(jni::JNIEnv& env_, const jni::Object<
void OfflineRegion::deleteOfflineRegion(jni::JNIEnv& env_, const jni::Object<OfflineRegionDeleteCallback>& callback_) {
auto globalCallback = jni::NewGlobal<jni::EnvAttachingDeleter>(env_, callback_);
- fileSource.deleteOfflineRegion(std::move(*region), [
+ fileSource->deleteOfflineRegion(std::move(*region), [
//Ensure the object is not gc'd in the meanwhile
callback = std::make_shared<decltype(globalCallback)>(std::move(globalCallback))
](std::exception_ptr error) mutable {
@@ -123,7 +123,7 @@ void OfflineRegion::updateOfflineRegionMetadata(jni::JNIEnv& env_, const jni::Ar
auto metadata = OfflineRegion::metadata(env_, jMetadata);
auto globalCallback = jni::NewGlobal<jni::EnvAttachingDeleter>(env_, callback_);
- fileSource.updateOfflineMetadata(region->getID(), metadata, [
+ fileSource->updateOfflineMetadata(region->getID(), metadata, [
//Ensure the object is not gc'd in the meanwhile
callback = std::make_shared<decltype(globalCallback)>(std::move(globalCallback))
](mbgl::expected<mbgl::OfflineRegionMetadata, std::exception_ptr> data) mutable {
diff --git a/platform/android/src/offline/offline_region.hpp b/platform/android/src/offline/offline_region.hpp
index 49fa0c8ff8..4618e1abbd 100644
--- a/platform/android/src/offline/offline_region.hpp
+++ b/platform/android/src/offline/offline_region.hpp
@@ -74,7 +74,7 @@ public:
private:
std::unique_ptr<mbgl::OfflineRegion> region;
- mbgl::DefaultFileSource& fileSource;
+ std::shared_ptr<mbgl::DefaultFileSource> fileSource;
};
} // namespace android
diff --git a/platform/android/src/snapshotter/map_snapshotter.cpp b/platform/android/src/snapshotter/map_snapshotter.cpp
index 8eb1d02605..47a2781cb5 100644
--- a/platform/android/src/snapshotter/map_snapshotter.cpp
+++ b/platform/android/src/snapshotter/map_snapshotter.cpp
@@ -37,7 +37,6 @@ MapSnapshotter::MapSnapshotter(jni::JNIEnv& _env,
}
jFileSource = FileSource::getNativePeer(_env, _jFileSource);
- auto& fileSource = mbgl::android::FileSource::getDefaultFileSource(_env, _jFileSource);
auto size = mbgl::Size { static_cast<uint32_t>(width), static_cast<uint32_t>(height) };
optional<mbgl::CameraOptions> cameraOptions;
@@ -56,11 +55,10 @@ MapSnapshotter::MapSnapshotter(jni::JNIEnv& _env,
} else {
style = std::make_pair(false, jni::Make<std::string>(_env, styleURL));
}
-
+
showLogo = _showLogo;
// Create the core snapshotter
- snapshotter = std::make_unique<mbgl::MapSnapshotter>(&fileSource,
- threadPool,
+ snapshotter = std::make_unique<mbgl::MapSnapshotter>(threadPool,
style,
size,
pixelRatio,
@@ -69,8 +67,8 @@ MapSnapshotter::MapSnapshotter(jni::JNIEnv& _env,
jni::Make<std::string>(_env, _programCacheDir),
_localIdeographFontFamily ?
jni::Make<std::string>(_env, _localIdeographFontFamily) :
- optional<std::string>{});
-
+ optional<std::string>{},
+ mbgl::android::FileSource::getSharedResourceOptions(_env, _jFileSource));
}
MapSnapshotter::~MapSnapshotter() = default;
diff --git a/platform/android/src/style/layers/symbol_layer.cpp b/platform/android/src/style/layers/symbol_layer.cpp
index 61e4d59326..810848e9cb 100644
--- a/platform/android/src/style/layers/symbol_layer.cpp
+++ b/platform/android/src/style/layers/symbol_layer.cpp
@@ -176,6 +176,16 @@ namespace android {
return std::move(*convert<jni::Local<jni::Object<>>>(env, toSymbolLayer(layer).getTextJustify()));
}
+ jni::Local<jni::Object<>> SymbolLayer::getTextRadialOffset(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ return std::move(*convert<jni::Local<jni::Object<>>>(env, toSymbolLayer(layer).getTextRadialOffset()));
+ }
+
+ jni::Local<jni::Object<>> SymbolLayer::getTextVariableAnchor(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ return std::move(*convert<jni::Local<jni::Object<>>>(env, toSymbolLayer(layer).getTextVariableAnchor()));
+ }
+
jni::Local<jni::Object<>> SymbolLayer::getTextAnchor(jni::JNIEnv& env) {
using namespace mbgl::android::conversion;
return std::move(*convert<jni::Local<jni::Object<>>>(env, toSymbolLayer(layer).getTextAnchor()));
@@ -514,6 +524,8 @@ namespace android {
METHOD(&SymbolLayer::getTextLineHeight, "nativeGetTextLineHeight"),
METHOD(&SymbolLayer::getTextLetterSpacing, "nativeGetTextLetterSpacing"),
METHOD(&SymbolLayer::getTextJustify, "nativeGetTextJustify"),
+ METHOD(&SymbolLayer::getTextRadialOffset, "nativeGetTextRadialOffset"),
+ METHOD(&SymbolLayer::getTextVariableAnchor, "nativeGetTextVariableAnchor"),
METHOD(&SymbolLayer::getTextAnchor, "nativeGetTextAnchor"),
METHOD(&SymbolLayer::getTextMaxAngle, "nativeGetTextMaxAngle"),
METHOD(&SymbolLayer::getTextRotate, "nativeGetTextRotate"),
diff --git a/platform/android/src/style/layers/symbol_layer.hpp b/platform/android/src/style/layers/symbol_layer.hpp
index f52597ef6f..3b0f8ee5d1 100644
--- a/platform/android/src/style/layers/symbol_layer.hpp
+++ b/platform/android/src/style/layers/symbol_layer.hpp
@@ -80,6 +80,10 @@ public:
jni::Local<jni::Object<jni::ObjectTag>> getTextJustify(jni::JNIEnv&);
+ jni::Local<jni::Object<jni::ObjectTag>> getTextRadialOffset(jni::JNIEnv&);
+
+ jni::Local<jni::Object<jni::ObjectTag>> getTextVariableAnchor(jni::JNIEnv&);
+
jni::Local<jni::Object<jni::ObjectTag>> getTextAnchor(jni::JNIEnv&);
jni::Local<jni::Object<jni::ObjectTag>> getTextMaxAngle(jni::JNIEnv&);
diff --git a/platform/android/vendor/mapbox-events-android b/platform/android/vendor/mapbox-events-android
-Subproject 1636d1ae9d5b0f0dd2367c8f32f1af958640b14
+Subproject 5bdf0d90292fb46cd8b1f795763d281b5ac83e0
diff --git a/platform/darwin/docs/guides/For Style Authors.md.ejs b/platform/darwin/docs/guides/For Style Authors.md.ejs
index cf0f79f419..8df541d0f7 100644
--- a/platform/darwin/docs/guides/For Style Authors.md.ejs
+++ b/platform/darwin/docs/guides/For Style Authors.md.ejs
@@ -431,5 +431,16 @@ In style JSON | In the format string
`["any", f0, …, fn]` | `p0 OR … OR pn`
`["none", f0, …, fn]` | `NOT (p0 OR … OR pn)`
+## Specifying the text format
+
+The following format attributes are defined as `NSString` constans that you
+can use to update the formatting of `MGLSymbolStyleLayer.text` property.
+
+In style JSON | In Objective-C | In Swift
+--------------|-----------------------|---------
+`text-font` | `MGLFontNamesAttribute` | `.fontNamesAttribute`
+`font-scale` | `MGLFontScaleAttribute` | `.fontScaleAttribute`
+`text-color` | `MGLFontColorAttribute` | `.fontColorAttribute`
+
See the “[Predicates and Expressions](predicates-and-expressions.html)” guide for
a full description of the supported operators and operand types.
diff --git a/platform/darwin/docs/guides/Predicates and Expressions.md b/platform/darwin/docs/guides/Predicates and Expressions.md
index 5f5d9a22a8..b2e01b94db 100644
--- a/platform/darwin/docs/guides/Predicates and Expressions.md
+++ b/platform/darwin/docs/guides/Predicates and Expressions.md
@@ -546,6 +546,14 @@ operator in the Mapbox Style Specification.
Concatenates and returns the array of `MGLAttributedExpression` objects, for use
with the `MGLSymbolStyleLayer.text` property.
+`MGLAttributedExpression.attributes` valid attributes.
+
+ Key | Value Type
+ --- | ---
+ `MGLFontNamesAttribute` | An `NSExpression` evaluating to an `NSString` array.
+ `MGLFontScaleAttribute` | An `NSExpression` evaluating to an `NSNumber` value.
+ `MGLFontColorAttribute` | An `NSExpression` evaluating to an `UIColor` (iOS) or `NSColor` (macOS).
+
This function corresponds to the
[`format`](https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-types-format)
operator in the Mapbox Style Specification.
diff --git a/platform/darwin/filesource-files.json b/platform/darwin/filesource-files.json
index 3ee96f9b95..b2e6fbc9b4 100644
--- a/platform/darwin/filesource-files.json
+++ b/platform/darwin/filesource-files.json
@@ -4,6 +4,7 @@
"platform/darwin/src/MGLLoggingConfiguration.m",
"platform/darwin/src/MGLNetworkConfiguration.m",
"platform/darwin/src/http_file_source.mm",
+ "platform/default/src/mbgl/storage/file_source.cpp",
"platform/default/src/mbgl/storage/sqlite3.cpp"
],
"public_headers": {},
diff --git a/platform/darwin/scripts/generate-style-code.js b/platform/darwin/scripts/generate-style-code.js
index a8bdec7865..2eabd0a92b 100755
--- a/platform/darwin/scripts/generate-style-code.js
+++ b/platform/darwin/scripts/generate-style-code.js
@@ -137,6 +137,8 @@ global.objCTestValue = function (property, layerType, arraysAsStructs, indent) {
}
return '@"{1, 1}"';
}
+ case 'anchor':
+ return `@"{'top','bottom'}"`;
default:
throw new Error(`unknown array type for ${property.name}`);
}
@@ -185,6 +187,8 @@ global.mbglTestValue = function (property, layerType) {
case 'offset':
case 'translate':
return '{ 1, 1 }';
+ case 'anchor':
+ return '{ mbgl::style::SymbolAnchorType::Top, mbgl::style::SymbolAnchorType::Bottom }';
default:
throw new Error(`unknown array type for ${property.name}`);
}
@@ -200,6 +204,13 @@ global.mbglExpressionTestValue = function (property, layerType) {
return `"${_.last(_.keys(property.values))}"`;
case 'color':
return 'mbgl::Color(1, 0, 0, 1)';
+ case 'array':
+ switch (arrayType(property)) {
+ case 'anchor':
+ return `{"top", "bottom"}`;
+ default:
+ break;
+ }
default:
return global.mbglTestValue(property, layerType);
}
@@ -341,6 +352,9 @@ global.propertyDoc = function (propertyName, property, layerType, kind) {
if (property.type === 'enum') {
doc += '* Any of the following constant string values:\n';
doc += Object.keys(property.values).map(value => ' * `' + value + '`: ' + property.values[value].doc).join('\n') + '\n';
+ } else if (property.type === 'array' && property.value === 'enum') {
+ doc += '* Constant array, whose each element is any of the following constant string values:\n';
+ doc += Object.keys(property.values).map(value => ' * `' + value + '`: ' + property.values[value].doc).join('\n') + '\n';
}
doc += '* Predefined functions, including mathematical and string operators\n' +
'* Conditional expressions\n' +
@@ -415,6 +429,8 @@ global.describeType = function (property) {
return '`CGVector`';
case 'position':
return '`MGLSphericalPosition`';
+ case 'anchor':
+ return '`MGLTextAnchor` array';
default:
return 'array';
}
@@ -539,11 +555,12 @@ global.propertyType = function (property) {
case 'font':
return 'NSArray<NSString *> *';
case 'padding':
- return 'NSValue *';
case 'position':
case 'offset':
case 'translate':
return 'NSValue *';
+ case 'anchor':
+ return 'NSArray<NSValue *> *';
default:
throw new Error(`unknown array type for ${property.name}`);
}
@@ -588,6 +605,8 @@ global.valueTransformerArguments = function (property) {
case 'offset':
case 'translate':
return ['std::array<float, 2>', objCType];
+ case 'anchor':
+ return ['std::vector<mbgl::style::SymbolAnchorType>', objCType, 'mbgl::style::SymbolAnchorType', 'MGLTextAnchor'];
default:
throw new Error(`unknown array type for ${property.name}`);
}
@@ -637,6 +656,8 @@ global.mbglType = function(property) {
return 'std::array<float, 2>';
case 'position':
return 'mbgl::style::Position';
+ case 'anchor':
+ return 'std::vector<mbgl::style::SymbolAnchorType>';
default:
throw new Error(`unknown array type for ${property.name}`);
}
diff --git a/platform/darwin/src/MGLAttributedExpression.h b/platform/darwin/src/MGLAttributedExpression.h
index aa5d51c66e..ea298c7a44 100644
--- a/platform/darwin/src/MGLAttributedExpression.h
+++ b/platform/darwin/src/MGLAttributedExpression.h
@@ -2,14 +2,33 @@
NS_ASSUME_NONNULL_BEGIN
-typedef NSString * MGLAttributedExpressionKey NS_EXTENSIBLE_STRING_ENUM;
+/** Options for `MGLAttributedExpression.attributes`. */
+typedef NSString * MGLAttributedExpressionKey NS_TYPED_ENUM;
+/** The font name string array expression used to format the text. */
FOUNDATION_EXTERN MGL_EXPORT MGLAttributedExpressionKey const MGLFontNamesAttribute;
-FOUNDATION_EXTERN MGL_EXPORT MGLAttributedExpressionKey const MGLFontSizeAttribute;
+
+/** The font scale number expression relative to `MGLSymbolStyleLayer.textFontSize` used to format the text. */
+FOUNDATION_EXTERN MGL_EXPORT MGLAttributedExpressionKey const MGLFontScaleAttribute;
+
+/** The font color expression used to format the text. */
+FOUNDATION_EXTERN MGL_EXPORT MGLAttributedExpressionKey const MGLFontColorAttribute;
/**
An `MGLAttributedExpression` object associates text formatting attibutes (such as font size or
font names) to an `NSExpression`.
+
+ ### Example
+ ```swift
+ let redColor = UIColor.red
+ let expression = NSExpression(forConstantValue: "Foo")
+ let attributes: [MGLAttributedExpressionKey: NSExpression] = [.fontNamesAttribute : NSExpression(forConstantValue: ["DIN Offc Pro Italic",
+ "Arial Unicode MS Regular"]),
+ .fontScaleAttribute: NSExpression(forConstantValue: 1.2),
+ .fontColorAttribute: NSExpression(forConstantValue: redColor)]
+ let attributedExpression = MGLAttributedExpression(expression, attributes:attributes)
+ ```
+
*/
MGL_EXPORT
@interface MGLAttributedExpression : NSObject
@@ -19,10 +38,29 @@ MGL_EXPORT
*/
@property (strong, nonatomic) NSExpression *expression;
+#if TARGET_OS_IPHONE
+/**
+ The formatting attributes dictionary.
+ Key | Value Type
+ --- | ---
+ `MGLFontNamesAttribute` | An `NSExpression` evaluating to an `NSString` array.
+ `MGLFontScaleAttribute` | An `NSExpression` evaluating to an `NSNumber` value.
+ `MGLFontColorAttribute` | An `NSExpression` evaluating to an `UIColor`.
+
+ */
+@property (strong, nonatomic, readonly) NSDictionary<MGLAttributedExpressionKey, NSExpression *> *attributes;
+#else
/**
- The formatting attributes.
+ The formatting attributes dictionary.
+ Key | Value Type
+ --- | ---
+ `MGLFontNamesAttribute` | An `NSExpression` evaluating to an `NSString` array.
+ `MGLFontScaleAttribute` | An `NSExpression` evaluating to an `NSNumber` value.
+ `MGLFontColorAttribute` | An `NSExpression` evaluating to an `NSColor` on macos.
*/
-@property (strong, nonatomic, readonly) NSDictionary<MGLAttributedExpressionKey, id> *attributes;
+@property (strong, nonatomic, readonly) NSDictionary<MGLAttributedExpressionKey, NSExpression *> *attributes;
+#endif
+
/**
Returns an `MGLAttributedExpression` object initialized with an expression and no attribute information.
@@ -32,12 +70,17 @@ MGL_EXPORT
/**
Returns an `MGLAttributedExpression` object initialized with an expression and text format attributes.
*/
-- (instancetype)initWithExpression:(NSExpression *)expression attributes:(nullable NSDictionary <MGLAttributedExpressionKey, id> *)attrs;
+- (instancetype)initWithExpression:(NSExpression *)expression attributes:(nonnull NSDictionary <MGLAttributedExpressionKey, NSExpression *> *)attrs;
/**
Creates an `MGLAttributedExpression` object initialized with an expression and the format attributes for font names and font size.
*/
-+ (instancetype)attributedExpression:(NSExpression *)expression fontNames:(nullable NSArray<NSString*> *)fontNames fontSize:(nullable NSNumber *)fontSize;
++ (instancetype)attributedExpression:(NSExpression *)expression fontNames:(nullable NSArray<NSString*> *)fontNames fontScale:(nullable NSNumber *)fontScale;
+
+/**
+ Creates an `MGLAttributedExpression` object initialized with an expression and the format attributes dictionary.
+ */
++ (instancetype)attributedExpression:(NSExpression *)expression attributes:(nonnull NSDictionary <MGLAttributedExpressionKey, NSExpression *> *)attrs;
@end
diff --git a/platform/darwin/src/MGLAttributedExpression.m b/platform/darwin/src/MGLAttributedExpression.m
index 715f74e42f..a34480a957 100644
--- a/platform/darwin/src/MGLAttributedExpression.m
+++ b/platform/darwin/src/MGLAttributedExpression.m
@@ -2,33 +2,42 @@
#import "MGLLoggingConfiguration_Private.h"
const MGLAttributedExpressionKey MGLFontNamesAttribute = @"text-font";
-const MGLAttributedExpressionKey MGLFontSizeAttribute = @"font-scale";
+const MGLAttributedExpressionKey MGLFontScaleAttribute = @"font-scale";
+const MGLAttributedExpressionKey MGLFontColorAttribute = @"text-color";
@implementation MGLAttributedExpression
- (instancetype)initWithExpression:(NSExpression *)expression {
- self = [self initWithExpression:expression attributes:nil];
+ self = [self initWithExpression:expression attributes:@{}];
return self;
}
-+ (instancetype)attributedExpression:(NSExpression *)expression fontNames:(nullable NSArray<NSString *> *)fontNames fontSize:(nullable NSNumber *)fontSize {
++ (instancetype)attributedExpression:(NSExpression *)expression fontNames:(nullable NSArray<NSString *> *)fontNames fontScale:(nullable NSNumber *)fontScale {
MGLAttributedExpression *attributedExpression;
NSMutableDictionary *attrs = [NSMutableDictionary dictionary];
if (fontNames && fontNames.count > 0) {
- attrs[MGLFontNamesAttribute] = fontNames;
+ attrs[MGLFontNamesAttribute] = [NSExpression expressionForConstantValue:fontNames];
}
- if (fontSize) {
- attrs[MGLFontSizeAttribute] = fontSize;
+ if (fontScale) {
+ attrs[MGLFontScaleAttribute] = [NSExpression expressionForConstantValue:fontScale];
}
attributedExpression = [[self alloc] initWithExpression:expression attributes:attrs];
return attributedExpression;
}
-- (instancetype)initWithExpression:(NSExpression *)expression attributes:(NSDictionary<MGLAttributedExpressionKey,id> *)attrs {
++ (instancetype)attributedExpression:(NSExpression *)expression attributes:(nonnull NSDictionary<MGLAttributedExpressionKey, NSExpression *> *)attrs {
+ MGLAttributedExpression *attributedExpression;
+
+ attributedExpression = [[self alloc] initWithExpression:expression attributes:attrs];
+
+ return attributedExpression;
+}
+
+- (instancetype)initWithExpression:(NSExpression *)expression attributes:(nonnull NSDictionary<MGLAttributedExpressionKey, NSExpression *> *)attrs {
if (self = [super init])
{
MGLLogInfo(@"Starting %@ initialization.", NSStringFromClass([self class]));
diff --git a/platform/darwin/src/MGLLoggingConfiguration.h b/platform/darwin/src/MGLLoggingConfiguration.h
index 6782dc60a7..d79336df4c 100644
--- a/platform/darwin/src/MGLLoggingConfiguration.h
+++ b/platform/darwin/src/MGLLoggingConfiguration.h
@@ -4,7 +4,7 @@
#ifndef MGL_LOGGING_DISABLED
#ifndef MGL_LOGGING_ENABLE_DEBUG
- #ifdef DEBUG
+ #ifndef NDEBUG
#define MGL_LOGGING_ENABLE_DEBUG 1
#endif
#endif
diff --git a/platform/darwin/src/MGLMapSnapshotter.mm b/platform/darwin/src/MGLMapSnapshotter.mm
index 3918008b78..171f24e4d0 100644
--- a/platform/darwin/src/MGLMapSnapshotter.mm
+++ b/platform/darwin/src/MGLMapSnapshotter.mm
@@ -3,8 +3,10 @@
#import <mbgl/actor/actor.hpp>
#import <mbgl/actor/scheduler.hpp>
#import <mbgl/util/geo.hpp>
+#import <mbgl/map/map_options.hpp>
#import <mbgl/map/map_snapshotter.hpp>
#import <mbgl/map/camera.hpp>
+#import <mbgl/storage/resource_options.hpp>
#import <mbgl/storage/default_file_source.hpp>
#import <mbgl/util/default_thread_pool.hpp>
#import <mbgl/util/string.hpp>
@@ -587,7 +589,9 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
_cancelled = NO;
_options = options;
- mbgl::DefaultFileSource *mbglFileSource = [MGLOfflineStorage sharedOfflineStorage].mbglFileSource;
+
+ auto mbglFileSource = [[MGLOfflineStorage sharedOfflineStorage] mbglFileSource];
+
_mbglThreadPool = mbgl::sharedThreadPool();
std::string styleURL = std::string([options.styleURL.absoluteString UTF8String]);
@@ -619,9 +623,14 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
// App-global configuration
MGLRendererConfiguration* config = [MGLRendererConfiguration currentConfiguration];
-
+
+ mbgl::ResourceOptions resourceOptions;
+ resourceOptions.withCachePath([[MGLOfflineStorage sharedOfflineStorage] mbglCachePath])
+ .withAssetPath([NSBundle mainBundle].resourceURL.path.UTF8String);
+
// Create the snapshotter
- _mbglMapSnapshotter = std::make_unique<mbgl::MapSnapshotter>(mbglFileSource, _mbglThreadPool, style, size, pixelRatio, cameraOptions, coordinateBounds, config.cacheDir, config.localFontFamilyName);
+ _mbglMapSnapshotter = std::make_unique<mbgl::MapSnapshotter>(
+ _mbglThreadPool, style, size, pixelRatio, cameraOptions, coordinateBounds, config.cacheDir, config.localFontFamilyName, resourceOptions);
}
@end
diff --git a/platform/darwin/src/MGLOfflinePack.mm b/platform/darwin/src/MGLOfflinePack.mm
index a8f807374c..0f2e8180fa 100644
--- a/platform/darwin/src/MGLOfflinePack.mm
+++ b/platform/darwin/src/MGLOfflinePack.mm
@@ -10,6 +10,7 @@
#import "NSValue+MGLAdditions.h"
+#include <mbgl/map/map_options.hpp>
#include <mbgl/storage/default_file_source.hpp>
const MGLExceptionName MGLInvalidOfflinePackException = @"MGLInvalidOfflinePackException";
@@ -58,6 +59,7 @@ private:
@implementation MGLOfflinePack {
BOOL _isSuspending;
+ std::shared_ptr<mbgl::DefaultFileSource> _mbglFileSource;
}
- (instancetype)init {
@@ -74,8 +76,8 @@ private:
_mbglOfflineRegion = region;
_state = MGLOfflinePackStateUnknown;
- mbgl::DefaultFileSource *mbglFileSource = [[MGLOfflineStorage sharedOfflineStorage] mbglFileSource];
- mbglFileSource->setOfflineRegionObserver(*_mbglOfflineRegion, std::make_unique<MBGLOfflineRegionObserver>(self));
+ _mbglFileSource = [[MGLOfflineStorage sharedOfflineStorage] mbglFileSource];
+ _mbglFileSource->setOfflineRegionObserver(*_mbglOfflineRegion, std::make_unique<MBGLOfflineRegionObserver>(self));
}
return self;
}
@@ -115,8 +117,7 @@ private:
self.state = MGLOfflinePackStateActive;
- mbgl::DefaultFileSource *mbglFileSource = [[MGLOfflineStorage sharedOfflineStorage] mbglFileSource];
- mbglFileSource->setOfflineRegionDownloadState(*_mbglOfflineRegion, mbgl::OfflineRegionDownloadState::Active);
+ _mbglFileSource->setOfflineRegionDownloadState(*_mbglOfflineRegion, mbgl::OfflineRegionDownloadState::Active);
}
- (void)suspend {
@@ -128,8 +129,7 @@ private:
_isSuspending = YES;
}
- mbgl::DefaultFileSource *mbglFileSource = [[MGLOfflineStorage sharedOfflineStorage] mbglFileSource];
- mbglFileSource->setOfflineRegionDownloadState(*_mbglOfflineRegion, mbgl::OfflineRegionDownloadState::Inactive);
+ _mbglFileSource->setOfflineRegionDownloadState(*_mbglOfflineRegion, mbgl::OfflineRegionDownloadState::Inactive);
}
- (void)invalidate {
@@ -137,8 +137,7 @@ private:
MGLAssert(_state != MGLOfflinePackStateInvalid, @"Cannot invalidate an already invalid offline pack.");
self.state = MGLOfflinePackStateInvalid;
- mbgl::DefaultFileSource *mbglFileSource = [[MGLOfflineStorage sharedOfflineStorage] mbglFileSource];
- mbglFileSource->setOfflineRegionObserver(*self.mbglOfflineRegion, nullptr);
+ _mbglFileSource->setOfflineRegionObserver(*self.mbglOfflineRegion, nullptr);
self.mbglOfflineRegion = nil;
}
@@ -164,10 +163,8 @@ private:
MGLLogInfo(@"Requesting pack progress.");
MGLAssertOfflinePackIsValid();
- mbgl::DefaultFileSource *mbglFileSource = [[MGLOfflineStorage sharedOfflineStorage] mbglFileSource];
-
__weak MGLOfflinePack *weakSelf = self;
- mbglFileSource->getOfflineRegionStatus(*_mbglOfflineRegion, [&, weakSelf](mbgl::expected<mbgl::OfflineRegionStatus, std::exception_ptr> status) {
+ _mbglFileSource->getOfflineRegionStatus(*_mbglOfflineRegion, [&, weakSelf](mbgl::expected<mbgl::OfflineRegionStatus, std::exception_ptr> status) {
if (status) {
mbgl::OfflineRegionStatus checkedStatus = *status;
dispatch_async(dispatch_get_main_queue(), ^{
diff --git a/platform/darwin/src/MGLOfflinePack_Private.h b/platform/darwin/src/MGLOfflinePack_Private.h
index 8a63152dca..ea3fb2da99 100644
--- a/platform/darwin/src/MGLOfflinePack_Private.h
+++ b/platform/darwin/src/MGLOfflinePack_Private.h
@@ -1,6 +1,6 @@
#import "MGLOfflinePack.h"
-#include <mbgl/storage/default_file_source.hpp>
+#include <mbgl/storage/offline.hpp>
NS_ASSUME_NONNULL_BEGIN
diff --git a/platform/darwin/src/MGLOfflineStorage.mm b/platform/darwin/src/MGLOfflineStorage.mm
index 4613b402fd..6effd8c3ce 100644
--- a/platform/darwin/src/MGLOfflineStorage.mm
+++ b/platform/darwin/src/MGLOfflineStorage.mm
@@ -10,7 +10,6 @@
#import "NSBundle+MGLAdditions.h"
#import "NSValue+MGLAdditions.h"
#import "NSDate+MGLAdditions.h"
-#import "NSData+MGLAdditions.h"
#import "MGLLoggingConfiguration_Private.h"
#if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
@@ -20,6 +19,8 @@
#include <mbgl/actor/actor.hpp>
#include <mbgl/actor/scheduler.hpp>
+#include <mbgl/storage/default_file_source.hpp>
+#include <mbgl/storage/resource_options.hpp>
#include <mbgl/storage/resource_transform.hpp>
#include <mbgl/util/chrono.hpp>
#include <mbgl/util/run_loop.hpp>
@@ -44,7 +45,8 @@ const MGLExceptionName MGLUnsupportedRegionTypeException = @"MGLUnsupportedRegio
@interface MGLOfflineStorage ()
@property (nonatomic, strong, readwrite) NSMutableArray<MGLOfflinePack *> *packs;
-@property (nonatomic) mbgl::DefaultFileSource *mbglFileSource;
+@property (nonatomic) std::shared_ptr<mbgl::DefaultFileSource> mbglFileSource;
+@property (nonatomic) std::string mbglCachePath;
@property (nonatomic, getter=isPaused) BOOL paused;
@end
@@ -223,7 +225,11 @@ const MGLExceptionName MGLUnsupportedRegionTypeException = @"MGLUnsupportedRegio
[[NSFileManager defaultManager] moveItemAtPath:subdirectorylessCacheURL.path toPath:cachePath error:NULL];
}
- _mbglFileSource = new mbgl::DefaultFileSource(cachePath.UTF8String, [NSBundle mainBundle].resourceURL.path.UTF8String);
+ _mbglCachePath = cachePath.UTF8String;
+ mbgl::ResourceOptions options;
+ options.withCachePath(_mbglCachePath)
+ .withAssetPath([NSBundle mainBundle].resourceURL.path.UTF8String);
+ _mbglFileSource = std::static_pointer_cast<mbgl::DefaultFileSource>(mbgl::FileSource::getSharedFileSource(options));
// Observe for changes to the API base URL (and find out the current one).
[[MGLAccountManager sharedManager] addObserver:self
@@ -250,9 +256,6 @@ const MGLExceptionName MGLUnsupportedRegionTypeException = @"MGLUnsupportedRegio
for (MGLOfflinePack *pack in self.packs) {
[pack invalidate];
}
-
- delete _mbglFileSource;
- _mbglFileSource = nullptr;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *, id> *)change context:(void *)context {
@@ -260,14 +263,14 @@ const MGLExceptionName MGLUnsupportedRegionTypeException = @"MGLUnsupportedRegio
if ([keyPath isEqualToString:@"accessToken"] && object == [MGLAccountManager sharedManager]) {
NSString *accessToken = change[NSKeyValueChangeNewKey];
if (![accessToken isKindOfClass:[NSNull class]]) {
- self.mbglFileSource->setAccessToken(accessToken.UTF8String);
+ _mbglFileSource->setAccessToken(accessToken.UTF8String);
}
} else if ([keyPath isEqualToString:@"apiBaseURL"] && object == [MGLAccountManager sharedManager]) {
NSURL *apiBaseURL = change[NSKeyValueChangeNewKey];
if ([apiBaseURL isKindOfClass:[NSNull class]]) {
- self.mbglFileSource->setAPIBaseURL(mbgl::util::API_BASE_URL);
+ _mbglFileSource->setAPIBaseURL(mbgl::util::API_BASE_URL);
} else {
- self.mbglFileSource->setAPIBaseURL(apiBaseURL.absoluteString.UTF8String);
+ _mbglFileSource->setAPIBaseURL(apiBaseURL.absoluteString.UTF8String);
}
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
@@ -333,7 +336,7 @@ const MGLExceptionName MGLUnsupportedRegionTypeException = @"MGLUnsupportedRegio
}
- (void)_addContentsOfFile:(NSString *)filePath withCompletionHandler:(void (^)(NSArray<MGLOfflinePack *> * _Nullable packs, NSError * _Nullable error))completion {
- self.mbglFileSource->mergeOfflineRegions(std::string(static_cast<const char *>([filePath UTF8String])), [&, completion, filePath](mbgl::expected<mbgl::OfflineRegions, std::exception_ptr> result) {
+ _mbglFileSource->mergeOfflineRegions(std::string(static_cast<const char *>([filePath UTF8String])), [&, completion, filePath](mbgl::expected<mbgl::OfflineRegions, std::exception_ptr> result) {
NSError *error;
NSMutableArray *packs;
if (!result) {
@@ -394,7 +397,7 @@ const MGLExceptionName MGLUnsupportedRegionTypeException = @"MGLUnsupportedRegio
const mbgl::OfflineRegionDefinition regionDefinition = [(id <MGLOfflineRegion_Private>)region offlineRegionDefinition];
mbgl::OfflineRegionMetadata metadata(context.length);
[context getBytes:&metadata[0] length:metadata.size()];
- self.mbglFileSource->createOfflineRegion(regionDefinition, metadata, [&, completion](mbgl::expected<mbgl::OfflineRegion, std::exception_ptr> mbglOfflineRegion) {
+ _mbglFileSource->createOfflineRegion(regionDefinition, metadata, [&, completion](mbgl::expected<mbgl::OfflineRegion, std::exception_ptr> mbglOfflineRegion) {
NSError *error;
if (!mbglOfflineRegion) {
NSString *errorDescription = @(mbgl::util::toString(mbglOfflineRegion.error()).c_str());
@@ -429,7 +432,7 @@ const MGLExceptionName MGLUnsupportedRegionTypeException = @"MGLUnsupportedRegio
return;
}
- self.mbglFileSource->deleteOfflineRegion(std::move(*mbglOfflineRegion), [&, completion](std::exception_ptr exception) {
+ _mbglFileSource->deleteOfflineRegion(std::move(*mbglOfflineRegion), [&, completion](std::exception_ptr exception) {
NSError *error;
if (exception) {
error = [NSError errorWithDomain:MGLErrorDomain code:-1 userInfo:@{
@@ -455,7 +458,7 @@ const MGLExceptionName MGLUnsupportedRegionTypeException = @"MGLUnsupportedRegio
}
- (void)getPacksWithCompletionHandler:(void (^)(NSArray<MGLOfflinePack *> *packs, NSError * _Nullable error))completion {
- self.mbglFileSource->listOfflineRegions([&, completion](mbgl::expected<mbgl::OfflineRegions, std::exception_ptr> result) {
+ _mbglFileSource->listOfflineRegions([&, completion](mbgl::expected<mbgl::OfflineRegions, std::exception_ptr> result) {
NSError *error;
NSMutableArray *packs;
if (!result) {
diff --git a/platform/darwin/src/MGLOfflineStorage_Private.h b/platform/darwin/src/MGLOfflineStorage_Private.h
index 7c7b80dc46..5ac64ea995 100644
--- a/platform/darwin/src/MGLOfflineStorage_Private.h
+++ b/platform/darwin/src/MGLOfflineStorage_Private.h
@@ -4,6 +4,8 @@
#include <mbgl/storage/default_file_source.hpp>
+#include <memory>
+
NS_ASSUME_NONNULL_BEGIN
@interface MGLOfflineStorage (Private)
@@ -11,7 +13,12 @@ NS_ASSUME_NONNULL_BEGIN
/**
The shared file source object owned by the shared offline storage object.
*/
-@property (nonatomic) mbgl::DefaultFileSource *mbglFileSource;
+@property (nonatomic) std::shared_ptr<mbgl::DefaultFileSource> mbglFileSource;
+
+/**
+ The shared offline cache path.
+ */
+@property (nonatomic) std::string mbglCachePath;
@end
diff --git a/platform/darwin/src/MGLRendererConfiguration.h b/platform/darwin/src/MGLRendererConfiguration.h
index a2ad4d6cdc..ef7122ec51 100644
--- a/platform/darwin/src/MGLRendererConfiguration.h
+++ b/platform/darwin/src/MGLRendererConfiguration.h
@@ -1,7 +1,8 @@
#import "MGLFoundation.h"
#import <Foundation/Foundation.h>
-#import <mbgl/storage/default_file_source.hpp>
-#import <mbgl/renderer/mode.hpp>
+
+#include <mbgl/renderer/mode.hpp>
+#include <mbgl/util/optional.hpp>
NS_ASSUME_NONNULL_BEGIN
@@ -15,9 +16,6 @@ MGL_EXPORT
/** Returns an instance of the current renderer configuration. */
@property (class, nonatomic, readonly) MGLRendererConfiguration *currentConfiguration;
-/** The file source to use. Defaults to `mbgl::DefaultFileSource` */
-@property (nonatomic, readonly) mbgl::DefaultFileSource *fileSource;
-
/** The GL context mode to use. Defaults to `mbgl::GLContextMode::Unique` */
@property (nonatomic, readonly) mbgl::GLContextMode contextMode;
diff --git a/platform/darwin/src/MGLRendererConfiguration.mm b/platform/darwin/src/MGLRendererConfiguration.mm
index 7a2f95cfda..78201987fe 100644
--- a/platform/darwin/src/MGLRendererConfiguration.mm
+++ b/platform/darwin/src/MGLRendererConfiguration.mm
@@ -57,10 +57,6 @@ static NSString * const MGLCollisionBehaviorPre4_0Key = @"MGLCollisionBehaviorPr
return self;
}
-- (mbgl::DefaultFileSource *)fileSource {
- return [MGLOfflineStorage sharedOfflineStorage].mbglFileSource;
-}
-
- (mbgl::GLContextMode)contextMode {
return mbgl::GLContextMode::Unique;
}
diff --git a/platform/darwin/src/MGLRendererFrontend.h b/platform/darwin/src/MGLRendererFrontend.h
index 2df67ca4e4..c0e03351c6 100644
--- a/platform/darwin/src/MGLRendererFrontend.h
+++ b/platform/darwin/src/MGLRendererFrontend.h
@@ -49,7 +49,12 @@ public:
mbgl::BackendScope guard { mbglBackend, mbgl::BackendScope::ScopeType::Implicit };
- renderer->render(*updateParameters);
+ // onStyleImageMissing might be called during a render. The user implemented method
+ // could trigger a call to MGLRenderFrontend#update which overwrites `updateParameters`.
+ // Copy the shared pointer here so that the parameters aren't destroyed while `render(...)` is
+ // still using them.
+ auto updateParameters_ = updateParameters;
+ renderer->render(*updateParameters_);
}
mbgl::Renderer* getRenderer() {
diff --git a/platform/darwin/src/MGLStyleValue_Private.h b/platform/darwin/src/MGLStyleValue_Private.h
index 84d7ccccec..fee34b4b71 100644
--- a/platform/darwin/src/MGLStyleValue_Private.h
+++ b/platform/darwin/src/MGLStyleValue_Private.h
@@ -307,10 +307,8 @@ private: // Private utilities for converting from mbgl to mgl values
// Enumerations
template <typename MBGLEnum = MBGLType, typename MGLEnum = ObjCEnum>
- static NSValue *toMGLRawStyleValue(const MBGLEnum &value) {
- auto str = mbgl::Enum<MBGLEnum>::toString(value);
- MGLEnum mglType = *mbgl::Enum<MGLEnum>::toEnum(str);
- return [NSValue value:&mglType withObjCType:@encode(MGLEnum)];
+ static NSString *toMGLRawStyleValue(const MBGLEnum &value) {
+ return @(mbgl::Enum<MBGLEnum>::toString(value));
}
/// Converts all types of mbgl property values into an equivalent NSExpression.
@@ -320,15 +318,6 @@ private: // Private utilities for converting from mbgl to mgl values
return nil;
}
- /**
- As hack to allow converting enum => string values, we accept a second, dummy parameter in
- the toRawStyleSpecValue() methods for converting 'atomic' (non-style-function) values.
- This allows us to use `std::enable_if` to test (at compile time) whether or not MBGLType is an Enum.
- */
- template <typename MBGLEnum = MBGLType,
- class = typename std::enable_if<!std::is_enum<MBGLEnum>::value>::type,
- typename MGLEnum = ObjCEnum,
- class = typename std::enable_if<!std::is_enum<MGLEnum>::value>::type>
NSExpression *operator()(const MBGLType &value) const {
id constantValue = toMGLRawStyleValue(value);
if ([constantValue isKindOfClass:[NSArray class]]) {
@@ -337,15 +326,6 @@ private: // Private utilities for converting from mbgl to mgl values
return [NSExpression expressionForConstantValue:constantValue];
}
- template <typename MBGLEnum = MBGLType,
- class = typename std::enable_if<std::is_enum<MBGLEnum>::value>::type,
- typename MGLEnum = ObjCEnum,
- class = typename std::enable_if<std::is_enum<MGLEnum>::value>::type>
- NSExpression *operator()(const MBGLEnum &value) const {
- NSString *constantValue = @(mbgl::Enum<MBGLEnum>::toString(value));
- return [NSExpression expressionForConstantValue:constantValue];
- }
-
NSExpression *operator()(const mbgl::style::PropertyExpression<MBGLType> &mbglValue) const {
return [NSExpression expressionWithMGLJSONObject:MGLJSONObjectFromMBGLExpression(mbglValue.getExpression())];
}
diff --git a/platform/darwin/src/MGLSymbolStyleLayer.h b/platform/darwin/src/MGLSymbolStyleLayer.h
index ee8afb1fb2..cf2c1466e7 100644
--- a/platform/darwin/src/MGLSymbolStyleLayer.h
+++ b/platform/darwin/src/MGLSymbolStyleLayer.h
@@ -223,6 +223,10 @@ typedef NS_ENUM(NSUInteger, MGLTextAnchor) {
*/
typedef NS_ENUM(NSUInteger, MGLTextJustification) {
/**
+ The text is aligned towards the anchor position.
+ */
+ MGLTextJustificationAuto,
+ /**
The text is aligned to the left.
*/
MGLTextJustificationLeft,
@@ -1279,6 +1283,7 @@ MGL_EXPORT
* Constant `MGLTextJustification` values
* Any of the following constant string values:
+ * `auto`: The text is aligned towards the anchor position.
* `left`: The text is aligned to the left.
* `center`: The text is centered.
* `right`: The text is aligned to the right.
@@ -1349,8 +1354,8 @@ MGL_EXPORT
`NSValue` object containing a `CGVector` struct set to 0 ems rightward and 0
ems downward. Set this property to `nil` to reset it to the default value.
- This property is only applied to the style if `text` is non-`nil`. Otherwise,
- it is ignored.
+ This property is only applied to the style if `text` is non-`nil`, and
+ `textRadialOffset` is set to `nil`. Otherwise, it is ignored.
You can set this property to an expression containing any of the following:
@@ -1372,8 +1377,8 @@ MGL_EXPORT
`NSValue` object containing a `CGVector` struct set to 0 ems rightward and 0
ems upward. Set this property to `nil` to reset it to the default value.
- This property is only applied to the style if `text` is non-`nil`. Otherwise,
- it is ignored.
+ This property is only applied to the style if `text` is non-`nil`, and
+ `textRadialOffset` is set to `nil`. Otherwise, it is ignored.
You can set this property to an expression containing any of the following:
@@ -1464,6 +1469,27 @@ MGL_EXPORT
@property (nonatomic, null_resettable) NSExpression *textPitchAlignment;
/**
+ Radial offset of text, in the direction of the symbol's anchor. Useful in
+ combination with `textVariableAnchor`, which doesn't support the
+ two-dimensional `textOffset`.
+
+ This property is measured in ems.
+
+ This property is only applied to the style if `textOffset` is set to `nil`.
+ Otherwise, it is ignored.
+
+ You can set this property to an expression containing any of the following:
+
+ * Constant numeric values
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Interpolation and step functions applied to the `$zoomLevel` variable and/or
+ feature attributes
+ */
+@property (nonatomic, null_resettable) NSExpression *textRadialOffset;
+
+/**
Rotates the text clockwise.
This property is measured in degrees.
@@ -1549,6 +1575,47 @@ MGL_EXPORT
*/
@property (nonatomic, null_resettable) NSExpression *textTransform;
+/**
+ To increase the chance of placing high-priority labels on the map, you can
+ provide an array of `textAnchor` locations: the render will attempt to place
+ the label at each location, in order, before moving onto the next label. Use
+ `textJustify: auto` to choose justification based on anchor position. To apply
+ an offset, use the `textRadialOffset` instead of the two-dimensional
+ `textOffset`.
+
+ This property is only applied to the style if `textAnchor` is set to `nil`, and
+ `textOffset` is set to `nil`, and `symbolPlacement` is set to an expression
+ that evaluates to or `MGLSymbolPlacementPoint`. Otherwise, it is ignored.
+
+ You can set this property to an expression containing any of the following:
+
+ * Constant `MGLTextAnchor` array values
+ * Constant array, whose each element is any of the following constant string
+ values:
+ * `center`: The center of the text is placed closest to the anchor.
+ * `left`: The left side of the text is placed closest to the anchor.
+ * `right`: The right side of the text is placed closest to the anchor.
+ * `top`: The top of the text is placed closest to the anchor.
+ * `bottom`: The bottom of the text is placed closest to the anchor.
+ * `top-left`: The top left corner of the text is placed closest to the
+ anchor.
+ * `top-right`: The top right corner of the text is placed closest to the
+ anchor.
+ * `bottom-left`: The bottom left corner of the text is placed closest to the
+ anchor.
+ * `bottom-right`: The bottom right corner of the text is placed closest to
+ the anchor.
+ * Predefined functions, including mathematical and string operators
+ * Conditional expressions
+ * Variable assignments and references to assigned variables
+ * Step functions applied to the `$zoomLevel` variable
+
+ This property does not support applying interpolation functions to the
+ `$zoomLevel` variable or applying interpolation or step functions to feature
+ attributes.
+ */
+@property (nonatomic, null_resettable) NSExpression *textVariableAnchor;
+
#pragma mark - Accessing the Paint Attributes
#if TARGET_OS_IPHONE
diff --git a/platform/darwin/src/MGLSymbolStyleLayer.mm b/platform/darwin/src/MGLSymbolStyleLayer.mm
index 60fc4d6881..6d91bbe87f 100644
--- a/platform/darwin/src/MGLSymbolStyleLayer.mm
+++ b/platform/darwin/src/MGLSymbolStyleLayer.mm
@@ -71,6 +71,7 @@ namespace mbgl {
});
MBGL_DEFINE_ENUM(MGLTextJustification, {
+ { MGLTextJustificationAuto, "auto" },
{ MGLTextJustificationLeft, "left" },
{ MGLTextJustificationCenter, "center" },
{ MGLTextJustificationRight, "right" },
@@ -906,6 +907,24 @@ namespace mbgl {
return MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLTextPitchAlignment>().toExpression(propertyValue);
}
+- (void)setTextRadialOffset:(NSExpression *)textRadialOffset {
+ MGLAssertStyleLayerIsValid();
+ MGLLogDebug(@"Setting textRadialOffset: %@", textRadialOffset);
+
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::PropertyValue<float>>(textRadialOffset, true);
+ self.rawLayer->setTextRadialOffset(mbglValue);
+}
+
+- (NSExpression *)textRadialOffset {
+ MGLAssertStyleLayerIsValid();
+
+ auto propertyValue = self.rawLayer->getTextRadialOffset();
+ if (propertyValue.isUndefined()) {
+ propertyValue = self.rawLayer->getDefaultTextRadialOffset();
+ }
+ return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue);
+}
+
- (void)setTextRotation:(NSExpression *)textRotation {
MGLAssertStyleLayerIsValid();
MGLLogDebug(@"Setting textRotation: %@", textRotation);
@@ -967,6 +986,24 @@ namespace mbgl {
return MGLStyleValueTransformer<mbgl::style::TextTransformType, NSValue *, mbgl::style::TextTransformType, MGLTextTransform>().toExpression(propertyValue);
}
+- (void)setTextVariableAnchor:(NSExpression *)textVariableAnchor {
+ MGLAssertStyleLayerIsValid();
+ MGLLogDebug(@"Setting textVariableAnchor: %@", textVariableAnchor);
+
+ auto mbglValue = MGLStyleValueTransformer<std::vector<mbgl::style::SymbolAnchorType>, NSArray<NSValue *> *, mbgl::style::SymbolAnchorType, MGLTextAnchor>().toPropertyValue<mbgl::style::PropertyValue<std::vector<mbgl::style::SymbolAnchorType>>>(textVariableAnchor, false);
+ self.rawLayer->setTextVariableAnchor(mbglValue);
+}
+
+- (NSExpression *)textVariableAnchor {
+ MGLAssertStyleLayerIsValid();
+
+ auto propertyValue = self.rawLayer->getTextVariableAnchor();
+ if (propertyValue.isUndefined()) {
+ propertyValue = self.rawLayer->getDefaultTextVariableAnchor();
+ }
+ return MGLStyleValueTransformer<std::vector<mbgl::style::SymbolAnchorType>, NSArray<NSValue *> *, mbgl::style::SymbolAnchorType, MGLTextAnchor>().toExpression(propertyValue);
+}
+
#pragma mark - Accessing the Paint Attributes
- (void)setIconColor:(NSExpression *)iconColor {
diff --git a/platform/darwin/src/NSBundle+MGLAdditions.m b/platform/darwin/src/NSBundle+MGLAdditions.m
index d472e40b1f..da70a95373 100644
--- a/platform/darwin/src/NSBundle+MGLAdditions.m
+++ b/platform/darwin/src/NSBundle+MGLAdditions.m
@@ -35,10 +35,15 @@ const MGLExceptionName MGLBundleNotFoundException = @"MGLBundleNotFoundException
+ (nullable NSString *)mgl_applicationBundleIdentifier {
NSString *bundleIdentifier = [NSBundle mainBundle].bundleIdentifier;
+
+#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && (__IPHONE_OS_VERSION_MAX_ALLOWED < 120200)) || \
+ (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && (__MAC_OS_X_VERSION_MAX_ALLOWED < 101404))
+ // Before SDK 12.2 (bundled with Xcode 10.2): There’s no main bundle identifier when running in a unit test bundle.
+ // 12.2 and after: the above bundle identifier is: com.apple.dt.xctest.tool
if (!bundleIdentifier) {
- // There’s no main bundle identifier when running in a unit test bundle.
bundleIdentifier = [NSBundle bundleForClass:[MGLAccountManager class]].bundleIdentifier;
}
+#endif
return bundleIdentifier;
}
diff --git a/platform/darwin/src/NSData+MGLAdditions.h b/platform/darwin/src/NSData+MGLAdditions.h
deleted file mode 100644
index 38af7961b6..0000000000
--- a/platform/darwin/src/NSData+MGLAdditions.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#import <Foundation/Foundation.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-@interface NSData (MGLAdditions)
-
-- (NSData *)mgl_compressedData;
-
-- (NSData *)mgl_decompressedData;
-
-@end
-
-NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/NSData+MGLAdditions.mm b/platform/darwin/src/NSData+MGLAdditions.mm
deleted file mode 100644
index 97c3bb4a26..0000000000
--- a/platform/darwin/src/NSData+MGLAdditions.mm
+++ /dev/null
@@ -1,23 +0,0 @@
-#import "NSData+MGLAdditions.h"
-
-#include <mbgl/util/compression.hpp>
-
-@implementation NSData (MGLAdditions)
-
-- (NSData *)mgl_compressedData
-{
- std::string string(static_cast<const char*>(self.bytes), self.length);
- std::string compressed_string = mbgl::util::compress(string);
-
- return [NSData dataWithBytes:&compressed_string[0] length:compressed_string.length()];
-}
-
-- (NSData *)mgl_decompressedData
-{
- std::string string(static_cast<const char*>(self.bytes), self.length);
- std::string decompressed_string = mbgl::util::decompress(string);
-
- return [NSData dataWithBytes:&decompressed_string[0] length:decompressed_string.length()];
-}
-
-@end
diff --git a/platform/darwin/src/NSExpression+MGLAdditions.mm b/platform/darwin/src/NSExpression+MGLAdditions.mm
index c4e2908888..4b1fdb818e 100644
--- a/platform/darwin/src/NSExpression+MGLAdditions.mm
+++ b/platform/darwin/src/NSExpression+MGLAdditions.mm
@@ -1,3 +1,4 @@
+#import "MGLFoundation_Private.h"
#import "NSExpression+MGLPrivateAdditions.h"
#import "MGLTypes.h"
@@ -878,9 +879,12 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) {
NSExpression *expression = [NSExpression expressionWithMGLJSONObject:argumentObjects[index]];
NSMutableDictionary *attrs = [NSMutableDictionary dictionary];
if ((index + 1) < argumentObjects.count) {
- attrs = argumentObjects[index + 1];
+ attrs = [NSMutableDictionary dictionaryWithDictionary:argumentObjects[index + 1]];
}
+ for (NSString *key in attrs.allKeys) {
+ attrs[key] = [NSExpression expressionWithMGLJSONObject:attrs[key]];
+ }
MGLAttributedExpression *attributedExpression = [[MGLAttributedExpression alloc] initWithExpression:expression attributes:attrs];
[attributedExpressions addObject:[NSExpression expressionForConstantValue:attributedExpression]];
@@ -1001,19 +1005,17 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) {
if ([constantValue isKindOfClass:[MGLAttributedExpression class]]) {
MGLAttributedExpression *attributedExpression = (MGLAttributedExpression *)constantValue;
id jsonObject = attributedExpression.expression.mgl_jsonExpressionObject;
- NSMutableArray *attributes = [NSMutableArray array];
- if ([jsonObject isKindOfClass:[NSArray class]]) {
- [attributes addObjectsFromArray:jsonObject];
- } else {
- [attributes addObject:jsonObject];
- }
+ NSMutableDictionary<MGLAttributedExpressionKey, NSExpression *> *attributedDictionary = [NSMutableDictionary dictionary];
+
if (attributedExpression.attributes) {
- [attributes addObject:attributedExpression.attributes];
- } else {
- [attributes addObject:@{}];
- }
-
- return attributes;
+ attributedDictionary = [NSMutableDictionary dictionaryWithDictionary:attributedExpression.attributes];
+
+ for (NSString *key in attributedExpression.attributes.allKeys) {
+ attributedDictionary[key] = attributedExpression.attributes[key].mgl_jsonExpressionObject;
+ }
+
+ }
+ return @[jsonObject, attributedDictionary];
}
return self.constantValue;
}
@@ -1215,27 +1217,10 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) {
}
case NSConditionalExpressionType: {
- NSMutableArray *arguments = [NSMutableArray arrayWithObjects:self.predicate.mgl_jsonExpressionObject, nil];
-
- if (self.trueExpression.expressionType == NSConditionalExpressionType) {
- // Fold nested conditionals into a single case expression.
- NSArray *trueArguments = self.trueExpression.mgl_jsonExpressionObject;
- trueArguments = [trueArguments subarrayWithRange:NSMakeRange(1, trueArguments.count - 1)];
- [arguments addObjectsFromArray:trueArguments];
- } else {
- [arguments addObject:self.trueExpression.mgl_jsonExpressionObject];
- }
-
- if (self.falseExpression.expressionType == NSConditionalExpressionType) {
- // Fold nested conditionals into a single case expression.
- NSArray *falseArguments = self.falseExpression.mgl_jsonExpressionObject;
- falseArguments = [falseArguments subarrayWithRange:NSMakeRange(1, falseArguments.count - 1)];
- [arguments addObjectsFromArray:falseArguments];
- } else {
- [arguments addObject:self.falseExpression.mgl_jsonExpressionObject];
- }
+ NSMutableArray *arguments = [NSMutableArray arrayWithObjects:@"case", self.predicate.mgl_jsonExpressionObject, nil];
+ [arguments addObject:self.trueExpression.mgl_jsonExpressionObject];
+ [arguments addObject:self.falseExpression.mgl_jsonExpressionObject];
- [arguments insertObject:@"case" atIndex:0];
return arguments;
}
diff --git a/platform/darwin/test/MGLAttributionInfoTests.m b/platform/darwin/test/MGLAttributionInfoTests.m
index 48779f3407..b6f053a8af 100644
--- a/platform/darwin/test/MGLAttributionInfoTests.m
+++ b/platform/darwin/test/MGLAttributionInfoTests.m
@@ -55,10 +55,21 @@
XCTAssertEqualObjects(infos[3].URL, [NSURL URLWithString:@"https://apps.mapbox.com/feedback/"]);
XCTAssertTrue(infos[3].feedbackLink);
NSURL *styleURL = [MGLStyle satelliteStreetsStyleURLWithVersion:99];
+
+#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 120200) || \
+ (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 101404)
+ NSString *bundleId = @"com.apple.dt.xctest.tool";
+#else
+ NSString *bundleId = @"com.mapbox.Mapbox";
+#endif
+
+ NSString *urlString = [NSString stringWithFormat:@"https://apps.mapbox.com/feedback/?referrer=%@#/77.63680/12.98108/14.00/0.0/0", bundleId];
XCTAssertEqualObjects([infos[3] feedbackURLAtCenterCoordinate:mapbox zoomLevel:14],
- [NSURL URLWithString:@"https://apps.mapbox.com/feedback/?referrer=com.mapbox.Mapbox#/77.63680/12.98108/14.00/0.0/0"]);
+ [NSURL URLWithString:urlString]);
+
+ urlString = [NSString stringWithFormat:@"https://apps.mapbox.com/feedback/?referrer=%@&owner=mapbox&id=satellite-streets-v99&access_token=pk.feedcafedeadbeefbadebede&map_sdk_version=1.0.0#/77.63680/12.98108/3.14/90.9/13", bundleId];
XCTAssertEqualObjects([infos[3] feedbackURLForStyleURL:styleURL atCenterCoordinate:mapbox zoomLevel:3.14159 direction:90.9 pitch:12.5],
- [NSURL URLWithString:@"https://apps.mapbox.com/feedback/?referrer=com.mapbox.Mapbox&owner=mapbox&id=satellite-streets-v99&access_token=pk.feedcafedeadbeefbadebede&map_sdk_version=1.0.0#/77.63680/12.98108/3.14/90.9/13"]);
+ [NSURL URLWithString:urlString]);
}
- (void)testStyle {
diff --git a/platform/darwin/test/MGLDocumentationExampleTests.swift b/platform/darwin/test/MGLDocumentationExampleTests.swift
index 91fb02dfd2..2a64fbc601 100644
--- a/platform/darwin/test/MGLDocumentationExampleTests.swift
+++ b/platform/darwin/test/MGLDocumentationExampleTests.swift
@@ -542,6 +542,24 @@ class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate {
}
}
+ func testMGLAttributedExpression() {
+ //#-example-code
+ #if os(macOS)
+ let redColor = NSColor.red
+ #else
+ let redColor = UIColor.red
+ #endif
+ let expression = NSExpression(forConstantValue: "Foo")
+ let attributes: [MGLAttributedExpressionKey: NSExpression] = [.fontNamesAttribute : NSExpression(forConstantValue: ["DIN Offc Pro Italic",
+ "Arial Unicode MS Regular"]),
+ .fontScaleAttribute: NSExpression(forConstantValue: 1.2),
+ .fontColorAttribute: NSExpression(forConstantValue: redColor)]
+ let attributedExpression = MGLAttributedExpression(expression, attributes:attributes)
+ //#-end-example-code
+
+ XCTAssertNotNil(attributedExpression)
+ }
+
// For testMGLMapView().
func myCustomFunction() {}
}
diff --git a/platform/darwin/test/MGLExpressionTests.mm b/platform/darwin/test/MGLExpressionTests.mm
index 8b8a79f184..68806e38f6 100644
--- a/platform/darwin/test/MGLExpressionTests.mm
+++ b/platform/darwin/test/MGLExpressionTests.mm
@@ -846,12 +846,9 @@ using namespace std::string_literals;
}
{
NSExpression *expression = [NSExpression expressionWithFormat:@"TERNARY(0 = 1, TRUE, TERNARY(1 = 2, TRUE, FALSE))"];
- NSArray *jsonExpression = @[@"case", @[@"==", @0, @1], @YES, @[@"==", @1, @2], @YES, @NO];
+ NSArray *jsonExpression = @[@"case", @[@"==", @0, @1], @YES, @[@"case", @[@"==", @1, @2], @YES, @NO]];
XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @NO);
- expression = [NSExpression expressionWithFormat:@"MGL_IF(%@, TRUE, %@, TRUE, FALSE)",
- MGLConstantExpression([NSPredicate predicateWithFormat:@"0 = 1"]),
- MGLConstantExpression([NSPredicate predicateWithFormat:@"1 = 2"])];
XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
}
{
@@ -995,16 +992,16 @@ using namespace std::string_literals;
{
MGLAttributedExpression *attribute1 = [MGLAttributedExpression attributedExpression:[NSExpression expressionForConstantValue:@"foo"]
fontNames:nil
- fontSize:@(1.2)];
+ fontScale:@(1.2)];
MGLAttributedExpression *attribute2 = [MGLAttributedExpression attributedExpression:[NSExpression expressionForConstantValue:@"biz"]
fontNames:nil
- fontSize:@(1.0)];
+ fontScale:@(1.0)];
MGLAttributedExpression *attribute3 = [MGLAttributedExpression attributedExpression:[NSExpression expressionForConstantValue:@"bar"]
fontNames:nil
- fontSize:@(0.8)];
+ fontScale:@(0.8)];
MGLAttributedExpression *attribute4 = [MGLAttributedExpression attributedExpression:[NSExpression expressionForConstantValue:@"\r"]
fontNames:@[]
- fontSize:nil];
+ fontScale:nil];
NSExpression *expression = [NSExpression expressionWithFormat:@"mgl_attributed:(%@, %@, %@, %@)",
MGLConstantExpression(attribute1),
MGLConstantExpression(attribute4),
@@ -1017,16 +1014,16 @@ using namespace std::string_literals;
{
MGLAttributedExpression *attribute1 = [MGLAttributedExpression attributedExpression:[NSExpression expressionForConstantValue:@"foo"]
fontNames:nil
- fontSize:@(1.2)];
+ fontScale:@(1.2)];
MGLAttributedExpression *attribute2 = [MGLAttributedExpression attributedExpression:[NSExpression expressionForConstantValue:@"biz"]
fontNames:nil
- fontSize:@(1.0)];
+ fontScale:@(1.0)];
MGLAttributedExpression *attribute3 = [MGLAttributedExpression attributedExpression:[NSExpression expressionForConstantValue:@"bar"]
fontNames:nil
- fontSize:@(0.8)];
+ fontScale:@(0.8)];
MGLAttributedExpression *attribute4 = [MGLAttributedExpression attributedExpression:[NSExpression expressionForConstantValue:@"\n"]
fontNames:@[]
- fontSize:nil];
+ fontScale:nil];
NSExpression *expression = [NSExpression expressionWithFormat:@"mgl_attributed:(%@, %@, %@, %@)",
MGLConstantExpression(attribute1),
MGLConstantExpression(attribute4),
@@ -1039,7 +1036,7 @@ using namespace std::string_literals;
{
MGLAttributedExpression *attribute1 = [MGLAttributedExpression attributedExpression:[NSExpression expressionForConstantValue:@"foo"]
fontNames:nil
- fontSize:@(1.2)];
+ fontScale:@(1.2)];
NSExpression *expression = [NSExpression expressionWithFormat:@"mgl_attributed:(%@)", MGLConstantExpression(attribute1)];
NSExpression *compatibilityExpression = [NSExpression expressionForFunction:@"mgl_attributed:" arguments:@[MGLConstantExpression(attribute1)]];
@@ -1050,18 +1047,79 @@ using namespace std::string_literals;
XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
}
{
+ MGLAttributedExpression *attribute1 = [[MGLAttributedExpression alloc] initWithExpression:[NSExpression expressionForConstantValue:@"foo"]
+ attributes:@{ MGLFontScaleAttribute: MGLConstantExpression(@(1.2)),
+ MGLFontColorAttribute: MGLConstantExpression(@"yellow") }] ;
+ NSExpression *expression = [NSExpression expressionWithFormat:@"mgl_attributed:(%@)", MGLConstantExpression(attribute1)];
+
+ NSExpression *compatibilityExpression = [NSExpression expressionForFunction:@"mgl_attributed:" arguments:@[MGLConstantExpression(attribute1)]];
+ NSArray *jsonExpression = @[ @"format", @"foo", @{ @"font-scale": @1.2, @"text-color": @"yellow" } ];
+ XCTAssertEqualObjects(compatibilityExpression.mgl_jsonExpressionObject, expression.mgl_jsonExpressionObject);
+ XCTAssertEqualObjects(compatibilityExpression, expression);
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ MGLAttributedExpression *attribute1 = [[MGLAttributedExpression alloc] initWithExpression:[NSExpression expressionForConstantValue:@"foo"]] ;
+ NSExpression *expression = [NSExpression expressionWithFormat:@"mgl_attributed:(%@)", MGLConstantExpression(attribute1)];
+
+ NSArray *jsonExpression = @[ @"format", @"foo", @{ } ];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *fontNames = [NSExpression expressionForAggregate:@[ MGLConstantExpression(@"DIN Offc Pro Bold"), MGLConstantExpression(@"Arial Unicode MS Bold") ]];
+ MGLAttributedExpression *attribute1 = [[MGLAttributedExpression alloc] initWithExpression:[NSExpression expressionForConstantValue:@"foo"]
+ attributes:@{ MGLFontScaleAttribute: MGLConstantExpression(@(1.2)),
+ MGLFontColorAttribute: MGLConstantExpression(@"yellow"),
+ MGLFontNamesAttribute: fontNames
+ }] ;
+ NSExpression *expression = [NSExpression expressionWithFormat:@"mgl_attributed:(%@)", MGLConstantExpression(attribute1)];
+
+ NSArray *jsonExpression = @[ @"format", @"foo", @{ @"font-scale": @1.2, @"text-color": @"yellow" , @"text-font" : @[ @"literal", @[ @"DIN Offc Pro Bold", @"Arial Unicode MS Bold" ]]} ];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ NSExpression *exp = [NSExpression expressionWithMGLJSONObject:jsonExpression];
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *fontNames = [NSExpression expressionForAggregate:@[ MGLConstantExpression(@"DIN Offc Pro Bold"), MGLConstantExpression(@"Arial Unicode MS Bold") ]];
+ MGLAttributedExpression *attribute1 = [[MGLAttributedExpression alloc] initWithExpression:[NSExpression expressionForConstantValue:@"foo"]
+ attributes:@{ MGLFontScaleAttribute: MGLConstantExpression(@(1.2)),
+ MGLFontColorAttribute: MGLConstantExpression([MGLColor redColor]),
+ MGLFontNamesAttribute: fontNames
+ }] ;
+ NSExpression *expression = [NSExpression expressionWithFormat:@"mgl_attributed:(%@)", MGLConstantExpression(attribute1)];
+
+ NSArray *jsonExpression = @[ @"format", @"foo", @{ @"font-scale": @1.2, @"text-color": @[@"rgb", @255, @0, @0] , @"text-font" : @[ @"literal", @[ @"DIN Offc Pro Bold", @"Arial Unicode MS Bold" ]]} ];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *fontNames = [NSExpression expressionForAggregate:@[ MGLConstantExpression(@"DIN Offc Pro Bold"), MGLConstantExpression(@"Arial Unicode MS Bold") ]];
+ MGLAttributedExpression *attribute1 = [[MGLAttributedExpression alloc] initWithExpression:[NSExpression expressionWithFormat:@"CAST(x, 'NSString')"]
+ attributes:@{ MGLFontScaleAttribute: MGLConstantExpression(@(1.2)),
+ MGLFontColorAttribute: MGLConstantExpression([MGLColor redColor]),
+ MGLFontNamesAttribute: fontNames
+ }] ;
+ NSExpression *expression = [NSExpression expressionWithFormat:@"mgl_attributed:(%@)", MGLConstantExpression(attribute1)];
+
+ NSArray *jsonExpression = @[ @"format", @[@"to-string", @[@"get", @"x"]], @{ @"font-scale": @1.2, @"text-color": @[@"rgb", @255, @0, @0] , @"text-font" : @[ @"literal", @[ @"DIN Offc Pro Bold", @"Arial Unicode MS Bold" ]]} ];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
MGLAttributedExpression *attribute1 = [MGLAttributedExpression attributedExpression:[NSExpression expressionForConstantValue:@"foo"]
fontNames:nil
- fontSize:@(1.2)];
+ fontScale:@(1.2)];
MGLAttributedExpression *attribute2 = [MGLAttributedExpression attributedExpression:[NSExpression expressionForConstantValue:@"biz"]
fontNames:nil
- fontSize:@(1.0)];
+ fontScale:@(1.0)];
MGLAttributedExpression *attribute3 = [MGLAttributedExpression attributedExpression:[NSExpression expressionForConstantValue:@"bar"]
fontNames:nil
- fontSize:@(0.8)];
+ fontScale:@(0.8)];
MGLAttributedExpression *attribute4 = [MGLAttributedExpression attributedExpression:[NSExpression expressionForConstantValue:@"\n"]
fontNames:@[]
- fontSize:nil];
+ fontScale:nil];
NSExpression *expression = [NSExpression mgl_expressionForAttributedExpressions:@[MGLConstantExpression(attribute1),
MGLConstantExpression(attribute4),
MGLConstantExpression(attribute2),
diff --git a/platform/darwin/test/MGLOfflineStorageTests.mm b/platform/darwin/test/MGLOfflineStorageTests.mm
index 7f0ead7cab..86dc28eb04 100644
--- a/platform/darwin/test/MGLOfflineStorageTests.mm
+++ b/platform/darwin/test/MGLOfflineStorageTests.mm
@@ -1,6 +1,7 @@
#import <Mapbox/Mapbox.h>
#import "MGLOfflineStorage_Private.h"
+#import "NSBundle+MGLAdditions.h"
#import "NSDate+MGLAdditions.h"
#import <XCTest/XCTest.h>
@@ -10,7 +11,6 @@
#pragma clang diagnostic ignored "-Wshadow"
@interface MGLOfflineStorageTests : XCTestCase <MGLOfflineStorageDelegate>
-
@end
@implementation MGLOfflineStorageTests
@@ -21,8 +21,7 @@
appropriateForURL:nil
create:NO
error:nil];
- // Unit tests don't use the main bundle; use com.mapbox.ios.sdk instead.
- NSString *bundleIdentifier = [NSBundle bundleForClass:[MGLMapView class]].bundleIdentifier;
+ NSString *bundleIdentifier = [NSBundle mgl_applicationBundleIdentifier];
cacheDirectoryURL = [cacheDirectoryURL URLByAppendingPathComponent:bundleIdentifier];
cacheDirectoryURL = [cacheDirectoryURL URLByAppendingPathComponent:@".mapbox"];
XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:cacheDirectoryURL.path], @"Cache subdirectory should exist.");
@@ -208,8 +207,8 @@
appropriateForURL:nil
create:NO
error:nil];
- // Unit tests don't use the main bundle; use com.mapbox.ios.sdk instead.
- NSString *bundleIdentifier = [NSBundle bundleForClass:[MGLMapView class]].bundleIdentifier;
+ // As of iOS SDK 12.2 unit tests now have a bundle id: com.apple.dt.xctest.tool
+ NSString *bundleIdentifier = [NSBundle mgl_applicationBundleIdentifier];
cacheDirectoryURL = [cacheDirectoryURL URLByAppendingPathComponent:bundleIdentifier];
cacheDirectoryURL = [cacheDirectoryURL URLByAppendingPathComponent:@".mapbox"];
XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:cacheDirectoryURL.path], @"Cache subdirectory should exist.");
diff --git a/platform/darwin/test/MGLSymbolStyleLayerTests.mm b/platform/darwin/test/MGLSymbolStyleLayerTests.mm
index 2f4206a96b..083b12bcc3 100644
--- a/platform/darwin/test/MGLSymbolStyleLayerTests.mm
+++ b/platform/darwin/test/MGLSymbolStyleLayerTests.mm
@@ -1741,6 +1741,75 @@
XCTAssertThrowsSpecificNamed(layer.textPitchAlignment = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
}
+ // text-radial-offset
+ {
+ XCTAssertTrue(rawLayer->getTextRadialOffset().isUndefined(),
+ @"text-radial-offset should be unset initially.");
+ NSExpression *defaultExpression = layer.textRadialOffset;
+
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"1"];
+ layer.textRadialOffset = constantExpression;
+ mbgl::style::PropertyValue<float> propertyValue = { 1.0 };
+ XCTAssertEqual(rawLayer->getTextRadialOffset(), propertyValue,
+ @"Setting textRadialOffset to a constant value expression should update text-radial-offset.");
+ XCTAssertEqualObjects(layer.textRadialOffset, constantExpression,
+ @"textRadialOffset should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"1"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.textRadialOffset = functionExpression;
+
+ {
+ using namespace mbgl::style::expression::dsl;
+ propertyValue = mbgl::style::PropertyExpression<float>(
+ step(zoom(), literal(1.0), 18.0, literal(1.0))
+ );
+ }
+
+ XCTAssertEqual(rawLayer->getTextRadialOffset(), propertyValue,
+ @"Setting textRadialOffset to a camera expression should update text-radial-offset.");
+ XCTAssertEqualObjects(layer.textRadialOffset, functionExpression,
+ @"textRadialOffset should round-trip camera expressions.");
+
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
+ layer.textRadialOffset = functionExpression;
+
+ {
+ using namespace mbgl::style::expression::dsl;
+ propertyValue = mbgl::style::PropertyExpression<float>(
+ interpolate(linear(), number(get("keyName")), 18.0, literal(1.0))
+ );
+ }
+
+ XCTAssertEqual(rawLayer->getTextRadialOffset(), propertyValue,
+ @"Setting textRadialOffset to a data expression should update text-radial-offset.");
+ NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}];
+ XCTAssertEqualObjects(layer.textRadialOffset, pedanticFunctionExpression,
+ @"textRadialOffset should round-trip data expressions.");
+
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ layer.textRadialOffset = functionExpression;
+
+ {
+ using namespace mbgl::style::expression::dsl;
+ propertyValue = mbgl::style::PropertyExpression<float>(
+ interpolate(linear(), zoom(), 10.0, interpolate(linear(), number(get("keyName")), 18.0, literal(1.0)))
+ );
+ }
+
+ XCTAssertEqual(rawLayer->getTextRadialOffset(), propertyValue,
+ @"Setting textRadialOffset to a camera-data expression should update text-radial-offset.");
+ pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
+ XCTAssertEqualObjects(layer.textRadialOffset, pedanticFunctionExpression,
+ @"textRadialOffset should round-trip camera-data expressions.");
+
+ layer.textRadialOffset = nil;
+ XCTAssertTrue(rawLayer->getTextRadialOffset().isUndefined(),
+ @"Unsetting textRadialOffset should return text-radial-offset to the default value.");
+ XCTAssertEqualObjects(layer.textRadialOffset, defaultExpression,
+ @"textRadialOffset should return the default value after being unset.");
+ }
+
// text-rotate
{
XCTAssertTrue(rawLayer->getTextRotate().isUndefined(),
@@ -1892,6 +1961,50 @@
@"textTransform should return the default value after being unset.");
}
+ // text-variable-anchor
+ {
+ XCTAssertTrue(rawLayer->getTextVariableAnchor().isUndefined(),
+ @"text-variable-anchor should be unset initially.");
+ NSExpression *defaultExpression = layer.textVariableAnchor;
+
+ NSExpression *constantExpression = [NSExpression expressionWithFormat:@"{'top','bottom'}"];
+ layer.textVariableAnchor = constantExpression;
+ mbgl::style::PropertyValue<std::vector<mbgl::style::SymbolAnchorType>> propertyValue = { { mbgl::style::SymbolAnchorType::Top, mbgl::style::SymbolAnchorType::Bottom } };
+ XCTAssertEqual(rawLayer->getTextVariableAnchor(), propertyValue,
+ @"Setting textVariableAnchor to a constant value expression should update text-variable-anchor.");
+ XCTAssertEqualObjects(layer.textVariableAnchor, constantExpression,
+ @"textVariableAnchor should round-trip constant value expressions.");
+
+ constantExpression = [NSExpression expressionWithFormat:@"{'top','bottom'}"];
+ NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}];
+ layer.textVariableAnchor = functionExpression;
+
+ {
+ using namespace mbgl::style::expression::dsl;
+ propertyValue = mbgl::style::PropertyExpression<std::vector<mbgl::style::SymbolAnchorType>>(
+ step(zoom(), literal({"top", "bottom"}), 18.0, literal({"top", "bottom"}))
+ );
+ }
+
+ XCTAssertEqual(rawLayer->getTextVariableAnchor(), propertyValue,
+ @"Setting textVariableAnchor to a camera expression should update text-variable-anchor.");
+ XCTAssertEqualObjects(layer.textVariableAnchor, functionExpression,
+ @"textVariableAnchor should round-trip camera expressions.");
+
+
+ layer.textVariableAnchor = nil;
+ XCTAssertTrue(rawLayer->getTextVariableAnchor().isUndefined(),
+ @"Unsetting textVariableAnchor should return text-variable-anchor to the default value.");
+ XCTAssertEqualObjects(layer.textVariableAnchor, defaultExpression,
+ @"textVariableAnchor should return the default value after being unset.");
+
+ functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
+ XCTAssertThrowsSpecificNamed(layer.textVariableAnchor = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}];
+ functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}];
+ XCTAssertThrowsSpecificNamed(layer.textVariableAnchor = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
+ }
+
// icon-color
{
XCTAssertTrue(rawLayer->getIconColor().isUndefined(),
@@ -2896,9 +3009,11 @@
[self testPropertyName:@"is-text-optional" isBoolean:YES];
[self testPropertyName:@"text-padding" isBoolean:NO];
[self testPropertyName:@"text-pitch-alignment" isBoolean:NO];
+ [self testPropertyName:@"text-radial-offset" isBoolean:NO];
[self testPropertyName:@"text-rotation" isBoolean:NO];
[self testPropertyName:@"text-rotation-alignment" isBoolean:NO];
[self testPropertyName:@"text-transform" isBoolean:NO];
+ [self testPropertyName:@"text-variable-anchor" isBoolean:NO];
[self testPropertyName:@"icon-color" isBoolean:NO];
[self testPropertyName:@"icon-halo-blur" isBoolean:NO];
[self testPropertyName:@"icon-halo-color" isBoolean:NO];
@@ -2949,6 +3064,7 @@
XCTAssertEqual([NSValue valueWithMGLTextAnchor:MGLTextAnchorTopRight].MGLTextAnchorValue, MGLTextAnchorTopRight);
XCTAssertEqual([NSValue valueWithMGLTextAnchor:MGLTextAnchorBottomLeft].MGLTextAnchorValue, MGLTextAnchorBottomLeft);
XCTAssertEqual([NSValue valueWithMGLTextAnchor:MGLTextAnchorBottomRight].MGLTextAnchorValue, MGLTextAnchorBottomRight);
+ XCTAssertEqual([NSValue valueWithMGLTextJustification:MGLTextJustificationAuto].MGLTextJustificationValue, MGLTextJustificationAuto);
XCTAssertEqual([NSValue valueWithMGLTextJustification:MGLTextJustificationLeft].MGLTextJustificationValue, MGLTextJustificationLeft);
XCTAssertEqual([NSValue valueWithMGLTextJustification:MGLTextJustificationCenter].MGLTextJustificationValue, MGLTextJustificationCenter);
XCTAssertEqual([NSValue valueWithMGLTextJustification:MGLTextJustificationRight].MGLTextJustificationValue, MGLTextJustificationRight);
diff --git a/platform/default/include/mbgl/map/map_snapshotter.hpp b/platform/default/include/mbgl/map/map_snapshotter.hpp
index 2deb2b3cda..ccc3ee17f7 100644
--- a/platform/default/include/mbgl/map/map_snapshotter.hpp
+++ b/platform/default/include/mbgl/map/map_snapshotter.hpp
@@ -18,6 +18,7 @@ struct CameraOptions;
class FileSource;
class Size;
class LatLngBounds;
+class ResourceOptions;
namespace style {
class Style;
@@ -25,15 +26,15 @@ class Style;
class MapSnapshotter {
public:
- MapSnapshotter(FileSource* fileSource,
- std::shared_ptr<Scheduler> scheduler,
+ MapSnapshotter(std::shared_ptr<Scheduler> scheduler,
const std::pair<bool, std::string> style,
const Size&,
const float pixelRatio,
const optional<CameraOptions> cameraOptions,
const optional<LatLngBounds> region,
- const optional<std::string> cacheDir = {},
- const optional<std::string> localFontFamily = {});
+ const optional<std::string> cacheDir,
+ const optional<std::string> localFontFamily,
+ const ResourceOptions&);
~MapSnapshotter();
diff --git a/platform/default/src/mbgl/gl/headless_frontend.cpp b/platform/default/src/mbgl/gl/headless_frontend.cpp
index f3dae2dbc9..c311e2df41 100644
--- a/platform/default/src/mbgl/gl/headless_frontend.cpp
+++ b/platform/default/src/mbgl/gl/headless_frontend.cpp
@@ -20,7 +20,13 @@ HeadlessFrontend::HeadlessFrontend(Size size_, float pixelRatio_, Scheduler& sch
asyncInvalidate([this] {
if (renderer && updateParameters) {
mbgl::BackendScope guard { backend };
- renderer->render(*updateParameters);
+
+ // onStyleImageMissing might be called during a render. The user implemented method
+ // could trigger a call to MGLRenderFrontend#update which overwrites `updateParameters`.
+ // Copy the shared pointer here so that the parameters aren't destroyed while `render(...)` is
+ // still using them.
+ auto updateParameters_ = updateParameters;
+ renderer->render(*updateParameters_);
}
}),
renderer(std::make_unique<Renderer>(backend, pixelRatio, scheduler, mode, programCacheDir, localFontFamily)) {
diff --git a/platform/default/src/mbgl/map/map_snapshotter.cpp b/platform/default/src/mbgl/map/map_snapshotter.cpp
index 415ef7befd..227a61d272 100644
--- a/platform/default/src/mbgl/map/map_snapshotter.cpp
+++ b/platform/default/src/mbgl/map/map_snapshotter.cpp
@@ -5,7 +5,7 @@
#include <mbgl/map/map.hpp>
#include <mbgl/map/map_options.hpp>
#include <mbgl/map/transform_state.hpp>
-#include <mbgl/storage/file_source.hpp>
+#include <mbgl/storage/resource_options.hpp>
#include <mbgl/style/style.hpp>
#include <mbgl/util/event.hpp>
#include <mbgl/map/transform.hpp>
@@ -14,15 +14,15 @@ namespace mbgl {
class MapSnapshotter::Impl {
public:
- Impl(FileSource*,
- std::shared_ptr<Scheduler>,
+ Impl(std::shared_ptr<Scheduler>,
const std::pair<bool, std::string> style,
const Size&,
const float pixelRatio,
const optional<CameraOptions> cameraOptions,
const optional<LatLngBounds> region,
const optional<std::string> programCacheDir,
- const optional<std::string> localFontFamily = {});
+ const optional<std::string> localFontFamily,
+ const ResourceOptions& resourceOptions);
void setStyleURL(std::string styleURL);
std::string getStyleURL() const;
@@ -47,19 +47,20 @@ private:
Map map;
};
-MapSnapshotter::Impl::Impl(FileSource* fileSource,
- std::shared_ptr<Scheduler> scheduler_,
- const std::pair<bool, std::string> style,
- const Size& size,
- const float pixelRatio,
- const optional<CameraOptions> cameraOptions,
- const optional<LatLngBounds> region,
- const optional<std::string> programCacheDir,
- const optional<std::string> localFontFamily)
- : scheduler(std::move(scheduler_))
- , frontend(size, pixelRatio, *scheduler, programCacheDir, GLContextMode::Unique, localFontFamily)
- , map(frontend, MapObserver::nullObserver(), size, pixelRatio, *fileSource, *scheduler, MapOptions().withMapMode(MapMode::Static)) {
-
+MapSnapshotter::Impl::Impl(std::shared_ptr<Scheduler> scheduler_,
+ const std::pair<bool, std::string> style,
+ const Size& size,
+ const float pixelRatio,
+ const optional<CameraOptions> cameraOptions,
+ const optional<LatLngBounds> region,
+ const optional<std::string> programCacheDir,
+ const optional<std::string> localFontFamily,
+ const ResourceOptions& resourceOptions)
+ : scheduler(std::move(scheduler_))
+ , frontend(size, pixelRatio, *scheduler, programCacheDir, GLContextMode::Unique, localFontFamily)
+ , map(frontend, MapObserver::nullObserver(), *scheduler,
+ MapOptions().withMapMode(MapMode::Static).withSize(size).withPixelRatio(pixelRatio),
+ resourceOptions) {
if (style.first) {
map.getStyle().loadJSON(style.second);
} else{
@@ -142,7 +143,7 @@ void MapSnapshotter::Impl::setSize(Size size) {
}
Size MapSnapshotter::Impl::getSize() const {
- return map.getSize();
+ return map.getMapOptions().size();
}
void MapSnapshotter::Impl::setCameraOptions(CameraOptions cameraOptions) {
@@ -164,17 +165,18 @@ LatLngBounds MapSnapshotter::Impl::getRegion() const {
return map.latLngBoundsForCamera(getCameraOptions());
}
-MapSnapshotter::MapSnapshotter(FileSource* fileSource,
- std::shared_ptr<Scheduler> scheduler,
+MapSnapshotter::MapSnapshotter(std::shared_ptr<Scheduler> scheduler,
const std::pair<bool, std::string> style,
const Size& size,
const float pixelRatio,
const optional<CameraOptions> cameraOptions,
const optional<LatLngBounds> region,
const optional<std::string> programCacheDir,
- const optional<std::string> localFontFamily)
- : impl(std::make_unique<util::Thread<MapSnapshotter::Impl>>("Map Snapshotter", fileSource, std::move(scheduler), style, size, pixelRatio, cameraOptions, region, programCacheDir, localFontFamily)) {
-}
+ const optional<std::string> localFontFamily,
+ const ResourceOptions& resourceOptions)
+ : impl(std::make_unique<util::Thread<MapSnapshotter::Impl>>(
+ "Map Snapshotter", std::move(scheduler), style, size, pixelRatio, cameraOptions,
+ region, programCacheDir, localFontFamily, resourceOptions.clone())) {}
MapSnapshotter::~MapSnapshotter() = default;
diff --git a/platform/default/src/mbgl/storage/default_file_source.cpp b/platform/default/src/mbgl/storage/default_file_source.cpp
index 32eb8b3d58..4d812044cf 100644
--- a/platform/default/src/mbgl/storage/default_file_source.cpp
+++ b/platform/default/src/mbgl/storage/default_file_source.cpp
@@ -201,9 +201,9 @@ private:
};
DefaultFileSource::DefaultFileSource(const std::string& cachePath,
- const std::string& assetRoot,
+ const std::string& assetPath,
uint64_t maximumCacheSize)
- : DefaultFileSource(cachePath, std::make_unique<AssetFileSource>(assetRoot), maximumCacheSize) {
+ : DefaultFileSource(cachePath, std::make_unique<AssetFileSource>(assetPath), maximumCacheSize) {
}
DefaultFileSource::DefaultFileSource(const std::string& cachePath,
diff --git a/platform/default/src/mbgl/storage/file_source.cpp b/platform/default/src/mbgl/storage/file_source.cpp
new file mode 100644
index 0000000000..a7bbe82f5a
--- /dev/null
+++ b/platform/default/src/mbgl/storage/file_source.cpp
@@ -0,0 +1,15 @@
+#include <mbgl/storage/resource_options.hpp>
+#include <mbgl/storage/default_file_source.hpp>
+
+#include <memory>
+
+namespace mbgl {
+
+std::shared_ptr<FileSource> FileSource::createPlatformFileSource(const ResourceOptions& options) {
+ auto fileSource = std::make_shared<DefaultFileSource>(options.cachePath(), options.assetPath());
+ fileSource->setAccessToken(options.accessToken());
+ fileSource->setAPIBaseURL(options.baseURL());
+ return fileSource;
+}
+
+} // namespace mbgl
diff --git a/platform/glfw/glfw_renderer_frontend.cpp b/platform/glfw/glfw_renderer_frontend.cpp
index 73205f1c56..9c5320cc78 100644
--- a/platform/glfw/glfw_renderer_frontend.cpp
+++ b/platform/glfw/glfw_renderer_frontend.cpp
@@ -32,7 +32,12 @@ void GLFWRendererFrontend::render() {
mbgl::BackendScope guard { glfwView, mbgl::BackendScope::ScopeType::Implicit };
- renderer->render(*updateParameters);
+ // onStyleImageMissing might be called during a render. The user implemented method
+ // could trigger a call to MGLRenderFrontend#update which overwrites `updateParameters`.
+ // Copy the shared pointer here so that the parameters aren't destroyed while `render(...)` is
+ // still using them.
+ auto updateParameters_ = updateParameters;
+ renderer->render(*updateParameters_);
}
mbgl::Renderer* GLFWRendererFrontend::getRenderer() {
diff --git a/platform/glfw/glfw_view.cpp b/platform/glfw/glfw_view.cpp
index e768851a53..601642cfa6 100644
--- a/platform/glfw/glfw_view.cpp
+++ b/platform/glfw/glfw_view.cpp
@@ -385,7 +385,7 @@ GLFWView::makeImage(const std::string& id, int width, int height, float pixelRat
void GLFWView::nextOrientation() {
using NO = mbgl::NorthOrientation;
- switch (map->getNorthOrientation()) {
+ switch (map->getMapOptions().northOrientation()) {
case NO::Upwards: map->setNorthOrientation(NO::Rightwards); break;
case NO::Rightwards: map->setNorthOrientation(NO::Downwards); break;
case NO::Downwards: map->setNorthOrientation(NO::Leftwards); break;
diff --git a/platform/glfw/main.cpp b/platform/glfw/main.cpp
index 38a41cbf18..fb7c2b4ffb 100644
--- a/platform/glfw/main.cpp
+++ b/platform/glfw/main.cpp
@@ -10,7 +10,7 @@
#include <mbgl/style/style.hpp>
#include <mbgl/renderer/renderer.hpp>
-#include <args/args.hxx>
+#include <args.hxx>
#include <csignal>
#include <fstream>
@@ -93,23 +93,26 @@ int main(int argc, char *argv[]) {
GLFWView backend(fullscreen, benchmark);
view = &backend;
- mbgl::DefaultFileSource fileSource(cacheDB, ".");
- if (!settings.online) {
- fileSource.setOnlineStatus(false);
- mbgl::Log::Warning(mbgl::Event::Setup, "Application is offline. Press `O` to toggle online status.");
- }
-
// Set access token if present
- const char *token = getenv("MAPBOX_ACCESS_TOKEN");
- if (token == nullptr) {
+ std::string token(getenv("MAPBOX_ACCESS_TOKEN") ?: "");
+ if (token.empty()) {
mbgl::Log::Warning(mbgl::Event::Setup, "no access token set. mapbox.com tiles won't work.");
- } else {
- fileSource.setAccessToken(std::string(token));
+ }
+
+ mbgl::ResourceOptions resourceOptions;
+ resourceOptions.withCachePath(cacheDB).withAccessToken(token);
+
+ auto fileSource = std::static_pointer_cast<mbgl::DefaultFileSource>(mbgl::FileSource::getSharedFileSource(resourceOptions));
+ if (!settings.online) {
+ fileSource->setOnlineStatus(false);
+ mbgl::Log::Warning(mbgl::Event::Setup, "Application is offline. Press `O` to toggle online status.");
}
mbgl::ThreadPool threadPool(4);
GLFWRendererFrontend rendererFrontend { std::make_unique<mbgl::Renderer>(backend, view->getPixelRatio(), threadPool), backend };
- mbgl::Map map(rendererFrontend, backend, view->getSize(), view->getPixelRatio(), fileSource, threadPool, mbgl::MapOptions());
+
+ mbgl::Map map(rendererFrontend, backend, threadPool,
+ mbgl::MapOptions().withSize(view->getSize()).withPixelRatio(view->getPixelRatio()), resourceOptions);
backend.setMap(&map);
@@ -124,9 +127,9 @@ int main(int argc, char *argv[]) {
.withPitch(settings.pitch));
map.setDebug(mbgl::MapDebugOptions(settings.debug));
- view->setOnlineStatusCallback([&settings, &fileSource]() {
+ view->setOnlineStatusCallback([&settings, fileSource]() {
settings.online = !settings.online;
- fileSource.setOnlineStatus(settings.online);
+ fileSource->setOnlineStatus(settings.online);
mbgl::Log::Info(mbgl::Event::Setup, "Application is %s. Press `O` to toggle online status.", settings.online ? "online" : "offline");
});
@@ -144,13 +147,13 @@ int main(int argc, char *argv[]) {
mbgl::Log::Info(mbgl::Event::Setup, "Changed style to: %s", newStyle.name);
});
- view->setPauseResumeCallback([&fileSource] () {
+ view->setPauseResumeCallback([fileSource] () {
static bool isPaused = false;
if (isPaused) {
- fileSource.resume();
+ fileSource->resume();
} else {
- fileSource.pause();
+ fileSource->pause();
}
isPaused = !isPaused;
diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md
index a1ab7c949a..d7a68c40b4 100644
--- a/platform/ios/CHANGELOG.md
+++ b/platform/ios/CHANGELOG.md
@@ -4,15 +4,29 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT
## 4.10.0
+### Styles and rendering
+
* Client-side text rendering of CJK ideographs is now enabled by default. ([#13988](https://github.com/mapbox/mapbox-gl-native/pull/13988))
-* Added an MGLMapView.prefetchesTiles property that you can disable if you don’t want to prefetch simplified tiles as a performance optimization. ([#14031](https://github.com/mapbox/mapbox-gl-native/pull/14031))
* Fixed an issue that caused `MGL_FUNCTION` to ignore multiple formatting parameters when passed a `format` function as parameter. ([#14064](https://github.com/mapbox/mapbox-gl-native/pull/14064))
+* Added `mgl_attributed:` expression operator, which concatenates `MGLAttributedExpression` objects for specifying rich text in the `MGLSymbolStyleLayer.text` property. ([#14094](https://github.com/mapbox/mapbox-gl-native/pull/14094))
+* Fixed an issue that caused conditional expressions to crash when passed nested conditional expressions as parameters. ([#14181](https://github.com/mapbox/mapbox-gl-native/pull/14181))
+* Added `-[MGLMapViewDelegate mapView:didFailToLoadImage:]` to load missing symbol icons in the style if they are not found. ([#14302](https://github.com/mapbox/mapbox-gl-native/pull/14302))
+
+### Packaging
+
* Added a Galician localization. ([#14095](https://github.com/mapbox/mapbox-gl-native/pull/14095))
-* Added `mgl_attributed:` expression operator, which concatenate `MGLAttributedExpression` objects for specifying rich text in the `MGLSymbolStyleLayer.text` property. ([#14094](https://github.com/mapbox/mapbox-gl-native/pull/14094))
+* Added support for building with Xcode 10.2 / iOS SDK 12.2. ([#14241](https://github.com/mapbox/mapbox-gl-native/pull/14241))
-### User interaction
+### Offline maps
+
+* Fixed a bug that caused offline packs created prior to v4.0.0 to be marked as `MGLOfflinePackStateInactive`. ([#14188](https://github.com/mapbox/mapbox-gl-native/pull/14188))
+
+### Other changes
+
+* Added `MGLOrnamentPosition` enum and margin properties to customize scale bar, compass, logo, and attribution position within the map view. ([#13911](https://github.com/mapbox/mapbox-gl-native/pull/13911))
+* Added an `MGLMapView.prefetchesTiles` property to configure lower-resolution tile prefetching behavior. ([#14031](https://github.com/mapbox/mapbox-gl-native/pull/14031))
+* Speculatively fixed a performance issue seen on iOS 12.2, when an `MGLMapView` is repeatedly removed and re-added in a view hierarchy. ([#14264](https://github.com/mapbox/mapbox-gl-native/pull/14264))
-* Added `MGLOrnamentPosition` enum and margins methods to customize MGLMapView's scale bar, compass, logo and attribution position. ([#13911](https://github.com/mapbox/mapbox-gl-native/pull/13911))
## 4.9.0 - February 27, 2019
diff --git a/platform/ios/Integration Tests/Annotation Tests/MGLAnnotationViewIntegrationTests.m b/platform/ios/Integration Tests/Annotation Tests/MGLAnnotationViewIntegrationTests.m
index 7ec45de072..0b32df55b4 100644
--- a/platform/ios/Integration Tests/Annotation Tests/MGLAnnotationViewIntegrationTests.m
+++ b/platform/ios/Integration Tests/Annotation Tests/MGLAnnotationViewIntegrationTests.m
@@ -405,7 +405,6 @@ static const CGFloat kAnnotationScale = 0.125f;
NSString * const MGLTestAnnotationReuseIdentifer = @"MGLTestAnnotationReuseIdentifer";
- CGFloat epsilon = 0.0000001;
CGSize size = self.mapView.bounds.size;
CGSize annotationSize = CGSizeMake(40.0, 40.0);
diff --git a/platform/ios/Integration Tests/MGLCameraTransitionTests.mm b/platform/ios/Integration Tests/MGLCameraTransitionTests.mm
index e422c46cf4..60d5fc6c9a 100644
--- a/platform/ios/Integration Tests/MGLCameraTransitionTests.mm
+++ b/platform/ios/Integration Tests/MGLCameraTransitionTests.mm
@@ -277,7 +277,7 @@
// Now set another coordinate.
MGLMapCamera *camera = [MGLMapCamera cameraLookingAtCenterCoordinate:target2
- fromDistance:altitude
+ altitude:altitude
pitch:0.0
heading:0.0];
diff --git a/platform/ios/Mapbox-iOS-SDK-snapshot-dynamic.podspec b/platform/ios/Mapbox-iOS-SDK-snapshot-dynamic.podspec
index bff5531290..4030511c1b 100644
--- a/platform/ios/Mapbox-iOS-SDK-snapshot-dynamic.podspec
+++ b/platform/ios/Mapbox-iOS-SDK-snapshot-dynamic.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |m|
- version = '4.10.0-alpha.2'
+ version = '4.10.0-beta.2'
m.name = 'Mapbox-iOS-SDK-snapshot-dynamic'
m.version = "#{version}-snapshot"
diff --git a/platform/ios/Mapbox-iOS-SDK-stripped.podspec b/platform/ios/Mapbox-iOS-SDK-stripped.podspec
index 9a32524ef0..d3a6d698a7 100644
--- a/platform/ios/Mapbox-iOS-SDK-stripped.podspec
+++ b/platform/ios/Mapbox-iOS-SDK-stripped.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |m|
- version = '4.10.0-alpha.2'
+ version = '4.10.0-beta.2'
m.name = 'Mapbox-iOS-SDK-stripped'
m.version = "#{version}-stripped"
diff --git a/platform/ios/Mapbox-iOS-SDK.podspec b/platform/ios/Mapbox-iOS-SDK.podspec
index 1cbd82c5e4..f8dc21a155 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 = '4.10.0-alpha.2'
+ version = '4.10.0-beta.2'
m.name = 'Mapbox-iOS-SDK'
m.version = version
diff --git a/platform/ios/app/MBXViewController.m b/platform/ios/app/MBXViewController.m
index 9c506cadfa..8d936d6a25 100644
--- a/platform/ios/app/MBXViewController.m
+++ b/platform/ios/app/MBXViewController.m
@@ -103,6 +103,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
MBXSettingsMiscellaneousToggleTwoMaps,
MBXSettingsMiscellaneousLocalizeLabels,
MBXSettingsMiscellaneousShowSnapshots,
+ MBXSettingsMiscellaneousMissingIcon,
MBXSettingsMiscellaneousShouldLimitCameraChanges,
MBXSettingsMiscellaneousShowCustomLocationManager,
MBXSettingsMiscellaneousOrnamentsPlacement,
@@ -499,6 +500,7 @@ CLLocationCoordinate2D randomWorldCoordinate() {
[NSString stringWithFormat:@"%@ Second Map", ([self.view viewWithTag:2] == nil ? @"Show" : @"Hide")],
[NSString stringWithFormat:@"Show Labels in %@", (_localizingLabels ? @"Default Language" : [[NSLocale currentLocale] displayNameForKey:NSLocaleIdentifier value:[self bestLanguageForUser]])],
@"Show Snapshots",
+ @"Missing Icon",
[NSString stringWithFormat:@"%@ Camera Changes", (_shouldLimitCameraChanges ? @"Unlimit" : @"Limit")],
@"View Route Simulation",
@"Ornaments Placement",
@@ -746,6 +748,11 @@ CLLocationCoordinate2D randomWorldCoordinate() {
[self performSegueWithIdentifier:@"ShowSnapshots" sender:nil];
break;
}
+ case MBXSettingsMiscellaneousMissingIcon:
+ {
+ [self loadMissingIcon];
+ break;
+ }
case MBXSettingsMiscellaneousShowCustomLocationManager:
{
[self performSegueWithIdentifier:@"ShowCustomLocationManger" sender:nil];
@@ -1718,6 +1725,19 @@ CLLocationCoordinate2D randomWorldCoordinate() {
[self.mapView addAnnotation:line];
}
+- (void)loadMissingIcon
+{
+ self.mapView.centerCoordinate = CLLocationCoordinate2DMake(0, 0);
+ self.mapView.zoomLevel = 1;
+ NSURL *customStyleJSON = [[NSBundle mainBundle] URLForResource:@"missing_icon" withExtension:@"json"];
+ [self.mapView setStyleURL:customStyleJSON];
+}
+
+- (UIImage *)mapView:(MGLMapView *)mapView didFailToLoadImage:(NSString *)imageName {
+ UIImage *backupImage = [UIImage imageNamed:@"AppIcon"];
+ return backupImage;
+}
+
- (void)printTelemetryLogFile
{
NSString *fileContents = [NSString stringWithContentsOfFile:[self telemetryDebugLogFilePath] encoding:NSUTF8StringEncoding error:nil];
diff --git a/platform/ios/app/missing_icon.json b/platform/ios/app/missing_icon.json
new file mode 100644
index 0000000000..5da4125990
--- /dev/null
+++ b/platform/ios/app/missing_icon.json
@@ -0,0 +1,40 @@
+{
+ "version": 8,
+ "name": "Mapbox Streets",
+ "sprite": "mapbox://sprites/mapbox/streets-v8",
+ "glyphs": "mapbox://fonts/mapbox/{fontstack}/{range}.pbf",
+ "sources": {
+ "point": {
+ "type": "geojson",
+ "data": {
+ "type": "Feature",
+ "properties": {},
+ "geometry": {
+ "type": "Point",
+ "coordinates": [0, 0]
+ }
+ }
+ }
+ },
+ "layers": [{
+ "id": "bg",
+ "type": "background",
+ "paint": {
+ "background-color": "#f00"
+ }
+ }, {
+ "id": "point",
+ "type": "circle",
+ "source": "point",
+ "paint": {
+ "circle-radius": 100
+ }
+ }, {
+ "id": "icon",
+ "type": "symbol",
+ "source": "point",
+ "layout": {
+ "icon-image": "missing-icon"
+ }
+ }]
+}
diff --git a/platform/ios/docs/guides/For Style Authors.md b/platform/ios/docs/guides/For Style Authors.md
index 73394ff6ed..1acf587cda 100644
--- a/platform/ios/docs/guides/For Style Authors.md
+++ b/platform/ios/docs/guides/For Style Authors.md
@@ -418,5 +418,16 @@ In style JSON | In the format string
`["any", f0, …, fn]` | `p0 OR … OR pn`
`["none", f0, …, fn]` | `NOT (p0 OR … OR pn)`
+## Specifying the text format
+
+The following format attributes are defined as `NSString` constans that you
+can use to update the formatting of `MGLSymbolStyleLayer.text` property.
+
+In style JSON | In Objective-C | In Swift
+--------------|-----------------------|---------
+`text-font` | `MGLFontNamesAttribute` | `.fontNamesAttribute`
+`font-scale` | `MGLFontScaleAttribute` | `.fontScaleAttribute`
+`text-color` | `MGLFontColorAttribute` | `.fontColorAttribute`
+
See the “[Predicates and Expressions](predicates-and-expressions.html)” guide for
a full description of the supported operators and operand types.
diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj
index b24bcbe110..1fe22d2c7d 100644
--- a/platform/ios/ios.xcodeproj/project.pbxproj
+++ b/platform/ios/ios.xcodeproj/project.pbxproj
@@ -98,9 +98,6 @@
35136D4D1D4277FC00C20EFD /* MGLSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 35136D4A1D4277FC00C20EFD /* MGLSource.h */; settings = {ATTRIBUTES = (Public, ); }; };
35136D4E1D4277FC00C20EFD /* MGLSource.mm in Sources */ = {isa = PBXBuildFile; fileRef = 35136D4B1D4277FC00C20EFD /* MGLSource.mm */; };
35136D4F1D4277FC00C20EFD /* MGLSource.mm in Sources */ = {isa = PBXBuildFile; fileRef = 35136D4B1D4277FC00C20EFD /* MGLSource.mm */; };
- 35305D481D22AA680007D005 /* NSData+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 35305D471D22AA450007D005 /* NSData+MGLAdditions.mm */; };
- 35305D491D22AA680007D005 /* NSData+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 35305D471D22AA450007D005 /* NSData+MGLAdditions.mm */; };
- 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.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3538AA1C1D542239008EC33D /* MGLForegroundStyleLayer.mm */; };
@@ -179,7 +176,6 @@
35E0CFE71D3E501500188327 /* MGLStyle_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 35E0CFE51D3E501500188327 /* MGLStyle_Private.h */; };
35E1A4D81D74336F007AA97F /* MGLValueEvaluator.h in Headers */ = {isa = PBXBuildFile; fileRef = 35E1A4D71D74336F007AA97F /* MGLValueEvaluator.h */; };
35E1A4D91D74336F007AA97F /* MGLValueEvaluator.h in Headers */ = {isa = PBXBuildFile; fileRef = 35E1A4D71D74336F007AA97F /* MGLValueEvaluator.h */; };
- 35E208A71D24210F00EC9A46 /* MGLNSDataAdditionsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 35E208A61D24210F00EC9A46 /* MGLNSDataAdditionsTests.m */; };
35E79F201D41266300957B9E /* MGLStyleLayer_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 35E79F1F1D41266300957B9E /* MGLStyleLayer_Private.h */; };
35E79F211D41266300957B9E /* MGLStyleLayer_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 35E79F1F1D41266300957B9E /* MGLStyleLayer_Private.h */; };
3E6465D62065767A00685536 /* LimeGreenStyleLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E6465D42065767A00685536 /* LimeGreenStyleLayer.m */; };
@@ -223,7 +219,6 @@
40834BEE1FE05E1800C1BD0D /* MMEEventsConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BB21FE05D6D00C1BD0D /* MMEEventsConfiguration.m */; };
40834BEF1FE05E1800C1BD0D /* MMEEventsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BA41FE05D6B00C1BD0D /* MMEEventsManager.m */; };
40834BF01FE05E1800C1BD0D /* MMELocationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BB81FE05D6D00C1BD0D /* MMELocationManager.m */; };
- 40834BF11FE05E1800C1BD0D /* MMENSDateWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BBC1FE05D6E00C1BD0D /* MMENSDateWrapper.m */; };
40834BF21FE05E1800C1BD0D /* MMENSURLSessionWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BC61FE05D7000C1BD0D /* MMENSURLSessionWrapper.m */; };
40834BF31FE05E1800C1BD0D /* MMETimerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BB91FE05D6E00C1BD0D /* MMETimerManager.m */; };
40834BF51FE05E1800C1BD0D /* MMETypes.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BBD1FE05D6E00C1BD0D /* MMETypes.m */; };
@@ -242,7 +237,7 @@
40834C021FE05E1800C1BD0D /* MMEEventsConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BB21FE05D6D00C1BD0D /* MMEEventsConfiguration.m */; };
40834C031FE05E1800C1BD0D /* MMEEventsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BA41FE05D6B00C1BD0D /* MMEEventsManager.m */; };
40834C041FE05E1800C1BD0D /* MMELocationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BB81FE05D6D00C1BD0D /* MMELocationManager.m */; };
- 40834C051FE05E1800C1BD0D /* MMENSDateWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BBC1FE05D6E00C1BD0D /* MMENSDateWrapper.m */; };
+ 40834C051FE05E1800C1BD0D /* MMEDate.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BBC1FE05D6E00C1BD0D /* MMEDate.m */; };
40834C061FE05E1800C1BD0D /* MMENSURLSessionWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BC61FE05D7000C1BD0D /* MMENSURLSessionWrapper.m */; };
40834C071FE05E1800C1BD0D /* MMETimerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BB91FE05D6E00C1BD0D /* MMETimerManager.m */; };
40834C091FE05E1800C1BD0D /* MMETypes.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BBD1FE05D6E00C1BD0D /* MMETypes.m */; };
@@ -340,7 +335,6 @@
55E5666221C2A2080008B8B5 /* MMELocationManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 40834BB31FE05D6D00C1BD0D /* MMELocationManager.h */; };
55E5666321C2A2080008B8B5 /* MMEMetrics.h in Headers */ = {isa = PBXBuildFile; fileRef = ACD024552187EAAF00D8C8A7 /* MMEMetrics.h */; };
55E5666421C2A2080008B8B5 /* MMEMetricsManager.h in Headers */ = {isa = PBXBuildFile; fileRef = ACD024562187EAAF00D8C8A7 /* MMEMetricsManager.h */; };
- 55E5666521C2A2080008B8B5 /* MMENSDateWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 40834BC51FE05D6F00C1BD0D /* MMENSDateWrapper.h */; };
55E5666621C2A2080008B8B5 /* MMENSURLSessionWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 40834BAA1FE05D6C00C1BD0D /* MMENSURLSessionWrapper.h */; };
55E5666721C2A2080008B8B5 /* MMETimerManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 40834BC91FE05D7000C1BD0D /* MMETimerManager.h */; };
55E5666821C2A2080008B8B5 /* MMETypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 40834BB61FE05D6D00C1BD0D /* MMETypes.h */; };
@@ -451,7 +445,6 @@
96E516F12000596800A02306 /* NSString+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8848171CBAFA6200AB86E3 /* NSString+MGLAdditions.h */; };
96E516F22000596D00A02306 /* NSException+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8848141CBAFA6200AB86E3 /* NSException+MGLAdditions.h */; };
96E516F32000597100A02306 /* NSDictionary+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 408AA8551DAEDA0800022900 /* NSDictionary+MGLAdditions.h */; };
- 96E516F42000597D00A02306 /* NSData+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 35305D461D22AA450007D005 /* NSData+MGLAdditions.h */; };
96E516F5200059B100A02306 /* MGLNetworkConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = DD0902A41DB18F1B00C5BDCE /* MGLNetworkConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; };
96E516F6200059EC00A02306 /* MGLRendererFrontend.h in Headers */ = {isa = PBXBuildFile; fileRef = 92F2C3EC1F0E3C3A00268EC0 /* MGLRendererFrontend.h */; };
96E516F720005A2700A02306 /* MGLAnnotationContainerView.h in Headers */ = {isa = PBXBuildFile; fileRef = 40EDA1BD1CFE0D4A00D9EA68 /* MGLAnnotationContainerView.h */; };
@@ -464,6 +457,9 @@
96E5170420005A6B00A02306 /* SMCalloutView.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8848891CBB037E00AB86E3 /* SMCalloutView.h */; };
96ED34DE22374C0900E9FCA9 /* MGLMapViewDirectionTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 96ED34DD22374C0900E9FCA9 /* MGLMapViewDirectionTests.mm */; };
96F3F73C1F57124B003E2D2C /* MGLUserLocationHeadingIndicator.h in Headers */ = {isa = PBXBuildFile; fileRef = 96F3F73B1F5711F1003E2D2C /* MGLUserLocationHeadingIndicator.h */; };
+ 9C188C4F2242C95A0022FA55 /* MMEDate.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BBC1FE05D6E00C1BD0D /* MMEDate.m */; };
+ 9C188C502242C96F0022FA55 /* MMEDate.h in Headers */ = {isa = PBXBuildFile; fileRef = 40834BC51FE05D6F00C1BD0D /* MMEDate.h */; };
+ A4F3FB1D2254865900A30170 /* missing_icon.json in Resources */ = {isa = PBXBuildFile; fileRef = A4F3FB1C2254865900A30170 /* missing_icon.json */; };
AC1B0916221CA14D00DB56C8 /* CLLocationManager+MMEMobileEvents.h in Headers */ = {isa = PBXBuildFile; fileRef = AC1B0914221CA14500DB56C8 /* CLLocationManager+MMEMobileEvents.h */; };
AC1B0917221CA14D00DB56C8 /* CLLocationManager+MMEMobileEvents.h in Headers */ = {isa = PBXBuildFile; fileRef = AC1B0914221CA14500DB56C8 /* CLLocationManager+MMEMobileEvents.h */; };
AC1B0918221CA14D00DB56C8 /* CLLocationManager+MMEMobileEvents.m in Sources */ = {isa = PBXBuildFile; fileRef = AC1B0915221CA14C00DB56C8 /* CLLocationManager+MMEMobileEvents.m */; };
@@ -914,8 +910,6 @@
35136D441D42275100C20EFD /* MGLSymbolStyleLayer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLSymbolStyleLayer.mm; sourceTree = "<group>"; };
35136D4A1D4277FC00C20EFD /* MGLSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLSource.h; sourceTree = "<group>"; };
35136D4B1D4277FC00C20EFD /* MGLSource.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLSource.mm; sourceTree = "<group>"; };
- 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.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>"; };
@@ -964,7 +958,6 @@
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>"; };
35E79F1F1D41266300957B9E /* MGLStyleLayer_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLStyleLayer_Private.h; sourceTree = "<group>"; };
36F1153C1D46080700878E1A /* libmbgl-platform-ios.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libmbgl-platform-ios.a"; path = "build/Debug-iphoneos/libmbgl-platform-ios.a"; sourceTree = "<group>"; };
3E6465D42065767A00685536 /* LimeGreenStyleLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = LimeGreenStyleLayer.m; path = ../../darwin/app/LimeGreenStyleLayer.m; sourceTree = "<group>"; };
@@ -1012,7 +1005,7 @@
40834BB91FE05D6E00C1BD0D /* MMETimerManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MMETimerManager.m; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMETimerManager.m"; sourceTree = SOURCE_ROOT; };
40834BBA1FE05D6E00C1BD0D /* MMEEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MMEEvent.h; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMEEvent.h"; sourceTree = SOURCE_ROOT; };
40834BBB1FE05D6E00C1BD0D /* MMEEventsConfiguration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MMEEventsConfiguration.h; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMEEventsConfiguration.h"; sourceTree = SOURCE_ROOT; };
- 40834BBC1FE05D6E00C1BD0D /* MMENSDateWrapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MMENSDateWrapper.m; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMENSDateWrapper.m"; sourceTree = SOURCE_ROOT; };
+ 40834BBC1FE05D6E00C1BD0D /* MMEDate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MMEDate.m; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMEDate.m"; sourceTree = SOURCE_ROOT; };
40834BBD1FE05D6E00C1BD0D /* MMETypes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MMETypes.m; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMETypes.m"; sourceTree = SOURCE_ROOT; };
40834BBE1FE05D6E00C1BD0D /* MMEUIApplicationWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MMEUIApplicationWrapper.h; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMEUIApplicationWrapper.h"; sourceTree = SOURCE_ROOT; };
40834BBF1FE05D6E00C1BD0D /* MMEUniqueIdentifier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MMEUniqueIdentifier.h; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMEUniqueIdentifier.h"; sourceTree = SOURCE_ROOT; };
@@ -1020,7 +1013,7 @@
40834BC21FE05D6F00C1BD0D /* CLLocation+MMEMobileEvents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "CLLocation+MMEMobileEvents.h"; path = "vendor/mapbox-events-ios/MapboxMobileEvents/CLLocation+MMEMobileEvents.h"; sourceTree = SOURCE_ROOT; };
40834BC31FE05D6F00C1BD0D /* CLLocation+MMEMobileEvents.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "CLLocation+MMEMobileEvents.m"; path = "vendor/mapbox-events-ios/MapboxMobileEvents/CLLocation+MMEMobileEvents.m"; sourceTree = SOURCE_ROOT; };
40834BC41FE05D6F00C1BD0D /* MMECategoryLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MMECategoryLoader.m; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMECategoryLoader.m"; sourceTree = SOURCE_ROOT; };
- 40834BC51FE05D6F00C1BD0D /* MMENSDateWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MMENSDateWrapper.h; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMENSDateWrapper.h"; sourceTree = SOURCE_ROOT; };
+ 40834BC51FE05D6F00C1BD0D /* MMEDate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MMEDate.h; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMEDate.h"; sourceTree = SOURCE_ROOT; };
40834BC61FE05D7000C1BD0D /* MMENSURLSessionWrapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MMENSURLSessionWrapper.m; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMENSURLSessionWrapper.m"; sourceTree = SOURCE_ROOT; };
40834BC71FE05D7000C1BD0D /* MMEEvent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MMEEvent.m; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMEEvent.m"; sourceTree = SOURCE_ROOT; };
40834BC81FE05D7000C1BD0D /* MMENamespacedDependencies.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MMENamespacedDependencies.h; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMENamespacedDependencies.h"; sourceTree = SOURCE_ROOT; };
@@ -1151,6 +1144,7 @@
96ED34DD22374C0900E9FCA9 /* MGLMapViewDirectionTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLMapViewDirectionTests.mm; sourceTree = "<group>"; };
96F017292118FBAE00892778 /* MGLMapView_Experimental.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLMapView_Experimental.h; sourceTree = "<group>"; };
96F3F73B1F5711F1003E2D2C /* MGLUserLocationHeadingIndicator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLUserLocationHeadingIndicator.h; sourceTree = "<group>"; };
+ A4F3FB1C2254865900A30170 /* missing_icon.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = missing_icon.json; sourceTree = "<group>"; };
AC1B0914221CA14500DB56C8 /* CLLocationManager+MMEMobileEvents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "CLLocationManager+MMEMobileEvents.h"; path = "../vendor/mapbox-events-ios/MapboxMobileEvents/CLLocationManager+MMEMobileEvents.h"; sourceTree = "<group>"; };
AC1B0915221CA14C00DB56C8 /* CLLocationManager+MMEMobileEvents.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "CLLocationManager+MMEMobileEvents.m"; path = "../vendor/mapbox-events-ios/MapboxMobileEvents/CLLocationManager+MMEMobileEvents.m"; sourceTree = "<group>"; };
AC518DFD201BB55A00EBC820 /* MGLTelemetryConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLTelemetryConfig.h; sourceTree = "<group>"; };
@@ -1774,8 +1768,8 @@
ACD024572187EAAF00D8C8A7 /* MMEMetrics.m */,
ACD024562187EAAF00D8C8A7 /* MMEMetricsManager.h */,
ACD024542187EAAF00D8C8A7 /* MMEMetricsManager.m */,
- 40834BC51FE05D6F00C1BD0D /* MMENSDateWrapper.h */,
- 40834BBC1FE05D6E00C1BD0D /* MMENSDateWrapper.m */,
+ 40834BC51FE05D6F00C1BD0D /* MMEDate.h */,
+ 40834BBC1FE05D6E00C1BD0D /* MMEDate.m */,
40834BAA1FE05D6C00C1BD0D /* MMENSURLSessionWrapper.h */,
40834BC61FE05D7000C1BD0D /* MMENSURLSessionWrapper.m */,
40834BC91FE05D7000C1BD0D /* MMETimerManager.h */,
@@ -1891,6 +1885,7 @@
children = (
353BAEF51D646370009A8DA9 /* amsterdam.geojson */,
DA1DC96C1CB6C6CE006E619F /* points.geojson */,
+ A4F3FB1C2254865900A30170 /* missing_icon.json */,
DA1DC96D1CB6C6CE006E619F /* polyline.geojson */,
1F26B6C220E1A351007BCC21 /* simple_route.json */,
DA1DC96F1CB6C6CE006E619F /* threestates.geojson */,
@@ -2041,7 +2036,6 @@
96ED34DD22374C0900E9FCA9 /* MGLMapViewDirectionTests.mm */,
16376B481FFEED010000563E /* MGLMapViewLayoutTests.m */,
9658C154204761FC00D8A674 /* MGLMapViewScaleBarTests.m */,
- 35E208A61D24210F00EC9A46 /* MGLNSDataAdditionsTests.m */,
1F95931C1E6DE2E900D5B294 /* MGLNSDateAdditionsTests.mm */,
96036A0520059BBA00510F3D /* MGLNSOrthographyAdditionsTests.m */,
DAE7DEC11E245455007505A6 /* MGLNSStringAdditionsTests.m */,
@@ -2318,8 +2312,6 @@
3510FFE91D6D9C7A00F413B2 /* NSComparisonPredicate+MGLAdditions.mm */,
3510FFF71D6DCC4700F413B2 /* NSCompoundPredicate+MGLAdditions.h */,
3510FFF81D6DCC4700F413B2 /* NSCompoundPredicate+MGLAdditions.mm */,
- 35305D461D22AA450007D005 /* NSData+MGLAdditions.h */,
- 35305D471D22AA450007D005 /* NSData+MGLAdditions.mm */,
353AFA121D65AB17005A69F4 /* NSDate+MGLAdditions.h */,
353AFA131D65AB17005A69F4 /* NSDate+MGLAdditions.mm */,
408AA8551DAEDA0800022900 /* NSDictionary+MGLAdditions.h */,
@@ -2461,6 +2453,7 @@
DD0902AB1DB192A800C5BDCE /* MGLNetworkConfiguration.h in Headers */,
35D3A1E61E9BE7EB002B38EE /* MGLScaleBar.h in Headers */,
0778DD431F67556700A73B34 /* MGLComputedShapeSource.h in Headers */,
+ 9C188C502242C96F0022FA55 /* MMEDate.h in Headers */,
1F6A82A221360F9D00BA5B41 /* MGLLoggingConfiguration.h in Headers */,
AC1B0916221CA14D00DB56C8 /* CLLocationManager+MMEMobileEvents.h in Headers */,
DA8848311CBAFA6200AB86E3 /* NSString+MGLAdditions.h in Headers */,
@@ -2530,7 +2523,6 @@
DA72620B1DEEE3480043BB89 /* MGLOpenGLStyleLayer.h in Headers */,
404C26E71D89C55D000AA13D /* MGLTileSource_Private.h in Headers */,
DA88485C1CBAFB9800AB86E3 /* MGLFaux3DUserLocationAnnotationView.h in Headers */,
- 35305D4A1D22AA6A0007D005 /* NSData+MGLAdditions.h in Headers */,
359F57461D2FDDA6005217F1 /* MGLUserLocationAnnotationView_Private.h in Headers */,
404C26E21D89B877000AA13D /* MGLTileSource.h in Headers */,
DA8847FD1CBAFA5100AB86E3 /* MGLTilePyramidOfflineRegion.h in Headers */,
@@ -2580,7 +2572,6 @@
55E5666221C2A2080008B8B5 /* MMELocationManager.h in Headers */,
55E5666321C2A2080008B8B5 /* MMEMetrics.h in Headers */,
55E5666421C2A2080008B8B5 /* MMEMetricsManager.h in Headers */,
- 55E5666521C2A2080008B8B5 /* MMENSDateWrapper.h in Headers */,
55E5666621C2A2080008B8B5 /* MMENSURLSessionWrapper.h in Headers */,
55E5666721C2A2080008B8B5 /* MMETimerManager.h in Headers */,
55E5666821C2A2080008B8B5 /* MMETypes.h in Headers */,
@@ -2724,7 +2715,6 @@
74CB5EB2219B252C00102936 /* MGLStyleLayerManager.h in Headers */,
9221BAB020699F8A0054BDF4 /* MGLTilePyramidOfflineRegion_Private.h in Headers */,
96E516F5200059B100A02306 /* MGLNetworkConfiguration.h in Headers */,
- 96E516F42000597D00A02306 /* NSData+MGLAdditions.h in Headers */,
96E516DD200054F200A02306 /* MGLPolygon_Private.h in Headers */,
353933F91D3FB79F003F57D7 /* MGLLineStyleLayer.h in Headers */,
96E516EB2000560B00A02306 /* MGLUserLocation_Private.h in Headers */,
@@ -2945,6 +2935,7 @@
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
+ English,
en,
Base,
"zh-Hans",
@@ -3014,6 +3005,7 @@
buildActionMask = 2147483647;
files = (
DD4823771D94AE6C00EB71B7 /* numeric_filter_style.json in Resources */,
+ A4F3FB1D2254865900A30170 /* missing_icon.json in Resources */,
DA1DC9701CB6C6CE006E619F /* points.geojson in Resources */,
353BAEF61D646370009A8DA9 /* amsterdam.geojson in Resources */,
DA1DC9711CB6C6CE006E619F /* polyline.geojson in Resources */,
@@ -3177,7 +3169,6 @@
357579831D502AE6000B822E /* MGLRasterStyleLayerTests.mm in Sources */,
DAF25720201902BC00367EF5 /* MGLHillshadeStyleLayerTests.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 */,
@@ -3189,6 +3180,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ 9C188C4F2242C95A0022FA55 /* MMEDate.m in Sources */,
35136D391D42271A00C20EFD /* MGLBackgroundStyleLayer.mm in Sources */,
3510FFEC1D6D9C7A00F413B2 /* NSComparisonPredicate+MGLAdditions.mm in Sources */,
40834C431FE05F7500C1BD0D /* TSKSPKIHashCache.m in Sources */,
@@ -3224,7 +3216,6 @@
40834BF31FE05E1800C1BD0D /* MMETimerManager.m in Sources */,
35136D421D42274500C20EFD /* MGLRasterStyleLayer.mm in Sources */,
3538AA1F1D542239008EC33D /* MGLForegroundStyleLayer.mm in Sources */,
- 40834BF11FE05E1800C1BD0D /* MMENSDateWrapper.m in Sources */,
AC1B0918221CA14D00DB56C8 /* CLLocationManager+MMEMobileEvents.m in Sources */,
40834C461FE05F7500C1BD0D /* TSKPinFailureReport.m in Sources */,
406E99B91FFEFF1B00D9FFCC /* MMEEventLogReportViewController.m in Sources */,
@@ -3272,7 +3263,6 @@
DA35A2A11CC9E95F00E826B2 /* MGLCoordinateFormatter.m in Sources */,
92FC0AEE207CEE16007B6B54 /* MGLShapeOfflineRegion.mm in Sources */,
ACD0245E2187EACB00D8C8A7 /* MMEMetrics.m in Sources */,
- 35305D481D22AA680007D005 /* NSData+MGLAdditions.mm in Sources */,
40834BF61FE05E1800C1BD0D /* MMEUIApplicationWrapper.m in Sources */,
DA8848291CBAFA6200AB86E3 /* MGLStyle.mm in Sources */,
357FE2DF1E02D2B20068B753 /* NSCoder+MGLAdditions.mm in Sources */,
@@ -3361,7 +3351,7 @@
ACA65F5A2140697200537748 /* MMEDispatchManager.m in Sources */,
3538AA201D542239008EC33D /* MGLForegroundStyleLayer.mm in Sources */,
DA00FC911D5EEB0D009AABC8 /* MGLAttributionInfo.mm in Sources */,
- 40834C051FE05E1800C1BD0D /* MMENSDateWrapper.m in Sources */,
+ 40834C051FE05E1800C1BD0D /* MMEDate.m in Sources */,
40834C531FE05F7600C1BD0D /* TSKPinFailureReport.m in Sources */,
AC1B0919221CA14D00DB56C8 /* CLLocationManager+MMEMobileEvents.m in Sources */,
40834BFA1FE05E1800C1BD0D /* CLLocation+MMEMobileEvents.m in Sources */,
@@ -3405,7 +3395,6 @@
DAA4E4281CBB730400178DFB /* MGLTypes.m in Sources */,
DA35A2A21CC9E95F00E826B2 /* MGLCoordinateFormatter.m in Sources */,
40834C511FE05F7600C1BD0D /* reporting_utils.m in Sources */,
- 35305D491D22AA680007D005 /* NSData+MGLAdditions.mm in Sources */,
357FE2E01E02D2B20068B753 /* NSCoder+MGLAdditions.mm in Sources */,
92FC0AEF207CEE16007B6B54 /* MGLShapeOfflineRegion.mm in Sources */,
DAA4E42D1CBB730400178DFB /* MGLAnnotationImage.m in Sources */,
@@ -3693,7 +3682,7 @@
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Integration Tests/integration-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
- SWIFT_VERSION = 3.0;
+ SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Integration Test Harness.app/Integration Test Harness";
};
@@ -3723,7 +3712,7 @@
PRODUCT_BUNDLE_IDENTIFIER = "com.mapbox.integration-tests";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Integration Tests/integration-Bridging-Header.h";
- SWIFT_VERSION = 3.0;
+ SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Integration Test Harness.app/Integration Test Harness";
};
@@ -3878,6 +3867,7 @@
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
GCC_PREFIX_HEADER = "$SRCROOT/src/Mapbox-Prefix.pch";
+ GCC_PREPROCESSOR_DEFINITIONS = "NDEBUG=1";
HEADER_SEARCH_PATHS = (
"$(mbgl_core_INCLUDE_DIRECTORIES)",
"$(mbgl_filesource_INCLUDE_DIRECTORIES)",
@@ -4007,7 +3997,7 @@
PRODUCT_BUNDLE_IDENTIFIER = "com.mapbox.integration-tests";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Integration Tests/integration-Bridging-Header.h";
- SWIFT_VERSION = 3.0;
+ SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Integration Test Harness.app/Integration Test Harness";
};
@@ -4312,6 +4302,7 @@
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
GCC_PREFIX_HEADER = "$SRCROOT/src/Mapbox-Prefix.pch";
+ GCC_PREPROCESSOR_DEFINITIONS = "NDEBUG=1";
HEADER_SEARCH_PATHS = (
"$(mbgl_core_INCLUDE_DIRECTORIES)",
"$(mbgl_filesource_INCLUDE_DIRECTORIES)",
diff --git a/platform/ios/scripts/package.sh b/platform/ios/scripts/package.sh
index 45aab45f3f..a37b3c7fda 100755
--- a/platform/ios/scripts/package.sh
+++ b/platform/ios/scripts/package.sh
@@ -11,6 +11,7 @@ PRODUCTS=${DERIVED_DATA}
LOG_PATH=build/xcodebuild-$(date +"%Y-%m-%d_%H%M%S").log
BUILD_FOR_DEVICE=${BUILD_DEVICE:-true}
+BUILD_DOCS=${BUILD_DOCS:-true}
SYMBOLS=${SYMBOLS:-YES}
BUILDTYPE=${BUILDTYPE:-Debug}
@@ -270,5 +271,7 @@ sed -i '' \
"${README}"
cp ${README} "${OUTPUT}"
-step "Generating API documentation…"
-make idocument OUTPUT="${OUTPUT}/documentation"
+if [ ${BUILD_DOCS} == true ]; then
+ step "Generating API documentation for ${BUILDTYPE} Build…"
+ make idocument OUTPUT="${OUTPUT}/documentation"
+fi
diff --git a/platform/ios/sdk-files.json b/platform/ios/sdk-files.json
index 7dbfee1a2d..94f928b77e 100644
--- a/platform/ios/sdk-files.json
+++ b/platform/ios/sdk-files.json
@@ -1,6 +1,7 @@
{
"//": "This file is generated. Do not edit. Regenerate it with scripts/generate-file-lists.js",
"sources": [
+ "platform/ios/vendor/mapbox-events-ios/MapboxMobileEvents/MMEDate.m",
"platform/darwin/src/MGLBackgroundStyleLayer.mm",
"platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm",
"platform/ios/vendor/mapbox-events-ios/vendor/TrustKit/Pinning/TSKSPKIHashCache.m",
@@ -36,7 +37,6 @@
"platform/ios/vendor/mapbox-events-ios/MapboxMobileEvents/MMETimerManager.m",
"platform/darwin/src/MGLRasterStyleLayer.mm",
"platform/darwin/src/MGLForegroundStyleLayer.mm",
- "platform/ios/vendor/mapbox-events-ios/MapboxMobileEvents/MMENSDateWrapper.m",
"platform/ios/vendor/mapbox-events-ios/MapboxMobileEvents/CLLocationManager+MMEMobileEvents.m",
"platform/ios/vendor/mapbox-events-ios/vendor/TrustKit/Reporting/TSKPinFailureReport.m",
"platform/ios/vendor/mapbox-events-ios/MapboxMobileEvents/MMEEventLogReportViewController.m",
@@ -84,7 +84,6 @@
"platform/darwin/src/MGLCoordinateFormatter.m",
"platform/darwin/src/MGLShapeOfflineRegion.mm",
"platform/ios/vendor/mapbox-events-ios/MapboxMobileEvents/MMEMetrics.m",
- "platform/darwin/src/NSData+MGLAdditions.mm",
"platform/ios/vendor/mapbox-events-ios/MapboxMobileEvents/MMEUIApplicationWrapper.m",
"platform/darwin/src/MGLStyle.mm",
"platform/darwin/src/NSCoder+MGLAdditions.mm",
@@ -243,6 +242,7 @@
"NSComparisonPredicate+MGLAdditions.h": "platform/darwin/src/NSComparisonPredicate+MGLAdditions.h",
"MGLMapAccessibilityElement.h": "platform/ios/src/MGLMapAccessibilityElement.h",
"MGLScaleBar.h": "platform/ios/src/MGLScaleBar.h",
+ "MMEDate.h": "platform/ios/vendor/mapbox-events-ios/MapboxMobileEvents/MMEDate.h",
"CLLocationManager+MMEMobileEvents.h": "platform/ios/vendor/mapbox-events-ios/MapboxMobileEvents/CLLocationManager+MMEMobileEvents.h",
"NSString+MGLAdditions.h": "platform/darwin/src/NSString+MGLAdditions.h",
"UIDevice+MGLAdditions.h": "platform/ios/src/UIDevice+MGLAdditions.h",
@@ -279,7 +279,6 @@
"MGLOpenGLStyleLayer_Private.h": "platform/darwin/src/MGLOpenGLStyleLayer_Private.h",
"MGLTileSource_Private.h": "platform/darwin/src/MGLTileSource_Private.h",
"MGLFaux3DUserLocationAnnotationView.h": "platform/ios/src/MGLFaux3DUserLocationAnnotationView.h",
- "NSData+MGLAdditions.h": "platform/darwin/src/NSData+MGLAdditions.h",
"MGLUserLocationAnnotationView_Private.h": "platform/ios/src/MGLUserLocationAnnotationView_Private.h",
"NSProcessInfo+MGLAdditions.h": "platform/darwin/src/NSProcessInfo+MGLAdditions.h",
"MGLRasterTileSource_Private.h": "platform/darwin/src/MGLRasterTileSource_Private.h",
@@ -323,7 +322,6 @@
"MMELocationManager.h": "platform/ios/vendor/mapbox-events-ios/MapboxMobileEvents/MMELocationManager.h",
"MMEMetrics.h": "platform/ios/vendor/mapbox-events-ios/MapboxMobileEvents/MMEMetrics.h",
"MMEMetricsManager.h": "platform/ios/vendor/mapbox-events-ios/MapboxMobileEvents/MMEMetricsManager.h",
- "MMENSDateWrapper.h": "platform/ios/vendor/mapbox-events-ios/MapboxMobileEvents/MMENSDateWrapper.h",
"MMENSURLSessionWrapper.h": "platform/ios/vendor/mapbox-events-ios/MapboxMobileEvents/MMENSURLSessionWrapper.h",
"MMETimerManager.h": "platform/ios/vendor/mapbox-events-ios/MapboxMobileEvents/MMETimerManager.h",
"MMETypes.h": "platform/ios/vendor/mapbox-events-ios/MapboxMobileEvents/MMETypes.h",
diff --git a/platform/ios/src/MGLMapView.h b/platform/ios/src/MGLMapView.h
index 1ef64a587b..589b7b547b 100644
--- a/platform/ios/src/MGLMapView.h
+++ b/platform/ios/src/MGLMapView.h
@@ -414,12 +414,12 @@ MGL_EXPORT IB_DESIGNABLE
/**
A Boolean value indicating whether the map should prefetch tiles.
- When this property is set to YES, the map view prefetches loads tiles designed for a
- low zoom level and displays them until receiving more detailed tiles for the current
- zoom level. The prefetched tiles typically contain simplified versions of each shape,
- improving the map view’s perceived performance.
+ When this property is set to `YES`, the map view prefetches tiles designed for
+ a low zoom level and displays them until receiving more detailed tiles for the
+ current zoom level. The prefetched tiles typically contain simplified versions
+ of each shape, improving the map view’s perceived performance.
- The default value of this property is YES.
+ The default value of this property is `YES`.
*/
@property (nonatomic, assign) BOOL prefetchesTiles;
@@ -434,17 +434,18 @@ MGL_EXPORT IB_DESIGNABLE
#pragma mark Displaying the User’s Location
/**
- The object that this map view uses to start and stop the delivery of location-related
- updates.
+ The object that this map view uses to start and stop the delivery of
+ location-related updates.
- To receive the current user location, implement the `-[MGLMapViewDelegate mapView:didUpdateUserLocation:]`
- and `-[MGLMapViewDelegate mapView:didFailToLocateUserWithError:]` methods.
+ To receive the current user location, implement the
+ `-[MGLMapViewDelegate mapView:didUpdateUserLocation:]` and
+ `-[MGLMapViewDelegate mapView:didFailToLocateUserWithError:]` methods.
- If setting this property to `nil` or if no custom manager is provided this property
- is set to the default location manager.
+ If setting this property to `nil` or if no custom manager is provided this
+ property is set to the default location manager.
- `MGLMapView` uses a default location manager. If you want to substitute your own
- location manager, you should do so by setting this property before setting
+ `MGLMapView` uses a default location manager. If you want to substitute your
+ own location manager, you should do so by setting this property before setting
`showsUserLocation` to `YES`. To restore the default location manager,
set this property to `nil`.
*/
diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm
index bda212de84..24e195c70a 100644
--- a/platform/ios/src/MGLMapView.mm
+++ b/platform/ios/src/MGLMapView.mm
@@ -11,7 +11,7 @@
#include <mbgl/util/platform.hpp>
#include <mbgl/storage/reachability.h>
#include <mbgl/util/default_thread_pool.hpp>
-#include <mbgl/storage/default_file_source.hpp>
+#include <mbgl/storage/resource_options.hpp>
#include <mbgl/storage/network_status.hpp>
#include <mbgl/style/style.hpp>
#include <mbgl/style/image.hpp>
@@ -156,6 +156,10 @@ const CGFloat MGLAnnotationImagePaddingForCallout = 1;
const CGSize MGLAnnotationAccessibilityElementMinimumSize = CGSizeMake(10, 10);
+/// The number of view annotations (excluding the user location view) that must
+/// be descendents of `MGLMapView` before presentsWithTransaction is enabled.
+static const NSUInteger MGLPresentsWithTransactionAnnotationCount = 0;
+
/// An indication that the requested annotation was not found or is nonexistent.
enum { MGLAnnotationTagNotFound = UINT32_MAX };
@@ -252,6 +256,7 @@ public:
@property (nonatomic) MGLAnnotationContainerView *annotationContainerView;
@property (nonatomic) MGLUserLocation *userLocation;
@property (nonatomic) NSMutableDictionary<NSString *, NSMutableArray<MGLAnnotationView *> *> *annotationViewReuseQueueByIdentifier;
+@property (nonatomic) BOOL enablePresentsWithTransaction;
/// Experimental rendering performance measurement.
@property (nonatomic) BOOL experimental_enableFrameRateMeasurement;
@@ -328,6 +333,9 @@ public:
CFTimeInterval _frameCounterStartTime;
NSInteger _frameCount;
CFTimeInterval _frameDurations;
+
+ BOOL _atLeastiOS_12_2_0;
+
}
#pragma mark - Setup & Teardown -
@@ -441,6 +449,7 @@ public:
{
_isTargetingInterfaceBuilder = NSProcessInfo.processInfo.mgl_isInterfaceBuilderDesignablesAgent;
_opaque = NO;
+ _atLeastiOS_12_2_0 = [NSProcessInfo.processInfo isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){12,2,0}];
BOOL background = [UIApplication sharedApplication].applicationState == UIApplicationStateBackground;
if (!background)
@@ -479,12 +488,18 @@ public:
mbgl::MapOptions mapOptions;
mapOptions.withMapMode(mbgl::MapMode::Continuous)
+ .withSize(self.size)
+ .withPixelRatio(config.scaleFactor)
.withConstrainMode(mbgl::ConstrainMode::None)
.withViewportMode(mbgl::ViewportMode::Default)
.withCrossSourceCollisions(enableCrossSourceCollisions);
+ mbgl::ResourceOptions resourceOptions;
+ resourceOptions.withCachePath([[MGLOfflineStorage sharedOfflineStorage] mbglCachePath])
+ .withAssetPath([NSBundle mainBundle].resourceURL.path.UTF8String);
+
NSAssert(!_mbglMap, @"_mbglMap should be NULL");
- _mbglMap = new mbgl::Map(*_rendererFrontend, *_mbglView, self.size, config.scaleFactor, *[config fileSource], *_mbglThreadPool, mapOptions);
+ _mbglMap = new mbgl::Map(*_rendererFrontend, *_mbglView, *_mbglThreadPool, mapOptions, resourceOptions);
// start paused if in IB
if (_isTargetingInterfaceBuilder || background) {
@@ -675,6 +690,20 @@ public:
static_cast<uint32_t>(self.glView.drawableHeight) };
}
++ (GLKView *)GLKViewWithFrame:(CGRect)frame context:(EAGLContext *)context opaque:(BOOL)opaque
+{
+ GLKView *glView = [[GLKView alloc] initWithFrame:frame context:context];
+ glView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
+ glView.enableSetNeedsDisplay = NO;
+ glView.drawableStencilFormat = GLKViewDrawableStencilFormat8;
+ glView.drawableDepthFormat = GLKViewDrawableDepthFormat16;
+ glView.contentScaleFactor = [UIScreen instancesRespondToSelector:@selector(nativeScale)] ? [[UIScreen mainScreen] nativeScale] : [[UIScreen mainScreen] scale];
+ glView.layer.opaque = opaque;
+ glView.contentMode = UIViewContentModeCenter;
+
+ return glView;
+}
+
- (void)createGLView
{
if (_context) return;
@@ -686,21 +715,14 @@ public:
// create GL view
//
- _glView = [[GLKView alloc] initWithFrame:self.bounds context:_context];
- _glView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
- _glView.enableSetNeedsDisplay = NO;
- _glView.drawableStencilFormat = GLKViewDrawableStencilFormat8;
- _glView.drawableDepthFormat = GLKViewDrawableDepthFormat16;
- _glView.contentScaleFactor = [UIScreen instancesRespondToSelector:@selector(nativeScale)] ? [[UIScreen mainScreen] nativeScale] : [[UIScreen mainScreen] scale];
- _glView.layer.opaque = _opaque;
+ _glView = [MGLMapView GLKViewWithFrame:self.bounds context:_context opaque:_opaque];
_glView.delegate = self;
CAEAGLLayer *eaglLayer = MGL_OBJC_DYNAMIC_CAST(_glView.layer, CAEAGLLayer);
- eaglLayer.presentsWithTransaction = YES;
+ eaglLayer.presentsWithTransaction = NO;
[_glView bindDrawable];
[self insertSubview:_glView atIndex:0];
- _glView.contentMode = UIViewContentModeCenter;
}
- (UIImage *)compassImage
@@ -1095,6 +1117,13 @@ public:
{
MGLAssertIsMainThread();
+ // Not "visible" - this isn't a full definition of visibility, but if
+ // the map view doesn't have a window then it *cannot* be visible.
+ if (!self.window) {
+ return;
+ }
+
+ // Mismatched display link
if (displayLink && displayLink != _displayLink) {
return;
}
@@ -1107,8 +1136,28 @@ public:
[self updateUserLocationAnnotationView];
[self updateAnnotationViews];
[self updateCalloutView];
-
- [self.glView display];
+
+#ifdef MGL_RECREATE_GL_IN_AN_EMERGENCY
+ // See https://github.com/mapbox/mapbox-gl-native/issues/14232
+ // glClear can be blocked for 1 second. This code is an "escape hatch",
+ // an attempt to detect this situation and rebuild the GL views.
+ if (self.enablePresentsWithTransaction && _atLeastiOS_12_2_0)
+ {
+ CFTimeInterval before = CACurrentMediaTime();
+ [self.glView display];
+ CFTimeInterval after = CACurrentMediaTime();
+
+ if (after-before >= 1.0) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [self emergencyRecreateGL];
+ });
+ }
+ }
+ else
+#endif
+ {
+ [self.glView display];
+ }
}
if (self.experimental_enableFrameRateMeasurement)
@@ -1159,7 +1208,7 @@ public:
BOOL isVisible = self.superview && self.window;
if (isVisible && ! _displayLink)
{
- if (_mbglMap && self.mbglMap.getConstrainMode() == mbgl::ConstrainMode::None)
+ if (_mbglMap && self.mbglMap.getMapOptions().constrainMode() == mbgl::ConstrainMode::None)
{
self.mbglMap.setConstrainMode(mbgl::ConstrainMode::HeightOnly);
}
@@ -1225,15 +1274,96 @@ public:
[self updateDisplayLinkPreferredFramesPerSecond];
}
+- (void)setEnablePresentsWithTransaction:(BOOL)enablePresentsWithTransaction
+{
+ if (_enablePresentsWithTransaction == enablePresentsWithTransaction)
+ {
+ return;
+ }
+
+ _enablePresentsWithTransaction = enablePresentsWithTransaction;
+
+ // If the map is visible, change the layer property too
+ if (self.window) {
+ CAEAGLLayer *eaglLayer = MGL_OBJC_DYNAMIC_CAST(_glView.layer, CAEAGLLayer);
+ eaglLayer.presentsWithTransaction = enablePresentsWithTransaction;
+ }
+}
+
+#ifdef MGL_RECREATE_GL_IN_AN_EMERGENCY
+// See https://github.com/mapbox/mapbox-gl-native/issues/14232
+- (void)emergencyRecreateGL {
+ MGLLogError(@"Rendering took too long - creating GL views");
+
+ CAEAGLLayer *eaglLayer = MGL_OBJC_DYNAMIC_CAST(_glView.layer, CAEAGLLayer);
+ eaglLayer.presentsWithTransaction = NO;
+
+ [self sleepGL:nil];
+
+ // Just performing a sleepGL/wakeGL pair isn't sufficient - in this case
+ // we can still get errors when calling bindDrawable. Here we completely
+ // recreate the GLKView
+
+ [self.userLocationAnnotationView removeFromSuperview];
+ [_glView removeFromSuperview];
+
+ _glView = [MGLMapView GLKViewWithFrame:self.bounds context:_context opaque:_opaque];
+ _glView.delegate = self;
+
+ [self insertSubview:_glView atIndex:0];
+
+ if (self.annotationContainerView)
+ {
+ [_glView insertSubview:self.annotationContainerView atIndex:0];
+ }
+
+ [self updateUserLocationAnnotationView];
+
+ // Do not bind...yet
+
+ if (self.window) {
+ [self wakeGL:nil];
+ CAEAGLLayer *eaglLayer = MGL_OBJC_DYNAMIC_CAST(_glView.layer, CAEAGLLayer);
+ eaglLayer.presentsWithTransaction = self.enablePresentsWithTransaction;
+ }
+ else {
+ MGLLogDebug(@"No window - skipping wakeGL");
+ }
+}
+#endif
+
- (void)willMoveToWindow:(UIWindow *)newWindow {
[super willMoveToWindow:newWindow];
[self refreshSupportedInterfaceOrientationsWithWindow:newWindow];
+
+ if (!newWindow)
+ {
+ // See https://github.com/mapbox/mapbox-gl-native/issues/14232
+ // In iOS 12.2, CAEAGLLayer.presentsWithTransaction can cause dramatic
+ // slow down. The exact cause of this is unknown, but this work around
+ // appears to lessen the effects.
+ //
+ // Also, consider calling the new mbgl::Renderer::flush()
+ CAEAGLLayer *eaglLayer = MGL_OBJC_DYNAMIC_CAST(_glView.layer, CAEAGLLayer);
+ eaglLayer.presentsWithTransaction = NO;
+
+ // Moved from didMoveToWindow
+ [self validateDisplayLink];
+ }
}
- (void)didMoveToWindow
{
- [self validateDisplayLink];
[super didMoveToWindow];
+
+ if (self.window)
+ {
+ // See above comment
+ CAEAGLLayer *eaglLayer = MGL_OBJC_DYNAMIC_CAST(_glView.layer, CAEAGLLayer);
+ eaglLayer.presentsWithTransaction = self.enablePresentsWithTransaction;
+
+ [self validateDisplayLink];
+ }
}
- (void)didMoveToSuperview
@@ -2508,10 +2638,15 @@ public:
{
MGLLogInfo(@"Resetting the map to the current style’s default viewport.");
auto camera = self.mbglMap.getStyle().getDefaultCamera();
- CGFloat pitch = *camera.pitch;
- CLLocationDirection heading = mbgl::util::wrap(*camera.bearing, 0., 360.);
- CLLocationDistance altitude = MGLAltitudeForZoomLevel(*camera.zoom, pitch, 0, self.frame.size);
- self.camera = [MGLMapCamera cameraLookingAtCenterCoordinate:MGLLocationCoordinate2DFromLatLng(*camera.center)
+
+ double pitch = camera.pitch ? *camera.pitch : 0.0;
+ double bearing = camera.bearing ? *camera.bearing : 0.0;
+ double zoom = camera.zoom ? *camera.zoom : 0.0;
+ mbgl::LatLng center = camera.center ? *camera.center : mbgl::LatLng();
+
+ CLLocationDirection heading = mbgl::util::wrap(bearing, 0., 360.);
+ CLLocationDistance altitude = MGLAltitudeForZoomLevel(zoom, pitch, 0, self.frame.size);
+ self.camera = [MGLMapCamera cameraLookingAtCenterCoordinate:MGLLocationCoordinate2DFromLatLng(center)
altitude:altitude
pitch:pitch
heading:heading];
@@ -2560,11 +2695,13 @@ public:
}
}
-- (void)setPrefetchesTiles:(BOOL)prefetchesTiles{
+- (void)setPrefetchesTiles:(BOOL)prefetchesTiles
+{
_mbglMap->setPrefetchZoomDelta(prefetchesTiles ? mbgl::util::DEFAULT_PREFETCH_ZOOM_DELTA : 0);
}
-- (BOOL)prefetchesTiles{
+- (BOOL)prefetchesTiles
+{
return _mbglMap->getPrefetchZoomDelta() > 0 ? YES : NO;
}
@@ -4138,6 +4275,8 @@ public:
[newAnnotationContainerView addSubviews:annotationViews];
[_glView insertSubview:newAnnotationContainerView atIndex:0];
self.annotationContainerView = newAnnotationContainerView;
+
+ self.enablePresentsWithTransaction = (self.annotationContainerView.annotationViews.count > MGLPresentsWithTransactionAnnotationCount);
}
/// Initialize and return a default annotation image that depicts a round pin
@@ -4311,6 +4450,8 @@ public:
annotationView.annotation = nil;
[annotationView removeFromSuperview];
[self.annotationContainerView.annotationViews removeObject:annotationView];
+
+ self.enablePresentsWithTransaction = (self.annotationContainerView.annotationViews.count > MGLPresentsWithTransactionAnnotationCount);
if (annotationTag == _selectedAnnotationTag)
{
@@ -6686,6 +6827,20 @@ public:
void onDidFinishLoadingStyle() override {
[nativeView didFinishLoadingStyle];
}
+
+ void onStyleImageMissing(const std::string& imageIdentifier) override {
+ NSString *imageName = [NSString stringWithUTF8String:imageIdentifier.c_str()];
+
+ if ([nativeView.delegate respondsToSelector:@selector(mapView:didFailToLoadImage:)]) {
+ UIImage *imageToLoad = [nativeView.delegate mapView:nativeView didFailToLoadImage:imageName];
+
+ if (imageToLoad) {
+ auto image = [imageToLoad mgl_styleImageWithIdentifier:imageName];
+ nativeView.mbglMap.getStyle().addImage(std::move(image));
+ }
+
+ }
+ }
mbgl::gl::ProcAddress getExtensionFunctionPointer(const char* name) override {
static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengles"));
diff --git a/platform/ios/src/MGLMapViewDelegate.h b/platform/ios/src/MGLMapViewDelegate.h
index 7e098f340d..055d4c9517 100644
--- a/platform/ios/src/MGLMapViewDelegate.h
+++ b/platform/ios/src/MGLMapViewDelegate.h
@@ -275,6 +275,8 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (void)mapView:(MGLMapView *)mapView didFinishLoadingStyle:(MGLStyle *)style;
+- (nullable UIImage *)mapView:(MGLMapView *)mapView didFailToLoadImage:(NSString *)imageName;
+
#pragma mark Tracking User Location
/**
diff --git a/platform/ios/src/UIColor+MGLAdditions.h b/platform/ios/src/UIColor+MGLAdditions.h
index 60cfe1c58b..19702fa105 100644
--- a/platform/ios/src/UIColor+MGLAdditions.h
+++ b/platform/ios/src/UIColor+MGLAdditions.h
@@ -17,5 +17,6 @@
+ (NSExpression *)mgl_expressionForRGBComponents:(NSArray<NSExpression *> *)components;
+ (NSExpression *)mgl_expressionForRGBAComponents:(NSArray<NSExpression *> *)components;
++ (UIColor *)mgl_colorWithRGBComponents:(NSArray<NSExpression *> *)components;
@end
diff --git a/platform/ios/test/MGLMapViewDelegateIntegrationTests.swift b/platform/ios/test/MGLMapViewDelegateIntegrationTests.swift
index 2bf3dc06bd..1330281faa 100644
--- a/platform/ios/test/MGLMapViewDelegateIntegrationTests.swift
+++ b/platform/ios/test/MGLMapViewDelegateIntegrationTests.swift
@@ -96,4 +96,6 @@ extension MGLMapViewDelegateIntegrationTests: MGLMapViewDelegate {
func mapView(_ mapView: MGLMapView, shouldChangeFrom oldCamera: MGLMapCamera, to newCamera: MGLMapCamera, reason: MGLCameraChangeReason) -> Bool { return false }
func mapViewUserLocationAnchorPoint(_ mapView: MGLMapView) -> CGPoint { return CGPoint(x: 100, y: 100) }
+
+ func mapView(_ mapView: MGLMapView, didFailToLoadImage imageName: String) -> UIImage? { return nil }
}
diff --git a/platform/ios/test/MGLNSDataAdditionsTests.m b/platform/ios/test/MGLNSDataAdditionsTests.m
deleted file mode 100644
index 8d145be4a0..0000000000
--- a/platform/ios/test/MGLNSDataAdditionsTests.m
+++ /dev/null
@@ -1,48 +0,0 @@
-#import <XCTest/XCTest.h>
-
-#import "../../darwin/src/NSData+MGLAdditions.h"
-
-@interface MGLNSDataAdditionsTests : XCTestCase
-@end
-
-@implementation MGLNSDataAdditionsTests
-
-- (void)testCompressDecompress
-{
- NSArray *originalArray = [self mockDataWithCount:180];
-
- NSData *originalData = [NSJSONSerialization dataWithJSONObject:originalArray options:0 error:nil];
-
- NSData *compressedData = [originalData mgl_compressedData];
- NSData *decompressedData = [compressedData mgl_decompressedData];
-
- NSArray *decompressedArray = [NSJSONSerialization JSONObjectWithData:decompressedData options:0 error:nil];
-
- XCTAssertTrue([originalArray isEqualToArray:decompressedArray], @"originalArray and decompressedArray should be equal");
-}
-
-- (NSArray *)mockDataWithCount:(NSUInteger)count
-{
- NSMutableArray *array = [NSMutableArray array];
-
- for (NSUInteger i=0;i<count;i++)
- {
- [array addObject:@{@"lat": @([self safeValueBetween:-90 and:90]),
- @"lng": @([self safeValueBetween:-180 and:180]),
- @"timestamp": @((floor([NSDate date].timeIntervalSince1970) * 100) / 100)}];
- }
-
- return array;
-}
-
-- (double)safeValueBetween:(double)lowerBound and:(double)upperBound
-{
- return floor([self randomBetween:lowerBound and:upperBound] * 100 ) / 100;
-}
-
-- (double)randomBetween:(double)lowerBound and:(double)upperBound
-{
- return lowerBound * drand48() + upperBound * drand48();
-}
-
-@end
diff --git a/platform/ios/vendor/mapbox-events-ios b/platform/ios/vendor/mapbox-events-ios
-Subproject d79e62581df5f51a0064dd2f78972c489c71d41
+Subproject 67d59dbe10f232dfeb3a1604c6696c6619abe88
diff --git a/platform/linux/config.cmake b/platform/linux/config.cmake
index 6d4715e451..4405e0583f 100644
--- a/platform/linux/config.cmake
+++ b/platform/linux/config.cmake
@@ -104,13 +104,8 @@ endmacro()
macro(mbgl_filesource)
- target_sources(mbgl-filesource
- # File source
- PRIVATE platform/default/src/mbgl/storage/http_file_source.cpp
-
- # Database
- PRIVATE platform/default/src/mbgl/storage/sqlite3.cpp
- )
+ # Modify platform/linux/filesource-files.json to change the source files for this target.
+ target_sources_from_file(mbgl-filesource PRIVATE platform/linux/filesource-files.json)
# We're not referencing any cURL symbols since we're dynamically loading it. However, we want to
# link the library anyway since we're definitely going to load it on startup anyway.
diff --git a/platform/linux/filesource-files.json b/platform/linux/filesource-files.json
new file mode 100644
index 0000000000..448f5f8613
--- /dev/null
+++ b/platform/linux/filesource-files.json
@@ -0,0 +1,10 @@
+{
+ "//": "This file can be edited manually and is the canonical source.",
+ "sources": [
+ "platform/default/src/mbgl/storage/file_source.cpp",
+ "platform/default/src/mbgl/storage/http_file_source.cpp",
+ "platform/default/src/mbgl/storage/sqlite3.cpp"
+ ],
+ "public_headers": {},
+ "private_headers": {}
+}
diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md
index 2542f57d95..ebfb3f335a 100644
--- a/platform/macos/CHANGELOG.md
+++ b/platform/macos/CHANGELOG.md
@@ -10,6 +10,12 @@
* Added `MGLNetworkConfiguration` class to customize the SDK's `NSURLSessionConfiguration` object. ([#11447](https://github.com/mapbox/mapbox-gl-native/pull/13886))
* Fixed an issue that caused `MGL_FUNCTION` to ignore multiple formatting parameters when passed a `format` function as parameter. ([#14064](https://github.com/mapbox/mapbox-gl-native/pull/14064))
* Added `mgl_attributed:` expression operator, which concatenate `MGLAttributedExpression` objects for specifying rich text in the `MGLSymbolStyleLayer.text` property. ([#14094](https://github.com/mapbox/mapbox-gl-native/pull/14094))
+* Fixed an issue that caused conditional expressions to crash when passed nested conditional expressions as parameters. ([#14181](https://github.com/mapbox/mapbox-gl-native/pull/14181))
+* Added `-[MGLMapViewDelegate mapView:didFailToLoadImage:]` to load missing symbol icons in the style if they are not found. ([#14302](https://github.com/mapbox/mapbox-gl-native/pull/14302))
+
+### Offline
+
+* Fixed a bug that caused offline packs created prior to v0.7.0 (introduced in [#11055](https://github.com/mapbox/mapbox-gl-native/pull/11055)) to be marked as `MGLOfflinePackStateInactive`. ([#14188](https://github.com/mapbox/mapbox-gl-native/pull/14188))
### Annotations
@@ -19,6 +25,7 @@
### Packaging
* Added Czech and Galician localizations. ([#13782](https://github.com/mapbox/mapbox-gl-native/pull/13782), [#14095](https://github.com/mapbox/mapbox-gl-native/pull/14095))
+* Added support for building with Xcode 10.2 / iOS SDK 12.2. ([#14241](https://github.com/mapbox/mapbox-gl-native/pull/14241))
## 0.13.0 - December 20, 2018
diff --git a/platform/macos/docs/guides/For Style Authors.md b/platform/macos/docs/guides/For Style Authors.md
index 038ddf1f93..5a81eb3593 100644
--- a/platform/macos/docs/guides/For Style Authors.md
+++ b/platform/macos/docs/guides/For Style Authors.md
@@ -411,5 +411,16 @@ In style JSON | In the format string
`["any", f0, …, fn]` | `p0 OR … OR pn`
`["none", f0, …, fn]` | `NOT (p0 OR … OR pn)`
+## Specifying the text format
+
+The following format attributes are defined as `NSString` constans that you
+can use to update the formatting of `MGLSymbolStyleLayer.text` property.
+
+In style JSON | In Objective-C | In Swift
+--------------|-----------------------|---------
+`text-font` | `MGLFontNamesAttribute` | `.fontNamesAttribute`
+`font-scale` | `MGLFontScaleAttribute` | `.fontScaleAttribute`
+`text-color` | `MGLFontColorAttribute` | `.fontColorAttribute`
+
See the “[Predicates and Expressions](predicates-and-expressions.html)” guide for
a full description of the supported operators and operand types.
diff --git a/platform/macos/macos.xcodeproj/project.pbxproj b/platform/macos/macos.xcodeproj/project.pbxproj
index 5d5a94c78a..57c4f198f0 100644
--- a/platform/macos/macos.xcodeproj/project.pbxproj
+++ b/platform/macos/macos.xcodeproj/project.pbxproj
@@ -2008,6 +2008,7 @@
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_ENABLE_CPP_RTTI = NO;
GCC_NO_COMMON_BLOCKS = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = "NDEBUG=1";
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
diff --git a/platform/macos/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm
index 911d254889..0fdecd6cc8 100644
--- a/platform/macos/src/MGLMapView.mm
+++ b/platform/macos/src/MGLMapView.mm
@@ -36,8 +36,8 @@
#import <mbgl/renderer/renderer.hpp>
#import <mbgl/renderer/renderer_backend.hpp>
#import <mbgl/renderer/backend_scope.hpp>
-#import <mbgl/storage/default_file_source.hpp>
#import <mbgl/storage/network_status.hpp>
+#import <mbgl/storage/resource_options.hpp>
#import <mbgl/math/wrap.hpp>
#import <mbgl/util/constants.hpp>
#import <mbgl/util/chrono.hpp>
@@ -292,10 +292,17 @@ public:
mbgl::MapOptions mapOptions;
mapOptions.withMapMode(mbgl::MapMode::Continuous)
+ .withSize(self.size)
+ .withPixelRatio(config.scaleFactor)
.withConstrainMode(mbgl::ConstrainMode::None)
.withViewportMode(mbgl::ViewportMode::Default)
.withCrossSourceCollisions(enableCrossSourceCollisions);
- _mbglMap = new mbgl::Map(*_rendererFrontend, *_mbglView, self.size, config.scaleFactor, *config.fileSource, *_mbglThreadPool, mapOptions);
+
+ mbgl::ResourceOptions resourceOptions;
+ resourceOptions.withCachePath([[MGLOfflineStorage sharedOfflineStorage] mbglCachePath])
+ .withAssetPath([NSBundle mainBundle].resourceURL.path.UTF8String);
+
+ _mbglMap = new mbgl::Map(*_rendererFrontend, *_mbglView, *_mbglThreadPool, mapOptions, resourceOptions);
// Install the OpenGL layer. Interface Builder’s synchronous drawing means
// we can’t display a map, so don’t even bother to have a map layer.
@@ -690,7 +697,7 @@ public:
self.dormant = NO;
}
- if (window && _mbglMap->getConstrainMode() == mbgl::ConstrainMode::None) {
+ if (window && _mbglMap->getMapOptions().constrainMode() == mbgl::ConstrainMode::None) {
_mbglMap->setConstrainMode(mbgl::ConstrainMode::HeightOnly);
}
diff --git a/platform/macos/src/NSColor+MGLAdditions.h b/platform/macos/src/NSColor+MGLAdditions.h
index 21c939fec6..a3c5aba63f 100644
--- a/platform/macos/src/NSColor+MGLAdditions.h
+++ b/platform/macos/src/NSColor+MGLAdditions.h
@@ -23,5 +23,6 @@
+ (NSExpression *)mgl_expressionForRGBComponents:(NSArray<NSExpression *> *)components;
+ (NSExpression *)mgl_expressionForRGBAComponents:(NSArray<NSExpression *> *)components;
++ (NSColor *)mgl_colorWithRGBComponents:(NSArray<NSExpression *> *)componentExpressions;
@end
diff --git a/platform/macos/src/NSColor+MGLAdditions.mm b/platform/macos/src/NSColor+MGLAdditions.mm
index c73c1a41b7..ea7d99f66d 100644
--- a/platform/macos/src/NSColor+MGLAdditions.mm
+++ b/platform/macos/src/NSColor+MGLAdditions.mm
@@ -37,7 +37,7 @@
@implementation NSExpression (MGLColorAdditions)
+ (NSExpression *)mgl_expressionForRGBComponents:(NSArray<NSExpression *> *)components {
- if (NSColor *color = [self mgl_colorWithComponentExpressions:components]) {
+ if (NSColor *color = [self mgl_colorWithRGBComponents:components]) {
return [NSExpression expressionForConstantValue:color];
}
@@ -49,7 +49,7 @@
}
+ (NSExpression *)mgl_expressionForRGBAComponents:(NSArray<NSExpression *> *)components {
- if (NSColor *color = [self mgl_colorWithComponentExpressions:components]) {
+ if (NSColor *color = [self mgl_colorWithRGBComponents:components]) {
return [NSExpression expressionForConstantValue:color];
}
@@ -62,7 +62,7 @@
/**
Returns a color object corresponding to the given component expressions.
*/
-+ (NSColor *)mgl_colorWithComponentExpressions:(NSArray<NSExpression *> *)componentExpressions {
++ (NSColor *)mgl_colorWithRGBComponents:(NSArray<NSExpression *> *)componentExpressions {
// Map the component expressions to constant components. If any component is
// a non-constant expression, the components cannot be converted into a
// constant color value.
diff --git a/platform/node/src/node_map.cpp b/platform/node/src/node_map.cpp
index 0d69e606c1..291dea6bb7 100644
--- a/platform/node/src/node_map.cpp
+++ b/platform/node/src/node_map.cpp
@@ -20,15 +20,25 @@
#include <mbgl/style/layers/raster_layer.hpp>
#include <mbgl/style/layers/symbol_layer.hpp>
+#include <mbgl/storage/resource_options.hpp>
#include <mbgl/style/style.hpp>
#include <mbgl/style/image.hpp>
#include <mbgl/style/light.hpp>
+#include <mbgl/map/map.hpp>
#include <mbgl/map/map_observer.hpp>
#include <mbgl/util/exception.hpp>
#include <mbgl/util/premultiply.hpp>
#include <unistd.h>
+namespace mbgl {
+
+std::shared_ptr<FileSource> FileSource::createPlatformFileSource(const ResourceOptions& options) {
+ return std::make_shared<node_mbgl::NodeFileSource>(reinterpret_cast<node_mbgl::NodeMap*>(options.platformContext()));
+}
+
+} // namespace mbgl
+
namespace node_mbgl {
struct NodeMap::RenderOptions {
@@ -621,13 +631,12 @@ void NodeMap::cancel() {
});
frontend = std::make_unique<mbgl::HeadlessFrontend>(mbgl::Size{ 256, 256 }, pixelRatio, threadpool);
- mbgl::MapOptions options;
- options.withMapMode(mode)
- .withConstrainMode(mbgl::ConstrainMode::HeightOnly)
- .withViewportMode(mbgl::ViewportMode::Default)
- .withCrossSourceCollisions(crossSourceCollisions);
- map = std::make_unique<mbgl::Map>(*frontend, mapObserver, frontend->getSize(), pixelRatio,
- fileSource, threadpool, options);
+ map = std::make_unique<mbgl::Map>(*frontend, mapObserver, threadpool,
+ mbgl::MapOptions().withSize(frontend->getSize())
+ .withPixelRatio(pixelRatio)
+ .withMapMode(mode)
+ .withCrossSourceCollisions(crossSourceCollisions),
+ mbgl::ResourceOptions().withPlatformContext(reinterpret_cast<void*>(this)));
// FIXME: Reload the style after recreating the map. We need to find
// a better way of canceling an ongoing rendering on the core level
@@ -1205,20 +1214,14 @@ NodeMap::NodeMap(v8::Local<v8::Object> options)
: true;
}())
, mapObserver(NodeMapObserver())
- , fileSource(this)
, frontend(std::make_unique<mbgl::HeadlessFrontend>(mbgl::Size { 256, 256 }, pixelRatio, threadpool))
- , map(std::make_unique<mbgl::Map>(*frontend,
- mapObserver,
- frontend->getSize(),
- pixelRatio,
- fileSource,
- threadpool,
- mbgl::MapOptions().withMapMode(mode)
- .withConstrainMode(mbgl::ConstrainMode::HeightOnly)
- .withViewportMode(mbgl::ViewportMode::Default)
- .withCrossSourceCollisions(crossSourceCollisions))),
- async(new uv_async_t) {
-
+ , map(std::make_unique<mbgl::Map>(*frontend, mapObserver, threadpool,
+ mbgl::MapOptions().withSize(frontend->getSize())
+ .withPixelRatio(pixelRatio)
+ .withMapMode(mode)
+ .withCrossSourceCollisions(crossSourceCollisions),
+ mbgl::ResourceOptions().withPlatformContext(reinterpret_cast<void*>(this))))
+ , async(new uv_async_t) {
async->data = this;
uv_async_init(uv_default_loop(), async, [](uv_async_t* h) {
reinterpret_cast<NodeMap *>(h->data)->renderFinished();
@@ -1232,8 +1235,6 @@ NodeMap::~NodeMap() {
if (map) release();
}
-NodeFileSource::NodeFileSource(NodeMap* nodeMap_) : nodeMap(nodeMap_) {}
-
std::unique_ptr<mbgl::AsyncRequest> NodeFileSource::request(const mbgl::Resource& resource, mbgl::FileSource::Callback callback_) {
assert(nodeMap);
@@ -1248,15 +1249,15 @@ std::unique_ptr<mbgl::AsyncRequest> NodeFileSource::request(const mbgl::Resource
Nan::New<v8::External>(&callback_)
};
- auto instance = Nan::NewInstance(Nan::New(NodeRequest::constructor), 2, argv).ToLocalChecked();
+ auto instance = Nan::NewInstance(Nan::New(node_mbgl::NodeRequest::constructor), 2, argv).ToLocalChecked();
Nan::Set(instance, Nan::New("url").ToLocalChecked(), Nan::New(resource.url).ToLocalChecked());
Nan::Set(instance, Nan::New("kind").ToLocalChecked(), Nan::New<v8::Integer>(resource.kind));
- auto request = Nan::ObjectWrap::Unwrap<NodeRequest>(instance);
+ auto request = Nan::ObjectWrap::Unwrap<node_mbgl::NodeRequest>(instance);
request->Execute();
- return std::make_unique<NodeRequest::NodeAsyncRequest>(request);
+ return std::make_unique<node_mbgl::NodeRequest::NodeAsyncRequest>(request);
}
} // namespace node_mbgl
diff --git a/platform/node/src/node_map.hpp b/platform/node/src/node_map.hpp
index 9e3eb1ad12..65664b34bb 100644
--- a/platform/node/src/node_map.hpp
+++ b/platform/node/src/node_map.hpp
@@ -15,26 +15,13 @@
#pragma GCC diagnostic pop
namespace mbgl {
-class Map;
class HeadlessFrontend;
} // namespace mbgl
namespace node_mbgl {
-class NodeMapObserver : public mbgl::MapObserver {
- void onDidFailLoadingMap(mbgl::MapLoadError, const std::string&) override;
-};
-
-class NodeMap;
-
-class NodeFileSource : public mbgl::FileSource {
-public:
- NodeFileSource(NodeMap*);
-
- std::unique_ptr<mbgl::AsyncRequest> request(const mbgl::Resource&, mbgl::FileSource::Callback) final;
-
-private:
- NodeMap* nodeMap;
+struct NodeMapObserver : public mbgl::MapObserver {
+ void onDidFailLoadingMap(mbgl::MapLoadError, const std::string&) final;
};
class RenderRequest;
@@ -94,7 +81,6 @@ public:
bool crossSourceCollisions;
NodeThreadPool threadpool;
NodeMapObserver mapObserver;
- NodeFileSource fileSource;
std::unique_ptr<mbgl::HeadlessFrontend> frontend;
std::unique_ptr<mbgl::Map> map;
@@ -108,4 +94,10 @@ public:
bool loaded = false;
};
+struct NodeFileSource : public mbgl::FileSource {
+ NodeFileSource(NodeMap* nodeMap_) : nodeMap(nodeMap_) {}
+ std::unique_ptr<mbgl::AsyncRequest> request(const mbgl::Resource&, mbgl::FileSource::Callback) final;
+ NodeMap* nodeMap;
+};
+
} // namespace node_mbgl
diff --git a/platform/node/test/ignores.json b/platform/node/test/ignores.json
index d0becfc58a..060f4935a6 100644
--- a/platform/node/test/ignores.json
+++ b/platform/node/test/ignores.json
@@ -149,24 +149,9 @@
"render-tests/symbol-sort-key/text-expression": "https://github.com/mapbox/mapbox-gl-native/issues/14028",
"render-tests/symbol-sort-key/text-placement": "https://github.com/mapbox/mapbox-gl-native/issues/14028",
"render-tests/fill-opacity/opaque-fill-over-symbol-layer": "skip - port https://github.com/mapbox/mapbox-gl-js/pull/7612",
- "render-tests/text-radial-offset/basic": "skip - port of https://github.com/mapbox/mapbox-gl-js/pull/7596",
- "render-tests/text-variable-anchor/all-anchors-offset": "skip - port of https://github.com/mapbox/mapbox-gl-js/pull/7596",
- "render-tests/text-variable-anchor/all-anchors": "skip - port of https://github.com/mapbox/mapbox-gl-js/pull/7596",
- "render-tests/text-variable-anchor/icon-image-all-anchors": "skip - port of https://github.com/mapbox/mapbox-gl-js/pull/7596",
- "render-tests/text-variable-anchor/icon-image": "skip - port of https://github.com/mapbox/mapbox-gl-js/pull/7596",
- "render-tests/text-variable-anchor/no-animate-zoom": "skip - port of https://github.com/mapbox/mapbox-gl-js/pull/7596",
- "render-tests/text-variable-anchor/pitched-offset": "skip - port of https://github.com/mapbox/mapbox-gl-js/pull/7596",
- "render-tests/text-variable-anchor/pitched-rotated-debug": "skip - port of https://github.com/mapbox/mapbox-gl-js/pull/7596",
- "render-tests/text-variable-anchor/pitched-with-map": "skip - port of https://github.com/mapbox/mapbox-gl-js/pull/7596",
- "render-tests/text-variable-anchor/pitched": "skip - port of https://github.com/mapbox/mapbox-gl-js/pull/7596",
- "render-tests/text-variable-anchor/remember-last-placement": "skip - port of https://github.com/mapbox/mapbox-gl-js/pull/7596",
- "render-tests/text-variable-anchor/rotated-offset": "skip - port of https://github.com/mapbox/mapbox-gl-js/pull/7596",
- "render-tests/text-variable-anchor/rotated-with-map": "skip - port of https://github.com/mapbox/mapbox-gl-js/pull/7596",
- "render-tests/text-variable-anchor/rotated": "skip - port of https://github.com/mapbox/mapbox-gl-js/pull/7596",
- "render-tests/text-variable-anchor/single-justification": "skip - port of https://github.com/mapbox/mapbox-gl-js/pull/7596",
- "render-tests/text-variable-anchor/single-line": "skip - port of https://github.com/mapbox/mapbox-gl-js/pull/7596",
- "render-tests/text-variable-anchor/top-bottom-left-right": "skip - port of https://github.com/mapbox/mapbox-gl-js/pull/7596",
- "render-tests/text-justify/auto": "skip - port of https://github.com/mapbox/mapbox-gl-js/pull/7596",
+ "render-tests/text-variable-anchor/pitched-rotated-debug": "https://github.com/mapbox/mapbox-gl-native/issues/14211",
+ "render-tests/text-variable-anchor/rotated-offset": "https://github.com/mapbox/mapbox-gl-native/issues/14211",
+ "render-tests/text-variable-anchor/remember-last-placement": "skip - fails on gl-native, as symbol index is not functional at static map mode - needs issue",
"render-tests/geojson/clustered-properties": "https://github.com/mapbox/mapbox-gl-native/issues/14043",
"render-tests/remove-feature-state/composite-expression": "https://github.com/mapbox/mapbox-gl-native/issues/12413",
"render-tests/remove-feature-state/data-expression": "https://github.com/mapbox/mapbox-gl-native/issues/12413",
diff --git a/platform/qt/qt.cmake b/platform/qt/qt.cmake
index 14f09007ac..911af25bc4 100644
--- a/platform/qt/qt.cmake
+++ b/platform/qt/qt.cmake
@@ -50,6 +50,7 @@ set(MBGL_QT_CORE_FILES
set(MBGL_QT_FILESOURCE_FILES
# File source
+ PRIVATE platform/default/src/mbgl/storage/file_source.cpp
PRIVATE platform/qt/src/http_file_source.cpp
PRIVATE platform/qt/src/http_file_source.hpp
PRIVATE platform/qt/src/http_request.cpp
diff --git a/platform/qt/src/qmapboxgl.cpp b/platform/qt/src/qmapboxgl.cpp
index b05c82a783..4f79525257 100644
--- a/platform/qt/src/qmapboxgl.cpp
+++ b/platform/qt/src/qmapboxgl.cpp
@@ -10,6 +10,7 @@
#include <mbgl/annotation/annotation.hpp>
#include <mbgl/map/camera.hpp>
#include <mbgl/map/map.hpp>
+#include <mbgl/map/map_options.hpp>
#include <mbgl/math/log2.hpp>
#include <mbgl/math/minmax.hpp>
#include <mbgl/style/style.hpp>
@@ -33,7 +34,9 @@
#include <mbgl/style/image.hpp>
#include <mbgl/renderer/renderer.hpp>
#include <mbgl/renderer/backend_scope.hpp>
+#include <mbgl/storage/default_file_source.hpp>
#include <mbgl/storage/network_status.hpp>
+#include <mbgl/storage/resource_options.hpp>
#include <mbgl/util/color.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/geo.hpp>
@@ -91,49 +94,6 @@ namespace {
QThreadStorage<std::shared_ptr<mbgl::util::RunLoop>> loop;
-std::shared_ptr<mbgl::DefaultFileSource> sharedDefaultFileSource(const QMapboxGLSettings &settings) {
- static std::mutex mutex;
- static std::unordered_map<std::string, std::weak_ptr<mbgl::DefaultFileSource>> fileSources;
-
- const std::string cachePath = settings.cacheDatabasePath().toStdString();
- const std::string accessToken = settings.accessToken().toStdString();
- const std::string apiBaseUrl = settings.apiBaseUrl().toStdString();
-
- std::lock_guard<std::mutex> lock(mutex);
-
- // Purge entries no longer in use.
- for (auto it = fileSources.begin(); it != fileSources.end();) {
- if (it->second.expired()) {
- it = fileSources.erase(it);
- } else {
- ++it;
- }
- }
-
- const auto key = cachePath + "|" + accessToken + "|" + apiBaseUrl;
-
- // Return an existing FileSource if available.
- auto sharedFileSource = fileSources.find(key);
- if (sharedFileSource != fileSources.end()) {
- auto lockedSharedFileSource = sharedFileSource->second.lock();
- if (lockedSharedFileSource) {
- return lockedSharedFileSource;
- }
- }
-
- // New path, create a new FileSource.
- auto newFileSource = std::make_shared<mbgl::DefaultFileSource>(
- cachePath, settings.assetPath().toStdString(), settings.cacheDatabaseMaximumSize());
-
- // Setup the FileSource
- newFileSource->setAccessToken(accessToken);
- newFileSource->setAPIBaseURL(apiBaseUrl);
-
- fileSources[key] = newFileSource;
-
- return newFileSource;
-}
-
// Conversion helper functions.
mbgl::Size sanitizedSize(const QSize& size) {
@@ -907,7 +867,7 @@ void QMapboxGL::pitchBy(double pitch_)
*/
QMapboxGL::NorthOrientation QMapboxGL::northOrientation() const
{
- return static_cast<QMapboxGL::NorthOrientation>(d_ptr->mapObj->getNorthOrientation());
+ return static_cast<QMapboxGL::NorthOrientation>(d_ptr->mapObj->getMapOptions().northOrientation());
}
/*!
@@ -1167,7 +1127,7 @@ void QMapboxGL::resize(const QSize& size_)
{
auto size = sanitizedSize(size_);
- if (d_ptr->mapObj->getSize() == size)
+ if (d_ptr->mapObj->getMapOptions().size() == size)
return;
d_ptr->mapObj->setSize(size);
@@ -1745,22 +1705,31 @@ void QMapboxGL::connectionEstablished()
\a copyrightsHtml is a string with a HTML snippet.
*/
+mbgl::MapOptions mapOptionsFromQMapboxGLSettings(const QMapboxGLSettings &settings, const QSize &size, qreal pixelRatio) {
+ return std::move(mbgl::MapOptions()
+ .withSize(sanitizedSize(size))
+ .withPixelRatio(pixelRatio)
+ .withMapMode(static_cast<mbgl::MapMode>(settings.mapMode()))
+ .withConstrainMode(static_cast<mbgl::ConstrainMode>(settings.constrainMode()))
+ .withViewportMode(static_cast<mbgl::ViewportMode>(settings.viewportMode())));
+}
+
+mbgl::ResourceOptions resourceOptionsFromQMapboxGLSettings(const QMapboxGLSettings &settings) {
+ return std::move(mbgl::ResourceOptions()
+ .withAccessToken(settings.accessToken().toStdString())
+ .withAssetPath(settings.assetPath().toStdString())
+ .withBaseURL(settings.apiBaseUrl().toStdString())
+ .withCachePath(settings.cacheDatabasePath().toStdString())
+ .withMaximumCacheSize(settings.cacheDatabaseMaximumSize()));
+}
+
QMapboxGLPrivate::QMapboxGLPrivate(QMapboxGL *q, const QMapboxGLSettings &settings, const QSize &size, qreal pixelRatio_)
: QObject(q)
- , m_fileSourceObj(sharedDefaultFileSource(settings))
, m_threadPool(mbgl::sharedThreadPool())
, m_mode(settings.contextMode())
, m_pixelRatio(pixelRatio_)
, m_localFontFamily(settings.localFontFamily())
{
- if (settings.resourceTransform()) {
- m_resourceTransform = std::make_unique<mbgl::Actor<mbgl::ResourceTransform>>(*mbgl::Scheduler::GetCurrent(),
- [callback = settings.resourceTransform()] (mbgl::Resource::Kind, const std::string &&url_) -> std::string {
- return callback(std::move(url_));
- });
- m_fileSourceObj->setResourceTransform(m_resourceTransform->self());
- }
-
// Setup MapObserver
m_mapObserver = std::make_unique<QMapboxGLMapObserver>(this);
@@ -1770,18 +1739,21 @@ QMapboxGLPrivate::QMapboxGLPrivate(QMapboxGL *q, const QMapboxGLSettings &settin
connect(m_mapObserver.get(), SIGNAL(mapLoadingFailed(QMapboxGL::MapLoadingFailure,QString)), q, SIGNAL(mapLoadingFailed(QMapboxGL::MapLoadingFailure,QString)));
connect(m_mapObserver.get(), SIGNAL(copyrightsChanged(QString)), q, SIGNAL(copyrightsChanged(QString)));
- mbgl::MapOptions options;
- options.withMapMode(static_cast<mbgl::MapMode>(settings.mapMode()))
- .withConstrainMode(static_cast<mbgl::ConstrainMode>(settings.constrainMode()))
- .withViewportMode(static_cast<mbgl::ViewportMode>(settings.viewportMode()));
-
- // Setup the Map object
- mapObj = std::make_unique<mbgl::Map>(
- *this, // RendererFrontend
- *m_mapObserver,
- sanitizedSize(size),
- m_pixelRatio, *m_fileSourceObj, *m_threadPool,
- options);
+ auto resourceOptions = resourceOptionsFromQMapboxGLSettings(settings);
+
+ // Setup the Map object.
+ mapObj = std::make_unique<mbgl::Map>(*this, *m_mapObserver, *m_threadPool,
+ mapOptionsFromQMapboxGLSettings(settings, size, m_pixelRatio),
+ resourceOptions);
+
+ if (settings.resourceTransform()) {
+ m_resourceTransform = std::make_unique<mbgl::Actor<mbgl::ResourceTransform>>(*mbgl::Scheduler::GetCurrent(),
+ [callback = settings.resourceTransform()] (mbgl::Resource::Kind, const std::string &&url_) -> std::string {
+ return callback(std::move(url_));
+ });
+ auto fs = mbgl::FileSource::getSharedFileSource(resourceOptions);
+ std::static_pointer_cast<mbgl::DefaultFileSource>(fs)->setResourceTransform(m_resourceTransform->self());
+ }
// Needs to be Queued to give time to discard redundant draw calls via the `renderQueued` flag.
connect(this, SIGNAL(needsRendering()), q, SIGNAL(needsRendering()), Qt::QueuedConnection);
diff --git a/platform/qt/src/qmapboxgl_p.hpp b/platform/qt/src/qmapboxgl_p.hpp
index 7157df0aba..6a5b5ce04f 100644
--- a/platform/qt/src/qmapboxgl_p.hpp
+++ b/platform/qt/src/qmapboxgl_p.hpp
@@ -7,7 +7,6 @@
#include <mbgl/actor/actor.hpp>
#include <mbgl/map/map.hpp>
#include <mbgl/renderer/renderer_frontend.hpp>
-#include <mbgl/storage/default_file_source.hpp>
#include <mbgl/storage/resource_transform.hpp>
#include <mbgl/util/default_thread_pool.hpp>
#include <mbgl/util/geo.hpp>
@@ -57,7 +56,6 @@ private:
std::shared_ptr<mbgl::UpdateParameters> m_updateParameters;
std::unique_ptr<QMapboxGLMapObserver> m_mapObserver;
- std::shared_ptr<mbgl::DefaultFileSource> m_fileSourceObj;
std::shared_ptr<mbgl::ThreadPool> m_threadPool;
std::unique_ptr<QMapboxGLMapRenderer> m_mapRenderer;
std::unique_ptr<mbgl::Actor<mbgl::ResourceTransform>> m_resourceTransform;