summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
authorm-stephen <truestyle2005@163.com>2019-09-17 10:46:33 +0800
committerGitHub <noreply@github.com>2019-09-17 10:46:33 +0800
commiteb1f8eb32286dd7b89ae76b839b774b0071ca5a5 (patch)
tree0db6df1811ffb8c9a5139687817386dee23cfef1 /platform
parentb0018568b84f9bb1c185f0441a41741e9fde5a84 (diff)
parenta99240a54ffd5eb77568d41e10186411b1b759eb (diff)
downloadqtlocation-mapboxgl-eb1f8eb32286dd7b89ae76b839b774b0071ca5a5.tar.gz
Merge branch 'master' into stephen-ios-error-report
Diffstat (limited to 'platform')
-rw-r--r--platform/android/.gitignore2
-rw-r--r--platform/android/CHANGELOG.md101
-rw-r--r--platform/android/LICENSE.md4
-rw-r--r--platform/android/MapboxGLAndroidSDK/gradle.properties2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java97
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java80
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUrl.java12
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentOptions.java3
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java8
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java16
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java81
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java10
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java79
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java22
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Style.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java13
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java5
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRenderer.java5
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewRenderThread.java16
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java1
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java21
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java7
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java187
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java12
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonOptions.java27
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/FontUtils.java31
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java42
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java35
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsAttrsTest.kt101
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/StyleTest.kt18
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/TransformTest.kt103
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java18
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/module/http/HttpRequestUrlTest.kt4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactoryTest.kt253
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapInstrumentationTest.kt41
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/NativeMapViewTest.kt38
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/VisibleRegionTest.kt64
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/offline/OfflineDownloadTest.kt31
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseTest.java12
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraAnimateTest.java296
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraEaseTest.java290
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraMoveTest.java292
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraTest.java307
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CustomGeometrySourceTest.kt11
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ExpressionTest.java200
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/TestConstants.java1
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/utils/FontUtilsTest.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/BulkMarkerActivity.java3
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimatorActivity.java7
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraPositionActivity.java8
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MapFragmentActivity.java4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationFragmentActivity.kt2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GeoJsonClusteringActivity.java11
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolGeneratorActivity.java7
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolLayerActivity.java26
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_position.xml1
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_gesture_detector.xml1
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/arrays.xml5
-rw-r--r--platform/android/build.gradle2
-rw-r--r--platform/android/config.cmake4
-rw-r--r--platform/android/core-files.json2
-rw-r--r--platform/android/gradle/dependencies.gradle4
-rw-r--r--platform/android/gradle/jacoco-report.gradle2
-rw-r--r--platform/android/gradle/wrapper/gradle-wrapper.properties2
-rw-r--r--platform/android/scripts/exclude-activity-gen.json5
-rw-r--r--platform/android/src/android_renderer_frontend.cpp4
-rw-r--r--platform/android/src/java_types.cpp8
-rw-r--r--platform/android/src/java_types.hpp6
-rwxr-xr-xplatform/android/src/jni.cpp157
-rw-r--r--platform/android/src/jni.hpp3
-rwxr-xr-xplatform/android/src/jni_native.cpp164
-rw-r--r--platform/android/src/jni_native.hpp11
-rw-r--r--platform/android/src/main.cpp2
-rw-r--r--platform/android/src/map/camera_position.cpp22
-rw-r--r--platform/android/src/map/camera_position.hpp4
-rw-r--r--platform/android/src/map_renderer.cpp6
-rw-r--r--platform/android/src/map_renderer.hpp2
-rwxr-xr-xplatform/android/src/native_map_view.cpp67
-rwxr-xr-xplatform/android/src/native_map_view.hpp15
-rw-r--r--platform/android/src/snapshotter/map_snapshotter.cpp8
-rw-r--r--platform/android/src/snapshotter/map_snapshotter.hpp1
-rw-r--r--platform/android/src/style/android_conversion.hpp18
-rw-r--r--platform/android/src/style/sources/custom_geometry_source.cpp14
-rw-r--r--platform/android/src/style/sources/source.cpp2
-rw-r--r--platform/android/src/style/value.cpp6
-rw-r--r--platform/android/src/style/value.hpp1
m---------platform/android/vendor/mapbox-gestures-android0
m---------platform/android/vendor/mapbox-java0
-rw-r--r--platform/darwin/src/MGLAccountManager.m2
-rw-r--r--platform/darwin/src/MGLAccountManager_Private.h3
-rw-r--r--platform/darwin/src/MGLComputedShapeSource.mm3
-rw-r--r--platform/darwin/src/MGLForegroundStyleLayer.mm16
-rw-r--r--platform/darwin/src/MGLImageSource.mm19
-rw-r--r--platform/darwin/src/MGLMapSnapshotter.h34
-rw-r--r--platform/darwin/src/MGLMapSnapshotter.mm107
-rw-r--r--platform/darwin/src/MGLOfflineStorage.h10
-rw-r--r--platform/darwin/src/MGLRasterTileSource.mm2
-rw-r--r--platform/darwin/src/MGLRasterTileSource_Private.h2
-rw-r--r--platform/darwin/src/MGLRendererConfiguration.h3
-rw-r--r--platform/darwin/src/MGLRendererConfiguration.mm4
-rw-r--r--platform/darwin/src/MGLShapeSource.mm16
-rw-r--r--platform/darwin/src/MGLSource.h3
-rw-r--r--platform/darwin/src/MGLSource.mm15
-rw-r--r--platform/darwin/src/MGLSource_Private.h15
-rw-r--r--platform/darwin/src/MGLStyle.mm21
-rw-r--r--platform/darwin/src/MGLStyleLayer.mm22
-rw-r--r--platform/darwin/src/MGLStyleLayer_Private.h1
-rw-r--r--platform/darwin/src/MGLSymbolStyleLayer.h13
-rw-r--r--platform/darwin/src/MGLTypes.h4
-rw-r--r--platform/darwin/src/MGLVectorStyleLayer.m25
-rw-r--r--platform/darwin/src/MGLVectorStyleLayer.mm34
-rw-r--r--platform/darwin/src/MGLVectorTileSource.mm4
-rw-r--r--platform/darwin/src/http_file_source.mm19
-rw-r--r--platform/darwin/src/string_nsstring.mm4
-rw-r--r--platform/darwin/test/MGLClockDirectionFormatterTests.m5
-rw-r--r--platform/darwin/test/MGLCompassDirectionFormatterTests.m5
-rw-r--r--platform/darwin/test/MGLCoordinateFormatterTests.m5
-rw-r--r--platform/darwin/test/MGLResourceTests.mm23
-rw-r--r--platform/darwin/test/MGLTileSetTests.mm19
-rw-r--r--platform/default/include/mbgl/gfx/headless_frontend.hpp2
-rw-r--r--platform/default/include/mbgl/map/map_snapshotter.hpp1
-rw-r--r--platform/default/include/mbgl/storage/offline_database.hpp5
-rw-r--r--platform/default/include/mbgl/storage/offline_download.hpp4
-rw-r--r--platform/default/src/mbgl/gfx/headless_frontend.cpp6
-rw-r--r--platform/default/src/mbgl/map/map_snapshotter.cpp7
-rw-r--r--platform/default/src/mbgl/storage/offline_database.cpp33
-rw-r--r--platform/default/src/mbgl/storage/offline_download.cpp62
-rw-r--r--platform/default/src/mbgl/storage/sqlite3.cpp1
-rw-r--r--platform/default/src/mbgl/util/format_number.cpp4
-rw-r--r--platform/ios/CHANGELOG.md47
-rw-r--r--platform/ios/INSTALL.md22
-rw-r--r--platform/ios/Integration Tests/Annotation Tests/MGLAnnotationViewIntegrationTests.mm (renamed from platform/ios/Integration Tests/Annotation Tests/MGLAnnotationViewIntegrationTests.m)273
-rw-r--r--platform/ios/Integration Tests/Camera Tests/MGLCameraTransitionFinishTests.mm109
-rw-r--r--platform/ios/Integration Tests/Camera Tests/MGLCameraTransitionTests.mm (renamed from platform/ios/Integration Tests/MGLCameraTransitionTests.mm)24
-rw-r--r--platform/ios/Integration Tests/MGLMapViewIntegrationTest.h3
-rw-r--r--platform/ios/Integration Tests/MGLMapViewIntegrationTest.m79
-rw-r--r--platform/ios/Integration Tests/MGLMapViewPendingBlockTests.m366
-rw-r--r--platform/ios/Integration Tests/MGLSourceTests.swift45
-rw-r--r--platform/ios/Integration Tests/MGLStyleLayerIntegrationTests.m51
-rw-r--r--platform/ios/Integration Tests/MGLStyleURLIntegrationTest.m16
-rw-r--r--platform/ios/Integration Tests/Snapshotter Tests/MGLMapSnapshotterSwiftTests.swift5
-rw-r--r--platform/ios/Integration Tests/Snapshotter Tests/MGLMapSnapshotterTest.m111
-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/Mapbox.playground/Contents.swift7
-rw-r--r--platform/ios/Mapbox.playground/contents.xcplayground2
-rw-r--r--platform/ios/app/MBXState.h2
-rw-r--r--platform/ios/app/MBXState.m9
-rw-r--r--platform/ios/app/MBXViewController.m53
-rw-r--r--platform/ios/app/Main.storyboard14
-rw-r--r--platform/ios/ios.xcodeproj/project.pbxproj64
-rw-r--r--platform/ios/ios.xcodeproj/xcshareddata/xcschemes/CI.xcscheme2
-rw-r--r--platform/ios/ios.xcodeproj/xcshareddata/xcschemes/dynamic.xcscheme26
-rwxr-xr-xplatform/ios/scripts/deploy-packages.sh6
-rwxr-xr-xplatform/ios/scripts/install-packaging-dependencies.sh9
-rwxr-xr-xplatform/ios/scripts/publish.sh44
-rw-r--r--platform/ios/sdk-files.json2
-rw-r--r--platform/ios/src/MGLCompassButton.mm9
-rw-r--r--platform/ios/src/MGLMapView+Impl.h2
-rw-r--r--platform/ios/src/MGLMapView+Impl.mm4
-rw-r--r--platform/ios/src/MGLMapView.h28
-rw-r--r--platform/ios/src/MGLMapView.mm339
-rw-r--r--platform/ios/src/MGLMapView_Private.h2
-rw-r--r--platform/ios/src/MGLMapboxEvents.h3
-rw-r--r--platform/ios/src/MGLMapboxEvents.m66
-rw-r--r--platform/ios/src/MGLScaleBar.mm18
-rw-r--r--platform/ios/test/MGLMapAccessibilityElementTests.m5
-rw-r--r--platform/ios/test/MGLMapViewDirectionTests.mm7
-rw-r--r--platform/ios/test/MGLMapViewPitchTests.m39
-rw-r--r--platform/ios/test/MGLMapViewZoomTests.mm (renamed from platform/ios/test/MGLMapViewZoomTests.m)68
-rw-r--r--platform/ios/test/MGLMockGestureRecognizers.h10
-rw-r--r--platform/ios/test/MGLMockGestureRecognizers.m11
-rw-r--r--platform/linux/README.md4
-rw-r--r--platform/linux/config.cmake8
-rw-r--r--platform/macos/CHANGELOG.md11
-rw-r--r--platform/macos/macos.xcodeproj/project.pbxproj8
-rw-r--r--platform/macos/macos.xcodeproj/xcshareddata/xcschemes/CI.xcscheme30
-rw-r--r--platform/macos/macos.xcodeproj/xcshareddata/xcschemes/dynamic.xcscheme26
-rw-r--r--platform/macos/macos.xcodeproj/xcshareddata/xcschemes/macosapp.xcscheme25
-rw-r--r--platform/macos/sdk-files.json2
-rw-r--r--platform/macos/src/MGLMapView+Impl.h2
-rw-r--r--platform/macos/src/MGLMapView+Impl.mm4
-rw-r--r--platform/macos/src/MGLMapView.h4
-rw-r--r--platform/macos/src/MGLMapView.mm2
-rw-r--r--platform/node/CHANGELOG.md15
-rw-r--r--platform/node/DEVELOPING.md2
-rw-r--r--platform/node/test/ignores.json26
-rw-r--r--platform/qt/src/local_glyph_rasterizer.cpp25
-rw-r--r--platform/qt/src/qmapboxgl_map_observer.cpp4
-rw-r--r--platform/qt/src/qmapboxgl_map_observer.hpp2
-rw-r--r--platform/qt/src/qmapboxgl_map_renderer.cpp2
-rw-r--r--platform/qt/src/qmapboxgl_renderer_observer.hpp4
196 files changed, 4192 insertions, 2233 deletions
diff --git a/platform/android/.gitignore b/platform/android/.gitignore
index f37dc37ea6..a4c2b818fa 100644
--- a/platform/android/.gitignore
+++ b/platform/android/.gitignore
@@ -30,3 +30,5 @@ MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/acti
# Input files for running render tests
MapboxGLAndroidSDKTestApp/src/main/assets/integration/
+# Local AS configuration file
+gradle.properties \ No newline at end of file
diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md
index 08c2e56892..a7fd332b65 100644
--- a/platform/android/CHANGELOG.md
+++ b/platform/android/CHANGELOG.md
@@ -3,23 +3,110 @@
Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started.
## master
-- Enable variable label placement when `text-allow-overlap` property is set to true [#15354](https://github.com/mapbox/mapbox-gl-native/pull/15354).
-- Introduce `text-writing-mode` layout property for symbol layer [#14932](https://github.com/mapbox/mapbox-gl-native/pull/14932). The `text-writing-mode` layout property allows control over symbol's preferred writing mode. The new property value is an array, whose values are enumeration values from a ( `horizontal` | `vertical` ) set.
+
+### Bug fixes
+ - Fixed constant repainting for the sources with invisible layers, caused by `RenderSource::hasFadingTiles()` returning `true` all the time. [#15600](https://github.com/mapbox/mapbox-gl-native/pull/15600)
+ - Fixed an issue that caused the state of CompassView not up to date when `UiSettings.setCompassEnabled()` is set to true. [#15606](https://github.com/mapbox/mapbox-gl-native/pull/15606)
+
+## 8.4.0-alpha.2 - September 11, 2019
+[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.4.0-alpha.1...android-v8.4.0-alpha.2) since [Mapbox Maps SDK for Android v8.4.0-alpha.1](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.4.0-alpha.1):
+
+### Performance improvements
+ - Newly loaded labels appear faster on the screen. [#15308](https://github.com/mapbox/mapbox-gl-native/pull/15308)
+
+### Bug fixes
+ - Fixed an issue of integer overflow when converting `tileCoordinates` to `LatLon`, which caused issues such as `queryRenderedFeatures` and `querySourceFeatures` returning incorrect coordinates at zoom levels 20 and higher. [#15560](https://github.com/mapbox/mapbox-gl-native/pull/15560)
+
+### Other Changes
+ - Bumped Java SDK dependency to 4.9.0-alpha.1 [#15570](https://github.com/mapbox/mapbox-gl-native/pull/15570)
+
+## 8.4.0-alpha.1 - September 4, 2019
+[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.3.0...android-v8.4.0-alpha.1) since [Mapbox Maps SDK for Android v8.3.0](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.3.0):
+
+### Features
+ - Introduce `clusterProperties` option for aggregated cluster properties. [#15425](https://github.com/mapbox/mapbox-gl-native/pull/15425)
+ - Expose the `CameraPosition#padding` field and associated utility camera position builders. This gives a choice to set a persisting map padding immediately during a transition instead of setting it lazily `MapboxMap#setPadding`, which required scheduling additional transition to be applied. This also deprecates `MapboxMap#setPadding` as there should be no need for a lazy padding setter. [#15444](https://github.com/mapbox/mapbox-gl-native/pull/15444)
+ - Add number-format expression that allows to format a number to a string, with configurations as minimal/maximal fraction and locale/currency. [#15424](https://github.com/mapbox/mapbox-gl-native/pull/15424)
+ - Enable using of `text-offset` option together with `text-variable-anchor` (if `text-radial-offset` option is not provided). If used with `text-variable-anchor`, input values will be taken as absolute values. Offsets along the x- and y-axis will be applied automatically based on the anchor position. [#15542](https://github.com/mapbox/mapbox-gl-native/pull/15542)
+
+### Bug fixes
+- Fixed a rendering issue of `collisionBox` when `text-translate` or `icon-translate` is enabled. [#15467](https://github.com/mapbox/mapbox-gl-native/pull/15467)
+- Fixed unnecessary layers blink when the same components are re-added after the style reload [#15513](https://github.com/mapbox/mapbox-gl-native/pull/15513)
+- Fixed an issue in JNI marshaling code that converted a float to long that produced invalid expressions [#15557](https://github.com/mapbox/mapbox-gl-native/pull/15557)
+- Call callback onFinish() immediately when trying to move camera to current position [#15558](https://github.com/mapbox/mapbox-gl-native/pull/15558)
+
+### Performance improvements
+ - Mark used offline region resources in batches. [#15521](https://github.com/mapbox/mapbox-gl-native/pull/15521)
+
+### Other Changes
+- JNI binding refactor [#15462](https://github.com/mapbox/mapbox-gl-native/pull/15462)
+- Javadoc changes to clarify OfflineManager methods [#15519](https://github.com/mapbox/mapbox-gl-native/pull/15519)
+
+## 8.3.0 - August 28, 2019
+[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.3.0-beta.1...android-v8.3.0) since [Mapbox Maps SDK for Android v8.3.0-beta.1](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.3.0-beta.1):
+
+This release changes how offline tile requests are billed — they are now billed on a pay-as-you-go basis and all developers are able raise the offline tile limit for their users. Offline requests were previously exempt from monthly active user (MAU) billing and increasing the offline per-user tile limit to more than 6,000 tiles required the purchase of an enterprise license. By upgrading to this release, you are opting into the changes outlined in [this blog post](https://blog.mapbox.com/offline-maps-for-all-bb0fc51827be) and [#15380](https://github.com/mapbox/mapbox-gl-native/pull/15380).
+
+### Features
+ - Allow ability to pass a string array resource into `localIdeographFontFamily` for enabling/disabling the feature and specifying fallback fonts. [#15488](https://github.com/mapbox/mapbox-gl-native/pull/15488)
+
+### Bug fixes
+ - Fixed a rendering issue caused by all icons being treated as SDFs if an SDF and non-SDF icon were in the same layer. [#15456](https://github.com/mapbox/mapbox-gl-native/pull/15456)
+ - Fixed an issue where changing location's render mode when the`LocationComponent` is disable wouldn't invalidate the foreground icon when it's back enabled. [#15507](https://github.com/mapbox/mapbox-gl-native/pull/15507)
+
+## 8.2.2 - August 23, 2019
+[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.2.1...android-v8.2.2) since [Mapbox Maps SDK for Android v8.2.1](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.2.1):
+
+### Bug fixes
+ - Fixed a possible crash that could be caused by invoking the wrong layer implementation casting function. [#15398](https://github.com/mapbox/mapbox-gl-native/pull/15398)
+ - Fixed use of objects after moving, potentially causing crashes. [#15408](https://github.com/mapbox/mapbox-gl-native/pull/1540)
+ - Fixed a wrong calculation of visibility in high pitch scenarios which might've led to tiles in the viewport not being rendered. [#15461](https://github.com/mapbox/mapbox-gl-native/pull/15461)
+
+### Other Changes
+ - Do not invalidate the camera immediately when map padding is set. Reverts a change introduced in the `v8.2.0`. [#15437](https://github.com/mapbox/mapbox-gl-native/pull/15437)
+
+## 8.3.0-beta.1 - August 22, 2019
+[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.3.0-alpha.3...android-v8.3.0-beta.1) since [Mapbox Maps SDK for Android v8.3.0-alpha.3](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.3.0-alpha.3):
+
+### Bug fixes
+ - Fixed a bug where glyphs generated through the LocalGlyphRasterizer interface were changing fonts during some zoom changes. [#15407](https://github.com/mapbox/mapbox-gl-native/pull/15407)
+ - Fixed use of objects after moving, potentially causing crashes. [#15408](https://github.com/mapbox/mapbox-gl-native/pull/15408)
+ - Fixed a possible crash that could be caused by invoking the wrong layer implementation casting function [#15398](https://github.com/mapbox/mapbox-gl-native/pull/15398).
+ - Font lookup on pre lollipop devices failed, provide default font list instead [#15410](https://github.com/mapbox/mapbox-gl-native/pull/15410).
+ - Fixed rendering and collision detection issues with using `text-variable-anchor` and `icon-text-fit` properties on the same layer [#15367](https://github.com/mapbox/mapbox-gl-native/pull/15367).
+ - Fixed a bug where quick-scale was registered during a move gesture that followed a double-tap. Bumped gestures library to `v0.5.1`. [#15427](https://github.com/mapbox/mapbox-gl-native/pull/15427)
+ - Fixed symbol overlap when zooming out quickly. [#15416](https://github.com/mapbox/mapbox-gl-native/pull/15416)
+
+### Other Changes
+ - Do not invalidate the camera immediately when map padding is set. Reverts a change introduced in the `v8.2.0`. [#15437](https://github.com/mapbox/mapbox-gl-native/pull/15437)
+
+### Docs
+ - Add javadoc to OnStyleImageMissingListener indicating the required synchronous addition images, document workaround [#15418](https://github.com/mapbox/mapbox-gl-native/pull/15418)
+
+## 8.3.0-alpha.3 - August 15, 2019
+[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.3.0-alpha.2...android-v8.3.0-alpha.3) since [Mapbox Maps SDK for Android v8.3.0-alpha.2](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.3.0-alpha.2):
+
+### Gestures handling
+ - Bumped gestures library version to v0.5.0 which replaces the compat gesture detector with a custom scale gesture detector implementation. This is a softly breaking change because the underlying scale gesture detector reference has been removed. This brings a set of improvements to gestures without removing any functionality from the previous implementation. [#15136](https://github.com/mapbox/mapbox-gl-native/pull/15136)
+ - Improved scale and rotate gestures by refining sensitivity thresholds and animation velocity. [#15136](https://github.com/mapbox/mapbox-gl-native/pull/15136)
+ - Improved quick-zoom gestures by making zoom changes linear. Quick-zoom scale changes are now executed based on y-axis delta changes. [#15386](https://github.com/mapbox/mapbox-gl-native/pull/15386)
### Features
- - Add fallback support to local ideograph font families [#15255](https://github.com/mapbox/mapbox-gl-native/pull/15255)
+ - Introduced the text-writing-mode layout property for symbol layers. This property allows labels to be placed horizontally or vertically. The property accepts an array of enumeration values from a ( horizontal | vertical ) set. [#14932](https://github.com/mapbox/mapbox-gl-native/pull/14932)
+ - Added support for fallback fonts in `localIdeographFontFamily`. [#15255](https://github.com/mapbox/mapbox-gl-native/pull/15255)
### Bug fixes
- Fixed an issue where it was possible to set the map’s content insets then tilt the map enough to see the horizon, causing performance issues [#15195](https://github.com/mapbox/mapbox-gl-native/pull/15195)
- - Allow loading of a map without a Style URI or Style JSON [#15293](https://github.com/mapbox/mapbox-gl-native/pull/15293)
+ - Allow loading of a map without a style URI or style JSON [#15293](https://github.com/mapbox/mapbox-gl-native/pull/15293)
- Fixed an issue where animated camera transitions zoomed in or out too dramatically [#15281](https://github.com/mapbox/mapbox-gl-native/pull/15281)
+ - Enable variable label placement when `text-allow-overlap` property is set to true [#15354](https://github.com/mapbox/mapbox-gl-native/pull/15354)
## 8.3.0-alpha.2 - August 7, 2019
[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.3.0-alpha.1...android-v8.3.0-alpha.2) since [Mapbox Maps SDK for Android v8.3.0-alpha.1](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.3.0-alpha.1):
### Bug fixes
-- Load a style without an URI or JSON [#15293](https://github.com/mapbox/mapbox-gl-native/pull/15293)
-- Do not try to wake up the RunLoop if a wake is already pending. Fixes offline downloads that could freeze after resuming. [#15330](https://github.com/mapbox/mapbox-gl-native/pull/15330)
+ - Load a style without an URI or JSON [#15293](https://github.com/mapbox/mapbox-gl-native/pull/15293)
+ - Do not try to wake up the RunLoop if a wake is already pending. Fixes offline downloads that could freeze after resuming. [#15330](https://github.com/mapbox/mapbox-gl-native/pull/15330)
## 8.0.2 - July 31, 2019
[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.0.1...android-v8.0.2) since [Mapbox Maps SDK for Android v8.0.1](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.0.1):
@@ -42,7 +129,7 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to
[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.2.0...android-v8.3.0-alpha.1) since [Mapbox Maps SDK for Android v8.2.0](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.2.0):
### Features
- - Do not include CJK ideographs in the offline packs by default. This decreases overall offline download size but changes appereance by a default set local glyph generation [#14269](https://github.com/mapbox/mapbox-gl-native/pull/14269)
+ - Do not include CJK ideographs in the offline packs by default. This decreases overall offline download size but changes appearance by a default set local glyph generation [#14269](https://github.com/mapbox/mapbox-gl-native/pull/14269)
- Update target SDK to 28, update support library and fix gradle warnings [#15135](https://github.com/mapbox/mapbox-gl-native/pull/15135)
- Introduce VertexVector::extend() and use it in placement code [#15194](https://github.com/mapbox/mapbox-gl-native/pull/15194)
diff --git a/platform/android/LICENSE.md b/platform/android/LICENSE.md
index 18e5cb41c3..8423a34a6a 100644
--- a/platform/android/LICENSE.md
+++ b/platform/android/LICENSE.md
@@ -185,13 +185,13 @@ License: [The Apache Software License, Version 2.0](http://www.apache.org/licens
===========================================================================
-Mapbox GL uses portions of the Mapbox Services SDK.
+Mapbox GL uses portions of the Mapbox Java SDK.
URL: [https://github.com/mapbox/mapbox-java](https://github.com/mapbox/mapbox-java)
License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt)
===========================================================================
-Mapbox GL uses portions of the Mapbox Services SDK.
+Mapbox GL uses portions of the Mapbox Java SDK.
URL: [https://github.com/mapbox/mapbox-java](https://github.com/mapbox/mapbox-java)
License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt)
diff --git a/platform/android/MapboxGLAndroidSDK/gradle.properties b/platform/android/MapboxGLAndroidSDK/gradle.properties
index 989a56fd63..f906453f56 100644
--- a/platform/android/MapboxGLAndroidSDK/gradle.properties
+++ b/platform/android/MapboxGLAndroidSDK/gradle.properties
@@ -1,4 +1,4 @@
-VERSION_NAME=8.3.0-SNAPSHOT
+VERSION_NAME=8.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/camera/CameraPosition.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java
index f44c0f1904..e2341029ff 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java
@@ -5,20 +5,23 @@ 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 android.support.annotation.Size;
+
import com.mapbox.mapboxsdk.R;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.utils.MathUtils;
+import java.util.Arrays;
+
/**
* Resembles the position, angle, zoom and tilt of the user's viewpoint.
*/
public final class CameraPosition implements Parcelable {
- public static final CameraPosition DEFAULT = new CameraPosition(new LatLng(), 0, 0, 0);
+ public static final CameraPosition DEFAULT = new CameraPosition(new LatLng(), 0, 0, 0, new double[] {0, 0, 0, 0});
public static final Parcelable.Creator<CameraPosition> CREATOR =
new Parcelable.Creator<CameraPosition>() {
@@ -27,7 +30,9 @@ public final class CameraPosition implements Parcelable {
LatLng target = in.readParcelable(LatLng.class.getClassLoader());
double tilt = in.readDouble();
double zoom = in.readDouble();
- return new CameraPosition(target, zoom, tilt, bearing);
+ double[] padding = new double[4];
+ in.readDoubleArray(padding);
+ return new CameraPosition(target, zoom, tilt, bearing, padding);
}
public CameraPosition[] newArray(int size) {
@@ -49,19 +54,26 @@ public final class CameraPosition implements Parcelable {
/**
* The angle, in degrees, of the camera angle from the nadir (directly facing the Earth).
- * See tilt(float) for details of restrictions on the range of values.
+ * See {@link Builder#tilt(double)} for details of restrictions on the range of values.
*/
@Keep
public final double tilt;
/**
- * Zoom level near the center of the screen. See zoom(float) for the definition of the camera's
+ * Zoom level near the center of the screen. See {@link Builder#zoom(double)} for the definition of the camera's
* zoom level.
*/
@Keep
public final double zoom;
/**
+ * Padding in pixels. Specified in left, top, right, bottom order.
+ * See {@link Builder#padding(double[])} for the definition of the camera's padding.
+ */
+ @Keep
+ public final double[] padding;
+
+ /**
* Constructs a CameraPosition.
*
* @param target The target location to align with the center of the screen.
@@ -73,13 +85,34 @@ public final class CameraPosition implements Parcelable {
* exclusive.
* @throws NullPointerException if target is null
* @throws IllegalArgumentException if tilt is outside the range of 0 to 90 degrees inclusive.
+ * @deprecated use {@link CameraPosition#CameraPosition(LatLng, double, double, double, double[])} instead.
*/
- @Keep
+ @Deprecated
CameraPosition(LatLng target, double zoom, double tilt, double bearing) {
+ this(target, zoom, tilt, bearing, null);
+ }
+
+ /**
+ * Constructs a CameraPosition.
+ *
+ * @param target The target location to align with the center of the screen.
+ * @param zoom Zoom level at target. See zoom(float) for details of restrictions.
+ * @param tilt The camera angle, in degrees, from the nadir (directly down). See tilt(float)
+ * for details of restrictions.
+ * @param bearing Direction that the camera is pointing in, in degrees clockwise from north.
+ * This value will be normalized to be within 0 degrees inclusive and 360 degrees
+ * exclusive.
+ * @param padding Padding in pixels. Specified in left, top, right, bottom order.
+ * @throws NullPointerException if target is null
+ * @throws IllegalArgumentException if tilt is outside the range of 0 to 90 degrees inclusive.
+ */
+ @Keep
+ CameraPosition(LatLng target, double zoom, double tilt, double bearing, double[] padding) {
this.target = target;
this.bearing = bearing;
this.tilt = tilt;
this.zoom = zoom;
+ this.padding = padding;
}
/**
@@ -106,6 +139,7 @@ public final class CameraPosition implements Parcelable {
out.writeParcelable(target, flags);
out.writeDouble(tilt);
out.writeDouble(zoom);
+ out.writeDoubleArray(padding);
}
/**
@@ -115,7 +149,8 @@ public final class CameraPosition implements Parcelable {
*/
@Override
public String toString() {
- return "Target: " + target + ", Zoom:" + zoom + ", Bearing:" + bearing + ", Tilt:" + tilt;
+ return "Target: " + target + ", Zoom:" + zoom + ", Bearing:" + bearing + ", Tilt:" + tilt
+ + ", Padding:" + Arrays.toString(padding);
}
/**
@@ -145,6 +180,8 @@ public final class CameraPosition implements Parcelable {
return false;
} else if (bearing != cameraPosition.bearing) {
return false;
+ } else if (!Arrays.equals(padding, cameraPosition.padding)) {
+ return false;
}
return true;
}
@@ -159,8 +196,16 @@ public final class CameraPosition implements Parcelable {
*/
@Override
public int hashCode() {
- int result = 1;
+ int result;
+ long temp;
+ temp = Double.doubleToLongBits(bearing);
+ result = (int) (temp ^ (temp >>> 32));
result = 31 * result + (target != null ? target.hashCode() : 0);
+ temp = Double.doubleToLongBits(tilt);
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(zoom);
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
+ result = 31 * result + Arrays.hashCode(padding);
return result;
}
@@ -174,6 +219,7 @@ public final class CameraPosition implements Parcelable {
private LatLng target = null;
private double tilt = -1;
private double zoom = -1;
+ private double[] padding = null;
/**
* Create an empty builder.
@@ -194,6 +240,7 @@ public final class CameraPosition implements Parcelable {
this.target = previous.target;
this.tilt = previous.tilt;
this.zoom = previous.zoom;
+ this.padding = previous.padding;
}
}
@@ -226,6 +273,7 @@ public final class CameraPosition implements Parcelable {
target = update.getTarget();
tilt = update.getTilt();
zoom = update.getZoom();
+ padding = update.getPadding();
}
}
@@ -307,12 +355,43 @@ public final class CameraPosition implements Parcelable {
}
/**
+ * Padding in pixels that shifts the viewport by the specified amount.
+ * Applied padding is going to persist and impact following camera transformations.
+ * <p>
+ * Specified in left, top, right, bottom order.
+ * </p>
+ *
+ * @param padding Camera padding
+ * @return this
+ */
+ @NonNull
+ public Builder padding(@Size(4) double[] padding) {
+ this.padding = padding;
+ return this;
+ }
+
+ /**
+ * Padding in pixels that shifts the viewport by the specified amount.
+ * Applied padding is going to persist and impact following camera transformations.
+ * <p>
+ * Specified in left, top, right, bottom order.
+ * </p>
+ *
+ * @return this
+ */
+ @NonNull
+ public Builder padding(double left, double top, double right, double bottom) {
+ this.padding = new double[] {left, top, right, bottom};
+ return this;
+ }
+
+ /**
* Builds the CameraPosition.
*
* @return CameraPosition
*/
public CameraPosition build() {
- return new CameraPosition(target, zoom, tilt, bearing);
+ return new CameraPosition(target, zoom, tilt, bearing, padding);
}
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java
index 16285468ee..b611456f43 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java
@@ -5,6 +5,7 @@ import android.graphics.PointF;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
import com.mapbox.mapboxsdk.maps.MapboxMap;
@@ -28,7 +29,7 @@ public final class CameraUpdateFactory {
*/
public static CameraUpdate newCameraPosition(@NonNull CameraPosition cameraPosition) {
return new CameraPositionUpdate(cameraPosition.bearing, cameraPosition.target, cameraPosition.tilt,
- cameraPosition.zoom);
+ cameraPosition.zoom, cameraPosition.padding);
}
/**
@@ -39,7 +40,7 @@ public final class CameraUpdateFactory {
* @return CameraUpdate Final Camera Position
*/
public static CameraUpdate newLatLng(@NonNull LatLng latLng) {
- return new CameraPositionUpdate(-1, latLng, -1, -1);
+ return new CameraPositionUpdate(-1, latLng, -1, -1, null);
}
/**
@@ -48,6 +49,7 @@ public final class CameraUpdateFactory {
* current camera position bearing and tilt values.
* <p>
* You can specify padding, in order to inset the bounding box from the map view's edges.
+ * The padding will not persist and impact following camera transformations.
* </p>
*
* @param bounds Bounds to match Camera position with
@@ -64,6 +66,7 @@ public final class CameraUpdateFactory {
* provided bearing and tilt values.
* <p>
* You can specify padding, in order to inset the bounding box from the map view's edges.
+ * The padding will not persist and impact following camera transformations.
* </p>
*
* @param bounds Bounds to match Camera position with
@@ -82,6 +85,7 @@ public final class CameraUpdateFactory {
* current camera position bearing and tilt values.
* <p>
* You can specify padding, in order to inset the bounding box from the map view's edges.
+ * The padding will not persist and impact following camera transformations.
* </p>
*
* @param bounds Bounds to base the Camera position out of
@@ -102,6 +106,7 @@ public final class CameraUpdateFactory {
* provided bearing and tilt values.
* <p>
* You can specify padding, in order to inset the bounding box from the map view's edges.
+ * The padding will not persist and impact following camera transformations.
* </p>
*
* @param bounds Bounds to base the Camera position out of
@@ -120,14 +125,31 @@ public final class CameraUpdateFactory {
/**
* Returns a CameraUpdate that moves the center of the screen to a latitude and longitude
- * specified by a LatLng object, and moves to the given zoom level.
+ * specified by a LatLng object taking the specified padding into account.
*
* @param latLng Target location to change to
* @param zoom Zoom level to change to
* @return CameraUpdate Final Camera Position
*/
public static CameraUpdate newLatLngZoom(@NonNull LatLng latLng, double zoom) {
- return new CameraPositionUpdate(-1, latLng, -1, zoom);
+ return new CameraPositionUpdate(-1, latLng, -1, zoom, null);
+ }
+
+ /**
+ * Returns a CameraUpdate that moves the center of the screen to a latitude and longitude
+ * specified by a LatLng object, and moves to the given zoom level.
+ * Applied padding is going to persist and impact following camera transformations.
+ *
+ * @param latLng Target location to change to
+ * @param left Left padding
+ * @param top Top padding
+ * @param right Right padding
+ * @param bottom Bottom padding
+ * @return CameraUpdate Final Camera Position
+ */
+ public static CameraUpdate newLatLngPadding(@NonNull LatLng latLng,
+ double left, double top, double right, double bottom) {
+ return new CameraPositionUpdate(-1, latLng, -1, -1, new double[] {left, top, right, bottom});
}
/**
@@ -188,7 +210,7 @@ public final class CameraUpdateFactory {
* @return CameraUpdate Final Camera Position
*/
public static CameraUpdate bearingTo(double bearing) {
- return new CameraPositionUpdate(bearing, null, -1, -1);
+ return new CameraPositionUpdate(bearing, null, -1, -1, null);
}
/**
@@ -198,7 +220,34 @@ public final class CameraUpdateFactory {
* @return CameraUpdate Final Camera Position
*/
public static CameraUpdate tiltTo(double tilt) {
- return new CameraPositionUpdate(-1, null, tilt, -1);
+ return new CameraPositionUpdate(-1, null, tilt, -1, null);
+ }
+
+ /**
+ * Returns a CameraUpdate that when animated changes the camera padding.
+ * Applied padding is going to persist and impact following camera transformations.
+ * <p>
+ * Specified in left, top, right, bottom order.
+ * </p>
+ *
+ * @param padding Padding to change to
+ * @return CameraUpdate Final Camera Position
+ */
+ public static CameraUpdate paddingTo(double[] padding) {
+ return new CameraPositionUpdate(-1, null, -1, -1, padding);
+ }
+
+ /**
+ * Returns a CameraUpdate that when animated changes the camera padding.
+ * Applied padding is going to persist and impact following camera transformations.
+ * <p>
+ * Specified in left, top, right, bottom order.
+ * </p>
+ *
+ * @return CameraUpdate Final Camera Position
+ */
+ public static CameraUpdate paddingTo(double left, double top, double right, double bottom) {
+ return paddingTo(new double[] {left, top, right, bottom});
}
//
@@ -211,12 +260,14 @@ public final class CameraUpdateFactory {
private final LatLng target;
private final double tilt;
private final double zoom;
+ private final double[] padding;
- CameraPositionUpdate(double bearing, LatLng target, double tilt, double zoom) {
+ CameraPositionUpdate(double bearing, LatLng target, double tilt, double zoom, double[] padding) {
this.bearing = bearing;
this.target = target;
this.tilt = tilt;
this.zoom = zoom;
+ this.padding = padding;
}
public LatLng getTarget() {
@@ -235,10 +286,14 @@ public final class CameraUpdateFactory {
return zoom;
}
+ public double[] getPadding() {
+ return padding;
+ }
+
@Override
public CameraPosition getCameraPosition(@NonNull MapboxMap mapboxMap) {
- CameraPosition previousPosition = mapboxMap.getCameraPosition();
if (target == null) {
+ CameraPosition previousPosition = mapboxMap.getCameraPosition();
return new CameraPosition.Builder(this)
.target(previousPosition.target)
.build();
@@ -247,7 +302,7 @@ public final class CameraUpdateFactory {
}
@Override
- public boolean equals(@Nullable Object o) {
+ public boolean equals(Object o) {
if (this == o) {
return true;
}
@@ -266,7 +321,10 @@ public final class CameraUpdateFactory {
if (Double.compare(that.zoom, zoom) != 0) {
return false;
}
- return target != null ? target.equals(that.target) : that.target == null;
+ if (target != null ? !target.equals(that.target) : that.target != null) {
+ return false;
+ }
+ return Arrays.equals(padding, that.padding);
}
@Override
@@ -280,6 +338,7 @@ public final class CameraUpdateFactory {
result = 31 * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(zoom);
result = 31 * result + (int) (temp ^ (temp >>> 32));
+ result = 31 * result + Arrays.hashCode(padding);
return result;
}
@@ -290,6 +349,7 @@ public final class CameraUpdateFactory {
+ ", target=" + target
+ ", tilt=" + tilt
+ ", zoom=" + zoom
+ + ", padding=" + Arrays.toString(padding)
+ '}';
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUrl.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUrl.java
index 706f57ce9c..1faf8f5e5e 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUrl.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUrl.java
@@ -10,7 +10,10 @@ public class HttpRequestUrl {
}
/**
- * Adapts a resource request url based on the host and query size.
+ * Adapts a resource request url based on the host, query size, and offline requirement.
+ * Mapbox resources downloaded for offline use are subject to separate Vector Tile and
+ * Raster Tile API pricing and are not included in the Maps SDK’s “unlimited” requests.
+ * See <a href="https://www.mapbox.com/pricing">our pricing page</a> for more information.
*
* @param host the host used as endpoint
* @param resourceUrl the resource to download
@@ -25,10 +28,11 @@ public class HttpRequestUrl {
} else {
resourceUrl = resourceUrl + "&";
}
- resourceUrl = resourceUrl + "sku=" + Mapbox.getSkuToken();
-
+ // Only add SKU token to requests not tagged as "offline" usage.
if (offline) {
- resourceUrl = resourceUrl + "&offline=true";
+ resourceUrl = resourceUrl + "offline=true";
+ } else {
+ resourceUrl = resourceUrl + "sku=" + Mapbox.getSkuToken();
}
}
return resourceUrl;
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 5b2dcd8554..46de3673e4 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
@@ -1182,7 +1182,6 @@ public final class LocationComponent {
}
isLayerReady = false;
- locationLayerController.hide();
staleStateManager.onStop();
if (compassEngine != null) {
updateCompassListenerState(false);
@@ -1289,6 +1288,7 @@ public final class LocationComponent {
private void disableLocationComponent() {
isEnabled = false;
+ locationLayerController.hide();
onLocationLayerStop();
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentOptions.java
index 8ab03e7acd..48c89622cd 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentOptions.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentOptions.java
@@ -1530,8 +1530,11 @@ public class LocationComponentOptions implements Parcelable {
* </p>
*
* @param padding The margins for the map in pixels (left, top, right, bottom).
+ * @deprecated Use {@link CameraPosition.Builder#padding(double, double, double, double)}
+ * or {@link CameraUpdateFactory#paddingTo(double, double, double, double)} instead.
*/
@NonNull
+ @Deprecated
public LocationComponentOptions.Builder padding(@Nullable int[] padding) {
if (padding == null) {
throw new NullPointerException("Null padding");
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 b18a7c4742..54f8ee6d1a 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
@@ -140,11 +140,11 @@ final class LocationLayerController {
}
this.renderMode = renderMode;
+ styleForeground(options);
+ determineIconsSource(options);
if (!isHidden) {
- styleForeground(options);
show();
}
- determineIconsSource(options);
internalRenderModeChangedListener.onRenderModeChanged(renderMode);
}
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 1367de8729..4521d2ae60 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
@@ -1013,14 +1013,18 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback {
}
/**
- * Interface definition for a callback to be invoked with the id of a missing icon.
+ * Interface definition for a callback to be invoked with the id of a missing icon. The icon should be added
+ * synchronously with {@link Style#addImage(String, Bitmap)} to be rendered on the current zoom level. When loading
+ * icons asynchronously, you can load a placeholder image and replace it when you icon has loaded.
* <p>
* {@link MapView#addOnStyleImageMissingListener(OnStyleImageMissingListener)}
* </p>
*/
public interface OnStyleImageMissingListener {
/**
- * Called when the map is missing an icon.
+ * Called when the map is missing an icon.The icon should be added synchronously with
+ * {@link Style#addImage(String, Bitmap)} to be rendered on the current zoom level. When loading icons
+ * asynchronously, you can load a placeholder image and replace it when you icon has loaded.
*
* @param id the id of the icon that is missing
*/
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 8e1019b379..acd5093dad 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
@@ -1540,24 +1540,38 @@ public final class MapboxMap {
* frame from the viewport. For instance, if the only the top edge is inset, the
* map center is effectively shifted downward.
* </p>
+ * <p>
+ * This method sets the padding "lazily".
+ * This means that the <b>padding is going to be applied with the next camera transformation.</b>
+ * To apply the padding immediately use {@link CameraPosition.Builder#padding(double, double, double, double)}
+ * or {@link CameraUpdateFactory#paddingTo(double, double, double, double)}.
+ * </p>
*
* @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.
+ * @deprecated Use {@link CameraPosition.Builder#padding(double, double, double, double)}
+ * or {@link CameraUpdateFactory#paddingTo(double, double, double, double)} instead.
*/
+ @Deprecated
public void setPadding(int left, int top, int right, int bottom) {
+ // TODO padding should be passed as doubles
projection.setContentPadding(new int[] {left, top, right, bottom});
uiSettings.invalidate();
}
/**
- * Returns the current configured content padding on map view.
+ * Returns the current configured content padding on map view. This might return the currently visible padding
+ * or the padding cached but not yet applied by {@link #setPadding(int, int, int, int)}.
*
* @return An array with length 4 in the LTRB order.
+ * @deprecated Use {@link CameraPosition#padding} instead.
*/
+ @Deprecated
@NonNull
public int[] getPadding() {
+ // TODO this should return double[] (semver major change)
return projection.getContentPadding();
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java
index f922117dd0..6cd3271d12 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java
@@ -10,6 +10,7 @@ import android.os.Parcelable;
import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
import android.support.v4.content.res.ResourcesCompat;
import android.text.TextUtils;
import android.util.AttributeSet;
@@ -70,7 +71,11 @@ public class MapboxMapOptions implements Parcelable {
private boolean prefetchesTiles = true;
private boolean zMediaOverlay = false;
+
+ private boolean localIdeographFontFamilyEnabled = true;
private String localIdeographFontFamily;
+ private String[] localIdeographFontFamilies;
+
private String apiBaseUri;
private boolean textureMode;
@@ -130,7 +135,9 @@ public class MapboxMapOptions implements Parcelable {
translucentTextureSurface = in.readByte() != 0;
prefetchesTiles = in.readByte() != 0;
zMediaOverlay = in.readByte() != 0;
+ localIdeographFontFamilyEnabled = in.readByte() != 0;
localIdeographFontFamily = in.readString();
+ localIdeographFontFamilies = in.createStringArray();
pixelRatio = in.readFloat();
foregroundLoadColor = in.readInt();
crossSourceCollisions = in.readByte() != 0;
@@ -156,9 +163,15 @@ public class MapboxMapOptions implements Parcelable {
*/
@NonNull
public static MapboxMapOptions createFromAttributes(@NonNull Context context, @Nullable AttributeSet attrs) {
- MapboxMapOptions mapboxMapOptions = new MapboxMapOptions();
- float pxlRatio = context.getResources().getDisplayMetrics().density;
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.mapbox_MapView, 0, 0);
+ return createFromAttributes(new MapboxMapOptions(), context, typedArray);
+ }
+
+ @VisibleForTesting
+ static MapboxMapOptions createFromAttributes(@NonNull MapboxMapOptions mapboxMapOptions,
+ @NonNull Context context,
+ @Nullable TypedArray typedArray) {
+ float pxlRatio = context.getResources().getDisplayMetrics().density;
try {
mapboxMapOptions.camera(new CameraPosition.Builder(typedArray).build());
@@ -247,12 +260,24 @@ public class MapboxMapOptions implements Parcelable {
mapboxMapOptions.renderSurfaceOnTop(
typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_enableZMediaOverlay, false));
- String localIdeographFontFamily =
- typedArray.getString(R.styleable.mapbox_MapView_mapbox_localIdeographFontFamily);
- if (localIdeographFontFamily == null) {
- localIdeographFontFamily = MapboxConstants.DEFAULT_FONT;
+ mapboxMapOptions.localIdeographFontFamilyEnabled =
+ typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_localIdeographEnabled, true);
+
+ int localIdeographFontFamiliesResId =
+ typedArray.getResourceId(R.styleable.mapbox_MapView_mapbox_localIdeographFontFamilies, 0);
+ if (localIdeographFontFamiliesResId != 0) {
+ String[] localIdeographFontFamilies =
+ context.getResources().getStringArray(localIdeographFontFamiliesResId);
+ mapboxMapOptions.localIdeographFontFamily(localIdeographFontFamilies);
+ } else {
+ // did user provide xml font string?
+ String localIdeographFontFamily =
+ typedArray.getString(R.styleable.mapbox_MapView_mapbox_localIdeographFontFamily);
+ if (localIdeographFontFamily == null) {
+ localIdeographFontFamily = MapboxConstants.DEFAULT_FONT;
+ }
+ mapboxMapOptions.localIdeographFontFamily(localIdeographFontFamily);
}
- mapboxMapOptions.localIdeographFontFamily(localIdeographFontFamily);
mapboxMapOptions.pixelRatio(
typedArray.getFloat(R.styleable.mapbox_MapView_mapbox_pixelRatio, 0));
@@ -632,6 +657,18 @@ public class MapboxMapOptions implements Parcelable {
}
/**
+ * Enable local ideograph font family, defaults to true.
+ *
+ * @param enabled true to enable, false to disable
+ * @return This
+ */
+ @NonNull
+ public MapboxMapOptions localIdeographFontFamilyEnabled(boolean enabled) {
+ this.localIdeographFontFamilyEnabled = enabled;
+ return this;
+ }
+
+ /**
* Set the font family for generating glyphs locally for ideographs in the &#x27;CJK Unified Ideographs&#x27;
* and &#x27;Hangul Syllables&#x27; ranges.
* <p>
@@ -944,6 +981,11 @@ public class MapboxMapOptions implements Parcelable {
return textureMode;
}
+ /**
+ * Returns true if TextureView supports a translucent surface
+ *
+ * @return True if translucent surface is active
+ */
public boolean getTranslucentTextureSurface() {
return translucentTextureSurface;
}
@@ -962,11 +1004,22 @@ public class MapboxMapOptions implements Parcelable {
* Returns the font-family for locally overriding generation of glyphs in the
* &#x27;CJK Unified Ideographs&#x27; and &#x27;Hangul Syllables&#x27; ranges.
* Default font for local ideograph font family is {@link MapboxConstants#DEFAULT_FONT}.
+ * Returns null if local ideograph font families are disabled.
*
* @return Local ideograph font family name.
*/
+ @Nullable
public String getLocalIdeographFontFamily() {
- return localIdeographFontFamily;
+ return localIdeographFontFamilyEnabled ? localIdeographFontFamily : null;
+ }
+
+ /**
+ * Returns true if local ideograph font family is enabled, defaults to true.
+ *
+ * @return True if local ideograph font family is enabled
+ */
+ public boolean isLocalIdeographFontFamilyEnabled() {
+ return localIdeographFontFamilyEnabled;
}
/**
@@ -1029,7 +1082,9 @@ public class MapboxMapOptions implements Parcelable {
dest.writeByte((byte) (translucentTextureSurface ? 1 : 0));
dest.writeByte((byte) (prefetchesTiles ? 1 : 0));
dest.writeByte((byte) (zMediaOverlay ? 1 : 0));
+ dest.writeByte((byte) (localIdeographFontFamilyEnabled ? 1 : 0));
dest.writeString(localIdeographFontFamily);
+ dest.writeStringArray(localIdeographFontFamilies);
dest.writeFloat(pixelRatio);
dest.writeInt(foregroundLoadColor);
dest.writeByte((byte) (crossSourceCollisions ? 1 : 0));
@@ -1114,7 +1169,6 @@ public class MapboxMapOptions implements Parcelable {
if (!Arrays.equals(attributionMargins, options.attributionMargins)) {
return false;
}
-
if (apiBaseUri != null ? !apiBaseUri.equals(options.apiBaseUri) : options.apiBaseUri != null) {
return false;
}
@@ -1124,9 +1178,16 @@ public class MapboxMapOptions implements Parcelable {
if (zMediaOverlay != options.zMediaOverlay) {
return false;
}
+ if (localIdeographFontFamilyEnabled != options.localIdeographFontFamilyEnabled) {
+ return false;
+ }
if (!localIdeographFontFamily.equals(options.localIdeographFontFamily)) {
return false;
}
+ if (!Arrays.equals(localIdeographFontFamilies, options.localIdeographFontFamilies)) {
+ return false;
+ }
+
if (pixelRatio != options.pixelRatio) {
return false;
}
@@ -1171,7 +1232,9 @@ public class MapboxMapOptions implements Parcelable {
result = 31 * result + (translucentTextureSurface ? 1 : 0);
result = 31 * result + (prefetchesTiles ? 1 : 0);
result = 31 * result + (zMediaOverlay ? 1 : 0);
+ result = 31 * result + (localIdeographFontFamilyEnabled ? 1 : 0);
result = 31 * result + (localIdeographFontFamily != null ? localIdeographFontFamily.hashCode() : 0);
+ result = 31 * result + Arrays.hashCode(localIdeographFontFamilies);
result = 31 * result + (int) pixelRatio;
result = 31 * result + (crossSourceCollisions ? 1 : 0);
return result;
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 da70013713..7f3017c7ae 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
@@ -41,12 +41,12 @@ interface NativeMap {
// Camera API
//
- void jumpTo(@NonNull LatLng center, double zoom, double pitch, double bearing);
+ void jumpTo(@NonNull LatLng center, double zoom, double pitch, double bearing, double[] padding);
- void easeTo(@NonNull LatLng center, double zoom, double bearing, double pitch, long duration,
+ void easeTo(@NonNull LatLng center, double zoom, double bearing, double pitch, double[] padding, long duration,
boolean easingInterpolator);
- void flyTo(@NonNull LatLng center, double zoom, double bearing, double pitch, long duration);
+ void flyTo(@NonNull LatLng center, double zoom, double bearing, double pitch, double[] padding, long duration);
void moveBy(double deltaX, double deltaY, long duration);
@@ -161,9 +161,9 @@ interface NativeMap {
// Content padding API
//
- void setContentPadding(float[] padding);
+ void setContentPadding(double[] padding);
- float[] getContentPadding();
+ double[] getContentPadding();
//
// Query API
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 fc68a408fa..8496160c7e 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
@@ -10,6 +10,7 @@ import android.support.annotation.Keep;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
+
import com.mapbox.geojson.Feature;
import com.mapbox.geojson.Geometry;
import com.mapbox.mapboxsdk.LibraryLoader;
@@ -68,6 +69,10 @@ final class NativeMapView implements NativeMap {
// Flag to indicate destroy was called
private boolean destroyed = false;
+ // Cached to enable lazily set padding.
+ // Whenever an animation is schedule, this value is cleared and the source of truth becomes the core transform state.
+ private double[] edgeInsets;
+
// Holds the pointer to JNI NativeMapView
@Keep
private long nativePtr = 0;
@@ -241,7 +246,8 @@ final class NativeMapView implements NativeMap {
if (checkState("setLatLng")) {
return;
}
- nativeSetLatLng(latLng.getLatitude(), latLng.getLongitude(), duration);
+ nativeSetLatLng(latLng.getLatitude(), latLng.getLongitude(),
+ getAnimationPaddingAndClearCachedInsets(null), duration);
}
@Override
@@ -374,30 +380,20 @@ final class NativeMapView implements NativeMap {
}
@Override
- public void setContentPadding(float[] padding) {
+ public void setContentPadding(double[] padding) {
if (checkState("setContentPadding")) {
return;
}
- // TopLeftBottomRight
- nativeSetContentPadding(
- padding[1] / pixelRatio,
- padding[0] / pixelRatio,
- padding[3] / pixelRatio,
- padding[2] / pixelRatio);
+ this.edgeInsets = padding;
}
@Override
- public float[] getContentPadding() {
+ public double[] getContentPadding() {
if (checkState("getContentPadding")) {
- return new float[] {0, 0, 0, 0};
+ return new double[] {0, 0, 0, 0};
}
- float[] topLeftBottomRight = nativeGetContentPadding();
- return new float[] {
- topLeftBottomRight[1] * pixelRatio,
- topLeftBottomRight[0] * pixelRatio,
- topLeftBottomRight[3] * pixelRatio,
- topLeftBottomRight[2] * pixelRatio
- };
+ // if cached insets are not applied yet, return them, otherwise, get the padding from the camera
+ return edgeInsets != null ? edgeInsets : getCameraPosition().padding;
}
@Override
@@ -672,29 +668,31 @@ final class NativeMapView implements NativeMap {
}
@Override
- public void jumpTo(@NonNull LatLng center, double zoom, double pitch, double angle) {
+ public void jumpTo(@NonNull LatLng center, double zoom, double pitch, double angle, double[] padding) {
if (checkState("jumpTo")) {
return;
}
- nativeJumpTo(angle, center.getLatitude(), center.getLongitude(), pitch, zoom);
+ nativeJumpTo(angle, center.getLatitude(), center.getLongitude(), pitch, zoom,
+ getAnimationPaddingAndClearCachedInsets(padding));
}
@Override
- public void easeTo(@NonNull LatLng center, double zoom, double angle, double pitch, long duration,
+ public void easeTo(@NonNull LatLng center, double zoom, double angle, double pitch, double[] padding, long duration,
boolean easingInterpolator) {
if (checkState("easeTo")) {
return;
}
nativeEaseTo(angle, center.getLatitude(), center.getLongitude(), duration, pitch, zoom,
- easingInterpolator);
+ getAnimationPaddingAndClearCachedInsets(padding), easingInterpolator);
}
@Override
- public void flyTo(@NonNull LatLng center, double zoom, double angle, double pitch, long duration) {
+ public void flyTo(@NonNull LatLng center, double zoom, double angle, double pitch, double[] padding, long duration) {
if (checkState("flyTo")) {
return;
}
- nativeFlyTo(angle, center.getLatitude(), center.getLongitude(), duration, pitch, zoom);
+ nativeFlyTo(angle, center.getLatitude(), center.getLongitude(), duration, pitch, zoom,
+ getAnimationPaddingAndClearCachedInsets(padding));
}
@Override
@@ -703,7 +701,11 @@ final class NativeMapView implements NativeMap {
if (checkState("getCameraValues")) {
return new CameraPosition.Builder().build();
}
- return nativeGetCameraPosition();
+ if (edgeInsets != null) {
+ return new CameraPosition.Builder(nativeGetCameraPosition()).padding(edgeInsets).build();
+ } else {
+ return nativeGetCameraPosition();
+ }
}
@Override
@@ -1126,7 +1128,7 @@ final class NativeMapView implements NativeMap {
private native void nativeMoveBy(double dx, double dy, long duration);
@Keep
- private native void nativeSetLatLng(double latitude, double longitude, long duration);
+ private native void nativeSetLatLng(double latitude, double longitude, double[] padding, long duration);
@NonNull
@Keep
@@ -1176,12 +1178,6 @@ final class NativeMapView implements NativeMap {
private native void nativeRotateBy(double sx, double sy, double ex, double ey, long duration);
@Keep
- private native void nativeSetContentPadding(float top, float left, float bottom, float right);
-
- @Keep
- private native float[] nativeGetContentPadding();
-
- @Keep
private native void nativeSetBearing(double degrees, long duration);
@Keep
@@ -1270,16 +1266,17 @@ final class NativeMapView implements NativeMap {
private native double nativeGetTopOffsetPixelsForAnnotationSymbol(String symbolName);
@Keep
- private native void nativeJumpTo(double angle, double latitude, double longitude, double pitch, double zoom);
+ private native void nativeJumpTo(double angle, double latitude, double longitude, double pitch, double zoom,
+ double[] padding);
@Keep
private native void nativeEaseTo(double angle, double latitude, double longitude,
- long duration, double pitch, double zoom,
+ long duration, double pitch, double zoom, double[] padding,
boolean easingInterpolator);
@Keep
private native void nativeFlyTo(double angle, double latitude, double longitude,
- long duration, double pitch, double zoom);
+ long duration, double pitch, double zoom, double[] padding);
@NonNull
@Keep
@@ -1437,6 +1434,20 @@ final class NativeMapView implements NativeMap {
return destroyed;
}
+ private double[] getAnimationPaddingAndClearCachedInsets(double[] providedPadding) {
+ if (providedPadding == null) {
+ providedPadding = this.edgeInsets;
+ }
+ this.edgeInsets = null;
+ return providedPadding == null ? null :
+ new double[] {
+ providedPadding[1] / pixelRatio,
+ providedPadding[0] / pixelRatio,
+ providedPadding[3] / pixelRatio,
+ providedPadding[2] / pixelRatio
+ };
+ }
+
public interface ViewCallback {
@Nullable
Bitmap getViewContent();
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java
index 8ed003b821..76395f9564 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java
@@ -3,6 +3,7 @@ package com.mapbox.mapboxsdk.maps;
import android.graphics.PointF;
import android.support.annotation.FloatRange;
import android.support.annotation.NonNull;
+
import com.mapbox.geojson.Point;
import com.mapbox.mapboxsdk.constants.GeometryConstants;
import com.mapbox.mapboxsdk.geometry.LatLng;
@@ -24,7 +25,6 @@ public class Projection {
private final NativeMap nativeMapView;
@NonNull
private final MapView mapView;
- private int[] contentPadding = new int[] {0, 0, 0, 0};
Projection(@NonNull NativeMap nativeMapView, @NonNull MapView mapView) {
this.nativeMapView = nativeMapView;
@@ -32,8 +32,7 @@ public class Projection {
}
void setContentPadding(int[] contentPadding) {
- this.contentPadding = contentPadding;
- float[] output = new float[contentPadding.length];
+ double[] output = new double[contentPadding.length];
for (int i = 0; i < contentPadding.length; i++) {
output[i] = contentPadding[i];
}
@@ -41,11 +40,15 @@ public class Projection {
}
int[] getContentPadding() {
- return contentPadding;
+ double[] padding = nativeMapView.getCameraPosition().padding;
+ return new int[] {(int) padding[0], (int) padding[1], (int) padding[2], (int) padding[3]};
}
+ /**
+ * @deprecated unused
+ */
+ @Deprecated
public void invalidateContentPadding() {
- setContentPadding(contentPadding);
}
/**
@@ -126,10 +129,11 @@ public class Projection {
top = 0;
bottom = mapView.getHeight();
} else {
- left = (float) contentPadding[0];
- right = (float) (mapView.getWidth() - contentPadding[2]);
- top = (float) contentPadding[1];
- bottom = (float) (mapView.getHeight() - contentPadding[3]);
+ int[] contentPadding = getContentPadding();
+ left = contentPadding[0];
+ right = mapView.getWidth() - contentPadding[2];
+ top = contentPadding[1];
+ bottom = mapView.getHeight() - contentPadding[3];
}
LatLng center = fromScreenLocation(new PointF(left + (right - left) / 2, top + (bottom - top) / 2));
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 a707ab13da..b21186050b 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
@@ -523,14 +523,12 @@ public class Style {
for (Layer layer : layers.values()) {
if (layer != null) {
layer.setDetached();
- nativeMap.removeLayer(layer);
}
}
for (Source source : sources.values()) {
if (source != null) {
source.setDetached();
- nativeMap.removeSource(source);
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java
index 1961cf0450..f785aacf3c 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java
@@ -108,7 +108,8 @@ public final class Transform implements MapView.OnCameraDidChangeListener {
if (isValidCameraPosition(cameraPosition)) {
cancelTransitions();
cameraChangeDispatcher.onCameraMoveStarted(OnCameraMoveStartedListener.REASON_API_ANIMATION);
- nativeMap.jumpTo(cameraPosition.target, cameraPosition.zoom, cameraPosition.tilt, cameraPosition.bearing);
+ nativeMap.jumpTo(cameraPosition.target, cameraPosition.zoom, cameraPosition.tilt, cameraPosition.bearing,
+ cameraPosition.padding);
cameraChangeDispatcher.onCameraIdle();
invalidateCameraPosition();
handler.post(new Runnable() {
@@ -119,6 +120,8 @@ public final class Transform implements MapView.OnCameraDidChangeListener {
}
}
});
+ } else if (callback != null) {
+ callback.onFinish();
}
}
@@ -135,7 +138,9 @@ public final class Transform implements MapView.OnCameraDidChangeListener {
}
mapView.addOnCameraDidChangeListener(this);
nativeMap.easeTo(cameraPosition.target, cameraPosition.zoom, cameraPosition.bearing, cameraPosition.tilt,
- durationMs, easingInterpolator);
+ cameraPosition.padding, durationMs, easingInterpolator);
+ } else if (callback != null) {
+ callback.onFinish();
}
}
@@ -155,7 +160,9 @@ public final class Transform implements MapView.OnCameraDidChangeListener {
}
mapView.addOnCameraDidChangeListener(this);
nativeMap.flyTo(cameraPosition.target, cameraPosition.zoom, cameraPosition.bearing,
- cameraPosition.tilt, durationMs);
+ cameraPosition.tilt, cameraPosition.padding, durationMs);
+ } else if (callback != null) {
+ callback.onFinish();
}
}
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 9e72be8e9b..3fd155837e 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
@@ -417,10 +417,6 @@ public final class UiSettings {
}
void update(@NonNull CameraPosition cameraPosition) {
- if (!isCompassEnabled()) {
- return;
- }
-
double clockwiseBearing = -cameraPosition.bearing;
compassView.update(clockwiseBearing);
}
@@ -1073,6 +1069,7 @@ public final class UiSettings {
*/
public void invalidate() {
setLogoMargins(getLogoMarginLeft(), getLogoMarginTop(), getLogoMarginRight(), getLogoMarginBottom());
+ setCompassEnabled(isCompassEnabled());
setCompassMargins(getCompassMarginLeft(), getCompassMarginTop(), getCompassMarginRight(), getCompassMarginBottom());
setAttributionMargins(getAttributionMarginLeft(), getAttributionMarginTop(), getAttributionMarginRight(),
getAttributionMarginBottom());
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRenderer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRenderer.java
index 833a875a09..947ed35555 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRenderer.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRenderer.java
@@ -8,7 +8,6 @@ import android.support.annotation.NonNull;
import com.mapbox.mapboxsdk.LibraryLoader;
import com.mapbox.mapboxsdk.log.Logger;
import com.mapbox.mapboxsdk.maps.MapboxMap;
-import com.mapbox.mapboxsdk.storage.FileSource;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
@@ -36,10 +35,9 @@ public abstract class MapRenderer implements MapRendererScheduler {
public MapRenderer(@NonNull Context context, String localIdeographFontFamily) {
float pixelRatio = context.getResources().getDisplayMetrics().density;
- String programCacheDir = FileSource.getInternalCachePath(context);
// Initialise native peer
- nativeInitialize(this, pixelRatio, programCacheDir, localIdeographFontFamily);
+ nativeInitialize(this, pixelRatio, localIdeographFontFamily);
}
public void onStart() {
@@ -119,7 +117,6 @@ public abstract class MapRenderer implements MapRendererScheduler {
private native void nativeInitialize(MapRenderer self,
float pixelRatio,
- String programCacheDir,
String localIdeographFontFamily);
@CallSuper
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 165b15a512..205e35641b 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
@@ -5,9 +5,13 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
import android.view.TextureView;
+
import com.mapbox.mapboxsdk.log.Logger;
import com.mapbox.mapboxsdk.maps.renderer.egl.EGLConfigChooser;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGL11;
import javax.microedition.khronos.egl.EGLConfig;
@@ -15,8 +19,6 @@ import javax.microedition.khronos.egl.EGLContext;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.egl.EGLSurface;
import javax.microedition.khronos.opengles.GL10;
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
/**
* The render thread is responsible for managing the communication between the
@@ -250,13 +252,13 @@ class TextureViewRenderThread extends Thread implements TextureView.SurfaceTextu
// Initialize EGL
if (initializeEGL) {
eglHolder.prepare();
- if (!eglHolder.createSurface()) {
- synchronized (lock) {
+ synchronized (lock) {
+ if (!eglHolder.createSurface()) {
// Cleanup the surface if one could not be created
// and wait for another to be ready.
destroySurface = true;
+ continue;
}
- continue;
}
mapRenderer.onSurfaceCreated(gl, eglHolder.eglConfig);
mapRenderer.onSurfaceChanged(gl, w, h);
@@ -265,7 +267,9 @@ class TextureViewRenderThread extends Thread implements TextureView.SurfaceTextu
// If the surface size has changed inform the map renderer.
if (recreateSurface) {
- eglHolder.createSurface();
+ synchronized (lock) {
+ eglHolder.createSurface();
+ }
mapRenderer.onSurfaceChanged(gl, w, h);
continue;
}
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 53c0c1c60f..b593076dc1 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
@@ -91,6 +91,7 @@ public final class CompassView extends ImageView implements Runnable {
resetAnimation();
setAlpha(1.0f);
setVisibility(View.VISIBLE);
+ update(rotation);
} else {
resetAnimation();
setAlpha(0.0f);
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 5bd0dd4bf6..faed46662a 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
@@ -307,7 +307,7 @@ public class OfflineManager {
}
/**
- * Forces revalidation of the ambient cache.
+ * Forces re-validation of the ambient cache.
* <p>
* Forces Mapbox GL Native to revalidate resources stored in the ambient
* cache with the tile server before using them, making sure they
@@ -537,7 +537,13 @@ public class OfflineManager {
}
/**
- * Create an offline region in the database.
+ * Creates an offline region in the database by downloading the resources needed to use
+ * the given region offline.
+ * <p>
+ * As of version 8.3.0 of the Maps SDK for Android, offline tile requests are no longer exempt from
+ * billing on mobile. Developers are subject to separate Vector Tile or Raster Tile API pricing for
+ * offline use. See <a href="https://www.mapbox.com/pricing/">our pricing page</a> for more information.
+ * </p>
* <p>
* When the initial database queries have completed, the provided callback will be
* executed on the main thread.
@@ -609,10 +615,15 @@ public class OfflineManager {
}
/**
- * Changing or bypassing this limit without permission from Mapbox is prohibited
- * by the Mapbox Terms of Service.
+ * Sets the maximum number of Mapbox-hosted tiles that may be downloaded and stored on the current device.
+ * By default, the limit is set to 6,000.
+ * <p>
+ * Once this limit is reached, {@link OfflineRegion.OfflineRegionObserver#mapboxTileCountLimitExceeded(long)}
+ * fires every additional attempt to download additional tiles until already downloaded tiles are removed
+ * by calling {@link OfflineRegion#deleteOfflineRegion(OfflineRegion.OfflineRegionDeleteCallback)}.
+ * </p>
*
- * @param limit the new tile count limit.
+ * @param limit the maximum number of tiles allowed to be downloaded
*/
@Keep
public native void setOfflineMapboxTileCountLimit(long limit);
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java
index 4c70d13b17..1e0069c25f 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java
@@ -339,11 +339,9 @@ public class MapSnapshotter {
fileSource.setApiBaseUrl(apiBaseUrl);
}
- String programCacheDir = FileSource.getInternalCachePath(context);
-
nativeInitialize(this, fileSource, options.pixelRatio, options.width,
options.height, options.styleUri, options.styleJson, options.region, options.cameraPosition,
- options.showLogo, programCacheDir, options.localIdeographFontFamily);
+ options.showLogo, options.localIdeographFontFamily);
}
/**
@@ -625,8 +623,7 @@ public class MapSnapshotter {
FileSource fileSource, float pixelRatio,
int width, int height, String styleUrl, String styleJson,
LatLngBounds region, CameraPosition position,
- boolean showLogo, String programCacheDir,
- String localIdeographFontFamily);
+ boolean showLogo, String localIdeographFontFamily);
@Keep
protected native void nativeStart();
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java
index 0f5ce76725..34b3308809 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java
@@ -5,7 +5,6 @@ import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.Size;
-
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
@@ -1436,6 +1435,27 @@ public class Expression {
}
/**
+ * Gets the value of a cluster property accumulated so far. Can only be used in the clusterProperties
+ * option of a clustered GeoJSON source.
+ * <p>
+ * Example usage:
+ * </p>
+ * <pre>
+ * {@code
+ * GeoJsonOptions options = new GeoJsonOptions()
+ * .withCluster(true)
+ * .withClusterProperty("max", max(accumulated(), get("max")).toArray(), get("mag").toArray());
+ * }
+ * </pre>
+ *
+ * @return expression
+ * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-accumulated">Style specification</a>
+ */
+ public static Expression accumulated() {
+ return new Expression("accumulated");
+ }
+
+ /**
* Gets the kernel density estimation of a pixel in a heatmap layer,
* which is a relative measure of how many data points are crowded around a particular pixel.
* Can only be used in the `heatmap-color` property.
@@ -3124,6 +3144,40 @@ public class Expression {
}
/**
+ * Converts the input number into a string representation using the providing formatting rules.
+ * If set, the locale argument specifies the locale to use, as a BCP 47 language tag.
+ * If set, the currency argument specifies an ISO 4217 code to use for currency-style formatting.
+ * If set, the min-fraction-digits and max-fraction-digits arguments specify the minimum and maximum number
+ * of fractional digits to include.
+ *
+ * @param number number expression
+ * @param options number formatting options
+ * @return expression
+ */
+ public static Expression numberFormat(@NonNull Expression number, @NonNull NumberFormatOption... options) {
+ final Map<String, Expression> map = new HashMap<>();
+ for (NumberFormatOption option : options) {
+ map.put(option.type, option.value);
+ }
+ return new Expression("number-format", number, new ExpressionMap(map));
+ }
+
+ /**
+ * Converts the input number into a string representation using the providing formatting rules.
+ * If set, the locale argument specifies the locale to use, as a BCP 47 language tag.
+ * If set, the currency argument specifies an ISO 4217 code to use for currency-style formatting.
+ * If set, the min-fraction-digits and max-fraction-digits arguments specify the minimum and maximum number
+ * of fractional digits to include.
+ *
+ * @param number number expression
+ * @param options number formatting options
+ * @return expression
+ */
+ public static Expression numberFormat(@NonNull Number number, @NonNull NumberFormatOption... options) {
+ return numberFormat(literal(number), options);
+ }
+
+ /**
* Asserts that the input value is a boolean.
* If multiple values are provided, each one is evaluated in order until a boolean value is obtained.
* If none of the inputs are booleans, the expression is an error.
@@ -4365,20 +4419,137 @@ public class Expression {
}
/**
+ * Base class for an option entry that is encapsulated as a json object member for an expression.
+ */
+ private static class Option {
+ @NonNull
+ String type;
+ @NonNull
+ Expression value;
+
+ /**
+ * Create an option option entry that is encapsulated as a json object member for an expression.
+ *
+ * @param type json object member name
+ * @param value json object member value
+ */
+ Option(@NonNull String type, @NonNull Expression value) {
+ this.type = type;
+ this.value = value;
+ }
+ }
+
+ /**
+ * Holds format options used in a {@link #numberFormat(Number, NumberFormatOption...)} expression.
+ */
+ public static class NumberFormatOption extends Option {
+
+ /**
+ * {@inheritDoc}
+ */
+ NumberFormatOption(@NonNull String type, @NonNull Expression value) {
+ super(type, value);
+ }
+
+ /**
+ * Number formatting option for specifying the locale to use, as a BCP 47 language tag.
+ *
+ * @param string the locale to use while performing number formatting
+ * @return number format option
+ */
+ @NonNull
+ public static NumberFormatOption locale(@NonNull Expression string) {
+ return new NumberFormatOption("locale", string);
+ }
+
+ /**
+ * Number formatting option for specifying the locale to use, as a BCP 47 language tag.
+ *
+ * @param string the locale to use while performing number formatting
+ * @return number format option
+ */
+ @NonNull
+ public static NumberFormatOption locale(@NonNull String string) {
+ return new NumberFormatOption("locale", literal(string));
+ }
+
+ /**
+ * Number formatting option for specifying the currency to use, an ISO 4217 code.
+ *
+ * @param string the currency to use while performing number formatting
+ * @return number format option
+ */
+ @NonNull
+ public static NumberFormatOption currency(@NonNull Expression string) {
+ return new NumberFormatOption("currency", string);
+ }
+
+ /**
+ * Number formatting options for specifying the currency to use, an ISO 4217 code.
+ *
+ * @param string the currency to use while performing number formatting
+ * @return number format option
+ */
+ @NonNull
+ public static NumberFormatOption currency(@NonNull String string) {
+ return new NumberFormatOption("currency", literal(string));
+ }
+
+ /**
+ * Number formatting options for specifying the minimum fraction digits to include.
+ *
+ * @param number the amount of minimum fraction digits to include
+ * @return number format option
+ */
+ @NonNull
+ public static NumberFormatOption minFractionDigits(@NonNull Expression number) {
+ return new NumberFormatOption("min-fraction-digits", number);
+ }
+
+ /**
+ * Number formatting options for specifying the minimum fraction digits to include.
+ *
+ * @param number the amount of minimum fraction digits to include
+ * @return number format option
+ */
+ @NonNull
+ public static NumberFormatOption minFractionDigits(int number) {
+ return new NumberFormatOption("min-fraction-digits", literal(number));
+ }
+
+ /**
+ * Number formatting options for specifying the maximum fraction digits to include.
+ *
+ * @param number the amount of minimum fraction digits to include
+ * @return number format option
+ */
+ @NonNull
+ public static NumberFormatOption maxFractionDigits(@NonNull Expression number) {
+ return new NumberFormatOption("max-fraction-digits", number);
+ }
+
+ /**
+ * Number formatting options for specifying the maximum fraction digits to include.
+ *
+ * @param number the amount of minimum fraction digits to include
+ * @return number format option
+ */
+ @NonNull
+ public static NumberFormatOption maxFractionDigits(@NonNull int number) {
+ return new NumberFormatOption("max-fraction-digits", literal(number));
+ }
+ }
+
+ /**
* Holds format options used in a {@link #formatEntry(Expression, FormatOption...)} that builds
* a {@link #format(FormatEntry...)} expression.
* <p>
* If an option is not set, it defaults to the base value defined for the symbol.
*/
- public static class FormatOption {
- @NonNull
- private String type;
- @NonNull
- private Expression value;
+ public static class FormatOption extends Option {
FormatOption(@NonNull String type, @NonNull Expression value) {
- this.type = type;
- this.value = value;
+ super(type, value);
}
/**
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java
index 82085b171c..66a6fe20b2 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
@@ -2296,7 +2296,7 @@ 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}.
+ * Radial offset of text, in the direction of the symbol's anchor. Useful in combination with {@link PropertyFactory#textVariableAnchor}, which defaults to using the two-dimensional {@link PropertyFactory#textOffset} if present.
*
* @param value a Float value
* @return property wrapper around Float
@@ -2306,7 +2306,7 @@ 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}.
+ * Radial offset of text, in the direction of the symbol's anchor. Useful in combination with {@link PropertyFactory#textVariableAnchor}, which defaults to using the two-dimensional {@link PropertyFactory#textOffset} if present.
*
* @param value a Float value
* @return property wrapper around Float
@@ -2316,7 +2316,7 @@ public class PropertyFactory {
}
/**
- * 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}.
+ * 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} or the two-dimensional {@link PropertyFactory#textOffset}.
*
* @param value a String[] value
* @return property wrapper around String[]
@@ -2326,7 +2326,7 @@ public class PropertyFactory {
}
/**
- * 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}.
+ * 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} or the two-dimensional {@link PropertyFactory#textOffset}.
*
* @param value a String[] value
* @return property wrapper around String[]
@@ -2476,7 +2476,7 @@ public class PropertyFactory {
}
/**
- * Offset distance of text from its anchor. Positive values indicate right and down, while negative values indicate left and up.
+ * Offset distance of text from its anchor. Positive values indicate right and down, while negative values indicate left and up. If used with text-variable-anchor, input values will be taken as absolute values. Offsets along the x- and y-axis will be applied automatically based on the anchor position.
*
* @param value a Float[] value
* @return property wrapper around Float[]
@@ -2486,7 +2486,7 @@ public class PropertyFactory {
}
/**
- * Offset distance of text from its anchor. Positive values indicate right and down, while negative values indicate left and up.
+ * Offset distance of text from its anchor. Positive values indicate right and down, while negative values indicate left and up. If used with text-variable-anchor, input values will be taken as absolute values. Offsets along the x- and y-axis will be applied automatically based on the anchor position.
*
* @param value a Float[] value
* @return property wrapper around Float[]
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonOptions.java
index 1e1b9bafa6..091079ab92 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonOptions.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonOptions.java
@@ -1,9 +1,12 @@
package com.mapbox.mapboxsdk.style.sources;
import android.support.annotation.NonNull;
+import com.mapbox.mapboxsdk.style.expressions.Expression;
import java.util.HashMap;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.ExpressionLiteral;
+
/**
* Builder class for composing GeoJsonSource objects.
*
@@ -109,4 +112,28 @@ public class GeoJsonOptions extends HashMap<String, Object> {
this.put("clusterRadius", clusterRadius);
return this;
}
+
+ /**
+ * An object defining custom properties on the generated clusters if clustering is enabled,
+ * aggregating values from clustered points. Has the form {"property_name": [operator, [map_expression]]} or
+ * {"property_name": [[operator, accumulated, expression], [map_expression]]}
+ *
+ * @param propertyName name of the property
+ * @param operatorExpr operatorExpr is any expression function that accepts at least 2 operands (e.g. "+" or "max").
+ * It accumulates the property value from clusters/points the cluster contains. It can either be
+ * a literal with single operator, or be a valid expression
+ * @param mapExpr map expression produces the value of a single point, it shall be a valid expression
+ * @return the current instance for chaining
+ */
+ @NonNull
+ public GeoJsonOptions withClusterProperty(String propertyName, Expression operatorExpr, Expression mapExpr) {
+ HashMap<String, Object[]> properties = containsKey("clusterProperties")
+ ? (HashMap<String, Object[]>) get("clusterProperties") : new HashMap<String, Object[]>();
+ Object operator = (operatorExpr instanceof ExpressionLiteral)
+ ? ((ExpressionLiteral)operatorExpr).toValue() : operatorExpr.toArray();
+ Object map = mapExpr.toArray();
+ properties.put(propertyName, new Object[]{operator, map});
+ this.put("clusterProperties", properties);
+ return this;
+ }
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/FontUtils.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/FontUtils.java
index 09064ee168..627b342179 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/FontUtils.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/FontUtils.java
@@ -1,7 +1,8 @@
package com.mapbox.mapboxsdk.utils;
import android.graphics.Typeface;
-
+import android.os.Build;
+import android.support.annotation.RequiresApi;
import com.mapbox.mapboxsdk.MapStrictMode;
import com.mapbox.mapboxsdk.log.Logger;
@@ -18,6 +19,14 @@ import static com.mapbox.mapboxsdk.constants.MapboxConstants.DEFAULT_FONT;
public class FontUtils {
private static final String TAG = "Mbgl-FontUtils";
+ private static final String TYPEFACE_FONTMAP_FIELD_NAME = "sSystemFontMap";
+ private static final List<String> DEFAULT_FONT_STACKS = new ArrayList<>();
+
+ static {
+ DEFAULT_FONT_STACKS.add("sans-serif");
+ DEFAULT_FONT_STACKS.add("serif");
+ DEFAULT_FONT_STACKS.add("monospace");
+ }
private FontUtils() {
// no instance
@@ -34,7 +43,13 @@ public class FontUtils {
return null;
}
- List<String> validFonts = getAvailableFonts();
+ List<String> validFonts;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ validFonts = getDeviceFonts();
+ } else {
+ validFonts = DEFAULT_FONT_STACKS;
+ }
+
for (String fontName : fontNames) {
if (validFonts.contains(fontName)) {
return fontName;
@@ -47,16 +62,18 @@ public class FontUtils {
return DEFAULT_FONT;
}
- private static List<String> getAvailableFonts() {
+ @SuppressWarnings( {"JavaReflectionMemberAccess", "unchecked"})
+ @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
+ private static List<String> getDeviceFonts() {
List<String> fonts = new ArrayList<>();
try {
Typeface typeface = Typeface.create(Typeface.DEFAULT, Typeface.NORMAL);
- Field f = Typeface.class.getDeclaredField("sSystemFontMap");
- f.setAccessible(true);
- Map<String, Typeface> fontMap = (Map<String, Typeface>) f.get(typeface);
+ Field field = Typeface.class.getDeclaredField(TYPEFACE_FONTMAP_FIELD_NAME);
+ field.setAccessible(true);
+ Map<String, Typeface> fontMap = (Map<String, Typeface>) field.get(typeface);
fonts.addAll(fontMap.keySet());
} catch (Exception exception) {
- Logger.e(TAG,"Couldn't load fonts from Typeface", exception);
+ Logger.e(TAG, "Couldn't load fonts from Typeface", exception);
MapStrictMode.strictModeViolation("Couldn't load fonts from Typeface", exception);
}
return fonts;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml
index 3e7124a414..ff8a32ac64 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml
@@ -7,7 +7,9 @@
<!--Configuration-->
<attr name="mapbox_apiBaseUri" format="string"/>
+ <attr name="mapbox_localIdeographEnabled" format="boolean"/>
<attr name="mapbox_localIdeographFontFamily" format="string"/>
+ <attr name="mapbox_localIdeographFontFamilies" format="reference"/>
<attr name="mapbox_cross_source_collisions" format="boolean"/>
<!--Camera-->
diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java
index 0c5f3a4be2..6974705fae 100644
--- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java
@@ -1,21 +1,24 @@
package com.mapbox.mapboxsdk.camera;
import android.content.res.TypedArray;
-import android.os.Parcelable;
+import android.os.Parcel;
import com.mapbox.mapboxsdk.R;
import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.utils.MockParcel;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+@RunWith(RobolectricTestRunner.class)
public class CameraPositionTest {
private static final double DELTA = 1e-15;
@@ -23,7 +26,7 @@ public class CameraPositionTest {
@Test
public void testSanity() {
LatLng latLng = new LatLng(1, 2);
- CameraPosition cameraPosition = new CameraPosition(latLng, 3, 4, 5);
+ CameraPosition cameraPosition = new CameraPosition(latLng, 3, 4, 5, new double[] {0, 500, 0, 0});
assertNotNull("cameraPosition should not be null", cameraPosition);
}
@@ -32,9 +35,10 @@ public class CameraPositionTest {
TypedArray typedArray = null;
CameraPosition cameraPosition = new CameraPosition.Builder(typedArray).build();
assertEquals("bearing should match", -1, cameraPosition.bearing, DELTA);
- assertEquals("latlng should match", null, cameraPosition.target);
+ assertNull("latlng should be null", cameraPosition.target);
assertEquals("tilt should match", -1, cameraPosition.tilt, DELTA);
assertEquals("zoom should match", -1, cameraPosition.zoom, DELTA);
+ assertNull("padding should be null", cameraPosition.padding);
}
@Test
@@ -63,16 +67,16 @@ public class CameraPositionTest {
@Test
public void testToString() {
LatLng latLng = new LatLng(1, 2);
- CameraPosition cameraPosition = new CameraPosition(latLng, 3, 4, 5);
+ CameraPosition cameraPosition = new CameraPosition(latLng, 3, 4, 5, new double[] {0, 500, 0, 0});
assertEquals("toString should match", "Target: LatLng [latitude=1.0, longitude=2.0, altitude=0.0], Zoom:3.0, "
- + "Bearing:5.0, Tilt:4.0", cameraPosition.toString());
+ + "Bearing:5.0, Tilt:4.0, Padding:[0.0, 500.0, 0.0, 0.0]", cameraPosition.toString());
}
@Test
public void testHashcode() {
LatLng latLng = new LatLng(1, 2);
- CameraPosition cameraPosition = new CameraPosition(latLng, 3, 4, 5);
- assertEquals("hashCode should match", -1007681505, cameraPosition.hashCode());
+ CameraPosition cameraPosition = new CameraPosition(latLng, 3, 4, 5, new double[] {0, 500, 0, 0});
+ assertEquals("hashCode should match", -420915327, cameraPosition.hashCode());
}
@Test
@@ -86,11 +90,12 @@ public class CameraPositionTest {
@Test
public void testEquals() {
LatLng latLng = new LatLng(1, 2);
- CameraPosition cameraPosition = new CameraPosition(latLng, 3, 4, 5);
- CameraPosition cameraPositionBearing = new CameraPosition(latLng, 3, 4, 9);
- CameraPosition cameraPositionTilt = new CameraPosition(latLng, 3, 9, 5);
- CameraPosition cameraPositionZoom = new CameraPosition(latLng, 9, 4, 5);
- CameraPosition cameraPositionTarget = new CameraPosition(new LatLng(), 3, 4, 5);
+ CameraPosition cameraPosition = new CameraPosition(latLng, 3, 4, 5, new double[] {0, 500, 0, 0});
+ CameraPosition cameraPositionBearing = new CameraPosition(latLng, 3, 4, 9, new double[] {0, 500, 0, 0});
+ CameraPosition cameraPositionTilt = new CameraPosition(latLng, 3, 9, 5, new double[] {0, 500, 0, 0});
+ CameraPosition cameraPositionZoom = new CameraPosition(latLng, 9, 4, 5, new double[] {0, 500, 0, 0});
+ CameraPosition cameraPositionTarget = new CameraPosition(new LatLng(), 3, 4, 5, new double[] {0, 500, 0, 0});
+ CameraPosition cameraPositionPadding = new CameraPosition(new LatLng(), 3, 4, 5, new double[] {0, 501, 0, 0});
assertEquals("cameraPosition should match itself", cameraPosition, cameraPosition);
assertNotEquals("cameraPosition should not match null", null, cameraPosition);
@@ -99,12 +104,17 @@ public class CameraPositionTest {
assertNotEquals("cameraPosition should not match for tilt", cameraPositionTilt, cameraPosition);
assertNotEquals("cameraPosition should not match for zoom", cameraPositionZoom, cameraPosition);
assertNotEquals("cameraPosition should not match for target", cameraPositionTarget, cameraPosition);
+ assertNotEquals("cameraPosition should not match for padding", cameraPositionPadding, cameraPosition);
}
@Test
public void testParcelable() {
- CameraPosition object = new CameraPosition(new LatLng(1, 2), 3, 4, 5);
- Parcelable parcelable = MockParcel.obtain(object);
- assertEquals("Parcel should match original object", parcelable, object);
+ CameraPosition cameraPosition1 = new CameraPosition(new LatLng(1, 2), 3, 4, 5, new double[] {0, 500, 0, 0});
+ Parcel parcel = Parcel.obtain();
+ cameraPosition1.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+
+ CameraPosition cameraPosition2 = CameraPosition.CREATOR.createFromParcel(parcel);
+ assertEquals("Parcel should match original object", cameraPosition1, cameraPosition2);
}
}
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 0fbc47df55..ed2d015d85 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
@@ -632,6 +632,41 @@ public class LocationLayerControllerTest {
verify(internalRenderModeChangedListener, times(1)).onRenderModeChanged(RenderMode.GPS);
}
+ @Test
+ public void layerHidden_renderModeChanged_layerShown_foregroundIconUpdated() {
+ OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class);
+ LayerSourceProvider sourceProvider = buildLayerProvider();
+ when(sourceProvider.generateSource(any(Feature.class))).thenReturn(mock(GeoJsonSource.class));
+ LocationComponentOptions options = mock(LocationComponentOptions.class);
+ int drawableResId = 123;
+ int tintColor = 456;
+ when(options.foregroundDrawable()).thenReturn(drawableResId);
+ when(options.foregroundTintColor()).thenReturn(tintColor);
+ LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class);
+ Bitmap bitmap = mock(Bitmap.class);
+ when(bitmapProvider.generateBitmap(drawableResId, tintColor)).thenReturn(bitmap);
+
+ LocationLayerController controller =
+ new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options),
+ bitmapProvider, options, internalRenderModeChangedListener);
+
+ verify(style).addImage(FOREGROUND_ICON, bitmap);
+
+ int drawableGpsResId = 789;
+ when(options.gpsDrawable()).thenReturn(drawableGpsResId);
+
+ Bitmap bitmapGps = mock(Bitmap.class);
+ when(bitmapProvider.generateBitmap(drawableGpsResId, tintColor)).thenReturn(bitmapGps);
+
+ controller.hide();
+
+ controller.setRenderMode(RenderMode.GPS);
+
+ controller.show();
+
+ verify(style).addImage(FOREGROUND_ICON, bitmapGps);
+ }
+
private LayerFeatureProvider buildFeatureProvider(@NonNull LocationComponentOptions options) {
LayerFeatureProvider provider = mock(LayerFeatureProvider.class);
when(provider.generateLocationFeature(null, options)).thenReturn(mock(Feature.class));
diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsAttrsTest.kt b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsAttrsTest.kt
new file mode 100644
index 0000000000..ee8024257f
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsAttrsTest.kt
@@ -0,0 +1,101 @@
+package com.mapbox.mapboxsdk.maps
+
+import android.content.Context
+import android.content.res.Resources
+import android.content.res.TypedArray
+import com.mapbox.mapboxsdk.R
+import io.mockk.MockKAnnotations
+import io.mockk.every
+import io.mockk.impl.annotations.RelaxedMockK
+import io.mockk.verify
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+
+@RunWith(RobolectricTestRunner::class)
+class MapboxMapOptionsAttrsTest {
+
+ @RelaxedMockK
+ private lateinit var options: MapboxMapOptions
+
+ @RelaxedMockK
+ private lateinit var typedArray: TypedArray
+
+ @RelaxedMockK
+ private lateinit var context: Context
+
+ @RelaxedMockK
+ private lateinit var resources: Resources
+
+ @Before
+ fun setUp() {
+ MockKAnnotations.init(this)
+ every {
+ context.resources
+ }.returns(resources)
+ }
+
+ @Test
+ fun enabledLocalIdeographFontFamily() {
+ mockEnableLocalIdeograph(enabled = true)
+
+ val options = MapboxMapOptions.createFromAttributes(options, context, typedArray)
+
+ verify(exactly = 1) {
+ options.localIdeographFontFamily(any())
+ }
+ }
+
+ @Test
+ fun localIdeographFontFamily() {
+ mockEnableLocalIdeograph(enabled = true)
+
+ val font = "foo"
+ mockLocalIdeographString(font)
+
+ val options = MapboxMapOptions.createFromAttributes(options, context, typedArray)
+
+ verify(exactly = 1) {
+ options.localIdeographFontFamily(font)
+ }
+ }
+
+ @Test
+ fun localIdeographFontFamilies() {
+ mockEnableLocalIdeograph(enabled = true)
+
+ val fonts = arrayOf("foo", "bar")
+ mockLocalIdeographStringArray(fonts)
+
+ val options = MapboxMapOptions.createFromAttributes(options, context, typedArray)
+
+ verify(exactly = 1) {
+ options.localIdeographFontFamily(*fonts)
+ }
+ }
+
+ private fun mockEnableLocalIdeograph(enabled: Boolean) {
+ every {
+ typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_localIdeographEnabled, true)
+ }.returns(enabled)
+ }
+
+ private fun mockLocalIdeographString(font: String) {
+ every {
+ typedArray.getString(R.styleable.mapbox_MapView_mapbox_localIdeographFontFamily)
+ }.returns(font)
+ }
+
+ private fun mockLocalIdeographStringArray(fonts: Array<String>) {
+ val resId = 9000
+
+ every {
+ typedArray.getResourceId(R.styleable.mapbox_MapView_mapbox_localIdeographFontFamilies, 0)
+ }.returns(resId)
+
+ every {
+ resources.getStringArray(resId)
+ }.returns(fonts)
+ }
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/StyleTest.kt b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/StyleTest.kt
index d618f17500..a5070ae5c0 100644
--- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/StyleTest.kt
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/StyleTest.kt
@@ -405,22 +405,4 @@ class StyleTest {
Assert.assertEquals("Layer that failed to be added shouldn't be cached", layer1, mapboxMap.style!!.getLayer("layer1"))
}
}
-
- @Test
- fun testClearRemovesSourcesFirst() {
- val source1 = mockk<GeoJsonSource>(relaxed = true)
- every { source1.id } returns "source1"
- val layer1 = mockk<SymbolLayer>(relaxed = true)
- every { layer1.id } returns "layer1"
-
- val builder = Style.Builder().withLayer(layer1).withSource(source1)
- mapboxMap.setStyle(builder)
- mapboxMap.notifyStyleLoaded()
- mapboxMap.setStyle(Style.MAPBOX_STREETS)
-
- verifyOrder {
- nativeMapView.removeLayer(layer1)
- nativeMapView.removeSource(source1)
- }
- }
} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/TransformTest.kt b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/TransformTest.kt
index 4f6e915d1f..fddf7eeaff 100644
--- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/TransformTest.kt
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/TransformTest.kt
@@ -25,8 +25,9 @@ class TransformTest {
every { nativeMapView.isDestroyed } returns false
every { nativeMapView.cameraPosition } returns CameraPosition.DEFAULT
every { nativeMapView.cancelTransitions() } answers {}
- every { nativeMapView.jumpTo(any(), any(), any(), any()) } answers {}
- every { nativeMapView.flyTo(any(), any(), any(), any(), any()) } answers {}
+ every { nativeMapView.jumpTo(any(), any(), any(), any(), any()) } answers {}
+ every { nativeMapView.easeTo(any(), any(), any(), any(), any(), any(), any()) } answers {}
+ every { nativeMapView.flyTo(any(), any(), any(), any(), any(), any()) } answers {}
every { nativeMapView.minZoom = any() } answers {}
every { nativeMapView.maxZoom = any() } answers {}
}
@@ -44,7 +45,103 @@ class TransformTest {
val update = CameraUpdateFactory.newCameraPosition(expected)
transform.moveCamera(mapboxMap, update, callback)
- verify { nativeMapView.jumpTo(target, -1.0, -1.0, -1.0) }
+ verify { nativeMapView.jumpTo(target, -1.0, -1.0, -1.0, null) }
+ verify { callback.onFinish() }
+ }
+
+ @Test
+ fun testMoveCameraToSamePosition() {
+ val mapboxMap = mockk<MapboxMap>()
+ every { mapboxMap.cameraPosition } answers { CameraPosition.DEFAULT }
+
+ val callback = mockk<MapboxMap.CancelableCallback>()
+ every { callback.onFinish() } answers {}
+
+ val expected = CameraPosition.DEFAULT
+ val update = CameraUpdateFactory.newCameraPosition(expected)
+
+ transform.moveCamera(mapboxMap, update, null) // Initialize camera position
+ transform.moveCamera(mapboxMap, update, callback)
+
+ verify(exactly = 1, verifyBlock = { nativeMapView.jumpTo(any(), any(), any(), any(), any()) })
+ verify { callback.onFinish() }
+ }
+
+ @Test
+ fun testEaseCamera() {
+ val mapboxMap = mockk<MapboxMap>()
+ every { mapboxMap.cameraPosition } answers { CameraPosition.DEFAULT }
+
+ every { mapView.addOnCameraDidChangeListener(any()) } answers { transform.onCameraDidChange(true) }
+ every { mapView.removeOnCameraDidChangeListener(any()) } answers {}
+
+ val callback = mockk<MapboxMap.CancelableCallback>()
+ every { callback.onFinish() } answers {}
+
+ val target = LatLng(1.0, 2.0)
+ val expected = CameraPosition.Builder().target(target).build()
+ val update = CameraUpdateFactory.newCameraPosition(expected)
+
+ transform.easeCamera(mapboxMap, update, 100, false, callback)
+
+ verify { nativeMapView.easeTo(target, -1.0, -1.0, -1.0, null, 100, false) }
+ verify { callback.onFinish() }
+ }
+
+ @Test
+ fun testEaseCameraToSamePosition() {
+ val mapboxMap = mockk<MapboxMap>()
+ every { mapboxMap.cameraPosition } answers { CameraPosition.DEFAULT }
+
+ val callback = mockk<MapboxMap.CancelableCallback>()
+ every { callback.onFinish() } answers {}
+
+ val expected = CameraPosition.DEFAULT
+ val update = CameraUpdateFactory.newCameraPosition(expected)
+ transform.moveCamera(mapboxMap, update, null)
+
+ transform.easeCamera(mapboxMap, update, 100, false, callback)
+
+ verify(exactly = 0, verifyBlock = { nativeMapView.easeTo(any(), any(), any(), any(), any(), any(), any()) })
+ verify { callback.onFinish() }
+ }
+
+ @Test
+ fun testAnimateCamera() {
+ val mapboxMap = mockk<MapboxMap>()
+ every { mapboxMap.cameraPosition } answers { CameraPosition.DEFAULT }
+
+ every { mapView.addOnCameraDidChangeListener(any()) } answers { transform.onCameraDidChange(true) }
+ every { mapView.removeOnCameraDidChangeListener(any()) } answers {}
+
+ val callback = mockk<MapboxMap.CancelableCallback>()
+ every { callback.onFinish() } answers {}
+
+ val target = LatLng(1.0, 2.0)
+ val expected = CameraPosition.Builder().target(target).build()
+ val update = CameraUpdateFactory.newCameraPosition(expected)
+
+ transform.animateCamera(mapboxMap, update, 100, callback)
+
+ verify { nativeMapView.flyTo(target, -1.0, -1.0, -1.0, null, 100) }
+ verify { callback.onFinish() }
+ }
+
+ @Test
+ fun testAnimateCameraToSamePosition() {
+ val mapboxMap = mockk<MapboxMap>()
+ every { mapboxMap.cameraPosition } answers { CameraPosition.DEFAULT }
+
+ val callback = mockk<MapboxMap.CancelableCallback>()
+ every { callback.onFinish() } answers {}
+
+ val expected = CameraPosition.DEFAULT
+ val update = CameraUpdateFactory.newCameraPosition(expected)
+ transform.moveCamera(mapboxMap, update, null)
+
+ transform.animateCamera(mapboxMap, update, 100, callback)
+
+ verify(exactly = 0, verifyBlock = { nativeMapView.flyTo(any(), any(), any(), any(), any(), any()) })
verify { callback.onFinish() }
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java
index cfcf0a0486..a84e93cd75 100644
--- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java
@@ -5,6 +5,7 @@ import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
+import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.maps.widgets.CompassView;
import org.junit.Before;
@@ -17,6 +18,7 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.verify;
public class UiSettingsTest {
@@ -412,4 +414,20 @@ public class UiSettingsTest {
assertEquals("Zoom rate should be 0.83f", 0.83f,
uiSettings.getZoomRate(), 0);
}
+
+ @Test
+ public void testUpdateWhenCompassViewNotHidden() {
+ CameraPosition cameraPosition = new CameraPosition.Builder(CameraPosition.DEFAULT).bearing(24.0f).build();
+ when(compassView.isHidden()).thenReturn(false);
+ uiSettings.update(cameraPosition);
+ verify(compassView).update(-24.0f);
+ }
+
+ @Test
+ public void testUpdateWhenCompassViewHidden() {
+ CameraPosition cameraPosition = new CameraPosition.Builder(CameraPosition.DEFAULT).bearing(24.0f).build();
+ when(compassView.isHidden()).thenReturn(true);
+ uiSettings.update(cameraPosition);
+ verify(compassView).update(-24.0f);
+ }
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/module/http/HttpRequestUrlTest.kt b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/module/http/HttpRequestUrlTest.kt
index 994a41938b..5db7b0b0f9 100644
--- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/module/http/HttpRequestUrlTest.kt
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/module/http/HttpRequestUrlTest.kt
@@ -20,14 +20,14 @@ class HttpRequestUrlTest {
@Test
fun testOfflineFlagMapboxCom() {
- val expected = "http://mapbox.com/path/of/no/return.pbf?sku=foobar&offline=true"
+ val expected = "http://mapbox.com/path/of/no/return.pbf?offline=true"
val actual = HttpRequestUrl.buildResourceUrl("mapbox.com", "http://mapbox.com/path/of/no/return.pbf", 0, true)
assertEquals(expected, actual)
}
@Test
fun testOfflineFlagMapboxCn() {
- val expected = "http://mapbox.cn/path/of/no/return.pbf?sku=foobar&offline=true"
+ val expected = "http://mapbox.cn/path/of/no/return.pbf?offline=true"
val actual = HttpRequestUrl.buildResourceUrl("mapbox.cn", "http://mapbox.cn/path/of/no/return.pbf", 0, true)
assertEquals(expected, actual)
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactoryTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactoryTest.kt
index 50b9626edc..f840e970d1 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactoryTest.kt
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactoryTest.kt
@@ -1,11 +1,15 @@
package com.mapbox.mapboxsdk.camera
+import android.graphics.PointF
+import android.support.test.annotation.UiThreadTest
import android.support.test.runner.AndroidJUnit4
import com.mapbox.mapboxsdk.geometry.LatLng
import com.mapbox.mapboxsdk.geometry.LatLngBounds
import com.mapbox.mapboxsdk.testapp.activity.BaseTest
import com.mapbox.mapboxsdk.testapp.activity.espresso.DeviceIndependentTestActivity
+import org.junit.Assert
import org.junit.Assert.assertEquals
+import org.junit.Assert.assertTrue
import org.junit.Test
import org.junit.runner.RunWith
@@ -17,127 +21,166 @@ class CameraUpdateFactoryTest : BaseTest() {
}
@Test
+ @UiThreadTest
fun testLatLngBoundsUntiltedUnrotated() {
- rule.runOnUiThread {
- mapboxMap.cameraPosition = CameraPosition.Builder()
- .target(LatLng(60.0, 24.0))
- .bearing(0.0)
- .tilt(0.0)
- .build()
-
- val bounds: LatLngBounds = LatLngBounds.Builder()
- .include(LatLng(62.0, 26.0))
- .include(LatLng(58.0, 22.0))
- .build()
-
- mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0))
-
- val cameraPosition = mapboxMap.cameraPosition
- assertEquals("latitude should match:", 60.0, cameraPosition.target.latitude, 0.1)
- assertEquals("longitude should match:", 24.0, cameraPosition.target.longitude, 0.1)
- assertEquals("bearing should match:", 0.0, cameraPosition.bearing, 0.1)
- assertEquals("zoom should match", 5.5, cameraPosition.zoom, 0.1)
- assertEquals("tilt should match:", 0.0, cameraPosition.tilt, 0.1)
- }
+ mapboxMap.cameraPosition = CameraPosition.Builder()
+ .target(LatLng(60.0, 24.0))
+ .bearing(0.0)
+ .tilt(0.0)
+ .build()
+
+ val bounds: LatLngBounds = LatLngBounds.Builder()
+ .include(LatLng(62.0, 26.0))
+ .include(LatLng(58.0, 22.0))
+ .build()
+
+ mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0))
+
+ val cameraPosition = mapboxMap.cameraPosition
+ assertEquals("latitude should match:", 60.0, cameraPosition.target.latitude, 0.1)
+ assertEquals("longitude should match:", 24.0, cameraPosition.target.longitude, 0.1)
+ assertEquals("bearing should match:", 0.0, cameraPosition.bearing, 0.1)
+ assertEquals("zoom should match", 5.5, cameraPosition.zoom, 0.1)
+ assertEquals("tilt should match:", 0.0, cameraPosition.tilt, 0.1)
}
@Test
+ @UiThreadTest
fun testLatLngBoundsTilted() {
- rule.runOnUiThread {
- mapboxMap.cameraPosition = CameraPosition.Builder()
- .target(LatLng(60.0, 24.0))
- .bearing(0.0)
- .tilt(45.0)
- .build()
-
- val bounds: LatLngBounds = LatLngBounds.Builder()
- .include(LatLng(62.0, 26.0))
- .include(LatLng(58.0, 22.0))
- .build()
-
- mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0))
-
- val cameraPosition = mapboxMap.cameraPosition
- assertEquals("latitude should match:", 60.0, cameraPosition.target.latitude, 0.1)
- assertEquals("longitude should match:", 24.0, cameraPosition.target.longitude, 0.1)
- assertEquals("bearing should match:", 0.0, cameraPosition.bearing, 0.1)
- assertEquals("zoom should match", 6.0, cameraPosition.zoom, 0.1)
- assertEquals("tilt should match:", 45.0, cameraPosition.tilt, 0.1)
- }
+ mapboxMap.cameraPosition = CameraPosition.Builder()
+ .target(LatLng(60.0, 24.0))
+ .bearing(0.0)
+ .tilt(45.0)
+ .build()
+
+ val bounds: LatLngBounds = LatLngBounds.Builder()
+ .include(LatLng(62.0, 26.0))
+ .include(LatLng(58.0, 22.0))
+ .build()
+
+ mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0))
+
+ val cameraPosition = mapboxMap.cameraPosition
+ assertEquals("latitude should match:", 60.0, cameraPosition.target.latitude, 0.1)
+ assertEquals("longitude should match:", 24.0, cameraPosition.target.longitude, 0.1)
+ assertEquals("bearing should match:", 0.0, cameraPosition.bearing, 0.1)
+ assertEquals("zoom should match", 6.0, cameraPosition.zoom, 0.1)
+ assertEquals("tilt should match:", 45.0, cameraPosition.tilt, 0.1)
}
@Test
+ @UiThreadTest
fun testLatLngBoundsRotated() {
- rule.runOnUiThread {
- mapboxMap.cameraPosition = CameraPosition.Builder()
- .target(LatLng(60.0, 24.0))
- .bearing(30.0)
- .tilt(0.0)
- .build()
-
- val bounds: LatLngBounds = LatLngBounds.Builder()
- .include(LatLng(62.0, 26.0))
- .include(LatLng(58.0, 22.0))
- .build()
-
- mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0))
-
- val cameraPosition = mapboxMap.cameraPosition
- assertEquals("latitude should match:", 60.0, cameraPosition.target.latitude, 0.1)
- assertEquals("longitude should match:", 24.0, cameraPosition.target.longitude, 0.1)
- assertEquals("bearing should match:", 30.0, cameraPosition.bearing, 0.1)
- assertEquals("zoom should match", 5.3, cameraPosition.zoom, 0.1)
- assertEquals("tilt should match:", 0.0, cameraPosition.tilt, 0.1)
- }
+ mapboxMap.cameraPosition = CameraPosition.Builder()
+ .target(LatLng(60.0, 24.0))
+ .bearing(30.0)
+ .tilt(0.0)
+ .build()
+
+ val bounds: LatLngBounds = LatLngBounds.Builder()
+ .include(LatLng(62.0, 26.0))
+ .include(LatLng(58.0, 22.0))
+ .build()
+
+ mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0))
+
+ val cameraPosition = mapboxMap.cameraPosition
+ assertEquals("latitude should match:", 60.0, cameraPosition.target.latitude, 0.1)
+ assertEquals("longitude should match:", 24.0, cameraPosition.target.longitude, 0.1)
+ assertEquals("bearing should match:", 30.0, cameraPosition.bearing, 0.1)
+ assertEquals("zoom should match", 5.3, cameraPosition.zoom, 0.1)
+ assertEquals("tilt should match:", 0.0, cameraPosition.tilt, 0.1)
}
@Test
+ @UiThreadTest
fun testLatLngBoundsTiltedRotated() {
- rule.runOnUiThread {
- mapboxMap.cameraPosition = CameraPosition.Builder()
- .target(LatLng(60.0, 24.0))
- .bearing(30.0)
- .tilt(45.0)
- .build()
-
- val bounds: LatLngBounds = LatLngBounds.Builder()
- .include(LatLng(62.0, 26.0))
- .include(LatLng(58.0, 22.0))
- .build()
-
- mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0))
-
- val cameraPosition = mapboxMap.cameraPosition
- assertEquals("latitude should match:", 60.0, cameraPosition.target.latitude, 0.1)
- assertEquals("longitude should match:", 24.0, cameraPosition.target.longitude, 0.1)
- assertEquals("bearing should match:", 30.0, cameraPosition.bearing, 0.1)
- assertEquals("zoom should match", 5.6, cameraPosition.zoom, 0.1)
- assertEquals("tilt should match:", 45.0, cameraPosition.tilt, 0.1)
- }
+ mapboxMap.cameraPosition = CameraPosition.Builder()
+ .target(LatLng(60.0, 24.0))
+ .bearing(30.0)
+ .tilt(45.0)
+ .build()
+
+ val bounds: LatLngBounds = LatLngBounds.Builder()
+ .include(LatLng(62.0, 26.0))
+ .include(LatLng(58.0, 22.0))
+ .build()
+
+ mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0))
+
+ val cameraPosition = mapboxMap.cameraPosition
+ assertEquals("latitude should match:", 60.0, cameraPosition.target.latitude, 0.1)
+ assertEquals("longitude should match:", 24.0, cameraPosition.target.longitude, 0.1)
+ assertEquals("bearing should match:", 30.0, cameraPosition.bearing, 0.1)
+ assertEquals("zoom should match", 5.6, cameraPosition.zoom, 0.1)
+ assertEquals("tilt should match:", 45.0, cameraPosition.tilt, 0.1)
}
@Test
+ @UiThreadTest
fun testLatLngBoundsWithProvidedTiltAndRotation() {
- rule.runOnUiThread {
- mapboxMap.cameraPosition = CameraPosition.Builder()
- .target(LatLng(60.0, 24.0))
- .bearing(0.0)
- .tilt(0.0)
- .build()
-
- val bounds: LatLngBounds = LatLngBounds.Builder()
- .include(LatLng(62.0, 26.0))
- .include(LatLng(58.0, 22.0))
- .build()
-
- mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 30.0, 40.0, 0))
-
- val cameraPosition = mapboxMap.cameraPosition
- assertEquals("latitude should match:", 60.0, cameraPosition.target.latitude, 0.1)
- assertEquals("longitude should match:", 24.0, cameraPosition.target.longitude, 0.1)
- assertEquals("bearing should match:", 30.0, cameraPosition.bearing, 0.1)
- assertEquals("zoom should match", 5.6, cameraPosition.zoom, 0.1)
- assertEquals("tilt should match:", 40.0, cameraPosition.tilt, 0.1)
- }
+ mapboxMap.cameraPosition = CameraPosition.Builder()
+ .target(LatLng(60.0, 24.0))
+ .bearing(0.0)
+ .tilt(0.0)
+ .build()
+
+ val bounds: LatLngBounds = LatLngBounds.Builder()
+ .include(LatLng(62.0, 26.0))
+ .include(LatLng(58.0, 22.0))
+ .build()
+
+ mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 30.0, 40.0, 0))
+
+ val cameraPosition = mapboxMap.cameraPosition
+ assertEquals("latitude should match:", 60.0, cameraPosition.target.latitude, 0.1)
+ assertEquals("longitude should match:", 24.0, cameraPosition.target.longitude, 0.1)
+ assertEquals("bearing should match:", 30.0, cameraPosition.bearing, 0.1)
+ assertEquals("zoom should match", 5.6, cameraPosition.zoom, 0.1)
+ assertEquals("tilt should match:", 40.0, cameraPosition.tilt, 0.1)
+ }
+
+ @Test
+ @UiThreadTest
+ fun withPadding_cameraInvalidated_paddingPersisting() {
+ val initialCameraPosition = mapboxMap.cameraPosition
+ val initialPoint = mapboxMap.projection.toScreenLocation(initialCameraPosition.target)
+
+ val bottomPadding = mapView.height / 4
+ val leftPadding = mapView.width / 4
+ val padding = doubleArrayOf(leftPadding.toDouble(), 0.0, 0.0, bottomPadding.toDouble())
+ mapboxMap.moveCamera(CameraUpdateFactory.paddingTo(leftPadding.toDouble(), 0.0, 0.0, bottomPadding.toDouble()))
+
+ Assert.assertArrayEquals(intArrayOf(leftPadding, 0, 0, bottomPadding), mapboxMap.padding)
+
+ val resultingCameraPosition = mapboxMap.cameraPosition
+ assertEquals(initialCameraPosition.target, resultingCameraPosition.target)
+ assertEquals(
+ PointF(initialPoint.x + leftPadding / 2, initialPoint.y - bottomPadding / 2),
+ mapboxMap.projection.toScreenLocation(resultingCameraPosition.target)
+ )
+ Assert.assertArrayEquals(padding, resultingCameraPosition.padding, 0.0001)
+ }
+
+ @Test
+ @UiThreadTest
+ fun withLatLngPadding_cameraInvalidated_paddingPersisting() {
+ val expectedTarget = LatLng(2.0, 2.0)
+
+ val topPadding = mapView.height / 4
+ val rightPadding = mapView.width / 4
+ val padding = doubleArrayOf(0.0, topPadding.toDouble(), rightPadding.toDouble(), 0.0)
+ mapboxMap.moveCamera(CameraUpdateFactory.newLatLngPadding(expectedTarget, 0.0, topPadding.toDouble(), rightPadding.toDouble(), 0.0))
+
+ Assert.assertArrayEquals(intArrayOf(0, topPadding, rightPadding, 0), mapboxMap.padding)
+
+ val resultingCameraPosition = mapboxMap.cameraPosition
+ assertEquals(expectedTarget.latitude, resultingCameraPosition.target.latitude, 0.1)
+ assertEquals(expectedTarget.longitude, resultingCameraPosition.target.longitude, 0.1)
+
+ val centerLatLng = mapboxMap.projection.fromScreenLocation(PointF((mapView.width / 2).toFloat(), (mapView.height / 2).toFloat()))
+ assertTrue(centerLatLng.latitude > resultingCameraPosition.target.latitude)
+ assertTrue(centerLatLng.longitude > resultingCameraPosition.target.longitude)
+ Assert.assertArrayEquals(padding, resultingCameraPosition.padding, 0.0001)
}
} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapInstrumentationTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapInstrumentationTest.kt
deleted file mode 100644
index e93f54161e..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapInstrumentationTest.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.mapbox.mapboxsdk.maps
-
-import android.graphics.PointF
-import android.support.test.runner.AndroidJUnit4
-import com.mapbox.mapboxsdk.camera.CameraUpdateFactory
-import com.mapbox.mapboxsdk.geometry.LatLng
-import com.mapbox.mapboxsdk.testapp.activity.BaseTest
-import com.mapbox.mapboxsdk.testapp.activity.espresso.DeviceIndependentTestActivity
-import org.junit.Assert.assertArrayEquals
-import org.junit.Assert.assertEquals
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-class MapboxMapInstrumentationTest : BaseTest() {
-
- override fun getActivityClass(): Class<*> {
- return DeviceIndependentTestActivity::class.java
- }
-
- @Test
- fun setPadding_cameraInvalidated() {
- rule.runOnUiThread {
- mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 0.0), 10.0))
- val initialCameraPosition = mapboxMap.cameraPosition
- val initialPoint = mapboxMap.projection.toScreenLocation(initialCameraPosition.target)
-
- val bottomPadding = mapView.height / 4
- val leftPadding = mapView.width / 4
- mapboxMap.setPadding(leftPadding, 0, 0, bottomPadding)
-
- val resultingCameraPosition = mapboxMap.cameraPosition
- assertArrayEquals(intArrayOf(leftPadding, 0, 0, bottomPadding), mapboxMap.padding)
- assertEquals(initialCameraPosition, resultingCameraPosition)
- assertEquals(
- PointF(initialPoint.x + leftPadding / 2, initialPoint.y - bottomPadding / 2),
- mapboxMap.projection.toScreenLocation(resultingCameraPosition.target)
- )
- }
- }
-} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/NativeMapViewTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/NativeMapViewTest.kt
index d5834db553..b13bb6b796 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/NativeMapViewTest.kt
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/NativeMapViewTest.kt
@@ -15,6 +15,7 @@ import com.mapbox.mapboxsdk.style.layers.TransitionOptions
import com.mapbox.mapboxsdk.testapp.utils.TestConstants
import junit.framework.Assert.*
import org.junit.After
+import org.junit.Assert
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -30,6 +31,7 @@ class NativeMapViewTest : AppCenter() {
const val BEARING_TEST = 60.0
const val PITCH_TEST = 40.0
const val ZOOM_TEST = 16.0
+ val PADDING_TEST = doubleArrayOf(80.0, 150.0, 0.0, 0.0)
const val WIDTH = 500
const val HEIGHT = WIDTH
val LATLNG_TEST = LatLng(12.0, 34.0)
@@ -88,6 +90,18 @@ class NativeMapViewTest : AppCenter() {
@Test
@UiThreadTest
+ fun testLatLngPadding() {
+ val expected = LATLNG_TEST
+ nativeMapView.contentPadding = PADDING_TEST
+ nativeMapView.setLatLng(expected, 0)
+ val actual = nativeMapView.latLng
+ assertEquals("Latitude should match", expected.latitude, actual.latitude, DELTA)
+ assertEquals("Longitude should match", expected.longitude, actual.longitude, DELTA)
+ Assert.assertArrayEquals(PADDING_TEST, nativeMapView.cameraPosition.padding, DELTA)
+ }
+
+ @Test
+ @UiThreadTest
fun testLatLngDefault() {
val expected = LatLng()
val actual = nativeMapView.latLng
@@ -145,14 +159,18 @@ class NativeMapViewTest : AppCenter() {
.target(LATLNG_TEST)
.tilt(PITCH_TEST)
.zoom(ZOOM_TEST)
+ .padding(PADDING_TEST)
.build()
- nativeMapView.jumpTo(LATLNG_TEST, ZOOM_TEST, PITCH_TEST, BEARING_TEST)
+ // verify that the lazily set padding is ignored when a value is provided with the camera
+ nativeMapView.contentPadding = doubleArrayOf(1.0, 2.0, 3.0, 4.0)
+ nativeMapView.jumpTo(LATLNG_TEST, ZOOM_TEST, PITCH_TEST, BEARING_TEST, PADDING_TEST)
val actual = nativeMapView.cameraPosition
assertEquals("Latitude should match", expected.target.latitude, actual.target.latitude, DELTA)
assertEquals("Longitude should match", expected.target.longitude, actual.target.longitude, DELTA)
assertEquals("Bearing should match", expected.bearing, actual.bearing, DELTA)
assertEquals("Pitch should match", expected.tilt, actual.tilt, DELTA)
assertEquals("Zoom should match", expected.zoom, actual.zoom, DELTA)
+ Assert.assertArrayEquals(expected.padding, actual.padding, DELTA)
}
@Test
@@ -206,7 +224,7 @@ class NativeMapViewTest : AppCenter() {
@Test
@UiThreadTest
fun testSetContentPadding() {
- val expected = floatArrayOf(1.0f, 2.0f, 3.0f, 4.0f)
+ val expected = doubleArrayOf(1.0, 2.0, 3.0, 4.0)
nativeMapView.contentPadding = expected
val actual = nativeMapView.contentPadding
assertEquals("Left should match", expected[0], actual[0])
@@ -258,14 +276,18 @@ class NativeMapViewTest : AppCenter() {
.tilt(30.0)
.target(LatLng(12.0, 14.0))
.bearing(20.0)
+ .padding(PADDING_TEST)
.build()
- nativeMapView.flyTo(expected.target, expected.zoom, expected.bearing, expected.tilt, 0)
+ // verify that the lazily set padding is ignored when a value is provided with the camera
+ nativeMapView.contentPadding = doubleArrayOf(1.0, 2.0, 3.0, 4.0)
+ nativeMapView.flyTo(expected.target, expected.zoom, expected.bearing, expected.tilt, PADDING_TEST, 0)
val actual = nativeMapView.cameraPosition
assertEquals("Bearing should match", expected.bearing, actual.bearing, TestConstants.BEARING_DELTA)
assertEquals("Latitude should match", expected.target.latitude, actual.target.latitude, TestConstants.LAT_LNG_DELTA)
assertEquals("Longitude should match", expected.target.longitude, actual.target.longitude, TestConstants.LAT_LNG_DELTA)
assertEquals("Tilt should match", expected.tilt, actual.tilt, TestConstants.TILT_DELTA)
assertEquals("Zoom should match", expected.zoom, actual.zoom, TestConstants.ZOOM_DELTA)
+ Assert.assertArrayEquals(expected.padding, actual.padding, DELTA)
}
@Test
@@ -276,14 +298,18 @@ class NativeMapViewTest : AppCenter() {
.tilt(30.0)
.target(LatLng(12.0, 14.0))
.bearing(20.0)
+ .padding(PADDING_TEST)
.build()
- nativeMapView.easeTo(expected.target, expected.zoom, expected.bearing, expected.tilt, 0, false)
+ // verify that the lazily set padding is ignored when a value is provided with the camera
+ nativeMapView.contentPadding = doubleArrayOf(1.0, 2.0, 3.0, 4.0)
+ nativeMapView.easeTo(expected.target, expected.zoom, expected.bearing, expected.tilt, PADDING_TEST, 0, false)
val actual = nativeMapView.cameraPosition
assertEquals("Bearing should match", expected.bearing, actual.bearing, TestConstants.BEARING_DELTA)
assertEquals("Latitude should match", expected.target.latitude, actual.target.latitude, TestConstants.LAT_LNG_DELTA)
assertEquals("Longitude should match", expected.target.longitude, actual.target.longitude, TestConstants.LAT_LNG_DELTA)
assertEquals("Tilt should match", expected.tilt, actual.tilt, TestConstants.TILT_DELTA)
assertEquals("Zoom should match", expected.zoom, actual.zoom, TestConstants.ZOOM_DELTA)
+ Assert.assertArrayEquals(expected.padding, actual.padding, DELTA)
}
@Test
@@ -294,8 +320,9 @@ class NativeMapViewTest : AppCenter() {
.tilt(0.0)
.target(LatLng(0.0, 0.0))
.bearing(0.0)
+ .padding(PADDING_TEST)
.build()
- nativeMapView.jumpTo(LatLng(1.0, 2.0), 12.0, 23.0, 1.0)
+ nativeMapView.jumpTo(LatLng(1.0, 2.0), 12.0, 23.0, 1.0, PADDING_TEST)
nativeMapView.resetPosition()
val actual = nativeMapView.cameraPosition
assertEquals("Bearing should match", expected.bearing, actual.bearing, TestConstants.BEARING_DELTA)
@@ -303,6 +330,7 @@ class NativeMapViewTest : AppCenter() {
assertEquals("Longitude should match", expected.target.longitude, actual.target.longitude, TestConstants.LAT_LNG_DELTA)
assertEquals("Tilt should match", expected.tilt, actual.tilt, TestConstants.TILT_DELTA)
assertEquals("Zoom should match", expected.zoom, actual.zoom, TestConstants.ZOOM_DELTA)
+ Assert.assertArrayEquals(expected.padding, actual.padding, DELTA)
}
@Test
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 14722ea37c..12dff5d452 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
@@ -7,7 +7,8 @@ import com.mapbox.mapboxsdk.geometry.LatLng
import com.mapbox.mapboxsdk.testapp.action.MapboxMapAction.invoke
import com.mapbox.mapboxsdk.testapp.activity.BaseTest
import com.mapbox.mapboxsdk.testapp.activity.espresso.PixelTestActivity
-import org.junit.Assert.*
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
import org.junit.Test
class VisibleRegionTest : BaseTest() {
@@ -68,7 +69,7 @@ class VisibleRegionTest : BaseTest() {
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
- assertEquals(1, filtered.size)
+ assertTrue(filtered.size == 1)
assertTrue(filtered.contains(mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)))
}
}
@@ -87,18 +88,14 @@ class VisibleRegionTest : BaseTest() {
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width / 4f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width * 3f / 4f, 0f)
+ mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
mapboxMap.setPadding(mapView.width / 4, 0, 0, 0)
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
- val filtered = latLngs.filter {
- visibleRegion.latLngBounds.contains(it)
- }
- assertEquals(5, filtered.size)
+ val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
+ assertTrue(filtered.size == 6)
assertFalse(filtered.contains(mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f)))
}
}
@@ -117,16 +114,14 @@ class VisibleRegionTest : BaseTest() {
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 4f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height * 3f / 4f)
+ mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
mapboxMap.setPadding(0, mapView.height / 4, 0, 0)
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
- assertEquals(5, filtered.size)
+ assertTrue(filtered.size == 6)
assertFalse(filtered.contains(mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f)))
}
}
@@ -145,16 +140,14 @@ class VisibleRegionTest : BaseTest() {
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width / 4f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width * 3f / 4f, 0f)
+ mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
mapboxMap.setPadding(0, 0, mapView.width / 4, 0)
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
- assertEquals(5, filtered.size)
+ assertTrue(filtered.size == 6)
assertFalse(filtered.contains(mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f)))
}
}
@@ -173,16 +166,14 @@ class VisibleRegionTest : BaseTest() {
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 4f),
- mapboxMap.getLatLngFromScreenCoords(0f, mapView.height * 3f / 4f)
+ mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
mapboxMap.setPadding(0, 0, 0, mapView.height / 4)
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
- assertEquals(5, filtered.size)
+ assertTrue(filtered.size == 6)
assertFalse(filtered.contains(mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat())))
}
}
@@ -236,7 +227,7 @@ class VisibleRegionTest : BaseTest() {
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
- assertEquals(1, filtered.size)
+ assertTrue(filtered.size == 1)
assertTrue(filtered.contains(mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)))
}
}
@@ -258,17 +249,14 @@ class VisibleRegionTest : BaseTest() {
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width / 4f, 0f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width * 3f / 4f, mapView.height / 2f)
- .also { it.longitude += 360 }
+ mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
mapboxMap.setPadding(mapView.width / 4, 0, 0, 0)
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
- assertEquals(5, filtered.size)
+ assertTrue(filtered.size == 6)
assertFalse(filtered.contains(mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f)))
}
}
@@ -278,6 +266,7 @@ class VisibleRegionTest : BaseTest() {
validateTestSetup()
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),
@@ -290,17 +279,14 @@ class VisibleRegionTest : BaseTest() {
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 4f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height * 3f / 4f)
- .also { it.longitude += 360 }
+ mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
mapboxMap.setPadding(0, mapView.height / 4, 0, 0)
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
- assertEquals(5, filtered.size)
+ assertTrue(filtered.size == 6)
assertFalse(filtered.contains(mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f)))
}
}
@@ -322,17 +308,14 @@ class VisibleRegionTest : BaseTest() {
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width / 4f, 0f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width * 3f / 4f, mapView.height / 2f)
- .also { it.longitude += 360 }
+ mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
mapboxMap.setPadding(0, 0, mapView.width / 4, 0)
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
- assertEquals(5, filtered.size)
+ assertTrue(filtered.size == 6)
assertFalse(filtered.contains(mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f)))
}
}
@@ -354,17 +337,14 @@ class VisibleRegionTest : BaseTest() {
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 4f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height * 3f / 4f)
- .also { it.longitude += 360 }
+ mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
mapboxMap.setPadding(0, 0, 0, mapView.height / 4)
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
- assertEquals(5, filtered.size)
+ assertTrue(filtered.size == 6)
assertFalse(filtered.contains(mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat())))
}
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/offline/OfflineDownloadTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/offline/OfflineDownloadTest.kt
index 93b59d6e33..6b5bc63adb 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/offline/OfflineDownloadTest.kt
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/offline/OfflineDownloadTest.kt
@@ -26,42 +26,39 @@ class OfflineDownloadTest : OfflineRegion.OfflineRegionObserver {
private val countDownLatch = CountDownLatch(1)
private lateinit var offlineRegion: OfflineRegion
- @Test(timeout = 30000)
+ @Test(timeout = 60000)
fun offlineDownload() {
rule.runOnUiThreadActivity {
OfflineManager.getInstance(rule.activity).createOfflineRegion(
createTestRegionDefinition(),
ByteArray(0),
object : OfflineManager.CreateOfflineRegionCallback {
- override fun onCreate(region: OfflineRegion?) {
- region?.let {
- offlineRegion = it
- offlineRegion.setDownloadState(OfflineRegion.STATE_ACTIVE)
- offlineRegion.setObserver(this@OfflineDownloadTest)
- }
+ override fun onCreate(region: OfflineRegion) {
+ offlineRegion = region
+ offlineRegion.setDownloadState(OfflineRegion.STATE_ACTIVE)
+ offlineRegion.setObserver(this@OfflineDownloadTest)
}
- override fun onError(error: String?) {
+ override fun onError(error: String) {
Logger.e(TAG, "Error while creating offline region: $error")
}
})
}
- if (!countDownLatch.await(30, TimeUnit.SECONDS)) {
+ if (!countDownLatch.await(60, TimeUnit.SECONDS)) {
throw TimeoutException()
}
}
- override fun onStatusChanged(status: OfflineRegionStatus?) {
- status?.let {
- if (it.isComplete) {
- offlineRegion.setDownloadState(OfflineRegion.STATE_INACTIVE)
- countDownLatch.countDown()
- }
+ override fun onStatusChanged(status: OfflineRegionStatus) {
+ Logger.i(TAG, "Download percentage ${100.0 * status.completedResourceCount / status.requiredResourceCount}")
+ if (status.isComplete) {
+ offlineRegion.setDownloadState(OfflineRegion.STATE_INACTIVE)
+ countDownLatch.countDown()
}
}
- override fun onError(error: OfflineRegionError?) {
+ override fun onError(error: OfflineRegionError) {
Logger.e(TAG, "Error while downloading offline region: $error")
}
@@ -69,7 +66,7 @@ class OfflineDownloadTest : OfflineRegion.OfflineRegionObserver {
Logger.e(TAG, "Tile count limited exceeded: $limit")
}
- fun createTestRegionDefinition(): OfflineRegionDefinition {
+ private fun createTestRegionDefinition(): OfflineRegionDefinition {
return OfflineGeometryRegionDefinition(
Style.MAPBOX_STREETS,
Point.fromLngLat(50.847857, 4.360137),
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 45dac23611..b6c16c8147 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
@@ -4,6 +4,7 @@ import android.content.Context;
import android.support.annotation.CallSuper;
import android.support.annotation.UiThread;
import android.support.test.rule.ActivityTestRule;
+import android.support.test.rule.GrantPermissionRule;
import com.mapbox.mapboxsdk.AppCenter;
import com.mapbox.mapboxsdk.Mapbox;
@@ -35,6 +36,10 @@ public abstract class BaseTest extends AppCenter {
@Rule
public TestName testName = new TestName();
+ @Rule
+ public GrantPermissionRule grantLocationPermissionRule = GrantPermissionRule
+ .grant(android.Manifest.permission.ACCESS_FINE_LOCATION);
+
protected MapboxMap mapboxMap;
protected MapView mapView;
private final CountDownLatch latch = new CountDownLatch(1);
@@ -75,7 +80,12 @@ public abstract class BaseTest extends AppCenter {
try {
rule.runOnUiThread(() -> {
mapView = rule.getActivity().findViewById(R.id.mapView);
- mapView.getMapAsync(this::initMap);
+ if (mapView != null) {
+ mapView.getMapAsync(this::initMap);
+ } else {
+ Timber.w("Skipping map load test since mapView is not found.");
+ latch.countDown();
+ }
});
} catch (Throwable throwable) {
throwable.printStackTrace();
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraAnimateTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraAnimateTest.java
index 625e37798f..69cf1264bf 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraAnimateTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraAnimateTest.java
@@ -1,297 +1,11 @@
package com.mapbox.mapboxsdk.testapp.camera;
-import android.support.test.espresso.Espresso;
-import android.support.test.espresso.IdlingRegistry;
-import android.support.test.espresso.idling.CountingIdlingResource;
-
-import com.mapbox.mapboxsdk.camera.CameraPosition;
-import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
-import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.geometry.LatLngBounds;
+import com.mapbox.mapboxsdk.camera.CameraUpdate;
import com.mapbox.mapboxsdk.maps.MapboxMap;
-import com.mapbox.mapboxsdk.testapp.activity.BaseTest;
-import com.mapbox.mapboxsdk.testapp.activity.espresso.DeviceIndependentTestActivity;
-import com.mapbox.mapboxsdk.testapp.utils.TestConstants;
-
-import org.junit.Test;
-
-import static com.mapbox.mapboxsdk.testapp.action.MapboxMapAction.invoke;
-import static org.junit.Assert.assertEquals;
-
-public class CameraAnimateTest extends BaseTest {
-
- private final CountingIdlingResource animationIdlingResource =
- new CountingIdlingResource("animation_idling_resource");
-
- @Override
- protected Class getActivityClass() {
- return DeviceIndependentTestActivity.class;
- }
+public class CameraAnimateTest extends CameraTest {
@Override
- public void beforeTest() {
- super.beforeTest();
- IdlingRegistry.getInstance().register(animationIdlingResource);
- }
-
- @Test
- public void testAnimateToCameraPositionTarget() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- float zoom = 1.0f;
- LatLng moveTarget = new LatLng(1, 1);
- CameraPosition initialPosition = new CameraPosition.Builder().target(
- new LatLng()).zoom(zoom).bearing(0).tilt(0).build();
- CameraPosition cameraPosition = mapboxMap.getCameraPosition();
- assertEquals("Default camera position should match default", cameraPosition, initialPosition);
-
- animationIdlingResource.increment();
- mapboxMap.animateCamera(CameraUpdateFactory.newLatLng(moveTarget), new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, moveTarget, zoom, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, moveTarget, zoom, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Test
- public void testAnimateToCameraPositionTargetZoom() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- final float moveZoom = 15.5f;
- final LatLng moveTarget = new LatLng(1.0000000001, 1.0000000003);
-
- animationIdlingResource.increment();
- mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(moveTarget, moveZoom), new MapboxMap
- .CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, moveTarget, moveZoom, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, moveTarget, moveZoom, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Test
- public void testAnimateToCameraPosition() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- final LatLng moveTarget = new LatLng(1.0000000001, 1.0000000003);
- final float moveZoom = 15.5f;
- final float moveTilt = 45.5f;
- final float moveBearing = 12.5f;
-
- animationIdlingResource.increment();
- mapboxMap.animateCamera(CameraUpdateFactory.newCameraPosition(
- new CameraPosition.Builder()
- .target(moveTarget)
- .zoom(moveZoom)
- .tilt(moveTilt)
- .bearing(moveBearing)
- .build()),
- new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, moveTarget, moveZoom, moveBearing, moveTilt);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, moveTarget, moveZoom, moveBearing, moveTilt);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Test
- public void testAnimateToBounds() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- final LatLng centerBounds = new LatLng(1, 1);
- LatLng cornerOne = new LatLng();
- LatLng cornerTwo = new LatLng(2, 2);
- final LatLngBounds.Builder builder = new LatLngBounds.Builder();
- builder.include(cornerOne);
- builder.include(cornerTwo);
-
- animationIdlingResource.increment();
- mapboxMap.animateCamera(CameraUpdateFactory.newLatLngBounds(builder.build(), 0), new MapboxMap
- .CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, centerBounds, mapboxMap.getCameraPosition().zoom, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, centerBounds, mapboxMap.getCameraPosition().zoom, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
+ void executeCameraMovement(CameraUpdate cameraUpdate, MapboxMap.CancelableCallback callback) {
+ mapboxMap.animateCamera(cameraUpdate, callback);
}
-
- @Test
- public void testAnimateToZoomIn() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- float zoom = 1.0f;
-
- animationIdlingResource.increment();
- mapboxMap.animateCamera(CameraUpdateFactory.zoomIn(), new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom + 1, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom + 1, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Test
- public void testAnimateToZoomOut() {
- validateTestSetup();
- float zoom = 10.0f;
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- animationIdlingResource.increment();
- mapboxMap.animateCamera(
- CameraUpdateFactory.newLatLngZoom(new LatLng(), zoom),
- new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- invoke(mapboxMap, ((uiController, mapboxMap1) -> {
- animationIdlingResource.increment();
- mapboxMap.animateCamera(CameraUpdateFactory.zoomOut(), new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom - 1, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom - 1, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- }));
-
- Espresso.onIdle();
- }
-
- @Test
- public void testAnimateToZoomBy() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- float zoom = 1.0f;
- final float zoomBy = 2.45f;
-
- animationIdlingResource.increment();
- mapboxMap.animateCamera(CameraUpdateFactory.zoomBy(zoomBy), new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom + zoomBy, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom + zoomBy, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Test
- public void testAnimateToZoomTo() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- final float zoomTo = 2.45f;
-
- animationIdlingResource.increment();
- mapboxMap.animateCamera(CameraUpdateFactory.zoomTo(zoomTo), new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoomTo, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoomTo, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Override
- public void afterTest() {
- super.afterTest();
- IdlingRegistry.getInstance().unregister(animationIdlingResource);
- }
-
- private void verifyCameraPosition(MapboxMap mapboxMap, LatLng moveTarget, double moveZoom, double moveBearing,
- double moveTilt) {
- CameraPosition cameraPosition = mapboxMap.getCameraPosition();
- assertEquals("Moved camera position latitude should match", cameraPosition.target.getLatitude(),
- moveTarget.getLatitude(), TestConstants.LAT_LNG_DELTA);
- assertEquals("Moved camera position longitude should match", cameraPosition.target.getLongitude(),
- moveTarget.getLongitude(), TestConstants.LAT_LNG_DELTA);
- assertEquals("Moved zoom should match", cameraPosition.zoom, moveZoom, TestConstants.ZOOM_DELTA);
- assertEquals("Moved zoom should match", cameraPosition.tilt, moveTilt, TestConstants.TILT_DELTA);
- assertEquals("Moved bearing should match", cameraPosition.bearing, moveBearing, TestConstants.BEARING_DELTA);
- }
-}
-
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraEaseTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraEaseTest.java
index ae81dc1302..be3b18ef8b 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraEaseTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraEaseTest.java
@@ -1,294 +1,12 @@
package com.mapbox.mapboxsdk.testapp.camera;
-import android.support.test.espresso.Espresso;
-import android.support.test.espresso.IdlingRegistry;
-import android.support.test.espresso.idling.CountingIdlingResource;
-
-import com.mapbox.mapboxsdk.camera.CameraPosition;
-import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
-import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.geometry.LatLngBounds;
+import com.mapbox.mapboxsdk.camera.CameraUpdate;
import com.mapbox.mapboxsdk.maps.MapboxMap;
-import com.mapbox.mapboxsdk.testapp.activity.BaseTest;
-import com.mapbox.mapboxsdk.testapp.activity.espresso.DeviceIndependentTestActivity;
-import com.mapbox.mapboxsdk.testapp.utils.TestConstants;
-
-import org.junit.Test;
-
-import static com.mapbox.mapboxsdk.testapp.action.MapboxMapAction.invoke;
-import static org.junit.Assert.assertEquals;
-
-public class CameraEaseTest extends BaseTest {
- private final CountingIdlingResource animationIdlingResource =
- new CountingIdlingResource("animation_idling_resource");
-
- @Override
- protected Class getActivityClass() {
- return DeviceIndependentTestActivity.class;
- }
+public class CameraEaseTest extends CameraTest {
@Override
- public void beforeTest() {
- super.beforeTest();
- IdlingRegistry.getInstance().register(animationIdlingResource);
- }
-
- @Test
- public void testEaseToCameraPositionTarget() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- float zoom = 1.0f;
- LatLng moveTarget = new LatLng(1, 1);
- CameraPosition initialPosition = new CameraPosition.Builder().target(
- new LatLng()).zoom(zoom).bearing(0).tilt(0).build();
- CameraPosition cameraPosition = mapboxMap.getCameraPosition();
- assertEquals("Default camera position should match default", cameraPosition, initialPosition);
-
- animationIdlingResource.increment();
- mapboxMap.easeCamera(CameraUpdateFactory.newLatLng(moveTarget), new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, moveTarget, zoom, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, moveTarget, zoom, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Test
- public void testEaseToCameraPositionTargetZoom() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- final float moveZoom = 15.5f;
- final LatLng moveTarget = new LatLng(1.0000000001, 1.0000000003);
-
- animationIdlingResource.increment();
- mapboxMap.easeCamera(CameraUpdateFactory.newLatLngZoom(moveTarget, moveZoom), new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, moveTarget, moveZoom, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, moveTarget, moveZoom, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Test
- public void testEaseToCameraPosition() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- final LatLng moveTarget = new LatLng(1.0000000001, 1.0000000003);
- final float moveZoom = 15.5f;
- final float moveTilt = 45.5f;
- final float moveBearing = 12.5f;
-
- animationIdlingResource.increment();
- mapboxMap.easeCamera(CameraUpdateFactory.newCameraPosition(
- new CameraPosition.Builder()
- .target(moveTarget)
- .zoom(moveZoom)
- .tilt(moveTilt)
- .bearing(moveBearing)
- .build()),
- new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, moveTarget, moveZoom, moveBearing, moveTilt);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, moveTarget, moveZoom, moveBearing, moveTilt);
- animationIdlingResource.decrement();
- }
- }
- );
- });
-
- Espresso.onIdle();
- }
-
- @Test
- public void testEaseToBounds() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- final LatLng centerBounds = new LatLng(1, 1);
- LatLng cornerOne = new LatLng();
- LatLng cornerTwo = new LatLng(2, 2);
- final LatLngBounds.Builder builder = new LatLngBounds.Builder();
- builder.include(cornerOne);
- builder.include(cornerTwo);
-
- animationIdlingResource.increment();
- mapboxMap.easeCamera(CameraUpdateFactory.newLatLngBounds(builder.build(), 0),
- new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, centerBounds, mapboxMap.getCameraPosition().zoom, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, centerBounds, mapboxMap.getCameraPosition().zoom, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Test
- public void testEaseToZoomIn() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- float zoom = 1.0f;
-
- animationIdlingResource.increment();
- mapboxMap.easeCamera(CameraUpdateFactory.zoomIn(), new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom + 1, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom + 1, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Test
- public void testEaseToZoomOut() {
- float zoom = 10.0f;
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- animationIdlingResource.increment();
- mapboxMap.easeCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(), zoom), new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- animationIdlingResource.increment();
- mapboxMap.easeCamera(CameraUpdateFactory.zoomOut(), new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom - 1, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom - 1, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Test
- public void testEaseToZoomBy() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- float zoom = 1.0f;
- final float zoomBy = 2.45f;
-
- animationIdlingResource.increment();
- mapboxMap.easeCamera(CameraUpdateFactory.zoomBy(zoomBy), new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom + zoomBy, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom + zoomBy, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Test
- public void testEaseToZoomTo() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- final float zoomTo = 2.45f;
-
- animationIdlingResource.increment();
- mapboxMap.easeCamera(CameraUpdateFactory.zoomTo(zoomTo), new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoomTo, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoomTo, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Override
- public void afterTest() {
- super.afterTest();
- IdlingRegistry.getInstance().unregister(animationIdlingResource);
- }
-
- private void verifyCameraPosition(MapboxMap mapboxMap, LatLng moveTarget, double moveZoom, double moveBearing,
- double moveTilt) {
- CameraPosition cameraPosition = mapboxMap.getCameraPosition();
- assertEquals("Moved camera position latitude should match", cameraPosition.target.getLatitude(),
- moveTarget.getLatitude(), TestConstants.LAT_LNG_DELTA);
- assertEquals("Moved camera position longitude should match", cameraPosition.target.getLongitude(),
- moveTarget.getLongitude(), TestConstants.LAT_LNG_DELTA);
- assertEquals("Moved zoom should match", cameraPosition.zoom, moveZoom, TestConstants.ZOOM_DELTA);
- assertEquals("Moved zoom should match", cameraPosition.tilt, moveTilt, TestConstants.TILT_DELTA);
- assertEquals("Moved bearing should match", cameraPosition.bearing, moveBearing, TestConstants.BEARING_DELTA);
+ void executeCameraMovement(CameraUpdate cameraUpdate, MapboxMap.CancelableCallback callback) {
+ mapboxMap.easeCamera(cameraUpdate, callback);
}
} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraMoveTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraMoveTest.java
index f8aa43d52d..2cd7b6ffe3 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraMoveTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraMoveTest.java
@@ -1,294 +1,12 @@
package com.mapbox.mapboxsdk.testapp.camera;
-import android.support.test.espresso.Espresso;
-import android.support.test.espresso.IdlingRegistry;
-import android.support.test.espresso.idling.CountingIdlingResource;
-
-import com.mapbox.mapboxsdk.camera.CameraPosition;
-import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
-import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.geometry.LatLngBounds;
+import com.mapbox.mapboxsdk.camera.CameraUpdate;
import com.mapbox.mapboxsdk.maps.MapboxMap;
-import com.mapbox.mapboxsdk.testapp.activity.BaseTest;
-import com.mapbox.mapboxsdk.testapp.activity.espresso.DeviceIndependentTestActivity;
-import com.mapbox.mapboxsdk.testapp.utils.TestConstants;
-
-import org.junit.Test;
-
-import static com.mapbox.mapboxsdk.testapp.action.MapboxMapAction.invoke;
-import static org.junit.Assert.assertEquals;
-
-public class CameraMoveTest extends BaseTest {
-
- private final CountingIdlingResource animationIdlingResource =
- new CountingIdlingResource("animation_idling_resource");
-
- @Override
- protected Class getActivityClass() {
- return DeviceIndependentTestActivity.class;
- }
-
- @Override
- public void beforeTest() {
- super.beforeTest();
- IdlingRegistry.getInstance().register(animationIdlingResource);
- }
-
- @Test
- public void testMoveToCameraPositionTarget() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- float zoom = 1.0f;
- LatLng moveTarget = new LatLng(1, 1);
- CameraPosition initialPosition = new CameraPosition.Builder().target(
- new LatLng()).zoom(zoom).bearing(0).tilt(0).build();
- CameraPosition cameraPosition = mapboxMap.getCameraPosition();
- assertEquals("Default camera position should match default", cameraPosition, initialPosition);
-
- animationIdlingResource.increment();
- mapboxMap.moveCamera(CameraUpdateFactory.newLatLng(moveTarget), new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, moveTarget, zoom, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, moveTarget, zoom, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Test
- public void testMoveToCameraPositionTargetZoom() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- final float moveZoom = 15.5f;
- final LatLng moveTarget = new LatLng(1.0000000001, 1.0000000003);
-
- animationIdlingResource.increment();
- mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(moveTarget, moveZoom), new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, moveTarget, moveZoom, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, moveTarget, moveZoom, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Test
- public void testMoveToCameraPosition() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- final LatLng moveTarget = new LatLng(1.0000000001, 1.0000000003);
- final float moveZoom = 15.5f;
- final float moveTilt = 45.5f;
- final float moveBearing = 12.5f;
-
- animationIdlingResource.increment();
- mapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition(
- new CameraPosition.Builder()
- .target(moveTarget)
- .zoom(moveZoom)
- .tilt(moveTilt)
- .bearing(moveBearing)
- .build()),
- new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, moveTarget, moveZoom, moveBearing, moveTilt);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, moveTarget, moveZoom, moveBearing, moveTilt);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Test
- public void testMoveToBounds() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- final LatLng centerBounds = new LatLng(1, 1);
- LatLng cornerOne = new LatLng();
- LatLng cornerTwo = new LatLng(2, 2);
- final LatLngBounds.Builder builder = new LatLngBounds.Builder();
- builder.include(cornerOne);
- builder.include(cornerTwo);
-
- animationIdlingResource.increment();
- mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(builder.build(), 0),
- new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, centerBounds, mapboxMap.getCameraPosition().zoom, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, centerBounds, mapboxMap.getCameraPosition().zoom, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Test
- public void testMoveToZoomIn() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- float zoom = 1.0f;
-
- animationIdlingResource.increment();
- mapboxMap.moveCamera(CameraUpdateFactory.zoomIn(), new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom + 1, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom + 1, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Test
- public void testMoveToZoomOut() {
- float zoom = 10.0f;
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- animationIdlingResource.increment();
- mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(), zoom), new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- animationIdlingResource.increment();
- mapboxMap.moveCamera(CameraUpdateFactory.zoomOut(), new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom - 1, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom - 1, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Test
- public void testMoveToZoomBy() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- float zoom = 1.0f;
- final float zoomBy = 2.45f;
-
- animationIdlingResource.increment();
- mapboxMap.moveCamera(CameraUpdateFactory.zoomBy(zoomBy), new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom + zoomBy, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom + zoomBy, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Test
- public void testMoveToZoomTo() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- final float zoomTo = 2.45f;
-
- animationIdlingResource.increment();
- mapboxMap.moveCamera(CameraUpdateFactory.zoomTo(zoomTo), new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoomTo, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoomTo, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
+public class CameraMoveTest extends CameraTest {
@Override
- public void afterTest() {
- super.afterTest();
- IdlingRegistry.getInstance().unregister(animationIdlingResource);
- }
-
- private void verifyCameraPosition(MapboxMap mapboxMap, LatLng moveTarget, double moveZoom, double moveBearing,
- double moveTilt) {
- CameraPosition cameraPosition = mapboxMap.getCameraPosition();
- assertEquals("Moved camera position latitude should match", cameraPosition.target.getLatitude(),
- moveTarget.getLatitude(), TestConstants.LAT_LNG_DELTA);
- assertEquals("Moved camera position longitude should match", cameraPosition.target.getLongitude(),
- moveTarget.getLongitude(), TestConstants.LAT_LNG_DELTA);
- assertEquals("Moved zoom should match", cameraPosition.zoom, moveZoom, TestConstants.ZOOM_DELTA);
- assertEquals("Moved zoom should match", cameraPosition.tilt, moveTilt, TestConstants.TILT_DELTA);
- assertEquals("Moved bearing should match", cameraPosition.bearing, moveBearing, TestConstants.BEARING_DELTA);
+ void executeCameraMovement(CameraUpdate cameraUpdate, MapboxMap.CancelableCallback callback) {
+ mapboxMap.moveCamera(cameraUpdate, callback);
}
-}
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraTest.java
new file mode 100644
index 0000000000..ebce9aaec5
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraTest.java
@@ -0,0 +1,307 @@
+package com.mapbox.mapboxsdk.testapp.camera;
+
+import com.mapbox.mapboxsdk.camera.CameraPosition;
+import com.mapbox.mapboxsdk.camera.CameraUpdate;
+import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
+import com.mapbox.mapboxsdk.geometry.LatLng;
+import com.mapbox.mapboxsdk.geometry.LatLngBounds;
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.testapp.activity.BaseTest;
+import com.mapbox.mapboxsdk.testapp.activity.espresso.DeviceIndependentTestActivity;
+import com.mapbox.mapboxsdk.testapp.utils.TestConstants;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import static com.mapbox.mapboxsdk.testapp.action.MapboxMapAction.invoke;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+public abstract class CameraTest extends BaseTest {
+
+ private CountDownLatch latch;
+
+ @Override
+ protected Class getActivityClass() {
+ return DeviceIndependentTestActivity.class;
+ }
+
+ @Override
+ public void beforeTest() {
+ super.beforeTest();
+ latch = new CountDownLatch(1);
+ }
+
+ @Test
+ public void testToCameraPositionTarget() throws InterruptedException {
+ validateTestSetup();
+ invoke(mapboxMap, (uiController, mapboxMap) -> {
+ float zoom = 1.0f;
+ LatLng moveTarget = new LatLng(1, 1);
+ CameraPosition initialPosition = new CameraPosition.Builder().target(
+ new LatLng()).zoom(zoom).bearing(0).tilt(0).padding(new double[4]).build();
+ CameraPosition cameraPosition = mapboxMap.getCameraPosition();
+ assertEquals("Default camera position should match default", cameraPosition, initialPosition);
+
+ executeCameraMovement(CameraUpdateFactory.newLatLng(moveTarget), new MapboxMap.CancelableCallback() {
+ @Override
+ public void onCancel() {
+ verifyCameraPosition(mapboxMap, moveTarget, zoom, 0, 0, new double[4]);
+ latch.countDown();
+ }
+
+ @Override
+ public void onFinish() {
+ verifyCameraPosition(mapboxMap, moveTarget, zoom, 0, 0, new double[4]);
+ latch.countDown();
+ }
+ });
+ });
+
+ if (!latch.await(10, TimeUnit.SECONDS)) {
+ Assert.fail("timeout");
+ }
+ }
+
+ @Test
+ public void testToCameraPositionTargetZoom() throws InterruptedException {
+ validateTestSetup();
+ invoke(mapboxMap, (uiController, mapboxMap) -> {
+ final float moveZoom = 15.5f;
+ final LatLng moveTarget = new LatLng(1.0000000001, 1.0000000003);
+
+ executeCameraMovement(CameraUpdateFactory.newLatLngZoom(moveTarget, moveZoom),
+ new MapboxMap.CancelableCallback() {
+ @Override
+ public void onCancel() {
+ verifyCameraPosition(mapboxMap, moveTarget, moveZoom, 0, 0, new double[4]);
+ latch.countDown();
+ }
+
+ @Override
+ public void onFinish() {
+ verifyCameraPosition(mapboxMap, moveTarget, moveZoom, 0, 0, new double[4]);
+ latch.countDown();
+ }
+ });
+ });
+
+ if (!latch.await(10, TimeUnit.SECONDS)) {
+ Assert.fail("timeout");
+ }
+ }
+
+ @Test
+ public void testToCameraPosition() throws InterruptedException {
+ validateTestSetup();
+ invoke(mapboxMap, (uiController, mapboxMap) -> {
+ final LatLng moveTarget = new LatLng(1.0000000001, 1.0000000003);
+ final float moveZoom = 15.5f;
+ final float moveTilt = 45.5f;
+ final float moveBearing = 12.5f;
+ final double[] movePadding = new double[] {0, 500, 350, 1};
+
+ executeCameraMovement(CameraUpdateFactory.newCameraPosition(
+ new CameraPosition.Builder()
+ .target(moveTarget)
+ .zoom(moveZoom)
+ .tilt(moveTilt)
+ .bearing(moveBearing)
+ .padding(movePadding)
+ .build()),
+ new MapboxMap.CancelableCallback() {
+ @Override
+ public void onCancel() {
+ verifyCameraPosition(mapboxMap, moveTarget, moveZoom, moveBearing, moveTilt, movePadding);
+ latch.countDown();
+ }
+
+ @Override
+ public void onFinish() {
+ verifyCameraPosition(mapboxMap, moveTarget, moveZoom, moveBearing, moveTilt, movePadding);
+ latch.countDown();
+ }
+ });
+ });
+
+ if (!latch.await(10, TimeUnit.SECONDS)) {
+ Assert.fail("timeout");
+ }
+ }
+
+ @Test
+ public void testToBounds() throws InterruptedException {
+ validateTestSetup();
+ invoke(mapboxMap, (uiController, mapboxMap) -> {
+ final LatLng centerBounds = new LatLng(1, 1);
+ LatLng cornerOne = new LatLng();
+ LatLng cornerTwo = new LatLng(2, 2);
+ final LatLngBounds.Builder builder = new LatLngBounds.Builder();
+ builder.include(cornerOne);
+ builder.include(cornerTwo);
+
+ executeCameraMovement(CameraUpdateFactory.newLatLngBounds(builder.build(), 0),
+ new MapboxMap.CancelableCallback() {
+ @Override
+ public void onCancel() {
+ verifyCameraPosition(mapboxMap, centerBounds, mapboxMap.getCameraPosition().zoom, 0, 0, new double[4]);
+ latch.countDown();
+ }
+
+ @Override
+ public void onFinish() {
+ verifyCameraPosition(mapboxMap, centerBounds, mapboxMap.getCameraPosition().zoom, 0, 0, new double[4]);
+ latch.countDown();
+ }
+ });
+ });
+
+ if (!latch.await(10, TimeUnit.SECONDS)) {
+ Assert.fail("timeout");
+ }
+ }
+
+ @Test
+ public void testToZoomIn() throws InterruptedException {
+ validateTestSetup();
+ invoke(mapboxMap, (uiController, mapboxMap) -> {
+ float zoom = 1.0f;
+
+ executeCameraMovement(CameraUpdateFactory.zoomIn(), new MapboxMap.CancelableCallback() {
+ @Override
+ public void onCancel() {
+ verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom + 1, 0, 0, new double[4]);
+ latch.countDown();
+ }
+
+ @Override
+ public void onFinish() {
+ verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom + 1, 0, 0, new double[4]);
+ latch.countDown();
+ }
+ });
+ });
+
+ if (!latch.await(10, TimeUnit.SECONDS)) {
+ Assert.fail("timeout");
+ }
+ }
+
+ @Test
+ public void testToZoomOut() throws InterruptedException {
+ float zoom = 10.0f;
+ validateTestSetup();
+ invoke(mapboxMap, (uiController, mapboxMap) -> {
+ executeCameraMovement(CameraUpdateFactory.newLatLngZoom(new LatLng(), zoom), new MapboxMap.CancelableCallback() {
+ @Override
+ public void onCancel() {
+ verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom, 0, 0, new double[4]);
+ latch.countDown();
+ }
+
+ @Override
+ public void onFinish() {
+ verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom, 0, 0, new double[4]);
+ latch.countDown();
+ }
+ });
+ });
+
+ if (!latch.await(10, TimeUnit.SECONDS)) {
+ Assert.fail("timeout");
+ }
+
+ latch = new CountDownLatch(1);
+
+ invoke(mapboxMap, (uiController, mapboxMap) -> {
+ executeCameraMovement(CameraUpdateFactory.zoomOut(), new MapboxMap.CancelableCallback() {
+ @Override
+ public void onCancel() {
+ verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom - 1, 0, 0, new double[4]);
+ latch.countDown();
+ }
+
+ @Override
+ public void onFinish() {
+ verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom - 1, 0, 0, new double[4]);
+ latch.countDown();
+ }
+ });
+ });
+
+ if (!latch.await(10, TimeUnit.SECONDS)) {
+ Assert.fail("timeout");
+ }
+ }
+
+ @Test
+ public void testToZoomBy() throws InterruptedException {
+ validateTestSetup();
+ invoke(mapboxMap, (uiController, mapboxMap) -> {
+ float zoom = 1.0f;
+ final float zoomBy = 2.45f;
+
+ executeCameraMovement(CameraUpdateFactory.zoomBy(zoomBy), new MapboxMap.CancelableCallback() {
+ @Override
+ public void onCancel() {
+ verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom + zoomBy, 0, 0, new double[4]);
+ latch.countDown();
+ }
+
+ @Override
+ public void onFinish() {
+ verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom + zoomBy, 0, 0, new double[4]);
+ latch.countDown();
+ }
+ });
+ });
+
+ if (!latch.await(10, TimeUnit.SECONDS)) {
+ Assert.fail("timeout");
+ }
+ }
+
+ @Test
+ public void testToZoomTo() throws InterruptedException {
+ validateTestSetup();
+ invoke(mapboxMap, (uiController, mapboxMap) -> {
+ final float zoomTo = 2.45f;
+
+ executeCameraMovement(CameraUpdateFactory.zoomTo(zoomTo), new MapboxMap.CancelableCallback() {
+ @Override
+ public void onCancel() {
+ verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoomTo, 0, 0, new double[4]);
+ latch.countDown();
+ }
+
+ @Override
+ public void onFinish() {
+ verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoomTo, 0, 0, new double[4]);
+ latch.countDown();
+ }
+ });
+ });
+
+ if (!latch.await(10, TimeUnit.SECONDS)) {
+ Assert.fail("timeout");
+ }
+ }
+
+ abstract void executeCameraMovement(CameraUpdate cameraUpdate, MapboxMap.CancelableCallback callback);
+
+ private void verifyCameraPosition(MapboxMap mapboxMap, LatLng moveTarget, double moveZoom, double moveBearing,
+ double moveTilt, double[] padding) {
+ CameraPosition cameraPosition = mapboxMap.getCameraPosition();
+ assertEquals("Moved camera position latitude should match", cameraPosition.target.getLatitude(),
+ moveTarget.getLatitude(), TestConstants.LAT_LNG_DELTA);
+ assertEquals("Moved camera position longitude should match", cameraPosition.target.getLongitude(),
+ moveTarget.getLongitude(), TestConstants.LAT_LNG_DELTA);
+ assertEquals("Moved zoom should match", cameraPosition.zoom, moveZoom, TestConstants.ZOOM_DELTA);
+ assertEquals("Moved zoom should match", cameraPosition.tilt, moveTilt, TestConstants.TILT_DELTA);
+ assertEquals("Moved bearing should match", cameraPosition.bearing, moveBearing, TestConstants.BEARING_DELTA);
+ assertArrayEquals("Moved padding should match", cameraPosition.padding, padding, TestConstants.PADDING_DELTA);
+ }
+}
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 a6238ebf14..9c2eb3df81 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
@@ -2,7 +2,6 @@ package com.mapbox.mapboxsdk.testapp.style
import android.support.test.espresso.Espresso.onView
import android.support.test.espresso.matcher.ViewMatchers.isRoot
-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
@@ -15,7 +14,6 @@ import com.mapbox.mapboxsdk.testapp.activity.style.GridSourceActivity.ID_GRID_LA
import com.mapbox.mapboxsdk.testapp.activity.style.GridSourceActivity.ID_GRID_SOURCE
import com.mapbox.mapboxsdk.testapp.utils.TestingAsyncUtils
import org.junit.Assert
-import org.junit.Ignore
import org.junit.Test
class CustomGeometrySourceTest : BaseTest() {
@@ -23,7 +21,6 @@ class CustomGeometrySourceTest : BaseTest() {
override fun getActivityClass(): Class<*> = GridSourceActivity::class.java
@Test
- @Ignore
fun sourceNotLeakingThreadsTest() {
validateTestSetup()
WaitAction.invoke(4000)
@@ -38,7 +35,6 @@ class CustomGeometrySourceTest : BaseTest() {
}
@Test
- @Ignore
fun threadsShutdownWhenSourceRemovedTest() {
validateTestSetup()
invoke(mapboxMap) { uiController, mapboxMap ->
@@ -48,13 +44,12 @@ class CustomGeometrySourceTest : BaseTest() {
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)
+ it.name.startsWith(THREAD_PREFIX)
}.count() == 0)
}
}
@Test
- @Ignore
fun threadsRestartedWhenSourceReAddedTest() {
validateTestSetup()
invoke(mapboxMap) { uiController, mapboxMap ->
@@ -67,8 +62,8 @@ class CustomGeometrySourceTest : BaseTest() {
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)
- }.count() == CustomGeometrySource.THREAD_POOL_LIMIT)
+ it.name.startsWith(THREAD_PREFIX)
+ }.count() == THREAD_POOL_LIMIT)
}
}
} \ No newline at end of file
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 fbb866ddff..95bd651cff 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
@@ -25,13 +25,19 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.IOException;
+import java.util.HashMap;
import timber.log.Timber;
import static com.mapbox.mapboxsdk.style.expressions.Expression.FormatOption.formatFontScale;
import static com.mapbox.mapboxsdk.style.expressions.Expression.FormatOption.formatTextColor;
import static com.mapbox.mapboxsdk.style.expressions.Expression.FormatOption.formatTextFont;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.NumberFormatOption.currency;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.NumberFormatOption.locale;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.NumberFormatOption.maxFractionDigits;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.NumberFormatOption.minFractionDigits;
import static com.mapbox.mapboxsdk.style.expressions.Expression.collator;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.color;
import static com.mapbox.mapboxsdk.style.expressions.Expression.eq;
import static com.mapbox.mapboxsdk.style.expressions.Expression.exponential;
import static com.mapbox.mapboxsdk.style.expressions.Expression.format;
@@ -41,6 +47,7 @@ import static com.mapbox.mapboxsdk.style.expressions.Expression.interpolate;
import static com.mapbox.mapboxsdk.style.expressions.Expression.literal;
import static com.mapbox.mapboxsdk.style.expressions.Expression.match;
import static com.mapbox.mapboxsdk.style.expressions.Expression.number;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.numberFormat;
import static com.mapbox.mapboxsdk.style.expressions.Expression.rgb;
import static com.mapbox.mapboxsdk.style.expressions.Expression.rgba;
import static com.mapbox.mapboxsdk.style.expressions.Expression.step;
@@ -56,8 +63,10 @@ import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillOutlineColor
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textColor;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textField;
import static com.mapbox.mapboxsdk.testapp.action.MapboxMapAction.invoke;
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
@RunWith(AndroidJUnit4.class)
@@ -561,6 +570,197 @@ public class ExpressionTest extends EspressoTest {
});
}
+ @Test
+ public void testNumberFormatCurrencyExpression() {
+ validateTestSetup();
+ invoke(mapboxMap, (uiController, mapboxMap) -> {
+ LatLng latLng = new LatLng(51, 17);
+ mapboxMap.getStyle()
+ .addSource(new GeoJsonSource("source", Point.fromLngLat(latLng.getLongitude(), latLng.getLatitude())));
+ SymbolLayer layer = new SymbolLayer("layer", "source");
+ mapboxMap.getStyle().addLayer(layer);
+
+ layer.setProperties(
+ textField(
+ numberFormat(12.345, locale("en-US"), currency("USD"))
+ )
+ );
+ TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
+
+ assertFalse(mapboxMap.queryRenderedFeatures(
+ mapboxMap.getProjection().toScreenLocation(latLng), "layer").isEmpty()
+ );
+ assertNull(layer.getTextField().getExpression());
+ assertEquals("$12.35", layer.getTextField().getValue().getFormattedSections()[0].getText());
+ });
+ }
+
+ @Test
+ public void testNumberFormatMaxExpression() {
+ validateTestSetup();
+ invoke(mapboxMap, (uiController, mapboxMap) -> {
+ LatLng latLng = new LatLng(51, 17);
+ mapboxMap.getStyle()
+ .addSource(new GeoJsonSource("source", Point.fromLngLat(latLng.getLongitude(), latLng.getLatitude())));
+ SymbolLayer layer = new SymbolLayer("layer", "source");
+ mapboxMap.getStyle().addLayer(layer);
+
+ layer.setProperties(
+ textField(
+ numberFormat(12.34567890, maxFractionDigits(5), minFractionDigits(0))
+ )
+ );
+ TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
+
+ assertFalse(mapboxMap.queryRenderedFeatures(
+ mapboxMap.getProjection().toScreenLocation(latLng), "layer").isEmpty()
+ );
+ assertNull(layer.getTextField().getExpression());
+ assertEquals("12.34568", layer.getTextField().getValue().getFormattedSections()[0].getText());
+ });
+ }
+
+ @Test
+ public void testNumberFormatMinExpression() {
+ validateTestSetup();
+ invoke(mapboxMap, (uiController, mapboxMap) -> {
+ LatLng latLng = new LatLng(51, 17);
+ mapboxMap.getStyle()
+ .addSource(new GeoJsonSource("source", Point.fromLngLat(latLng.getLongitude(), latLng.getLatitude())));
+ SymbolLayer layer = new SymbolLayer("layer", "source");
+ mapboxMap.getStyle().addLayer(layer);
+
+ layer.setProperties(
+ textField(
+ numberFormat(12.0000001, maxFractionDigits(5), minFractionDigits(0))
+ )
+ );
+ TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
+
+ assertFalse(mapboxMap.queryRenderedFeatures(
+ mapboxMap.getProjection().toScreenLocation(latLng), "layer").isEmpty()
+ );
+ assertNull(layer.getTextField().getExpression());
+ assertEquals("12", layer.getTextField().getValue().getFormattedSections()[0].getText());
+ });
+ }
+
+ @Test
+ public void testNumberFormatLocaleExpression() {
+ validateTestSetup();
+ invoke(mapboxMap, (uiController, mapboxMap) -> {
+ LatLng latLng = new LatLng(51, 17);
+ mapboxMap.getStyle()
+ .addSource(new GeoJsonSource("source", Point.fromLngLat(latLng.getLongitude(), latLng.getLatitude())));
+ SymbolLayer layer = new SymbolLayer("layer", "source");
+ mapboxMap.getStyle().addLayer(layer);
+
+ layer.setProperties(
+ textField(
+ numberFormat(12.0000001, locale("nl-BE"), maxFractionDigits(5), minFractionDigits(1))
+ )
+ );
+ TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
+
+ assertFalse(mapboxMap.queryRenderedFeatures(
+ mapboxMap.getProjection().toScreenLocation(latLng), "layer").isEmpty()
+ );
+ assertNull(layer.getTextField().getExpression());
+ assertEquals("12,0", layer.getTextField().getValue().getFormattedSections()[0].getText());
+ });
+ }
+
+ @Test
+ public void testNumberFormatNonConstantExpression() {
+ validateTestSetup();
+ invoke(mapboxMap, (uiController, mapboxMap) -> {
+ LatLng latLng = new LatLng(51, 17);
+ Feature feature = Feature.fromGeometry(Point.fromLngLat(latLng.getLongitude(), latLng.getLatitude()));
+ feature.addNumberProperty("number_value", 12.345678);
+ feature.addStringProperty("locale_value", "nl-BE");
+ feature.addNumberProperty("max_value", 5);
+ feature.addNumberProperty("min_value", 1);
+
+
+ mapboxMap.getStyle().addSource(new GeoJsonSource("source", feature));
+ SymbolLayer layer = new SymbolLayer("layer", "source");
+ mapboxMap.getStyle().addLayer(layer);
+
+ Expression numberFormatExpression = numberFormat(
+ number(number(get("number_value"))),
+ locale(string(get("locale_value"))),
+ maxFractionDigits(number(get("max_value"))),
+ minFractionDigits(number(get("min_value")))
+ );
+
+ layer.setProperties(textField(numberFormatExpression));
+ TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView);
+
+ assertFalse(mapboxMap.queryRenderedFeatures(
+ mapboxMap.getProjection().toScreenLocation(latLng), "layer").isEmpty()
+ );
+
+ assertNotNull(layer.getTextField().getExpression());
+
+ // Expressions evaluated to string are wrapped by a format expression, take array index 1 to get original
+ Object[] returnExpression = (Object[]) layer.getTextField().getExpression().toArray()[1];
+ Object[] setExpression = numberFormatExpression.toArray();
+ assertEquals("Number format should match",returnExpression[0], setExpression[0]);
+ assertArrayEquals("Get value expression should match",
+ (Object[]) returnExpression[1],
+ (Object[]) setExpression[1]
+ );
+
+ // number format objects
+ HashMap<String, Object> returnMap = (HashMap<String, Object>) returnExpression[2];
+ HashMap<String, Object> setMap = (HashMap<String, Object>) returnExpression[2];
+
+ assertArrayEquals("Number format min fraction digits should match ",
+ (Object[]) returnMap.get("min-fraction-digits"),
+ (Object[]) setMap.get("min-fraction-digits")
+ );
+
+ assertArrayEquals("Number format max fraction digits should match ",
+ (Object[]) returnMap.get("max-fraction-digits"),
+ (Object[]) setMap.get("max-fraction-digits")
+ );
+
+ assertArrayEquals("Number format min fraction digits should match ",
+ (Object[]) returnMap.get("locale"),
+ (Object[]) setMap.get("locale")
+ );
+ });
+
+ }
+
+ /**
+ * Regression test for #15532
+ */
+ @Test
+ public void testDoubleConversion() {
+ validateTestSetup();
+ invoke(mapboxMap, (uiController, mapboxMap) -> {
+ LatLng latLng = new LatLng(51, 17);
+ mapboxMap.getStyle().addSource(
+ new GeoJsonSource("source", Point.fromLngLat(latLng.getLongitude(), latLng.getLatitude()))
+ );
+
+ CircleLayer layer = new CircleLayer("layer", "source");
+ mapboxMap.getStyle().addLayer(layer);
+
+ Expression input = interpolate(
+ exponential(0.5f), zoom(),
+ stop(-0.1, color(Color.RED)),
+ stop(0, color(Color.BLUE))
+ );
+
+ layer.setProperties(circleColor(input));
+
+ Expression output = layer.getCircleColor().getExpression();
+ assertArrayEquals("Expression should match", input.toArray(), output.toArray());
+ });
+ }
+
private void setupStyle() {
invoke(mapboxMap, (uiController, mapboxMap) -> {
// Add a source
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/TestConstants.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/TestConstants.java
index 09e27d30f2..255d1e1e7d 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/TestConstants.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/TestConstants.java
@@ -5,6 +5,7 @@ public class TestConstants {
public static final double BEARING_DELTA = 0.1;
public static final double TILT_DELTA = 0.3;
public static final double ZOOM_DELTA = 0.3;
+ public static final double PADDING_DELTA = 0.0001;
public static final String TEXT_MARKER_TITLE = "Marker";
public static final String TEXT_MARKER_SNIPPET = "Snippet";
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/utils/FontUtilsTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/utils/FontUtilsTest.java
index 694215d16f..fa068cb973 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/utils/FontUtilsTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/utils/FontUtilsTest.java
@@ -1,9 +1,7 @@
package com.mapbox.mapboxsdk.utils;
import android.support.test.runner.AndroidJUnit4;
-
import com.mapbox.mapboxsdk.constants.MapboxConstants;
-
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/BulkMarkerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/BulkMarkerActivity.java
index 05337081dc..d8fd428762 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/BulkMarkerActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/BulkMarkerActivity.java
@@ -151,6 +151,9 @@ public class BulkMarkerActivity extends AppCompatActivity implements AdapterView
@Override
protected void onDestroy() {
super.onDestroy();
+ if (progressDialog != null) {
+ progressDialog.dismiss();
+ }
mapView.onDestroy();
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimatorActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimatorActivity.java
index e278d033be..7ce54831f2 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimatorActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimatorActivity.java
@@ -36,6 +36,7 @@ public class CameraAnimatorActivity extends AppCompatActivity implements OnMapRe
private static final LatLng START_LAT_LNG = new LatLng(37.787947, -122.407432);
private final LongSparseArray<Animator> animators = new LongSparseArray<>();
+ private Animator set;
{
AnimatorSet accelerateDecelerateAnimatorSet = new AnimatorSet();
@@ -92,7 +93,8 @@ public class CameraAnimatorActivity extends AppCompatActivity implements OnMapRe
.bearing(135)
.build();
- createExampleAnimator(mapboxMap.getCameraPosition(), animatedPosition).start();
+ set = createExampleAnimator(mapboxMap.getCameraPosition(), animatedPosition);
+ set.start();
});
}
@@ -237,6 +239,9 @@ public class CameraAnimatorActivity extends AppCompatActivity implements OnMapRe
for (int i = 0; i < animators.size(); i++) {
animators.get(animators.keyAt(i)).cancel();
}
+ if (set != null) {
+ set.cancel();
+ }
}
@Override
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraPositionActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraPositionActivity.java
index 83b0c415ec..6979097658 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraPositionActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraPositionActivity.java
@@ -63,12 +63,12 @@ public class CameraPositionActivity extends FragmentActivity implements OnMapRea
fab = findViewById(R.id.fab);
fab.setColorFilter(ContextCompat.getColor(CameraPositionActivity.this, R.color.primary));
fab.setOnClickListener(this);
- });
- toggleLogCameraChanges();
+ toggleLogCameraChanges();
- // listen to long click events to toggle logging camera changes
- mapboxMap.addOnMapLongClickListener(this);
+ // listen to long click events to toggle logging camera changes
+ mapboxMap.addOnMapLongClickListener(this);
+ });
}
@Override
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MapFragmentActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MapFragmentActivity.java
index 40ea7509b1..a0e8b31fcd 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
@@ -81,7 +81,9 @@ public class MapFragmentActivity extends AppCompatActivity implements MapFragmen
@Override
protected void onDestroy() {
super.onDestroy();
- mapView.removeOnDidFinishRenderingFrameListener(this);
+ if (mapView != null) {
+ mapView.removeOnDidFinishRenderingFrameListener(this);
+ }
}
@Override
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationFragmentActivity.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationFragmentActivity.kt
index ff2afb50c5..7e18cbfa2f 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationFragmentActivity.kt
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/location/LocationFragmentActivity.kt
@@ -116,7 +116,7 @@ class LocationFragmentActivity : AppCompatActivity() {
}
override fun onSuccess(result: LocationEngineResult?) {
- mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(LatLng(result?.lastLocation), 12.0))
+ if (!mapView.isDestroyed) mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(LatLng(result?.lastLocation), 12.0))
}
override fun onFailure(exception: Exception) {
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GeoJsonClusteringActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GeoJsonClusteringActivity.java
index 732a7929b8..cb2701d436 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GeoJsonClusteringActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GeoJsonClusteringActivity.java
@@ -30,6 +30,8 @@ import java.util.List;
import java.util.Objects;
import static com.mapbox.mapboxsdk.style.expressions.Expression.all;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.accumulated;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.concat;
import static com.mapbox.mapboxsdk.style.expressions.Expression.division;
import static com.mapbox.mapboxsdk.style.expressions.Expression.exponential;
import static com.mapbox.mapboxsdk.style.expressions.Expression.get;
@@ -39,6 +41,8 @@ import static com.mapbox.mapboxsdk.style.expressions.Expression.has;
import static com.mapbox.mapboxsdk.style.expressions.Expression.interpolate;
import static com.mapbox.mapboxsdk.style.expressions.Expression.literal;
import static com.mapbox.mapboxsdk.style.expressions.Expression.lt;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.max;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.neq;
import static com.mapbox.mapboxsdk.style.expressions.Expression.rgb;
import static com.mapbox.mapboxsdk.style.expressions.Expression.stop;
import static com.mapbox.mapboxsdk.style.expressions.Expression.toNumber;
@@ -138,6 +142,9 @@ public class GeoJsonClusteringActivity extends AppCompatActivity {
.withCluster(true)
.withClusterMaxZoom(14)
.withClusterRadius(50)
+ .withClusterProperty("max", max(accumulated(), get("max")), get("mag"))
+ .withClusterProperty("sum", literal("+"), get("mag"))
+ .withClusterProperty("felt", literal("any"), neq(get("felt"), literal("null")))
);
}
@@ -182,9 +189,9 @@ public class GeoJsonClusteringActivity extends AppCompatActivity {
}
private SymbolLayer createClusterTextLayer() {
- return new SymbolLayer("count", "earthquakes")
+ return new SymbolLayer("property", "earthquakes")
.withProperties(
- textField(Expression.toString(get("point_count"))),
+ textField(concat(get("point_count"), literal(", "), get("max"))),
textSize(12f),
textColor(Color.WHITE),
textIgnorePlacement(true),
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolGeneratorActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolGeneratorActivity.java
index 24bfe62e75..e80d6fe3e1 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolGeneratorActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolGeneratorActivity.java
@@ -362,7 +362,12 @@ public class SymbolGeneratorActivity extends AppCompatActivity implements OnMapR
@Override
protected void onPostExecute(HashMap<String, Bitmap> bitmapHashMap) {
super.onPostExecute(bitmapHashMap);
- mapboxMap.getStyle().addImagesAsync(bitmapHashMap);
+ mapboxMap.getStyle(new Style.OnStyleLoaded() {
+ @Override
+ public void onStyleLoaded(@NonNull Style style) {
+ style.addImagesAsync(bitmapHashMap);
+ }
+ });
}
}
} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolLayerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolLayerActivity.java
index 3d65a92f72..ee562ad6e8 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolLayerActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolLayerActivity.java
@@ -38,12 +38,15 @@ import java.util.Random;
import static com.mapbox.mapboxsdk.style.expressions.Expression.FormatOption.formatFontScale;
import static com.mapbox.mapboxsdk.style.expressions.Expression.FormatOption.formatTextColor;
import static com.mapbox.mapboxsdk.style.expressions.Expression.FormatOption.formatTextFont;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.NumberFormatOption.currency;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.NumberFormatOption.locale;
import static com.mapbox.mapboxsdk.style.expressions.Expression.concat;
import static com.mapbox.mapboxsdk.style.expressions.Expression.format;
import static com.mapbox.mapboxsdk.style.expressions.Expression.formatEntry;
import static com.mapbox.mapboxsdk.style.expressions.Expression.get;
import static com.mapbox.mapboxsdk.style.expressions.Expression.literal;
import static com.mapbox.mapboxsdk.style.expressions.Expression.match;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.numberFormat;
import static com.mapbox.mapboxsdk.style.expressions.Expression.rgb;
import static com.mapbox.mapboxsdk.style.expressions.Expression.stop;
import static com.mapbox.mapboxsdk.style.expressions.Expression.switchCase;
@@ -72,8 +75,6 @@ import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textSize;
*/
public class SymbolLayerActivity extends AppCompatActivity implements MapboxMap.OnMapClickListener, OnMapReadyCallback {
- private static final String MARKER_SOURCE = "marker-source";
- private static final String MARKER_LAYER = "marker-layer";
private static final String ID_FEATURE_PROPERTY = "id";
private static final String SELECTED_FEATURE_PROPERTY = "selected";
private static final String TITLE_FEATURE_PROPERTY = "title";
@@ -81,8 +82,13 @@ public class SymbolLayerActivity extends AppCompatActivity implements MapboxMap.
private static final String[] NORMAL_FONT_STACK = new String[] {"DIN Offc Pro Regular", "Arial Unicode MS Regular"};
private static final String[] BOLD_FONT_STACK = new String[] {"DIN Offc Pro Bold", "Arial Unicode MS Regular"};
+ // layer & source constants
+ private static final String MARKER_SOURCE = "marker-source";
+ private static final String MARKER_LAYER = "marker-layer";
private static final String MAPBOX_SIGN_SOURCE = "mapbox-sign-source";
private static final String MAPBOX_SIGN_LAYER = "mapbox-sign-layer";
+ private static final String NUMBER_FORMAT_SOURCE = "mapbox-number-source";
+ private static final String NUMBER_FORMAT_LAYER = "mapbox-number-layer";
private static final Expression TEXT_FIELD_EXPRESSION =
switchCase(toBool(get(SELECTED_FEATURE_PROPERTY)),
@@ -108,6 +114,7 @@ public class SymbolLayerActivity extends AppCompatActivity implements MapboxMap.
private FeatureCollection markerCollection;
private SymbolLayer markerSymbolLayer;
private SymbolLayer mapboxSignSymbolLayer;
+ private SymbolLayer numberFormatSymbolLayer;
private MapboxMap mapboxMap;
private MapView mapView;
@@ -177,11 +184,20 @@ public class SymbolLayerActivity extends AppCompatActivity implements MapboxMap.
mapboxSignSymbolLayer = new SymbolLayer(MAPBOX_SIGN_LAYER, MAPBOX_SIGN_SOURCE);
shuffleMapboxSign();
+ // number format layer
+ Source numberFormatSource = new GeoJsonSource(NUMBER_FORMAT_SOURCE, Point.fromLngLat(4.92756, 52.3516));
+ numberFormatSymbolLayer = new SymbolLayer(NUMBER_FORMAT_LAYER, NUMBER_FORMAT_SOURCE);
+ numberFormatSymbolLayer.setProperties(
+ textField(
+ numberFormat(123.456789, locale("nl-NL"), currency("EUR"))
+ )
+ );
+
mapboxMap.setStyle(new Style.Builder()
.fromUri("asset://streets.json")
.withImage("Car", Objects.requireNonNull(carBitmap), false)
- .withSources(markerSource, mapboxSignSource)
- .withLayers(markerSymbolLayer, mapboxSignSymbolLayer)
+ .withSources(markerSource, mapboxSignSource, numberFormatSource)
+ .withLayers(markerSymbolLayer, mapboxSignSymbolLayer, numberFormatSymbolLayer)
);
// Set a click-listener so we can manipulate the map
@@ -205,7 +221,7 @@ public class SymbolLayerActivity extends AppCompatActivity implements MapboxMap.
// validate symbol flicker regression for #13407
markerSymbolLayer.setProperties(iconOpacity(match(
get(ID_FEATURE_PROPERTY), literal(1.0f),
- stop(feature.getStringProperty("id"), selected ? 0.3f : 1.0f)
+ stop(feature.getStringProperty("id"), selected ? 0.3f : 1.0f)
)));
}
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_position.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_position.xml
index 28bdaf7b2a..9b57e18a7a 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_position.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_position.xml
@@ -18,6 +18,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="?android:attr/actionBarSize"
+ app:mapbox_localIdeographFontFamilies="@array/array_local_ideograph_family_test"
app:mapbox_uiAttributionTintColor="@color/redAccent"/>
<android.support.design.widget.FloatingActionButton
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_gesture_detector.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_gesture_detector.xml
index 26c61e1639..58e49c3cef 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_gesture_detector.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_gesture_detector.xml
@@ -10,6 +10,7 @@
android:id="@id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ app:mapbox_localIdeographEnabled="false"
app:mapbox_cameraTargetLat="51.50325"
app:mapbox_cameraTargetLng="-0.11968"
app:mapbox_cameraZoom="15" />
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/arrays.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/arrays.xml
index 4b7ded8e3a..ad9f88a46e 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/arrays.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/arrays.xml
@@ -7,4 +7,9 @@
<item>1000</item>
<item>10000</item>
</string-array>
+ <string-array name="array_local_ideograph_family_test">
+ <item>foo</item>
+ <item>monospace</item>
+ <item>bar</item>
+ </string-array>
</resources> \ No newline at end of file
diff --git a/platform/android/build.gradle b/platform/android/build.gradle
index 46666e2ef1..607958a8a8 100644
--- a/platform/android/build.gradle
+++ b/platform/android/build.gradle
@@ -6,7 +6,7 @@ buildscript {
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.4.2'
+ classpath 'com.android.tools.build:gradle:3.5.0'
classpath dependenciesList.licensesPlugin
classpath dependenciesList.kotlinPlugin
classpath dependenciesList.bintrayPlugin
diff --git a/platform/android/config.cmake b/platform/android/config.cmake
index 4bd628fcdd..98d18ca324 100644
--- a/platform/android/config.cmake
+++ b/platform/android/config.cmake
@@ -43,7 +43,7 @@ macro(mbgl_platform_core)
)
target_link_libraries(mbgl-core
- PUBLIC jni.hpp
+ PUBLIC Mapbox::Base::jni.hpp
PUBLIC -llog
PUBLIC -landroid
PUBLIC -ljnigraphics
@@ -61,7 +61,7 @@ macro(mbgl_filesource)
target_link_libraries(mbgl-filesource
PUBLIC sqlite
- PUBLIC jni.hpp
+ PUBLIC Mapbox::Base::jni.hpp
PUBLIC -llog
PUBLIC -landroid
PUBLIC -latomic
diff --git a/platform/android/core-files.json b/platform/android/core-files.json
index 62ecc0c671..b19e5d9a93 100644
--- a/platform/android/core-files.json
+++ b/platform/android/core-files.json
@@ -38,6 +38,7 @@
"platform/android/src/java/util.cpp",
"platform/android/src/java_types.cpp",
"platform/android/src/jni.cpp",
+ "platform/android/src/jni_native.cpp",
"platform/android/src/logger.cpp",
"platform/android/src/logging_android.cpp",
"platform/android/src/map/camera_position.cpp",
@@ -142,6 +143,7 @@
"java/util.hpp": "platform/android/src/java/util.hpp",
"java_types.hpp": "platform/android/src/java_types.hpp",
"jni.hpp": "platform/android/src/jni.hpp",
+ "jni_native.hpp": "platform/android/src/jni_native.hpp",
"logger.hpp": "platform/android/src/logger.hpp",
"map/camera_position.hpp": "platform/android/src/map/camera_position.hpp",
"map/image.hpp": "platform/android/src/map/image.hpp",
diff --git a/platform/android/gradle/dependencies.gradle b/platform/android/gradle/dependencies.gradle
index 526861e8b1..c1c4894727 100644
--- a/platform/android/gradle/dependencies.gradle
+++ b/platform/android/gradle/dependencies.gradle
@@ -7,10 +7,10 @@ ext {
]
versions = [
- mapboxServices : '4.8.0',
+ mapboxServices : '4.9.0-alpha.1',
mapboxTelemetry : '4.5.1',
mapboxCore : '1.3.0',
- mapboxGestures : '0.5.0',
+ mapboxGestures : '0.5.1',
mapboxAccounts : '0.2.0',
supportLib : '28.0.0',
constraintLayout: '1.1.2',
diff --git a/platform/android/gradle/jacoco-report.gradle b/platform/android/gradle/jacoco-report.gradle
index c4e0bb9131..64c99e09f0 100644
--- a/platform/android/gradle/jacoco-report.gradle
+++ b/platform/android/gradle/jacoco-report.gradle
@@ -15,7 +15,7 @@ task jacocoTestReport(type: JacocoReport, dependsOn: ['testDebugUnitTest']) {
}
def fileExcludes = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*', '**/*Test*.*', 'android/**/*.*']
- def debugTree = fileTree(dir: "${project.buildDir}/intermediates/javac/debug/compileDebugJavaWithJavac/classes", excludes: fileExcludes)
+ def debugTree = fileTree(dir: "${project.buildDir}/intermediates/javac/debug/classes", excludes: fileExcludes)
def mainSrc = "${project.projectDir}/src/main/java"
println(mainSrc)
def ecSrc = fileTree(dir: "$project.buildDir", include: "**/*.ec")
diff --git a/platform/android/gradle/wrapper/gradle-wrapper.properties b/platform/android/gradle/wrapper/gradle-wrapper.properties
index a60d82ac08..efceced3ca 100644
--- a/platform/android/gradle/wrapper/gradle-wrapper.properties
+++ b/platform/android/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-5.5.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.6-all.zip
diff --git a/platform/android/scripts/exclude-activity-gen.json b/platform/android/scripts/exclude-activity-gen.json
index 0f5bb81b55..ab84957e34 100644
--- a/platform/android/scripts/exclude-activity-gen.json
+++ b/platform/android/scripts/exclude-activity-gen.json
@@ -5,7 +5,6 @@
"MapSnapshotterLocalStyleActivity",
"LatLngBoundsActivity",
"BottomSheetActivity",
- "MapSnapshotterActivity",
"MockLocationEngine",
"DeleteRegionActivity",
"RealTimeGeoJsonActivity",
@@ -50,7 +49,5 @@
"EspressoTestActivity",
"FragmentBackStackActivity",
"ChildFragmentMapInDialogActivity",
- "PerformanceMeasurementActivity",
- "DownloadRegionActivity",
- "CacheManagementActivity"
+ "PerformanceMeasurementActivity"
]
diff --git a/platform/android/src/android_renderer_frontend.cpp b/platform/android/src/android_renderer_frontend.cpp
index 6862fabcb4..d1a2624f0d 100644
--- a/platform/android/src/android_renderer_frontend.cpp
+++ b/platform/android/src/android_renderer_frontend.cpp
@@ -42,8 +42,8 @@ public:
delegate.invoke(&RendererObserver::onWillStartRenderingFrame);
}
- void onDidFinishRenderingFrame(RenderMode mode, bool repaintNeeded) override {
- delegate.invoke(&RendererObserver::onDidFinishRenderingFrame, mode, repaintNeeded);
+ void onDidFinishRenderingFrame(RenderMode mode, bool repaintNeeded, bool placementChanged) override {
+ delegate.invoke(&RendererObserver::onDidFinishRenderingFrame, mode, repaintNeeded, placementChanged);
}
void onDidFinishRenderingMap() override {
diff --git a/platform/android/src/java_types.cpp b/platform/android/src/java_types.cpp
index dd165470cf..7a1ba93a58 100644
--- a/platform/android/src/java_types.cpp
+++ b/platform/android/src/java_types.cpp
@@ -18,6 +18,10 @@ namespace java {
jni::jclass* Map::jclass;
jni::jmethodID* Map::getMethodId;
+ jni::jmethodID* Map::keySetMethodId;
+
+ jni::jclass* Set::jclass;
+ jni::jmethodID* Set::toArrayMethodId;
void registerNatives(JNIEnv& env) {
ObjectArray::jclass = jni::NewGlobalRef(env, &jni::FindClass(env, "[Ljava/lang/Object;")).release();
@@ -34,6 +38,10 @@ namespace java {
Map::jclass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/util/Map")).release();
Map::getMethodId = &jni::GetMethodID(env, *Map::jclass, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
+ Map::keySetMethodId = &jni::GetMethodID(env, *Map::jclass, "keySet", "()Ljava/util/Set;");
+
+ Set::jclass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/util/Set")).release();
+ Set::toArrayMethodId = &jni::GetMethodID(env, *Set::jclass, "toArray", "()[Ljava/lang/Object;");
}
}
diff --git a/platform/android/src/java_types.hpp b/platform/android/src/java_types.hpp
index edec5cb550..c7c93ce71b 100644
--- a/platform/android/src/java_types.hpp
+++ b/platform/android/src/java_types.hpp
@@ -29,6 +29,12 @@ namespace java {
struct Map {
static jni::jclass* jclass;
static jni::jmethodID* getMethodId;
+ static jni::jmethodID* keySetMethodId;
+ };
+
+ struct Set {
+ static jni::jclass* jclass;
+ static jni::jmethodID* toArrayMethodId;
};
void registerNatives(JNIEnv&);
diff --git a/platform/android/src/jni.cpp b/platform/android/src/jni.cpp
index 088b3b796c..189ec29dce 100755
--- a/platform/android/src/jni.cpp
+++ b/platform/android/src/jni.cpp
@@ -2,66 +2,9 @@
#include <mbgl/util/logging.hpp>
-#include "annotation/marker.hpp"
-#include "annotation/polygon.hpp"
-#include "annotation/polyline.hpp"
-#include "bitmap.hpp"
-#include "bitmap_factory.hpp"
-#include "connectivity_listener.hpp"
-#include "conversion/conversion.hpp"
-#include "conversion/collection.hpp"
-#include "file_source.hpp"
-#include "geojson/feature.hpp"
-#include "geojson/feature_collection.hpp"
-#include "geojson/geometry.hpp"
-#include "geojson/geometry_collection.hpp"
-#include "geojson/line_string.hpp"
-#include "geojson/multi_line_string.hpp"
-#include "geojson/multi_point.hpp"
-#include "geojson/multi_polygon.hpp"
-#include "geojson/point.hpp"
-#include "geojson/polygon.hpp"
-#include "geometry/lat_lng.hpp"
-#include "geometry/lat_lng_bounds.hpp"
-#include "geometry/lat_lng_quad.hpp"
-#include "geometry/projected_meters.hpp"
-#include "graphics/pointf.hpp"
-#include "graphics/rectf.hpp"
-#include "gson/json_array.hpp"
-#include "gson/json_element.hpp"
-#include "gson/json_object.hpp"
-#include "gson/json_primitive.hpp"
-#include "java_types.hpp"
-#include "map_renderer.hpp"
-#include "map_renderer_runnable.hpp"
-#include "native_map_view.hpp"
-#ifndef MBGL_MODULE_OFFLINE_DISABLE
-#include "offline/offline_manager.hpp"
-#include "offline/offline_region.hpp"
-#include "offline/offline_region_definition.hpp"
-#include "offline/offline_region_error.hpp"
-#include "offline/offline_region_status.hpp"
-#endif
-#include "style/transition_options.hpp"
-#include "style/layers/layer_manager.hpp"
-#include "style/sources/source.hpp"
-#include "style/light.hpp"
-#include "style/formatted.hpp"
-#include "style/formatted_section.hpp"
-#ifndef MBGL_MODULE_SNAPSHOT_DISABLE
-#include "snapshotter/map_snapshotter.hpp"
-#include "snapshotter/map_snapshot.hpp"
-#endif
-#include "text/collator_jni.hpp"
-#include "text/local_glyph_rasterizer_jni.hpp"
-#include "text/format_number_jni.hpp"
-#include "logger.hpp"
-
namespace mbgl {
namespace android {
-void RegisterNativeHTTPRequest(JNIEnv&);
-
JavaVM* theJVM;
//TODO: remove
@@ -107,105 +50,5 @@ void detach_jni_thread(JavaVM* vm, JNIEnv** env, bool detach) {
*env = nullptr;
}
-void registerNatives(JavaVM *vm) {
- theJVM = vm;
-
- jni::JNIEnv& env = jni::GetEnv(*vm, jni::jni_version_1_6);
-
- // For the DefaultFileSource
- static mbgl::util::RunLoop mainRunLoop;
- FileSource::registerNative(env);
-
- // Basic types
- java::registerNatives(env);
- java::util::registerNative(env);
- PointF::registerNative(env);
- RectF::registerNative(env);
-
- // GeoJSON
- geojson::Feature::registerNative(env);
- geojson::FeatureCollection::registerNative(env);
- geojson::Geometry::registerNative(env);
- geojson::GeometryCollection::registerNative(env);
- geojson::LineString::registerNative(env);
- geojson::MultiLineString::registerNative(env);
- geojson::MultiPoint::registerNative(env);
- geojson::MultiPolygon::registerNative(env);
- geojson::Point::registerNative(env);
- geojson::Polygon::registerNative(env);
-
- // Geometry
- LatLng::registerNative(env);
- LatLngBounds::registerNative(env);
- LatLngQuad::registerNative(env);
- ProjectedMeters::registerNative(env);
-
- // GSon
- gson::JsonArray::registerNative(env);
- gson::JsonElement::registerNative(env);
- gson::JsonObject::registerNative(env);
- gson::JsonPrimitive::registerNative(env);
-
- //Annotation
- Marker::registerNative(env);
- Polygon::registerNative(env);
- Polyline::registerNative(env);
-
- // Map
- MapRenderer::registerNative(env);
- MapRendererRunnable::registerNative(env);
- NativeMapView::registerNative(env);
-
- // Http
- RegisterNativeHTTPRequest(env);
-
- // Bitmap
- Bitmap::registerNative(env);
- BitmapFactory::registerNative(env);
-
- // Style
- TransitionOptions::registerNative(env);
- LayerManagerAndroid::get()->registerNative(env);
- Source::registerNative(env);
- Light::registerNative(env);
- Position::registerNative(env);
- Formatted::registerNative(env);
- FormattedSection::registerNative(env);
-
- // Map
- CameraPosition::registerNative(env);
- Image::registerNative(env);
-
- // Connectivity
- ConnectivityListener::registerNative(env);
-
- // Offline
-#ifndef MBGL_MODULE_OFFLINE_DISABLE
- OfflineManager::registerNative(env);
- OfflineRegion::registerNative(env);
- OfflineRegionDefinition::registerNative(env);
- OfflineTilePyramidRegionDefinition::registerNative(env);
- OfflineGeometryRegionDefinition::registerNative(env);
- OfflineRegionError::registerNative(env);
- OfflineRegionStatus::registerNative(env);
-#endif
-
- // Snapshotter
-#ifndef MBGL_MODULE_SNAPSHOT_DISABLE
- MapSnapshotter::registerNative(env);
- MapSnapshot::registerNative(env);
-#endif
-
- // text
- LocalGlyphRasterizer::registerNative(env);
- Locale::registerNative(env);
- Collator::registerNative(env);
- StringUtils::registerNative(env);
- NumberFormat::registerNative(env);
-
- // Logger
- Logger::registerNative(env);
-}
-
} // namespace android
} // namespace mbgl
diff --git a/platform/android/src/jni.hpp b/platform/android/src/jni.hpp
index e5df92e701..cb519f911d 100644
--- a/platform/android/src/jni.hpp
+++ b/platform/android/src/jni.hpp
@@ -1,6 +1,7 @@
#pragma once
#include <string>
+#include <jni/jni.hpp>
typedef struct _jmethodID* jmethodID;
typedef struct _JavaVM JavaVM;
@@ -17,7 +18,5 @@ extern std::string dataPath;
bool attach_jni_thread(JavaVM* vm, JNIEnv** env, std::string threadName);
void detach_jni_thread(JavaVM* vm, JNIEnv** env, bool detach);
-extern void registerNatives(JavaVM* vm);
-
} // namespace android
} // namespace mbgl
diff --git a/platform/android/src/jni_native.cpp b/platform/android/src/jni_native.cpp
new file mode 100755
index 0000000000..df96ba9759
--- /dev/null
+++ b/platform/android/src/jni_native.cpp
@@ -0,0 +1,164 @@
+#include "jni_native.hpp"
+
+#include "annotation/marker.hpp"
+#include "annotation/polygon.hpp"
+#include "annotation/polyline.hpp"
+#include "bitmap.hpp"
+#include "bitmap_factory.hpp"
+#include "connectivity_listener.hpp"
+#include "conversion/conversion.hpp"
+#include "conversion/collection.hpp"
+#include "file_source.hpp"
+#include "geojson/feature.hpp"
+#include "geojson/feature_collection.hpp"
+#include "geojson/geometry.hpp"
+#include "geojson/geometry_collection.hpp"
+#include "geojson/line_string.hpp"
+#include "geojson/multi_line_string.hpp"
+#include "geojson/multi_point.hpp"
+#include "geojson/multi_polygon.hpp"
+#include "geojson/point.hpp"
+#include "geojson/polygon.hpp"
+#include "geometry/lat_lng.hpp"
+#include "geometry/lat_lng_bounds.hpp"
+#include "geometry/lat_lng_quad.hpp"
+#include "geometry/projected_meters.hpp"
+#include "graphics/pointf.hpp"
+#include "graphics/rectf.hpp"
+#include "gson/json_array.hpp"
+#include "gson/json_element.hpp"
+#include "gson/json_object.hpp"
+#include "gson/json_primitive.hpp"
+#include "java_types.hpp"
+#include "map_renderer.hpp"
+#include "map_renderer_runnable.hpp"
+#include "native_map_view.hpp"
+#ifndef MBGL_MODULE_OFFLINE_DISABLE
+#include "offline/offline_manager.hpp"
+#include "offline/offline_region.hpp"
+#include "offline/offline_region_definition.hpp"
+#include "offline/offline_region_error.hpp"
+#include "offline/offline_region_status.hpp"
+#endif
+#include "style/transition_options.hpp"
+#include "style/layers/layer_manager.hpp"
+#include "style/sources/source.hpp"
+#include "style/light.hpp"
+#include "style/formatted.hpp"
+#include "style/formatted_section.hpp"
+#ifndef MBGL_MODULE_SNAPSHOT_DISABLE
+#include "snapshotter/map_snapshotter.hpp"
+#include "snapshotter/map_snapshot.hpp"
+#endif
+#include "text/collator_jni.hpp"
+#include "text/local_glyph_rasterizer_jni.hpp"
+#include "text/format_number_jni.hpp"
+#include "logger.hpp"
+
+namespace mbgl {
+namespace android {
+
+void RegisterNativeHTTPRequest(JNIEnv&);
+
+void registerNatives(JavaVM *vm) {
+ theJVM = vm;
+
+ jni::JNIEnv& env = jni::GetEnv(*vm, jni::jni_version_1_6);
+
+ // For the DefaultFileSource
+ static mbgl::util::RunLoop mainRunLoop;
+ FileSource::registerNative(env);
+
+ // Basic types
+ java::registerNatives(env);
+ java::util::registerNative(env);
+ PointF::registerNative(env);
+ RectF::registerNative(env);
+
+ // GeoJSON
+ geojson::Feature::registerNative(env);
+ geojson::FeatureCollection::registerNative(env);
+ geojson::Geometry::registerNative(env);
+ geojson::GeometryCollection::registerNative(env);
+ geojson::LineString::registerNative(env);
+ geojson::MultiLineString::registerNative(env);
+ geojson::MultiPoint::registerNative(env);
+ geojson::MultiPolygon::registerNative(env);
+ geojson::Point::registerNative(env);
+ geojson::Polygon::registerNative(env);
+
+ // Geometry
+ LatLng::registerNative(env);
+ LatLngBounds::registerNative(env);
+ LatLngQuad::registerNative(env);
+ ProjectedMeters::registerNative(env);
+
+ // GSon
+ gson::JsonArray::registerNative(env);
+ gson::JsonElement::registerNative(env);
+ gson::JsonObject::registerNative(env);
+ gson::JsonPrimitive::registerNative(env);
+
+ //Annotation
+ Marker::registerNative(env);
+ Polygon::registerNative(env);
+ Polyline::registerNative(env);
+
+ // Map
+ MapRenderer::registerNative(env);
+ MapRendererRunnable::registerNative(env);
+ NativeMapView::registerNative(env);
+
+ // Http
+ RegisterNativeHTTPRequest(env);
+
+ // Bitmap
+ Bitmap::registerNative(env);
+ BitmapFactory::registerNative(env);
+
+ // Style
+ TransitionOptions::registerNative(env);
+ LayerManagerAndroid::get()->registerNative(env);
+ Source::registerNative(env);
+ Light::registerNative(env);
+ Position::registerNative(env);
+ Formatted::registerNative(env);
+ FormattedSection::registerNative(env);
+
+ // Map
+ CameraPosition::registerNative(env);
+ Image::registerNative(env);
+
+ // Connectivity
+ ConnectivityListener::registerNative(env);
+
+ // Offline
+#ifndef MBGL_MODULE_OFFLINE_DISABLE
+ OfflineManager::registerNative(env);
+ OfflineRegion::registerNative(env);
+ OfflineRegionDefinition::registerNative(env);
+ OfflineTilePyramidRegionDefinition::registerNative(env);
+ OfflineGeometryRegionDefinition::registerNative(env);
+ OfflineRegionError::registerNative(env);
+ OfflineRegionStatus::registerNative(env);
+#endif
+
+ // Snapshotter
+#ifndef MBGL_MODULE_SNAPSHOT_DISABLE
+ MapSnapshotter::registerNative(env);
+ MapSnapshot::registerNative(env);
+#endif
+
+ // text
+ LocalGlyphRasterizer::registerNative(env);
+ Locale::registerNative(env);
+ Collator::registerNative(env);
+ StringUtils::registerNative(env);
+ NumberFormat::registerNative(env);
+
+ // Logger
+ Logger::registerNative(env);
+}
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/jni_native.hpp b/platform/android/src/jni_native.hpp
new file mode 100644
index 0000000000..a4c89d3036
--- /dev/null
+++ b/platform/android/src/jni_native.hpp
@@ -0,0 +1,11 @@
+#pragma once
+
+#include "jni.hpp"
+
+namespace mbgl {
+namespace android {
+
+void registerNatives(JavaVM* vm);
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/main.cpp b/platform/android/src/main.cpp
index 03a8288719..9b5c6c1974 100644
--- a/platform/android/src/main.cpp
+++ b/platform/android/src/main.cpp
@@ -1,4 +1,5 @@
#include "jni.hpp"
+#include "jni_native.hpp"
#include <jni/jni.hpp>
extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *) {
@@ -6,4 +7,3 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *) {
mbgl::android::registerNatives(vm);
return JNI_VERSION_1_6;
}
-
diff --git a/platform/android/src/map/camera_position.cpp b/platform/android/src/map/camera_position.cpp
index fcbec5639a..cbf5f2e408 100644
--- a/platform/android/src/map/camera_position.cpp
+++ b/platform/android/src/map/camera_position.cpp
@@ -4,9 +4,9 @@
namespace mbgl {
namespace android {
-jni::Local<jni::Object<CameraPosition>> CameraPosition::New(jni::JNIEnv &env, mbgl::CameraOptions options) {
+jni::Local<jni::Object<CameraPosition>> CameraPosition::New(jni::JNIEnv &env, mbgl::CameraOptions options, float pixelRatio) {
static auto& javaClass = jni::Class<CameraPosition>::Singleton(env);
- static auto constructor = javaClass.GetConstructor<jni::Object<LatLng>, double, double, double>(env);
+ static auto constructor = javaClass.GetConstructor<jni::Object<LatLng>, double, double, double, jni::Array<jni::jdouble>>(env);
// wrap LatLng values coming from core
auto center = options.center.value();
@@ -25,21 +25,33 @@ jni::Local<jni::Object<CameraPosition>> CameraPosition::New(jni::JNIEnv &env, mb
// convert tilt, core ranges from [0 rad, 1,0472 rad], android ranges from 0 to 60
double tilt_degrees = options.pitch.value_or(0);
- return javaClass.New(env, constructor, LatLng::New(env, center), options.zoom.value_or(0), tilt_degrees, bearing_degrees);
+ std::vector<jdouble> paddingVect;
+ auto insets = options.padding.value_or(EdgeInsets {0, 0, 0, 0});
+ auto padding = jni::Array<jni::jdouble>::New(env, 4);
+ paddingVect.push_back(insets.left() * pixelRatio);
+ paddingVect.push_back(insets.top() * pixelRatio);
+ paddingVect.push_back(insets.right() * pixelRatio);
+ paddingVect.push_back(insets.bottom() * pixelRatio);
+ padding.SetRegion<std::vector<jni::jdouble>>(env, 0, paddingVect);
+
+ return javaClass.New(env, constructor, LatLng::New(env, center), options.zoom.value_or(0), tilt_degrees, bearing_degrees, padding);
}
-mbgl::CameraOptions CameraPosition::getCameraOptions(jni::JNIEnv& env, const jni::Object<CameraPosition>& position) {
+mbgl::CameraOptions CameraPosition::getCameraOptions(jni::JNIEnv& env, const jni::Object<CameraPosition>& position, float pixelRatio) {
static auto& javaClass = jni::Class<CameraPosition>::Singleton(env);
static auto bearing = javaClass.GetField<jni::jdouble>(env, "bearing");
static auto target = javaClass.GetField<jni::Object<LatLng>>(env, "target");
static auto tilt = javaClass.GetField<jni::jdouble>(env, "tilt");
static auto zoom = javaClass.GetField<jni::jdouble>(env, "zoom");
+ static auto paddingField = javaClass.GetField<jni::Array<jni::jdouble>>(env, "padding");
+ static auto padding = position.Get(env, paddingField);
auto center = LatLng::getLatLng(env, position.Get(env, target));
return mbgl::CameraOptions {
center,
- {},
+ padding ? EdgeInsets {padding.Get(env, 1) * pixelRatio, padding.Get(env, 0) * pixelRatio,
+ padding.Get(env, 3) * pixelRatio, padding.Get(env, 2) * pixelRatio} : (EdgeInsets) {},
{},
position.Get(env, zoom),
position.Get(env, bearing),
diff --git a/platform/android/src/map/camera_position.hpp b/platform/android/src/map/camera_position.hpp
index 7579f9fed1..b677f04ea0 100644
--- a/platform/android/src/map/camera_position.hpp
+++ b/platform/android/src/map/camera_position.hpp
@@ -12,9 +12,9 @@ class CameraPosition : private mbgl::util::noncopyable {
public:
static constexpr auto Name() { return "com/mapbox/mapboxsdk/camera/CameraPosition"; };
- static jni::Local<jni::Object<CameraPosition>> New(jni::JNIEnv&, mbgl::CameraOptions);
+ static jni::Local<jni::Object<CameraPosition>> New(jni::JNIEnv&, mbgl::CameraOptions, float pixelRatio);
- static mbgl::CameraOptions getCameraOptions(jni::JNIEnv&, const jni::Object<CameraPosition>&);
+ static mbgl::CameraOptions getCameraOptions(jni::JNIEnv&, const jni::Object<CameraPosition>&, float pixelRatio);
static void registerNative(jni::JNIEnv&);
};
diff --git a/platform/android/src/map_renderer.cpp b/platform/android/src/map_renderer.cpp
index 92444c404d..6be708b994 100644
--- a/platform/android/src/map_renderer.cpp
+++ b/platform/android/src/map_renderer.cpp
@@ -16,11 +16,9 @@ namespace android {
MapRenderer::MapRenderer(jni::JNIEnv& _env,
const jni::Object<MapRenderer>& obj,
jni::jfloat pixelRatio_,
- const jni::String& programCacheDir_,
const jni::String& localIdeographFontFamily_)
: javaPeer(_env, obj)
, pixelRatio(pixelRatio_)
- , programCacheDir(jni::Make<std::string>(_env, programCacheDir_))
, localIdeographFontFamily(localIdeographFontFamily_ ? jni::Make<std::string>(_env, localIdeographFontFamily_) : optional<std::string>{})
, mailbox(std::make_shared<Mailbox>(*this)) {
}
@@ -173,7 +171,7 @@ void MapRenderer::onSurfaceCreated(JNIEnv&) {
// Create the new backend and renderer
backend = std::make_unique<AndroidRendererBackend>();
- renderer = std::make_unique<Renderer>(*backend, pixelRatio, programCacheDir, localIdeographFontFamily);
+ renderer = std::make_unique<Renderer>(*backend, pixelRatio, localIdeographFontFamily);
rendererRef = std::make_unique<ActorRef<Renderer>>(*renderer, mailbox);
// Set the observer on the new Renderer implementation
@@ -214,7 +212,7 @@ void MapRenderer::registerNative(jni::JNIEnv& env) {
// Register the peer
jni::RegisterNativePeer<MapRenderer>(env, javaClass, "nativePtr",
- jni::MakePeer<MapRenderer, const jni::Object<MapRenderer>&, jni::jfloat, const jni::String&, const jni::String&>,
+ jni::MakePeer<MapRenderer, const jni::Object<MapRenderer>&, jni::jfloat, const jni::String&>,
"nativeInitialize", "finalize",
METHOD(&MapRenderer::render, "nativeRender"),
METHOD(&MapRenderer::onRendererReset, "nativeReset"),
diff --git a/platform/android/src/map_renderer.hpp b/platform/android/src/map_renderer.hpp
index efbe55af7f..5a8ddeeb91 100644
--- a/platform/android/src/map_renderer.hpp
+++ b/platform/android/src/map_renderer.hpp
@@ -44,7 +44,6 @@ public:
MapRenderer(jni::JNIEnv& _env,
const jni::Object<MapRenderer>&,
jni::jfloat pixelRatio,
- const jni::String& programCacheDir,
const jni::String& localIdeographFontFamily);
~MapRenderer() override;
@@ -104,7 +103,6 @@ private:
jni::WeakReference<jni::Object<MapRenderer>, jni::EnvAttachingDeleter> javaPeer;
float pixelRatio;
- std::string programCacheDir;
optional<std::string> localIdeographFontFamily;
std::shared_ptr<ThreadPool> threadPool;
diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp
index 47f2c6d9aa..7b87693cf5 100755
--- a/platform/android/src/native_map_view.cpp
+++ b/platform/android/src/native_map_view.cpp
@@ -185,7 +185,7 @@ void NativeMapView::onWillStartRenderingFrame() {
}
}
-void NativeMapView::onDidFinishRenderingFrame(MapObserver::RenderMode mode) {
+void NativeMapView::onDidFinishRenderingFrame(MapObserver::RenderFrameStatus status) {
assert(vm != nullptr);
android::UniqueEnv _env = android::AttachEnv();
@@ -193,7 +193,7 @@ void NativeMapView::onDidFinishRenderingFrame(MapObserver::RenderMode mode) {
static auto onDidFinishRenderingFrame = javaClass.GetMethod<void (jboolean)>(*_env, "onDidFinishRenderingFrame");
auto weakReference = javaPeer.get(*_env);
if (weakReference) {
- weakReference.Call(*_env, onDidFinishRenderingFrame, (jboolean) (mode != MapObserver::RenderMode::Partial));
+ weakReference.Call(*_env, onDidFinishRenderingFrame, (jboolean) (status.mode != MapObserver::RenderMode::Partial));
}
}
@@ -336,13 +336,17 @@ void NativeMapView::moveBy(jni::JNIEnv&, jni::jdouble dx, jni::jdouble dy, jni::
map->moveBy({dx, dy}, animationOptions);
}
-void NativeMapView::jumpTo(jni::JNIEnv&, jni::jdouble bearing, jni::jdouble latitude, jni::jdouble longitude, jni::jdouble pitch, jni::jdouble zoom) {
+void NativeMapView::jumpTo(jni::JNIEnv& env, jni::jdouble bearing, jni::jdouble latitude, jni::jdouble longitude, jni::jdouble pitch, jni::jdouble zoom, const jni::Array<jni::jdouble>& padding) {
mbgl::CameraOptions options;
if (bearing != -1) {
options.bearing = bearing;
}
options.center = mbgl::LatLng(latitude, longitude);
- options.padding = insets;
+ if (padding) {
+ assert(padding.Length(env) == 4);
+ options.padding = mbgl::EdgeInsets{padding.Get(env, 0), padding.Get(env, 1),
+ padding.Get(env, 2), padding.Get(env, 3)};
+ }
if (pitch != -1) {
options.pitch = pitch;
}
@@ -353,13 +357,17 @@ void NativeMapView::jumpTo(jni::JNIEnv&, jni::jdouble bearing, jni::jdouble lati
map->jumpTo(options);
}
-void NativeMapView::easeTo(jni::JNIEnv&, jni::jdouble bearing, jni::jdouble latitude, jni::jdouble longitude, jni::jlong duration, jni::jdouble pitch, jni::jdouble zoom, jni::jboolean easing) {
+void NativeMapView::easeTo(jni::JNIEnv& env, jni::jdouble bearing, jni::jdouble latitude, jni::jdouble longitude, jni::jlong duration, jni::jdouble pitch, jni::jdouble zoom, const jni::Array<jni::jdouble>& padding, jni::jboolean easing) {
mbgl::CameraOptions cameraOptions;
if (bearing != -1) {
cameraOptions.bearing = bearing;
}
cameraOptions.center = mbgl::LatLng(latitude, longitude);
- cameraOptions.padding = insets;
+ if (padding) {
+ assert(padding.Length(env) == 4);
+ cameraOptions.padding = mbgl::EdgeInsets{padding.Get(env, 0), padding.Get(env, 1),
+ padding.Get(env, 2), padding.Get(env, 3)};
+ }
if (pitch != -1) {
cameraOptions.pitch = pitch;
}
@@ -377,13 +385,17 @@ void NativeMapView::easeTo(jni::JNIEnv&, jni::jdouble bearing, jni::jdouble lati
map->easeTo(cameraOptions, animationOptions);
}
-void NativeMapView::flyTo(jni::JNIEnv&, jni::jdouble bearing, jni::jdouble latitude, jni::jdouble longitude, jni::jlong duration, jni::jdouble pitch, jni::jdouble zoom) {
+void NativeMapView::flyTo(jni::JNIEnv& env, jni::jdouble bearing, jni::jdouble latitude, jni::jdouble longitude, jni::jlong duration, jni::jdouble pitch, jni::jdouble zoom, const jni::Array<jni::jdouble>& padding) {
mbgl::CameraOptions cameraOptions;
if (bearing != -1) {
cameraOptions.bearing = bearing;
}
cameraOptions.center = mbgl::LatLng(latitude, longitude);
- cameraOptions.padding = insets;
+ if (padding) {
+ assert(padding.Length(env) == 4);
+ cameraOptions.padding = mbgl::EdgeInsets{padding.Get(env, 0), padding.Get(env, 1),
+ padding.Get(env, 2), padding.Get(env, 3)};
+ }
if (pitch != -1) {
cameraOptions.pitch = pitch;
}
@@ -397,23 +409,29 @@ void NativeMapView::flyTo(jni::JNIEnv&, jni::jdouble bearing, jni::jdouble latit
}
jni::Local<jni::Object<LatLng>> NativeMapView::getLatLng(JNIEnv& env) {
- return LatLng::New(env, *map->getCameraOptions(insets).center);
+ return LatLng::New(env, *map->getCameraOptions(mbgl::nullopt).center);
}
-void NativeMapView::setLatLng(jni::JNIEnv&, jni::jdouble latitude, jni::jdouble longitude, jni::jlong duration) {
- map->easeTo(mbgl::CameraOptions().withCenter(mbgl::LatLng(latitude, longitude)).withPadding(insets),
- mbgl::AnimationOptions{mbgl::Milliseconds(duration)});
+void NativeMapView::setLatLng(jni::JNIEnv& env, jni::jdouble latitude, jni::jdouble longitude, const jni::Array<jni::jdouble>& padding, jni::jlong duration) {
+ mbgl::CameraOptions cameraOptions;
+ cameraOptions.center = mbgl::LatLng(latitude, longitude);
+ if (padding) {
+ assert(padding.Length(env) == 4);
+ cameraOptions.padding = mbgl::EdgeInsets{padding.Get(env, 0), padding.Get(env, 1),
+ padding.Get(env, 2), padding.Get(env, 3)};
+ }
+ map->easeTo(cameraOptions, mbgl::AnimationOptions{mbgl::Milliseconds(duration)});
}
jni::Local<jni::Object<CameraPosition>> NativeMapView::getCameraForLatLngBounds(jni::JNIEnv& env, const jni::Object<LatLngBounds>& jBounds, double top, double left, double bottom, double right, double bearing, double tilt) {
mbgl::EdgeInsets padding = {top, left, bottom, right};
- return CameraPosition::New(env, map->cameraForLatLngBounds(mbgl::android::LatLngBounds::getLatLngBounds(env, jBounds), padding, bearing, tilt));
+ return CameraPosition::New(env, map->cameraForLatLngBounds(mbgl::android::LatLngBounds::getLatLngBounds(env, jBounds), padding, bearing, tilt), pixelRatio);
}
jni::Local<jni::Object<CameraPosition>> NativeMapView::getCameraForGeometry(jni::JNIEnv& env, const jni::Object<geojson::Geometry>& jGeometry, double top, double left, double bottom, double right, double bearing, double tilt) {
auto geometry = geojson::Geometry::convert(env, jGeometry);
mbgl::EdgeInsets padding = {top, left, bottom, right};
- return CameraPosition::New(env, map->cameraForGeometry(geometry, padding, bearing, tilt));
+ return CameraPosition::New(env, map->cameraForGeometry(geometry, padding, bearing, tilt), pixelRatio);
}
void NativeMapView::setReachability(jni::JNIEnv&, jni::jboolean reachable) {
@@ -514,23 +532,6 @@ void NativeMapView::setVisibleCoordinateBounds(JNIEnv& env, const jni::Array<jni
map->easeTo(cameraOptions, animationOptions);
}
-void NativeMapView::setContentPadding(JNIEnv&, float top, float left, float bottom, float right) {
- insets = {top, left, bottom, right};
- // invalidate the camera position to consider the new padding
- map->jumpTo(map->getCameraOptions(insets));
-}
-
-jni::Local<jni::Array<jni::jfloat>> NativeMapView::getContentPadding(JNIEnv& env) {
- auto result = jni::Array<jni::jfloat>::New(env, 4);
- std::vector<jfloat> vect;
- vect.push_back(insets.top());
- vect.push_back(insets.left());
- vect.push_back(insets.bottom());
- vect.push_back(insets.right());
- result.SetRegion<std::vector<jni::jfloat>>(env, 0, vect);
- return result;
-}
-
void NativeMapView::scheduleSnapshot(jni::JNIEnv&) {
mapRenderer.requestSnapshot([&](PremultipliedImage image) {
auto _env = android::AttachEnv();
@@ -548,7 +549,7 @@ void NativeMapView::scheduleSnapshot(jni::JNIEnv&) {
}
jni::Local<jni::Object<CameraPosition>> NativeMapView::getCameraPosition(jni::JNIEnv& env) {
- return CameraPosition::New(env, map->getCameraOptions(insets));
+ return CameraPosition::New(env, map->getCameraOptions(mbgl::nullopt), pixelRatio);
}
void NativeMapView::updateMarker(jni::JNIEnv& env, jni::jlong markerId, jni::jdouble lat, jni::jdouble lon, const jni::String& jid) {
@@ -1098,8 +1099,6 @@ void NativeMapView::registerNative(jni::JNIEnv& env) {
METHOD(&NativeMapView::getBearing, "nativeGetBearing"),
METHOD(&NativeMapView::resetNorth, "nativeResetNorth"),
METHOD(&NativeMapView::setVisibleCoordinateBounds, "nativeSetVisibleCoordinateBounds"),
- METHOD(&NativeMapView::setContentPadding, "nativeSetContentPadding"),
- METHOD(&NativeMapView::getContentPadding, "nativeGetContentPadding"),
METHOD(&NativeMapView::scheduleSnapshot, "nativeTakeSnapshot"),
METHOD(&NativeMapView::getCameraPosition, "nativeGetCameraPosition"),
METHOD(&NativeMapView::updateMarker, "nativeUpdateMarker"),
diff --git a/platform/android/src/native_map_view.hpp b/platform/android/src/native_map_view.hpp
index 4ea4781b36..ba2178022e 100755
--- a/platform/android/src/native_map_view.hpp
+++ b/platform/android/src/native_map_view.hpp
@@ -62,7 +62,7 @@ public:
void onDidFinishLoadingMap() override;
void onDidFailLoadingMap(MapLoadError, const std::string&) override;
void onWillStartRenderingFrame() override;
- void onDidFinishRenderingFrame(MapObserver::RenderMode) override;
+ void onDidFinishRenderingFrame(MapObserver::RenderFrameStatus) override;
void onWillStartRenderingMap() override;
void onDidFinishRenderingMap(MapObserver::RenderMode) override;
void onDidBecomeIdle() override;
@@ -91,15 +91,15 @@ public:
void moveBy(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jlong);
- void jumpTo(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jdouble, jni::jdouble);
+ void jumpTo(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jdouble, jni::jdouble, const jni::Array<jni::jdouble>&);
- void easeTo(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong, jni::jdouble, jni::jdouble, jni::jboolean);
+ void easeTo(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong, jni::jdouble, jni::jdouble, const jni::Array<jni::jdouble>&, jni::jboolean);
- void flyTo(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong, jni::jdouble, jni::jdouble);
+ void flyTo(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong, jni::jdouble, jni::jdouble, const jni::Array<jni::jdouble>&);
jni::Local<jni::Object<LatLng>> getLatLng(JNIEnv&);
- void setLatLng(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jlong);
+ void setLatLng(jni::JNIEnv&, jni::jdouble, jni::jdouble, const jni::Array<jni::jdouble>&, jni::jlong);
jni::Local<jni::Object<CameraPosition>> getCameraForLatLngBounds(jni::JNIEnv&, const jni::Object<mbgl::android::LatLngBounds>&, double top, double left, double bottom, double right, double bearing, double tilt);
@@ -139,10 +139,6 @@ public:
void setVisibleCoordinateBounds(JNIEnv&, const jni::Array<jni::Object<LatLng>>&, const jni::Object<RectF>&, jni::jdouble, jni::jlong);
- void setContentPadding(JNIEnv&, float, float, float, float);
-
- jni::Local<jni::Array<jni::jfloat>> getContentPadding(JNIEnv&);
-
void scheduleSnapshot(jni::JNIEnv&);
jni::Local<jni::Object<CameraPosition>> getCameraPosition(jni::JNIEnv&);
@@ -259,7 +255,6 @@ private:
// Ensure these are initialised last
std::unique_ptr<mbgl::Map> map;
- mbgl::EdgeInsets insets;
};
} // namespace android
diff --git a/platform/android/src/snapshotter/map_snapshotter.cpp b/platform/android/src/snapshotter/map_snapshotter.cpp
index 2eca6595e1..0b38269ada 100644
--- a/platform/android/src/snapshotter/map_snapshotter.cpp
+++ b/platform/android/src/snapshotter/map_snapshotter.cpp
@@ -23,7 +23,6 @@ MapSnapshotter::MapSnapshotter(jni::JNIEnv& _env,
const jni::Object<LatLngBounds>& region,
const jni::Object<CameraPosition>& position,
jni::jboolean _showLogo,
- const jni::String& _programCacheDir,
const jni::String& _localIdeographFontFamily)
: javaPeer(_env, _obj)
, pixelRatio(_pixelRatio) {
@@ -39,7 +38,7 @@ MapSnapshotter::MapSnapshotter(jni::JNIEnv& _env,
optional<mbgl::CameraOptions> cameraOptions;
if (position) {
- cameraOptions = CameraPosition::getCameraOptions(_env, position);
+ cameraOptions = CameraPosition::getCameraOptions(_env, position, pixelRatio);
}
optional<mbgl::LatLngBounds> bounds;
@@ -61,7 +60,6 @@ MapSnapshotter::MapSnapshotter(jni::JNIEnv& _env,
pixelRatio,
cameraOptions,
bounds,
- jni::Make<std::string>(_env, _programCacheDir),
_localIdeographFontFamily ?
jni::Make<std::string>(_env, _localIdeographFontFamily) :
optional<std::string>{},
@@ -126,7 +124,7 @@ void MapSnapshotter::setSize(JNIEnv&, jni::jint width, jni::jint height) {
}
void MapSnapshotter::setCameraPosition(JNIEnv& env, const jni::Object<CameraPosition>& position) {
- auto options = CameraPosition::getCameraOptions(env, position);
+ auto options = CameraPosition::getCameraOptions(env, position, pixelRatio);
snapshotter->setCameraOptions(options);
}
@@ -161,7 +159,7 @@ void MapSnapshotter::registerNative(jni::JNIEnv& env) {
// Register the peer
jni::RegisterNativePeer<MapSnapshotter>(env, javaClass, "nativePtr",
- jni::MakePeer<MapSnapshotter, const jni::Object<MapSnapshotter>&, const jni::Object<FileSource>&, jni::jfloat, jni::jint, jni::jint, const jni::String&, const jni::String&, const jni::Object<LatLngBounds>&, const jni::Object<CameraPosition>&, jni::jboolean, const jni::String&, const jni::String&>,
+ jni::MakePeer<MapSnapshotter, const jni::Object<MapSnapshotter>&, const jni::Object<FileSource>&, jni::jfloat, jni::jint, jni::jint, const jni::String&, const jni::String&, const jni::Object<LatLngBounds>&, const jni::Object<CameraPosition>&, jni::jboolean, const jni::String&>,
"nativeInitialize",
"finalize",
METHOD(&MapSnapshotter::setStyleUrl, "setStyleUrl"),
diff --git a/platform/android/src/snapshotter/map_snapshotter.hpp b/platform/android/src/snapshotter/map_snapshotter.hpp
index 791aa61d6a..608a4c855f 100644
--- a/platform/android/src/snapshotter/map_snapshotter.hpp
+++ b/platform/android/src/snapshotter/map_snapshotter.hpp
@@ -34,7 +34,6 @@ public:
const jni::Object<LatLngBounds>& region,
const jni::Object<CameraPosition>& position,
jni::jboolean showLogo,
- const jni::String& programCacheDir,
const jni::String& localIdeographFontFamily);
~MapSnapshotter();
diff --git a/platform/android/src/style/android_conversion.hpp b/platform/android/src/style/android_conversion.hpp
index 8559720b2f..dc0a0acb31 100644
--- a/platform/android/src/style/android_conversion.hpp
+++ b/platform/android/src/style/android_conversion.hpp
@@ -47,9 +47,18 @@ public:
}
template <class Fn>
- static optional<Error> eachMember(const mbgl::android::Value&, Fn&&) {
- // TODO
- mbgl::Log::Warning(mbgl::Event::Android, "eachMember not implemented");
+ static optional<Error> eachMember(const mbgl::android::Value& value, Fn&& fn) {
+ assert(value.isObject());
+ mbgl::android::Value keys = value.keyArray();
+ std::size_t length = arrayLength(keys);
+ for(std::size_t i = 0; i < length; ++i){
+ const auto k = keys.get(i).toString();
+ auto v = value.get(k.c_str());
+ optional<Error> result = fn(k, std::move(v));
+ if (result) {
+ return result;
+ }
+ }
return {};
}
@@ -94,8 +103,7 @@ public:
} else if (value.isString()) {
return { value.toString() };
} else if (value.isNumber()) {
- auto doubleVal = value.toDouble();
- return { doubleVal - (int) doubleVal > 0.0 ? doubleVal : value.toLong() };
+ return { value.toDouble() };
} else {
return {};
}
diff --git a/platform/android/src/style/sources/custom_geometry_source.cpp b/platform/android/src/style/sources/custom_geometry_source.cpp
index 057f5c99ba..dccca4cf46 100644
--- a/platform/android/src/style/sources/custom_geometry_source.cpp
+++ b/platform/android/src/style/sources/custom_geometry_source.cpp
@@ -65,7 +65,12 @@ namespace android {
static auto& javaClass = jni::Class<CustomGeometrySource>::Singleton(*_env);
static auto fetchTile = javaClass.GetMethod<void (jni::jint, jni::jint, jni::jint)>(*_env, "fetchTile");
- assert(javaPeer);
+ // The source is removed on the main thread, but it still exists on the Render thread until the frame is complete.
+ // This might cause fetchTile/cancelTile invocations when the Java thread is shutting down and the peer has already been released.
+ // See https://github.com/mapbox/mapbox-gl-native/issues/12551.
+ if(!javaPeer) {
+ return;
+ }
auto peer = jni::Cast(*_env, javaClass, javaPeer);
peer.Call(*_env, fetchTile, (int)tileID.z, (int)tileID.x, (int)tileID.y);
@@ -77,7 +82,12 @@ namespace android {
static auto& javaClass = jni::Class<CustomGeometrySource>::Singleton(*_env);
static auto cancelTile = javaClass.GetMethod<void (jni::jint, jni::jint, jni::jint)>(*_env, "cancelTile");
- assert(javaPeer);
+ // The source is removed on the main thread, but it still exists on the Render thread until the frame is complete.
+ // This might cause fetchTile/cancelTile invocations when the Java thread is shutting down and the peer has already been released.
+ // See https://github.com/mapbox/mapbox-gl-native/issues/12551.
+ if(!javaPeer) {
+ return;
+ }
auto peer = jni::Cast(*_env, javaClass, javaPeer);
peer.Call(*_env, cancelTile, (int)tileID.z, (int)tileID.x, (int)tileID.y);
diff --git a/platform/android/src/style/sources/source.cpp b/platform/android/src/style/sources/source.cpp
index be4c0367fc..786e5cb586 100644
--- a/platform/android/src/style/sources/source.cpp
+++ b/platform/android/src/style/sources/source.cpp
@@ -133,7 +133,7 @@ namespace android {
// Release the peer relationships. These will be re-established when the source is added to a map
assert(ownedSource->peer.has_value());
ownedSource->peer.get<std::unique_ptr<Source>>().release();
- ownedSource->peer = util::peer();
+ ownedSource->peer = mapbox::base::TypeWrapper();
// Release the strong reference to the java peer
assert(javaPeer);
diff --git a/platform/android/src/style/value.cpp b/platform/android/src/style/value.cpp
index f916909687..2f04840729 100644
--- a/platform/android/src/style/value.cpp
+++ b/platform/android/src/style/value.cpp
@@ -63,6 +63,12 @@ namespace android {
return Value(env, jni::Local<jni::Object<>>(env, member));
}
+ Value Value::keyArray() const{
+ jni::jobject* set = jni::CallMethod<jni::jobject*>(env, value.get(), *java::Map::keySetMethodId);
+ jni::jobject* array = jni::CallMethod<jni::jobject*>(env, set, *java::Set::toArrayMethodId);
+ return Value(env, jni::Local<jni::Object<>>(env, array));
+ }
+
int Value::getLength() const {
auto array = (jni::jarray<jni::jobject>*) value.get();
return jni::GetArrayLength(env, *array);
diff --git a/platform/android/src/style/value.hpp b/platform/android/src/style/value.hpp
index 0c702bb465..b507c5ed11 100644
--- a/platform/android/src/style/value.hpp
+++ b/platform/android/src/style/value.hpp
@@ -31,6 +31,7 @@ public:
long toLong() const;
bool toBool() const;
Value get(const char* key) const;
+ Value keyArray() const;
int getLength() const;
Value get(const int index ) const;
diff --git a/platform/android/vendor/mapbox-gestures-android b/platform/android/vendor/mapbox-gestures-android
-Subproject d099f39e00358d6700c3e1c588e08e1a80f6c45
+Subproject ae08de82ca178dca7f005dfc8056554cf77124a
diff --git a/platform/android/vendor/mapbox-java b/platform/android/vendor/mapbox-java
-Subproject 305f6a78d1c1c4ec45735b0cf98bd7c4ea4658f
+Subproject 84de2d4b02e93a9eda9d0254332cd356d17445d
diff --git a/platform/darwin/src/MGLAccountManager.m b/platform/darwin/src/MGLAccountManager.m
index 69170459bc..c37195967a 100644
--- a/platform/darwin/src/MGLAccountManager.m
+++ b/platform/darwin/src/MGLAccountManager.m
@@ -13,6 +13,8 @@ static NSString * const MGLAccountManagerExternalClassName = @"MBXAccounts";
static NSString * const MGLAccountManagerExternalMethodName = @"skuToken";
#endif
+NSString * const MGLMapboxAccountTypeKey = @"MGLMapboxAccountType";
+
@interface MGLAccountManager ()
@property (atomic) NSString *accessToken;
diff --git a/platform/darwin/src/MGLAccountManager_Private.h b/platform/darwin/src/MGLAccountManager_Private.h
index 3fd45f1ae8..4bf7963182 100644
--- a/platform/darwin/src/MGLAccountManager_Private.h
+++ b/platform/darwin/src/MGLAccountManager_Private.h
@@ -2,6 +2,9 @@
NS_ASSUME_NONNULL_BEGIN
+/// NSUserDefaults key that controls developer account type
+FOUNDATION_EXTERN NSString * const MGLMapboxAccountTypeKey;
+
@interface MGLAccountManager (Private)
/// Returns the shared instance of the `MGLAccountManager` class.
diff --git a/platform/darwin/src/MGLComputedShapeSource.mm b/platform/darwin/src/MGLComputedShapeSource.mm
index 5110435b03..a04181af2f 100644
--- a/platform/darwin/src/MGLComputedShapeSource.mm
+++ b/platform/darwin/src/MGLComputedShapeSource.mm
@@ -199,6 +199,7 @@ mbgl::style::CustomGeometrySource::Options MBGLCustomGeometrySourceOptionsFromDi
}
- (void)setFeatures:(NSArray<MGLShape <MGLFeature> *>*)features inTileAtX:(NSUInteger)x y:(NSUInteger)y zoomLevel:(NSUInteger)zoomLevel {
+ MGLAssertStyleSourceIsValid();
mbgl::CanonicalTileID tileID = mbgl::CanonicalTileID((uint8_t)zoomLevel, (uint32_t)x, (uint32_t)y);
mbgl::FeatureCollection featureCollection;
featureCollection.reserve(features.count);
@@ -236,10 +237,12 @@ mbgl::style::CustomGeometrySource::Options MBGLCustomGeometrySourceOptionsFromDi
}
- (void) invalidateBounds:(MGLCoordinateBounds)bounds {
+ MGLAssertStyleSourceIsValid();
((mbgl::style::CustomGeometrySource *)self.rawSource)->invalidateRegion(MGLLatLngBoundsFromCoordinateBounds(bounds));
}
- (void) invalidateTileAtX:(NSUInteger)x y:(NSUInteger)y zoomLevel:(NSUInteger)z {
+ MGLAssertStyleSourceIsValid();
((mbgl::style::CustomGeometrySource *)self.rawSource)->invalidateTile(mbgl::CanonicalTileID(z, (unsigned int)x, (unsigned int)y));
}
diff --git a/platform/darwin/src/MGLForegroundStyleLayer.mm b/platform/darwin/src/MGLForegroundStyleLayer.mm
index 76700d6f77..eaa5e83e59 100644
--- a/platform/darwin/src/MGLForegroundStyleLayer.mm
+++ b/platform/darwin/src/MGLForegroundStyleLayer.mm
@@ -1,4 +1,5 @@
#import "MGLForegroundStyleLayer.h"
+#import "MGLStyleLayer_Private.h"
@implementation MGLForegroundStyleLayer
@@ -9,10 +10,17 @@
}
- (NSString *)description {
- return [NSString stringWithFormat:
- @"<%@: %p; identifier = %@; sourceIdentifier = %@; visible = %@>",
- NSStringFromClass([self class]), (void *)self, self.identifier,
- self.sourceIdentifier, self.visible ? @"YES" : @"NO"];
+ if (self.rawLayer) {
+ return [NSString stringWithFormat:
+ @"<%@: %p; identifier = %@; sourceIdentifier = %@; visible = %@>",
+ NSStringFromClass([self class]), (void *)self, self.identifier,
+ self.sourceIdentifier, self.visible ? @"YES" : @"NO"];
+ }
+ else {
+ return [NSString stringWithFormat:
+ @"<%@: %p; identifier = %@; sourceIdentifier = <unknown>; visible = NO>",
+ NSStringFromClass([self class]), (void *)self, self.identifier];
+ }
}
@end
diff --git a/platform/darwin/src/MGLImageSource.mm b/platform/darwin/src/MGLImageSource.mm
index 351247e901..421cc7a155 100644
--- a/platform/darwin/src/MGLImageSource.mm
+++ b/platform/darwin/src/MGLImageSource.mm
@@ -45,11 +45,13 @@
}
- (NSURL *)URL {
+ MGLAssertStyleSourceIsValid();
auto url = self.rawSource->getURL();
return url ? [NSURL URLWithString:@(url->c_str())] : nil;
}
- (void)setURL:(NSURL *)url {
+ MGLAssertStyleSourceIsValid();
if (url) {
self.rawSource->setURL(url.mgl_URLByStandardizingScheme.absoluteString.UTF8String);
_image = nil;
@@ -59,6 +61,7 @@
}
- (void)setImage:(MGLImage *)image {
+ MGLAssertStyleSourceIsValid();
if (image != nullptr) {
self.rawSource->setImage(image.mgl_premultipliedImage);
} else {
@@ -68,16 +71,27 @@
}
- (MGLCoordinateQuad)coordinates {
+ MGLAssertStyleSourceIsValid();
return MGLCoordinateQuadFromLatLngArray(self.rawSource->getCoordinates());
}
- (void)setCoordinates: (MGLCoordinateQuad)coordinateQuad {
+ MGLAssertStyleSourceIsValid();
self.rawSource->setCoordinates(MGLLatLngArrayFromCoordinateQuad(coordinateQuad));
}
- (NSString *)description {
- return [NSString stringWithFormat:@"<%@: %p; identifier = %@; coordinates = %@; URL = %@; image = %@>",
- NSStringFromClass([self class]), (void *)self, self.identifier, MGLStringFromCoordinateQuad(self.coordinates), self.URL, self.image];
+ if (self.rawSource) {
+ return [NSString stringWithFormat:@"<%@: %p; identifier = %@; coordinates = %@; URL = %@; image = %@>",
+ NSStringFromClass([self class]), (void *)self, self.identifier,
+ MGLStringFromCoordinateQuad(self.coordinates),
+ self.URL,
+ self.image];
+ }
+ else {
+ return [NSString stringWithFormat:@"<%@: %p; identifier = %@; coordinates = <unknown>; URL = <unknown>; image = %@>",
+ NSStringFromClass([self class]), (void *)self, self.identifier, self.image];
+ }
}
- (mbgl::style::ImageSource *)rawSource {
@@ -85,6 +99,7 @@
}
- (NSString *)attributionHTMLString {
+ MGLAssertStyleSourceIsValid();
auto attribution = self.rawSource->getAttribution();
return attribution ? @(attribution->c_str()) : nil;
}
diff --git a/platform/darwin/src/MGLMapSnapshotter.h b/platform/darwin/src/MGLMapSnapshotter.h
index 1ee9bd99bb..0f20cf1bb2 100644
--- a/platform/darwin/src/MGLMapSnapshotter.h
+++ b/platform/darwin/src/MGLMapSnapshotter.h
@@ -6,6 +6,30 @@
NS_ASSUME_NONNULL_BEGIN
/**
+ An overlay that is placed within a `MGLMapSnapshot`.
+ To access this object, use `-[MGLMapSnapshotter startWithOverlayHandler:completionHandler:]`.
+ */
+
+MGL_EXPORT
+@interface MGLMapSnapshotOverlay : NSObject
+
+/**
+ The current `CGContext` that snapshot is drawing within. You may use this context
+ to perform additional custom drawing.
+ */
+@property (nonatomic, readonly) CGContextRef context;
+
+@end
+
+/**
+A block provided during the snapshot drawing process, enabling the ability to
+draw custom overlays rendered with Core Graphics.
+
+ @param snapshotOverlay The `MGLMapSnapshotOverlay` provided during snapshot drawing.
+ */
+typedef void (^MGLMapSnapshotOverlayHandler)(MGLMapSnapshotOverlay * snapshotOverlay);
+
+/**
The options to use when creating images with the `MGLMapSnapshotter`.
*/
MGL_EXPORT
@@ -201,6 +225,16 @@ MGL_EXPORT
- (void)startWithQueue:(dispatch_queue_t)queue completionHandler:(MGLMapSnapshotCompletionHandler)completionHandler;
/**
+ Starts the snapshot creation and executes the specified blocks with the result
+ on the specified queue. Use this option if you want to add custom drawing on top of the
+ resulting `MGLMapSnapShot`.
+ @param queue The queue to handle the result on.
+ @param overlayHandler The block to handle manipulation of the `MGLMapSnapshotter`'s `CGContext`.
+ @param completionHandler The block to handle the result in.
+ */
+- (void)startWithOverlayHandler:(MGLMapSnapshotOverlayHandler)overlayHandler completionHandler:(MGLMapSnapshotCompletionHandler)completionHandler;
+
+/**
Cancels the snapshot creation request, if any.
Once you call this method, you cannot resume the snapshot. In order to obtain
diff --git a/platform/darwin/src/MGLMapSnapshotter.mm b/platform/darwin/src/MGLMapSnapshotter.mm
index 9ba0cbebfe..85619a780b 100644
--- a/platform/darwin/src/MGLMapSnapshotter.mm
+++ b/platform/darwin/src/MGLMapSnapshotter.mm
@@ -32,6 +32,26 @@
const CGPoint MGLLogoImagePosition = CGPointMake(8, 8);
const CGFloat MGLSnapshotterMinimumPixelSize = 64;
+
+@interface MGLMapSnapshotOverlay()
+
+- (instancetype)initWithContext:(CGContextRef)context;
+
+@end
+
+@implementation MGLMapSnapshotOverlay
+
+- (instancetype) initWithContext:(CGContextRef)context {
+ self = [super init];
+ if (self) {
+ _context = context;
+ }
+
+ return self;
+}
+
+@end
+
@implementation MGLMapSnapshotOptions
- (instancetype _Nonnull)initWithStyleURL:(nullable NSURL *)styleURL camera:(MGLMapCamera *)camera size:(CGSize)size
@@ -183,7 +203,15 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
[self startWithQueue:dispatch_get_main_queue() completionHandler:completion];
}
-- (void)startWithQueue:(dispatch_queue_t)queue completionHandler:(MGLMapSnapshotCompletionHandler)completion
+- (void)startWithQueue:(dispatch_queue_t)queue completionHandler:(MGLMapSnapshotCompletionHandler)completionHandler {
+ [self startWithQueue:queue overlayHandler:nil completionHandler:completionHandler];
+}
+
+- (void)startWithOverlayHandler:(MGLMapSnapshotOverlayHandler)overlayHandler completionHandler:(MGLMapSnapshotCompletionHandler)completion {
+ [self startWithQueue:dispatch_get_main_queue() overlayHandler:overlayHandler completionHandler:completion];
+}
+
+- (void)startWithQueue:(dispatch_queue_t)queue overlayHandler:(MGLMapSnapshotOverlayHandler)overlayHandler completionHandler:(MGLMapSnapshotCompletionHandler)completion
{
if (!mbgl::Scheduler::GetCurrent()) {
[NSException raise:NSInvalidArgumentException
@@ -210,8 +238,8 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
// capture weakSelf to avoid retain cycle if callback is never called (ie snapshot cancelled)
_snapshotCallback = std::make_unique<mbgl::Actor<mbgl::MapSnapshotter::Callback>>(
- *mbgl::Scheduler::GetCurrent(),
- [=](std::exception_ptr mbglError, mbgl::PremultipliedImage image, mbgl::MapSnapshotter::Attributions attributions, mbgl::MapSnapshotter::PointForFn pointForFn, mbgl::MapSnapshotter::LatLngForFn latLngForFn) {
+ *mbgl::Scheduler::GetCurrent(),
+ [=](std::exception_ptr mbglError, mbgl::PremultipliedImage image, mbgl::MapSnapshotter::Attributions attributions, mbgl::MapSnapshotter::PointForFn pointForFn, mbgl::MapSnapshotter::LatLngForFn latLngForFn) {
__typeof__(self) strongSelf = weakSelf;
// If self had died, _snapshotCallback would have been destroyed and this block would not be executed
@@ -227,12 +255,12 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
#if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
[[MMEEventsManager sharedManager] reportError:error];
#endif
-
// Dispatch to result queue
dispatch_async(queue, ^{
strongSelf.completion(nil, error);
strongSelf.completion = nil;
});
+
} else {
#if TARGET_OS_IPHONE
MGLImage *mglImage = [[MGLImage alloc] initWithMGLPremultipliedImage:std::move(image) scale:strongSelf.options.scale];
@@ -241,11 +269,12 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
mglImage.size = NSMakeSize(mglImage.size.width / strongSelf.options.scale,
mglImage.size.height / strongSelf.options.scale);
#endif
- [strongSelf drawAttributedSnapshot:attributions snapshotImage:mglImage pointForFn:pointForFn latLngForFn:latLngForFn];
+
+ [strongSelf drawAttributedSnapshot:attributions snapshotImage:mglImage pointForFn:pointForFn latLngForFn:latLngForFn overlayHandler:overlayHandler];
}
strongSelf->_snapshotCallback = NULL;
- });
+ });
// Launches snapshot on background Thread owned by mbglMapSnapshotter
// _snapshotCallback->self() is an ActorRef: if the callback is destroyed, further messages
@@ -253,7 +282,7 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
_mbglMapSnapshotter->snapshot(_snapshotCallback->self());
}
-+ (MGLImage*)drawAttributedSnapshotWorker:(mbgl::MapSnapshotter::Attributions)attributions snapshotImage:(MGLImage *)mglImage pointForFn:(mbgl::MapSnapshotter::PointForFn)pointForFn latLngForFn:(mbgl::MapSnapshotter::LatLngForFn)latLngForFn scale:(CGFloat)scale size:(CGSize)size {
++ (MGLImage*)drawAttributedSnapshotWorker:(mbgl::MapSnapshotter::Attributions)attributions snapshotImage:(MGLImage *)mglImage pointForFn:(mbgl::MapSnapshotter::PointForFn)pointForFn latLngForFn:(mbgl::MapSnapshotter::LatLngForFn)latLngForFn scale:(CGFloat)scale size:(CGSize)size overlayHandler:(MGLMapSnapshotOverlayHandler)overlayHandler {
NSArray<MGLAttributionInfo *>* attributionInfo = [MGLMapSnapshotter generateAttributionInfos:attributions];
@@ -295,7 +324,23 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
UIGraphicsBeginImageContextWithOptions(mglImage.size, NO, scale);
[mglImage drawInRect:CGRectMake(0, 0, mglImage.size.width, mglImage.size.height)];
-
+
+ CGContextRef currentContext = UIGraphicsGetCurrentContext();
+
+ if (currentContext && overlayHandler) {
+ MGLMapSnapshotOverlay *snapshotOverlay = [[MGLMapSnapshotOverlay alloc] initWithContext:currentContext];
+ CGContextSaveGState(snapshotOverlay.context);
+ overlayHandler(snapshotOverlay);
+ CGContextRestoreGState(snapshotOverlay.context);
+ currentContext = UIGraphicsGetCurrentContext();
+ }
+
+ if (!currentContext && overlayHandler) {
+ // If the current context has been corrupted by the user,
+ // return nil so we can generate an error later.
+ return nil;
+ }
+
[logoImage drawInRect:logoImageRect];
UIImage *currentImage = UIGraphicsGetImageFromCurrentImageContext();
@@ -362,6 +407,21 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
[sourceImageRep drawInRect: targetFrame];
+ NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
+ if (currentContext && overlayHandler) {
+ MGLMapSnapshotOverlay *snapshotOverlay = [[MGLMapSnapshotOverlay alloc] initWithContext:currentContext.CGContext];
+ [currentContext saveGraphicsState];
+ overlayHandler(snapshotOverlay);
+ [currentContext restoreGraphicsState];
+ currentContext = [NSGraphicsContext currentContext];
+ }
+
+ if (!currentContext && overlayHandler) {
+ // If the current context has been corrupted by the user,
+ // return nil so we can generate an error later.
+ return nil;
+ }
+
if (logoImage) {
[logoImage drawInRect:logoImageRect];
}
@@ -382,8 +442,8 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
#endif
}
-- (void)drawAttributedSnapshot:(mbgl::MapSnapshotter::Attributions)attributions snapshotImage:(MGLImage *)mglImage pointForFn:(mbgl::MapSnapshotter::PointForFn)pointForFn latLngForFn:(mbgl::MapSnapshotter::LatLngForFn)latLngForFn {
-
+- (void)drawAttributedSnapshot:(mbgl::MapSnapshotter::Attributions)attributions snapshotImage:(MGLImage *)mglImage pointForFn:(mbgl::MapSnapshotter::PointForFn)pointForFn latLngForFn:(mbgl::MapSnapshotter::LatLngForFn)latLngForFn overlayHandler:(MGLMapSnapshotOverlayHandler)overlayHandler {
+
// Process image watermark in a work queue
dispatch_queue_t workQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_queue_t resultQueue = self.resultQueue;
@@ -397,19 +457,30 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
dispatch_async(workQueue, ^{
// Call a class method to ensure we're not accidentally capturing self
- MGLImage *compositedImage = [MGLMapSnapshotter drawAttributedSnapshotWorker:attributions snapshotImage:mglImage pointForFn:pointForFn latLngForFn:latLngForFn scale:scale size:size];
+ MGLImage *compositedImage = [MGLMapSnapshotter drawAttributedSnapshotWorker:attributions snapshotImage:mglImage pointForFn:pointForFn latLngForFn:latLngForFn scale:scale size:size overlayHandler:overlayHandler];
// Dispatch result to origin queue
dispatch_async(resultQueue, ^{
__typeof__(self) strongself = weakself;
if (strongself.completion) {
- MGLMapSnapshot* snapshot = [[MGLMapSnapshot alloc] initWithImage:compositedImage
- scale:scale
- pointForFn:pointForFn
- latLngForFn:latLngForFn];
- strongself.completion(snapshot, nil);
- strongself.completion = nil;
+
+ if (!compositedImage) {
+ NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"Failed to generate composited snapshot."};
+ NSError *error = [NSError errorWithDomain:MGLErrorDomain
+ code:MGLErrorCodeSnapshotFailed
+ userInfo:userInfo];
+
+ strongself.completion(nil, error);
+ strongself.completion = nil;
+ } else {
+ MGLMapSnapshot* snapshot = [[MGLMapSnapshot alloc] initWithImage:compositedImage
+ scale:scale
+ pointForFn:pointForFn
+ latLngForFn:latLngForFn];
+ strongself.completion(snapshot, nil);
+ strongself.completion = nil;
+ }
}
});
});
@@ -630,7 +701,7 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
// Create the snapshotter
_mbglMapSnapshotter = std::make_unique<mbgl::MapSnapshotter>(
- style, size, pixelRatio, cameraOptions, coordinateBounds, config.cacheDir, config.localFontFamilyName, resourceOptions);
+ style, size, pixelRatio, cameraOptions, coordinateBounds, config.localFontFamilyName, resourceOptions);
}
@end
diff --git a/platform/darwin/src/MGLOfflineStorage.h b/platform/darwin/src/MGLOfflineStorage.h
index 1ed364ddf3..d093bb938a 100644
--- a/platform/darwin/src/MGLOfflineStorage.h
+++ b/platform/darwin/src/MGLOfflineStorage.h
@@ -173,6 +173,11 @@ typedef NS_ENUM(NSUInteger, MGLResourceKind) {
packs and ambient caching. All of this class’s instance methods are asynchronous,
reflecting the fact that offline resources are stored in a database. The shared
object maintains a canonical collection of offline packs in its `packs` property.
+
+ Mapbox resources downloaded via this API are subject to separate Vector Tile and
+ Raster Tile API pricing and are not included in the Maps SDK’s “unlimited” requests.
+ See <a href="https://www.mapbox.com/pricing/">our pricing page</a> for more
+ information.
#### Related examples
See the <a href="https://docs.mapbox.com/ios/maps/examples/offline-pack/">
@@ -341,8 +346,7 @@ MGL_EXPORT
attempt to download additional tiles until already downloaded tiles are removed
by calling the `-removePack:withCompletionHandler:` method.
- @note The <a href="https://www.mapbox.com/tos/">Mapbox Terms of Service</a>
- prohibits changing or bypassing this limit without permission from Mapbox.
+ @param maximumCount The maximum number of tiles allowed to be downloaded.
*/
- (void)setMaximumAllowedMapboxTiles:(uint64_t)maximumCount;
@@ -420,7 +424,7 @@ MGL_EXPORT
- (void)resetDatabaseWithCompletionHandler:(void (^)(NSError *_Nullable error))completion;
-/*
+/**
Inserts the provided resource into the ambient cache.
This method mimics the caching that would take place if the equivalent resource
diff --git a/platform/darwin/src/MGLRasterTileSource.mm b/platform/darwin/src/MGLRasterTileSource.mm
index 61e9ef97fd..e89367711e 100644
--- a/platform/darwin/src/MGLRasterTileSource.mm
+++ b/platform/darwin/src/MGLRasterTileSource.mm
@@ -65,11 +65,13 @@ static const CGFloat MGLRasterTileSourceRetinaTileSize = 512;
}
- (NSURL *)configurationURL {
+ MGLAssertStyleSourceIsValid();
auto url = self.rawSource->getURL();
return url ? [NSURL URLWithString:@(url->c_str())] : nil;
}
- (NSString *)attributionHTMLString {
+ MGLAssertStyleSourceIsValid();
auto attribution = self.rawSource->getAttribution();
return attribution ? @(attribution->c_str()) : nil;
}
diff --git a/platform/darwin/src/MGLRasterTileSource_Private.h b/platform/darwin/src/MGLRasterTileSource_Private.h
index 128dcb447d..8502b811e2 100644
--- a/platform/darwin/src/MGLRasterTileSource_Private.h
+++ b/platform/darwin/src/MGLRasterTileSource_Private.h
@@ -12,7 +12,7 @@ NS_ASSUME_NONNULL_BEGIN
@interface MGLRasterTileSource (Private)
-@property (nonatomic, readonly) mbgl::style::RasterSource *rawSource;
+@property (nonatomic, readonly, nullable) mbgl::style::RasterSource *rawSource;
- (std::unique_ptr<mbgl::style::RasterSource>)pendingSourceWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL tileSize:(CGFloat)tileSize;
diff --git a/platform/darwin/src/MGLRendererConfiguration.h b/platform/darwin/src/MGLRendererConfiguration.h
index bfe88b7209..0c539f86f1 100644
--- a/platform/darwin/src/MGLRendererConfiguration.h
+++ b/platform/darwin/src/MGLRendererConfiguration.h
@@ -20,9 +20,6 @@ MGL_EXPORT
Based on the native scale where available, otherwise the standard screen scale. */
@property (nonatomic, readonly) const float scaleFactor;
-/** The cache dir to use. */
-@property (nonatomic, readonly) mbgl::optional<std::string> cacheDir;
-
/** The name of the font family to use for client-side text rendering of CJK ideographs.
Set MGLIdeographicFontFamilyName in your containing application's Info.plist to
diff --git a/platform/darwin/src/MGLRendererConfiguration.mm b/platform/darwin/src/MGLRendererConfiguration.mm
index 54bdcaa691..136dc929a6 100644
--- a/platform/darwin/src/MGLRendererConfiguration.mm
+++ b/platform/darwin/src/MGLRendererConfiguration.mm
@@ -66,10 +66,6 @@ static NSString * const MGLIdeographicFontFamilyNameKey = @"MGLIdeographicFontFa
#endif
}
-- (mbgl::optional<std::string>)cacheDir {
- return mbgl::optional<std::string>();
-}
-
- (mbgl::optional<std::string>)localFontFamilyName {
return [self _localFontFamilyNameWithPropertyDictionary:[[NSBundle mainBundle] infoDictionary]];
}
diff --git a/platform/darwin/src/MGLShapeSource.mm b/platform/darwin/src/MGLShapeSource.mm
index fc526f9850..3628a0eb74 100644
--- a/platform/darwin/src/MGLShapeSource.mm
+++ b/platform/darwin/src/MGLShapeSource.mm
@@ -150,11 +150,13 @@ mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NSDictionary<MGLShap
}
- (NSURL *)URL {
+ MGLAssertStyleSourceIsValid();
auto url = self.rawSource->getURL();
return url ? [NSURL URLWithString:@(url->c_str())] : nil;
}
- (void)setURL:(NSURL *)url {
+ MGLAssertStyleSourceIsValid();
if (url) {
self.rawSource->setURL(url.mgl_URLByStandardizingScheme.absoluteString.UTF8String);
_shape = nil;
@@ -164,17 +166,24 @@ mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NSDictionary<MGLShap
}
- (void)setShape:(MGLShape *)shape {
+ MGLAssertStyleSourceIsValid();
self.rawSource->setGeoJSON({ shape.geoJSONObject });
_shape = shape;
}
- (NSString *)description {
- return [NSString stringWithFormat:@"<%@: %p; identifier = %@; URL = %@; shape = %@>",
- NSStringFromClass([self class]), (void *)self, self.identifier, self.URL, self.shape];
+ if (self.rawSource) {
+ return [NSString stringWithFormat:@"<%@: %p; identifier = %@; URL = %@; shape = %@>",
+ NSStringFromClass([self class]), (void *)self, self.identifier, self.URL, self.shape];
+ }
+ else {
+ return [NSString stringWithFormat:@"<%@: %p; identifier = %@; URL = <unknown>; shape = %@>",
+ NSStringFromClass([self class]), (void *)self, self.identifier, self.shape];
+ }
}
- (NSArray<id <MGLFeature>> *)featuresMatchingPredicate:(nullable NSPredicate *)predicate {
-
+ MGLAssertStyleSourceIsValid();
mbgl::optional<mbgl::style::Filter> optionalFilter;
if (predicate) {
optionalFilter = predicate.mgl_filter;
@@ -190,6 +199,7 @@ mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NSDictionary<MGLShap
#pragma mark - MGLCluster management
- (mbgl::optional<mbgl::FeatureExtensionValue>)featureExtensionValueOfCluster:(MGLShape<MGLCluster> *)cluster extension:(std::string)extension options:(const std::map<std::string, mbgl::Value>)options {
+ MGLAssertStyleSourceIsValid();
mbgl::optional<mbgl::FeatureExtensionValue> extensionValue;
// Check parameters
diff --git a/platform/darwin/src/MGLSource.h b/platform/darwin/src/MGLSource.h
index 7bbf02fa7c..dc92e652e8 100644
--- a/platform/darwin/src/MGLSource.h
+++ b/platform/darwin/src/MGLSource.h
@@ -1,9 +1,12 @@
#import <Foundation/Foundation.h>
#import "MGLFoundation.h"
+#import "MGLTypes.h"
NS_ASSUME_NONNULL_BEGIN
+FOUNDATION_EXTERN MGL_EXPORT MGLExceptionName const MGLInvalidStyleSourceException;
+
/**
`MGLSource` is an abstract base class for map content sources. A map content
source supplies content to be shown on the map. A source is added to an
diff --git a/platform/darwin/src/MGLSource.mm b/platform/darwin/src/MGLSource.mm
index 62308ce5e1..1d7b46e1cc 100644
--- a/platform/darwin/src/MGLSource.mm
+++ b/platform/darwin/src/MGLSource.mm
@@ -11,6 +11,8 @@
#include <mbgl/map/map.hpp>
#include <mbgl/style/source.hpp>
+const MGLExceptionName MGLInvalidStyleSourceException = @"MGLInvalidStyleSourceException";
+
@interface MGLSource ()
// Even though this class is abstract, MGLStyle uses it to represent some
@@ -23,13 +25,14 @@
@implementation MGLSource {
std::unique_ptr<mbgl::style::Source> _pendingSource;
+ mapbox::base::WeakPtr<mbgl::style::Source> _weakSource;
}
- (instancetype)initWithIdentifier:(NSString *)identifier
{
if (self = [super init]) {
- _identifier = identifier;
+ _identifier = [identifier copy];
}
return self;
}
@@ -37,13 +40,18 @@
- (instancetype)initWithRawSource:(mbgl::style::Source *)rawSource mapView:(MGLMapView *)mapView {
NSString *identifier = @(rawSource->getID().c_str());
if (self = [self initWithIdentifier:identifier]) {
- _rawSource = rawSource;
- _rawSource->peer = SourceWrapper { self };
+ _weakSource = rawSource->makeWeakPtr();
+ rawSource->peer = SourceWrapper { self };
_mapView = mapView;
}
return self;
}
+- (mbgl::style::Source *)rawSource
+{
+ return _weakSource.get();
+}
+
- (instancetype)initWithPendingSource:(std::unique_ptr<mbgl::style::Source>)pendingSource {
if (self = [self initWithRawSource:pendingSource.get() mapView:nil]) {
_pendingSource = std::move(pendingSource);
@@ -63,6 +71,7 @@
}
- (BOOL)removeFromMapView:(MGLMapView *)mapView error:(NSError * __nullable * __nullable)outError {
+ MGLAssertStyleSourceIsValid();
BOOL removed = NO;
if (self.rawSource == mapView.style.rawStyle->getSource(self.identifier.UTF8String)) {
diff --git a/platform/darwin/src/MGLSource_Private.h b/platform/darwin/src/MGLSource_Private.h
index af14c11b90..4a7c31694d 100644
--- a/platform/darwin/src/MGLSource_Private.h
+++ b/platform/darwin/src/MGLSource_Private.h
@@ -2,6 +2,7 @@
#include <memory>
+
NS_ASSUME_NONNULL_BEGIN
namespace mbgl {
@@ -18,6 +19,20 @@ struct SourceWrapper {
__weak MGLSource *source;
};
+/**
+ Assert that the style source is valid.
+
+ This macro should be used at the beginning of any public-facing instance method
+ of `MGLSource` and its subclasses. For private methods, an assertion is more appropriate.
+ */
+#define MGLAssertStyleSourceIsValid() \
+do { \
+ if (!self.rawSource) { \
+ [NSException raise:MGLInvalidStyleSourceException \
+ format:@"This source got invalidated after the style change"]; \
+ } \
+} while (NO);
+
@class MGLMapView;
@interface MGLSource (Private)
diff --git a/platform/darwin/src/MGLStyle.mm b/platform/darwin/src/MGLStyle.mm
index 5768a7aaa7..cab0eaae28 100644
--- a/platform/darwin/src/MGLStyle.mm
+++ b/platform/darwin/src/MGLStyle.mm
@@ -226,12 +226,23 @@ static_assert(6 == mbgl::util::default_styles::numOrderedStyles,
MGLLogDebug(@"Removing source: %@", source);
if (!source.rawSource) {
- [NSException raise:NSInvalidArgumentException format:
- @"The source %@ cannot be removed from the style. "
- @"Make sure the source was created as a member of a concrete subclass of MGLSource.",
- source];
+ NSString *errorMessage = [NSString stringWithFormat:
+ @"The source %@ cannot be removed from the style. "
+ @"Make sure the source was created as a member of a concrete subclass of MGLSource."
+ @"Automatic re-addition of sources after style changes is not currently supported.",
+ source];
+
+ if (outError) {
+ *outError = [NSError errorWithDomain:MGLErrorDomain
+ code:MGLErrorCodeSourceCannotBeRemovedFromStyle
+ userInfo:@{ NSLocalizedDescriptionKey : errorMessage }];
+ return NO;
+ }
+ else {
+ [NSException raise:NSInvalidArgumentException format:@"%@", errorMessage];
+ }
}
-
+
return [source removeFromMapView:self.mapView error:outError];
}
diff --git a/platform/darwin/src/MGLStyleLayer.mm b/platform/darwin/src/MGLStyleLayer.mm
index 05885bc63e..7847cbb319 100644
--- a/platform/darwin/src/MGLStyleLayer.mm
+++ b/platform/darwin/src/MGLStyleLayer.mm
@@ -14,13 +14,14 @@ const MGLExceptionName MGLInvalidStyleLayerException = @"MGLInvalidStyleLayerExc
@implementation MGLStyleLayer {
std::unique_ptr<mbgl::style::Layer> _pendingLayer;
+ mapbox::base::WeakPtr<mbgl::style::Layer> _weakLayer;
}
- (instancetype)initWithRawLayer:(mbgl::style::Layer *)rawLayer {
if (self = [super init]) {
_identifier = @(rawLayer->getID().c_str());
- _rawLayer = rawLayer;
- _rawLayer->peer = LayerWrapper { self };
+ _weakLayer = rawLayer->makeWeakPtr();
+ rawLayer->peer = LayerWrapper { self };
}
return self;
}
@@ -32,6 +33,11 @@ const MGLExceptionName MGLInvalidStyleLayerException = @"MGLInvalidStyleLayerExc
return self;
}
+- (mbgl::style::Layer *)rawLayer
+{
+ return _weakLayer.get();
+}
+
- (void)addToStyle:(MGLStyle *)style belowLayer:(MGLStyleLayer *)otherLayer
{
if (_pendingLayer == nullptr) {
@@ -103,9 +109,15 @@ const MGLExceptionName MGLInvalidStyleLayerException = @"MGLInvalidStyleLayerExc
- (NSString *)description
{
- return [NSString stringWithFormat:@"<%@: %p; identifier = %@; visible = %@>",
- NSStringFromClass([self class]), (void *)self, self.identifier,
- self.visible ? @"YES" : @"NO"];
+ if (self.rawLayer) {
+ return [NSString stringWithFormat:@"<%@: %p; identifier = %@; visible = %@>",
+ NSStringFromClass([self class]), (void *)self, self.identifier,
+ self.visible ? @"YES" : @"NO"];
+ }
+ else {
+ return [NSString stringWithFormat:@"<%@: %p; identifier = %@; visible = NO>",
+ NSStringFromClass([self class]), (void *)self, self.identifier];
+ }
}
@end
diff --git a/platform/darwin/src/MGLStyleLayer_Private.h b/platform/darwin/src/MGLStyleLayer_Private.h
index 314f61f680..52254f78c6 100644
--- a/platform/darwin/src/MGLStyleLayer_Private.h
+++ b/platform/darwin/src/MGLStyleLayer_Private.h
@@ -27,6 +27,7 @@ struct LayerWrapper {
if (!self.rawLayer) { \
[NSException raise:MGLInvalidStyleLayerException \
format: \
+ @"Either this layer got invalidated after the style change or " \
@"-[MGLStyle removeLayer:] has been called " \
@"with this instance but another style layer instance was added with the same identifer. It is an " \
@"error to send any message to this layer since it cannot be recovered after removal due to the " \
diff --git a/platform/darwin/src/MGLSymbolStyleLayer.h b/platform/darwin/src/MGLSymbolStyleLayer.h
index fb00b0d165..53bc488a41 100644
--- a/platform/darwin/src/MGLSymbolStyleLayer.h
+++ b/platform/darwin/src/MGLSymbolStyleLayer.h
@@ -1404,8 +1404,7 @@ MGL_EXPORT
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`, and
- `textRadialOffset` is set to `nil`, and `textVariableAnchor` is set to `nil`.
- Otherwise, it is ignored.
+ `textRadialOffset` is set to `nil`. Otherwise, it is ignored.
You can set this property to an expression containing any of the following:
@@ -1428,8 +1427,7 @@ MGL_EXPORT
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`, and
- `textRadialOffset` is set to `nil`, and `textVariableAnchor` is set to `nil`.
- Otherwise, it is ignored.
+ `textRadialOffset` is set to `nil`. Otherwise, it is ignored.
You can set this property to an expression containing any of the following:
@@ -1521,8 +1519,8 @@ MGL_EXPORT
/**
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`.
+ combination with `textVariableAnchor`, which defaults to using the
+ two-dimensional `textOffset` if present.
This property is measured in ems.
@@ -1634,8 +1632,7 @@ MGL_EXPORT
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`.
+ an offset, use the `textRadialOffset` or the two-dimensional `textOffset`.
This property is only applied to the style if `text` is non-`nil`, and
`symbolPlacement` is set to an expression that evaluates to or
diff --git a/platform/darwin/src/MGLTypes.h b/platform/darwin/src/MGLTypes.h
index df3c61a61c..963eda384b 100644
--- a/platform/darwin/src/MGLTypes.h
+++ b/platform/darwin/src/MGLTypes.h
@@ -56,8 +56,10 @@ typedef NS_ENUM(NSInteger, MGLErrorCode) {
MGLErrorCodeSourceIdentifierMismatch = 8,
/** An error occurred while modifying the offline storage database */
MGLErrorCodeModifyingOfflineStorageFailed = 9,
+ /** Source is invalid and cannot be removed from the style (e.g. after a style change) */
+ MGLErrorCodeSourceCannotBeRemovedFromStyle = 10,
/** An error occurred while rendering */
- MGLErrorCodeRenderingError = 10,
+ MGLErrorCodeRenderingError = 11,
};
/** Options for enabling debugging features in an `MGLMapView` instance. */
diff --git a/platform/darwin/src/MGLVectorStyleLayer.m b/platform/darwin/src/MGLVectorStyleLayer.m
deleted file mode 100644
index 23f3556e0b..0000000000
--- a/platform/darwin/src/MGLVectorStyleLayer.m
+++ /dev/null
@@ -1,25 +0,0 @@
-#import "MGLVectorStyleLayer.h"
-
-@implementation MGLVectorStyleLayer
-
-- (void)setPredicate:(NSPredicate *)predicate {
- [NSException raise:MGLAbstractClassException
- format:@"MGLVectorStyleLayer is an abstract class"];
-}
-
-- (NSPredicate *)predicate {
- [NSException raise:MGLAbstractClassException
- format:@"MGLVectorStyleLayer is an abstract class"];
- return nil;
-}
-
-- (NSString *)description {
- return [NSString stringWithFormat:
- @"<%@: %p; identifier = %@; sourceIdentifier = %@; "
- @"sourceLayerIdentifier = %@; predicate = %@; visible = %@>",
- NSStringFromClass([self class]), (void *)self, self.identifier,
- self.sourceIdentifier, self.sourceLayerIdentifier, self.predicate,
- self.visible ? @"YES" : @"NO"];
-}
-
-@end
diff --git a/platform/darwin/src/MGLVectorStyleLayer.mm b/platform/darwin/src/MGLVectorStyleLayer.mm
new file mode 100644
index 0000000000..691668629a
--- /dev/null
+++ b/platform/darwin/src/MGLVectorStyleLayer.mm
@@ -0,0 +1,34 @@
+#import "MGLVectorStyleLayer.h"
+#import "MGLStyleLayer_Private.h"
+
+@implementation MGLVectorStyleLayer
+
+- (void)setPredicate:(NSPredicate *)predicate {
+ [NSException raise:MGLAbstractClassException
+ format:@"MGLVectorStyleLayer is an abstract class"];
+}
+
+- (NSPredicate *)predicate {
+ [NSException raise:MGLAbstractClassException
+ format:@"MGLVectorStyleLayer is an abstract class"];
+ return nil;
+}
+
+- (NSString *)description {
+ if (self.rawLayer) {
+ return [NSString stringWithFormat:
+ @"<%@: %p; identifier = %@; sourceIdentifier = %@; "
+ @"sourceLayerIdentifier = %@; predicate = %@; visible = %@>",
+ NSStringFromClass([self class]), (void *)self, self.identifier,
+ self.sourceIdentifier, self.sourceLayerIdentifier, self.predicate,
+ self.visible ? @"YES" : @"NO"];
+ }
+ else {
+ return [NSString stringWithFormat:
+ @"<%@: %p; identifier = %@; sourceIdentifier = <unknown>; "
+ @"sourceLayerIdentifier = <unknown>; predicate = <unknown>; visible = <unknown>>",
+ NSStringFromClass([self class]), (void *)self, self.identifier];
+ }
+}
+
+@end
diff --git a/platform/darwin/src/MGLVectorTileSource.mm b/platform/darwin/src/MGLVectorTileSource.mm
index f7a6869ade..85270c4a49 100644
--- a/platform/darwin/src/MGLVectorTileSource.mm
+++ b/platform/darwin/src/MGLVectorTileSource.mm
@@ -38,17 +38,19 @@
}
- (NSURL *)configurationURL {
+ MGLAssertStyleSourceIsValid();
auto url = self.rawSource->getURL();
return url ? [NSURL URLWithString:@(url->c_str())] : nil;
}
- (NSString *)attributionHTMLString {
+ MGLAssertStyleSourceIsValid();
auto attribution = self.rawSource->getAttribution();
return attribution ? @(attribution->c_str()) : nil;
}
- (NSArray<id <MGLFeature>> *)featuresInSourceLayersWithIdentifiers:(NSSet<NSString *> *)sourceLayerIdentifiers predicate:(nullable NSPredicate *)predicate {
-
+ MGLAssertStyleSourceIsValid();
mbgl::optional<std::vector<std::string>> optionalSourceLayerIDs;
if (sourceLayerIdentifiers) {
__block std::vector<std::string> layerIDs;
diff --git a/platform/darwin/src/http_file_source.mm b/platform/darwin/src/http_file_source.mm
index 5737d8b999..b0f69f4a7f 100644
--- a/platform/darwin/src/http_file_source.mm
+++ b/platform/darwin/src/http_file_source.mm
@@ -88,15 +88,14 @@ class HTTPFileSource::Impl {
public:
Impl() {
@autoreleasepool {
-
- NSURLSessionConfiguration *sessionConfig =
- [MGLNetworkConfiguration sharedManager].sessionConfiguration;
-
+ NSURLSessionConfiguration *sessionConfig = [MGLNetworkConfiguration sharedManager].sessionConfiguration;
session = [NSURLSession sessionWithConfiguration:sessionConfig];
userAgent = getUserAgent();
- accountType = [[NSUserDefaults standardUserDefaults] integerForKey:@"MGLMapboxAccountType"];
+#if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
+ accountType = [[NSUserDefaults standardUserDefaults] integerForKey:MGLMapboxAccountTypeKey];
+#endif
}
}
@@ -205,13 +204,13 @@ NSURL *resourceURLWithAccountType(const Resource& resource, NSInteger accountTyp
if (accountType == 0 &&
([url.host isEqualToString:@"mapbox.com"] || [url.host hasSuffix:@".mapbox.com"])) {
NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO];
- NSURLQueryItem *accountsQueryItem = [NSURLQueryItem queryItemWithName:@"sku" value:MGLAccountManager.skuToken];
-
- NSMutableArray *queryItems = [NSMutableArray arrayWithObject:accountsQueryItem];
-
- // offline here
+ NSMutableArray *queryItems = [NSMutableArray array];
+
if (resource.usage == Resource::Usage::Offline) {
[queryItems addObject:[NSURLQueryItem queryItemWithName:@"offline" value:@"true"]];
+ } else {
+ // Only add SKU token to requests not tagged as "offline" usage.
+ [queryItems addObject:[NSURLQueryItem queryItemWithName:@"sku" value:MGLAccountManager.skuToken]];
}
if (components.queryItems) {
diff --git a/platform/darwin/src/string_nsstring.mm b/platform/darwin/src/string_nsstring.mm
index 096ed2b212..382a2acf33 100644
--- a/platform/darwin/src/string_nsstring.mm
+++ b/platform/darwin/src/string_nsstring.mm
@@ -43,6 +43,10 @@ std::string formatNumber(double number, const std::string& localeId, const std::
numberFormatter.maximumFractionDigits = maxFractionDigits;
numberFormatter.numberStyle = NSNumberFormatterDecimalStyle;
} else {
+ // Reset fraction digits to NSNumberFormatter's default values, so that the
+ // system will choose formatting based on number formatter locale.
+ numberFormatter.minimumFractionDigits = 0;
+ numberFormatter.maximumFractionDigits = 0;
numberFormatter.numberStyle = NSNumberFormatterCurrencyStyle;
}
NSString *formatted = [numberFormatter stringFromNumber:@(number)];
diff --git a/platform/darwin/test/MGLClockDirectionFormatterTests.m b/platform/darwin/test/MGLClockDirectionFormatterTests.m
index 1b2f058d18..05ebc3af2d 100644
--- a/platform/darwin/test/MGLClockDirectionFormatterTests.m
+++ b/platform/darwin/test/MGLClockDirectionFormatterTests.m
@@ -7,11 +7,6 @@
@implementation MGLClockDirectionFormatterTests
-- (void)setUp {
- // FIXME: https://github.com/mapbox/mapbox-gl-native/issues/14908
- XCTAssertEqualObjects(NSLocale.currentLocale.localeIdentifier, @"en_US", @"Device locale must be en_US for these tests to pass.");
-}
-
- (void)testClockDirections {
MGLClockDirectionFormatter *shortFormatter = [[MGLClockDirectionFormatter alloc] init];
shortFormatter.unitStyle = NSFormattingUnitStyleShort;
diff --git a/platform/darwin/test/MGLCompassDirectionFormatterTests.m b/platform/darwin/test/MGLCompassDirectionFormatterTests.m
index cd3aaebab7..c4ccc6ac4f 100644
--- a/platform/darwin/test/MGLCompassDirectionFormatterTests.m
+++ b/platform/darwin/test/MGLCompassDirectionFormatterTests.m
@@ -7,11 +7,6 @@
@implementation MGLCompassDirectionFormatterTests
-- (void)setUp {
- // FIXME: https://github.com/mapbox/mapbox-gl-native/issues/14908
- XCTAssertEqualObjects(NSLocale.currentLocale.localeIdentifier, @"en_US", @"Device locale must be en_US for these tests to pass.");
-}
-
- (void)testCompassDirections {
MGLCompassDirectionFormatter *shortFormatter = [[MGLCompassDirectionFormatter alloc] init];
shortFormatter.unitStyle = NSFormattingUnitStyleShort;
diff --git a/platform/darwin/test/MGLCoordinateFormatterTests.m b/platform/darwin/test/MGLCoordinateFormatterTests.m
index 4d4d8cf971..ac083fa103 100644
--- a/platform/darwin/test/MGLCoordinateFormatterTests.m
+++ b/platform/darwin/test/MGLCoordinateFormatterTests.m
@@ -7,11 +7,6 @@
@implementation MGLCoordinateFormatterTests
-- (void)setUp {
- // FIXME: https://github.com/mapbox/mapbox-gl-native/issues/14908
- XCTAssertEqualObjects(NSLocale.currentLocale.localeIdentifier, @"en_US", @"Device locale must be en_US for these tests to pass.");
-}
-
- (void)testStrings {
MGLCoordinateFormatter *shortFormatter = [[MGLCoordinateFormatter alloc] init];
shortFormatter.unitStyle = NSFormattingUnitStyleShort;
diff --git a/platform/darwin/test/MGLResourceTests.mm b/platform/darwin/test/MGLResourceTests.mm
index 0420997c39..7fcccc535c 100644
--- a/platform/darwin/test/MGLResourceTests.mm
+++ b/platform/darwin/test/MGLResourceTests.mm
@@ -22,18 +22,28 @@ namespace mbgl {
NSURL *url = [NSURL URLWithString:@(testURL.c_str())];
NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO];
NSArray<NSURLQueryItem *> *items = components.queryItems;
- XCTAssert(items.count == 2 );
+ XCTAssert(items.count == 2);
}
Resource resource(Resource::Kind::Unknown, testURL);
- // By default, resource are NOT offline
+ // By default, resources are NOT offline
{
+ bool skuTokenQueryItemFound;
NSURL *url = resourceURLWithAccountType(resource, 0);
NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO];
for (NSURLQueryItem *item in components.queryItems) {
XCTAssertFalse([item.name isEqualToString:@"offline"]);
+ if ([item.name isEqualToString:@"sku"]) {
+ skuTokenQueryItemFound = YES;
+ }
}
+
+#if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
+ XCTAssertTrue(skuTokenQueryItemFound, "Default resource URL should have SKU token query item");
+#else
+ XCTAssertFalse(skuTokenQueryItemFound, "Non-iOS platforms should not have a SKU token query item");
+#endif
}
// Now check offline
@@ -43,20 +53,20 @@ namespace mbgl {
NSURL *url = resourceURLWithAccountType(resource, 0);
NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO];
- // For offline, we expect a single offline param and a sku param
+ // For offline, we expect a single offline query item
NSInteger foundCount = 0;
#if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
for (NSURLQueryItem *item in components.queryItems) {
if (([item.name isEqualToString:@"offline"] && [item.value isEqualToString:@"true"]) ||
([item.name isEqualToString:@"a"] && [item.value isEqualToString:@"one"]) ||
- ([item.name isEqualToString:@"b"] && [item.value isEqualToString:@"two"]) ||
- ([item.name isEqualToString:@"sku"])) {
+ ([item.name isEqualToString:@"b"] && [item.value isEqualToString:@"two"])) {
foundCount++;
}
+ XCTAssertFalse([item.name isEqualToString:@"sku"]);
}
- XCTAssert(foundCount == 4);
+ XCTAssert(foundCount == 3);
#else
// NOTE: Currently the macOS SDK does not supply the sku or offline query parameters
for (NSURLQueryItem *item in components.queryItems) {
@@ -64,6 +74,7 @@ namespace mbgl {
([item.name isEqualToString:@"b"] && [item.value isEqualToString:@"two"])) {
foundCount++;
}
+ XCTAssertFalse([item.name isEqualToString:@"sku"]);
}
XCTAssert(foundCount == 2);
diff --git a/platform/darwin/test/MGLTileSetTests.mm b/platform/darwin/test/MGLTileSetTests.mm
index 998d4baee6..65e096ae7f 100644
--- a/platform/darwin/test/MGLTileSetTests.mm
+++ b/platform/darwin/test/MGLTileSetTests.mm
@@ -84,9 +84,18 @@
// the attribution is reflected by the mbgl tileset
#if TARGET_OS_IPHONE
- NSString *html = (@"<font style=\"font-family: 'Helvetica'; font-weight: normal; font-style: normal; font-size: 12.00pt\">"
- @"<a href=\"https://www.mapbox.com/\">Mapbox</a> </font>"
- @"<font style=\"font-family: 'Helvetica'; font-weight: normal; font-style: normal; font-size: 12.00pt; background-color: #ff0000\">GL</font>\n");
+ NSString *html;
+ if (@available(iOS 13.0, *)) {
+ // TODO: investigate visual impact
+ // iOS 13 evidently changes font size from points to pixels
+ html = (@"<font style=\"font-family: 'Helvetica'; font-weight: normal; font-style: normal; font-size: 12.00px\">"
+ @"<a href=\"https://www.mapbox.com/\">Mapbox</a> </font>"
+ @"<font style=\"font-family: 'Helvetica'; font-weight: normal; font-style: normal; font-size: 12.00px; background-color: #ff0000\">GL</font>\n");
+ } else {
+ html = (@"<font style=\"font-family: 'Helvetica'; font-weight: normal; font-style: normal; font-size: 12.00pt\">"
+ @"<a href=\"https://www.mapbox.com/\">Mapbox</a> </font>"
+ @"<font style=\"font-family: 'Helvetica'; font-weight: normal; font-style: normal; font-size: 12.00pt; background-color: #ff0000\">GL</font>\n");
+ }
#else
NSString *html = (@"<font face=\"Helvetica\" size=\"3\" style=\"font: 12.0px Helvetica\">"
@"<a href=\"https://www.mapbox.com/\">Mapbox</a> </font>"
@@ -111,7 +120,7 @@
// the scheme is reflected by the mbgl tileset
XCTAssertEqual(tileSet.scheme, mbgl::Tileset::Scheme::TMS);
- // when the dem enciding is changed using an NSNumber
+ // when the dem encoding is changed using an NSNumber
tileSet = MGLTileSetFromTileURLTemplates(tileURLTemplates, @{
MGLTileSourceOptionDEMEncoding: @(MGLDEMEncodingTerrarium),
});
@@ -119,7 +128,7 @@
// the encoding is reflected by the mbgl tileset
XCTAssertEqual(tileSet.encoding, mbgl::Tileset::DEMEncoding::Terrarium);
- // when the dem enciding is changed using an NSValue
+ // when the dem encoding is changed using an NSValue
MGLDEMEncoding terrarium = MGLDEMEncodingTerrarium;
tileSet = MGLTileSetFromTileURLTemplates(tileURLTemplates, @{
MGLTileSourceOptionDEMEncoding: [NSValue value:&terrarium withObjCType:@encode(MGLDEMEncoding)],
diff --git a/platform/default/include/mbgl/gfx/headless_frontend.hpp b/platform/default/include/mbgl/gfx/headless_frontend.hpp
index 7f937b34b8..8f7a7bf202 100644
--- a/platform/default/include/mbgl/gfx/headless_frontend.hpp
+++ b/platform/default/include/mbgl/gfx/headless_frontend.hpp
@@ -17,12 +17,10 @@ class TransformState;
class HeadlessFrontend : public RendererFrontend {
public:
HeadlessFrontend(float pixelRatio_,
- const optional<std::string> programCacheDir = {},
gfx::ContextMode mode = gfx::ContextMode::Unique,
const optional<std::string> localFontFamily = {});
HeadlessFrontend(Size,
float pixelRatio_,
- const optional<std::string> programCacheDir = {},
gfx::ContextMode mode = gfx::ContextMode::Unique,
const optional<std::string> localFontFamily = {});
~HeadlessFrontend() override;
diff --git a/platform/default/include/mbgl/map/map_snapshotter.hpp b/platform/default/include/mbgl/map/map_snapshotter.hpp
index db1ba1f267..c1544c36ab 100644
--- a/platform/default/include/mbgl/map/map_snapshotter.hpp
+++ b/platform/default/include/mbgl/map/map_snapshotter.hpp
@@ -31,7 +31,6 @@ public:
const float pixelRatio,
const optional<CameraOptions> cameraOptions,
const optional<LatLngBounds> region,
- const optional<std::string> cacheDir,
const optional<std::string> localFontFamily,
const ResourceOptions&);
diff --git a/platform/default/include/mbgl/storage/offline_database.hpp b/platform/default/include/mbgl/storage/offline_database.hpp
index afce87b542..e19dcfade9 100644
--- a/platform/default/include/mbgl/storage/offline_database.hpp
+++ b/platform/default/include/mbgl/storage/offline_database.hpp
@@ -78,8 +78,8 @@ public:
std::exception_ptr invalidateRegion(int64_t regionID);
// Return value is (response, stored size)
- optional<std::pair<Response, uint64_t>> getRegionResource(int64_t regionID, const Resource&);
- optional<int64_t> hasRegionResource(int64_t regionID, const Resource&);
+ optional<std::pair<Response, uint64_t>> getRegionResource(const Resource&);
+ optional<int64_t> hasRegionResource(const Resource&);
uint64_t putRegionResource(int64_t regionID, const Resource&, const Response&);
void putRegionResources(int64_t regionID, const std::list<std::tuple<Resource, Response>>&, OfflineRegionStatus&);
@@ -92,6 +92,7 @@ public:
bool offlineMapboxTileCountLimitExceeded();
uint64_t getOfflineMapboxTileCount();
bool exceedsOfflineMapboxTileCountLimit(const Resource&);
+ void markUsedResources(int64_t regionID, const std::list<Resource>&);
private:
void initialize();
diff --git a/platform/default/include/mbgl/storage/offline_download.hpp b/platform/default/include/mbgl/storage/offline_download.hpp
index 84b319fb5a..53b42ae9d1 100644
--- a/platform/default/include/mbgl/storage/offline_download.hpp
+++ b/platform/default/include/mbgl/storage/offline_download.hpp
@@ -46,7 +46,7 @@ private:
* While the request is in progress, it is recorded in `requests`. If the download
* is deactivated, all in progress requests are cancelled.
*/
- void ensureResource(const Resource&, std::function<void (Response)> = {});
+ void ensureResource(Resource&&, std::function<void (Response)> = {});
void onMapboxTileCountLimitExceeded();
@@ -60,10 +60,12 @@ private:
std::list<std::unique_ptr<AsyncRequest>> requests;
std::unordered_set<std::string> requiredSourceURLs;
std::deque<Resource> resourcesRemaining;
+ std::list<Resource> resourcesToBeMarkedAsUsed;
std::list<std::tuple<Resource, Response>> buffer;
void queueResource(Resource&&);
void queueTiles(style::SourceType, uint16_t tileSize, const Tileset&);
+ void markPendingUsedResources();
};
} // namespace mbgl
diff --git a/platform/default/src/mbgl/gfx/headless_frontend.cpp b/platform/default/src/mbgl/gfx/headless_frontend.cpp
index f5e6b7f482..287567adbd 100644
--- a/platform/default/src/mbgl/gfx/headless_frontend.cpp
+++ b/platform/default/src/mbgl/gfx/headless_frontend.cpp
@@ -10,16 +10,14 @@
namespace mbgl {
HeadlessFrontend::HeadlessFrontend(float pixelRatio_,
- const optional<std::string> programCacheDir,
const gfx::ContextMode contextMode,
const optional<std::string> localFontFamily)
: HeadlessFrontend(
- { 256, 256 }, pixelRatio_, programCacheDir, contextMode, localFontFamily) {
+ { 256, 256 }, pixelRatio_, contextMode, localFontFamily) {
}
HeadlessFrontend::HeadlessFrontend(Size size_,
float pixelRatio_,
- const optional<std::string> programCacheDir,
const gfx::ContextMode contextMode,
const optional<std::string> localFontFamily)
: size(size_),
@@ -38,7 +36,7 @@ HeadlessFrontend::HeadlessFrontend(Size size_,
renderer->render(*updateParameters_);
}
}),
- renderer(std::make_unique<Renderer>(*getBackend(), pixelRatio, programCacheDir, localFontFamily)) {
+ renderer(std::make_unique<Renderer>(*getBackend(), pixelRatio, localFontFamily)) {
}
HeadlessFrontend::~HeadlessFrontend() = default;
diff --git a/platform/default/src/mbgl/map/map_snapshotter.cpp b/platform/default/src/mbgl/map/map_snapshotter.cpp
index f0b107e77e..5f4060e3f0 100644
--- a/platform/default/src/mbgl/map/map_snapshotter.cpp
+++ b/platform/default/src/mbgl/map/map_snapshotter.cpp
@@ -19,7 +19,6 @@ public:
const float pixelRatio,
const optional<CameraOptions> cameraOptions,
const optional<LatLngBounds> region,
- const optional<std::string> programCacheDir,
const optional<std::string> localFontFamily,
const ResourceOptions& resourceOptions);
@@ -50,11 +49,10 @@ MapSnapshotter::Impl::Impl(const std::pair<bool, std::string> style,
const float pixelRatio,
const optional<CameraOptions> cameraOptions,
const optional<LatLngBounds> region,
- const optional<std::string> programCacheDir,
const optional<std::string> localFontFamily,
const ResourceOptions& resourceOptions)
: frontend(
- size, pixelRatio, programCacheDir, gfx::ContextMode::Unique, localFontFamily),
+ size, pixelRatio, gfx::ContextMode::Unique, localFontFamily),
map(frontend,
MapObserver::nullObserver(),
MapOptions().withMapMode(MapMode::Static).withSize(size).withPixelRatio(pixelRatio),
@@ -168,12 +166,11 @@ MapSnapshotter::MapSnapshotter(const std::pair<bool, std::string> style,
const float pixelRatio,
const optional<CameraOptions> cameraOptions,
const optional<LatLngBounds> region,
- const optional<std::string> programCacheDir,
const optional<std::string> localFontFamily,
const ResourceOptions& resourceOptions)
: impl(std::make_unique<util::Thread<MapSnapshotter::Impl>>(
"Map Snapshotter", style, size, pixelRatio, cameraOptions,
- region, programCacheDir, localFontFamily, resourceOptions.clone())) {}
+ region, localFontFamily, resourceOptions.clone())) {}
MapSnapshotter::~MapSnapshotter() = default;
diff --git a/platform/default/src/mbgl/storage/offline_database.cpp b/platform/default/src/mbgl/storage/offline_database.cpp
index d85b560d5a..83eea7bcc4 100644
--- a/platform/default/src/mbgl/storage/offline_database.cpp
+++ b/platform/default/src/mbgl/storage/offline_database.cpp
@@ -877,27 +877,15 @@ std::exception_ptr OfflineDatabase::deleteRegion(OfflineRegion&& region) try {
return std::current_exception();
}
-optional<std::pair<Response, uint64_t>> OfflineDatabase::getRegionResource(int64_t regionID, const Resource& resource) try {
- auto response = getInternal(resource);
-
- if (response) {
- markUsed(regionID, resource);
- }
-
- return response;
+optional<std::pair<Response, uint64_t>> OfflineDatabase::getRegionResource(const Resource& resource) try {
+ return getInternal(resource);
} catch (const mapbox::sqlite::Exception& ex) {
handleError(ex, "read region resource");
return nullopt;
}
-optional<int64_t> OfflineDatabase::hasRegionResource(int64_t regionID, const Resource& resource) try {
- auto response = hasInternal(resource);
-
- if (response) {
- markUsed(regionID, resource);
- }
-
- return response;
+optional<int64_t> OfflineDatabase::hasRegionResource(const Resource& resource) try {
+ return hasInternal(resource);
} catch (const mapbox::sqlite::Exception& ex) {
handleError(ex, "query region resource");
return nullopt;
@@ -1278,6 +1266,19 @@ bool OfflineDatabase::exceedsOfflineMapboxTileCountLimit(const Resource& resourc
&& offlineMapboxTileCountLimitExceeded();
}
+void OfflineDatabase::markUsedResources(int64_t regionID, const std::list<Resource>& resources) try {
+ if (!db) {
+ initialize();
+ }
+ mapbox::sqlite::Transaction transaction(*db);
+ for (const auto& resource : resources) {
+ markUsed(regionID, resource);
+ }
+ transaction.commit();
+} catch (const mapbox::sqlite::Exception& ex) {
+ handleError(ex, "mark resources as used");
+}
+
std::exception_ptr OfflineDatabase::resetDatabase() try {
removeExisting();
initialize();
diff --git a/platform/default/src/mbgl/storage/offline_download.cpp b/platform/default/src/mbgl/storage/offline_download.cpp
index bdcc99cc15..939164bd35 100644
--- a/platform/default/src/mbgl/storage/offline_download.cpp
+++ b/platform/default/src/mbgl/storage/offline_download.cpp
@@ -21,6 +21,13 @@
#include <set>
+namespace {
+
+const size_t kResourcesBatchSize = 64;
+const size_t kMarkBatchSize = 200;
+
+} // namespace
+
namespace mbgl {
using namespace style;
@@ -144,8 +151,9 @@ OfflineRegionStatus OfflineDownload::getStatus() const {
auto handleTiledSource = [&] (const variant<std::string, Tileset>& urlOrTileset, const uint16_t tileSize) {
if (urlOrTileset.is<Tileset>()) {
- result->requiredResourceCount +=
- tileCount(definition, type, tileSize, urlOrTileset.get<Tileset>().zoomRange);
+ uint64_t tileSourceCount = tileCount(definition, type, tileSize, urlOrTileset.get<Tileset>().zoomRange);
+ result->requiredTileCount += tileSourceCount;
+ result->requiredResourceCount += tileSourceCount;
} else {
result->requiredResourceCount += 1;
const auto& url = urlOrTileset.get<std::string>();
@@ -154,8 +162,9 @@ OfflineRegionStatus OfflineDownload::getStatus() const {
style::conversion::Error error;
optional<Tileset> tileset = style::conversion::convertJSON<Tileset>(*sourceResponse->data, error);
if (tileset) {
- result->requiredResourceCount +=
- tileCount(definition, type, tileSize, (*tileset).zoomRange);
+ uint64_t tileSourceCount = tileCount(definition, type, tileSize, (*tileset).zoomRange);
+ result->requiredTileCount += tileSourceCount;
+ result->requiredResourceCount += tileSourceCount;
}
} else {
result->requiredResourceCountIsPrecise = false;
@@ -228,7 +237,7 @@ void OfflineDownload::activateDownload() {
styleResource.setPriority(Resource::Priority::Low);
styleResource.setUsage(Resource::Usage::Offline);
- ensureResource(styleResource, [&](Response styleResponse) {
+ ensureResource(std::move(styleResource), [&](Response styleResponse) {
status.requiredResourceCountIsPrecise = true;
style::Parser parser;
@@ -250,7 +259,7 @@ void OfflineDownload::activateDownload() {
sourceResource.setPriority(Resource::Priority::Low);
sourceResource.setUsage(Resource::Usage::Offline);
- ensureResource(sourceResource, [=](Response sourceResponse) {
+ ensureResource(std::move(sourceResource), [=](Response sourceResponse) {
style::conversion::Error error;
optional<Tileset> tileset = style::conversion::convertJSON<Tileset>(*sourceResponse.data, error);
if (tileset) {
@@ -353,12 +362,15 @@ void OfflineDownload::activateDownload() {
*/
void OfflineDownload::continueDownload() {
if (resourcesRemaining.empty() && status.complete()) {
+ markPendingUsedResources();
setState(OfflineRegionDownloadState::Inactive);
return;
}
+ if (resourcesToBeMarkedAsUsed.size() >= kMarkBatchSize) markPendingUsedResources();
+
while (!resourcesRemaining.empty() && requests.size() < onlineFileSource.getMaximumConcurrentRequests()) {
- ensureResource(resourcesRemaining.front());
+ ensureResource(std::move(resourcesRemaining.front()));
resourcesRemaining.pop_front();
}
}
@@ -373,12 +385,16 @@ void OfflineDownload::queueResource(Resource&& resource) {
resource.setPriority(Resource::Priority::Low);
resource.setUsage(Resource::Usage::Offline);
status.requiredResourceCount++;
+ if (resource.kind == mbgl::Resource::Kind::Tile) {
+ status.requiredTileCount++;
+ }
resourcesRemaining.push_front(std::move(resource));
}
void OfflineDownload::queueTiles(SourceType type, uint16_t tileSize, const Tileset& tileset) {
tileCover(definition, type, tileSize, tileset.zoomRange, [&](const auto& tile) {
status.requiredResourceCount++;
+ status.requiredTileCount++;
auto tileResource = Resource::tile(
tileset.tiles[0], definition.match([](auto& def) { return def.pixelRatio; }),
@@ -391,7 +407,12 @@ void OfflineDownload::queueTiles(SourceType type, uint16_t tileSize, const Tiles
});
}
-void OfflineDownload::ensureResource(const Resource& resource,
+void OfflineDownload::markPendingUsedResources() {
+ offlineDatabase.markUsedResources(id, resourcesToBeMarkedAsUsed);
+ resourcesToBeMarkedAsUsed.clear();
+}
+
+void OfflineDownload::ensureResource(Resource&& resource,
std::function<void(Response)> callback) {
assert(resource.priority == Resource::Priority::Low);
assert(resource.usage == Resource::Usage::Offline);
@@ -399,24 +420,29 @@ void OfflineDownload::ensureResource(const Resource& resource,
auto workRequestsIt = requests.insert(requests.begin(), nullptr);
*workRequestsIt = util::RunLoop::Get()->invokeCancellable([=]() {
requests.erase(workRequestsIt);
-
+ const auto resourceKind = resource.kind;
auto getResourceSizeInDatabase = [&] () -> optional<int64_t> {
+ optional<int64_t> result;
if (!callback) {
- return offlineDatabase.hasRegionResource(id, resource);
- }
- optional<std::pair<Response, uint64_t>> response = offlineDatabase.getRegionResource(id, resource);
- if (!response) {
- return {};
+ result = offlineDatabase.hasRegionResource(resource);
+ } else {
+ optional<std::pair<Response, uint64_t>> response = offlineDatabase.getRegionResource(resource);
+ if (response) {
+ callback(response->first);
+ result = response->second;
+ }
}
- callback(response->first);
- return response->second;
+
+ if (result) resourcesToBeMarkedAsUsed.emplace_back(std::move(resource));
+ return result;
};
optional<int64_t> offlineResponse = getResourceSizeInDatabase();
if (offlineResponse) {
+ assert(!resourcesToBeMarkedAsUsed.empty());
status.completedResourceCount++;
status.completedResourceSize += *offlineResponse;
- if (resource.kind == Resource::Kind::Tile) {
+ if (resourceKind == Resource::Kind::Tile) {
status.completedTileCount += 1;
status.completedTileSize += *offlineResponse;
}
@@ -448,7 +474,7 @@ void OfflineDownload::ensureResource(const Resource& resource,
buffer.emplace_back(resource, onlineResponse);
// Flush buffer periodically
- if (buffer.size() == 64 || resourcesRemaining.size() == 0) {
+ if (buffer.size() == kResourcesBatchSize || resourcesRemaining.empty()) {
try {
offlineDatabase.putRegionResources(id, buffer, status);
} catch (const MapboxTileLimitExceededException&) {
diff --git a/platform/default/src/mbgl/storage/sqlite3.cpp b/platform/default/src/mbgl/storage/sqlite3.cpp
index 665e23b437..522210f88f 100644
--- a/platform/default/src/mbgl/storage/sqlite3.cpp
+++ b/platform/default/src/mbgl/storage/sqlite3.cpp
@@ -125,6 +125,7 @@ mapbox::util::variant<Database, Exception> Database::tryOpen(const std::string &
const int error = sqlite3_open_v2(filename.c_str(), &db, flags | SQLITE_OPEN_URI, nullptr);
if (error != SQLITE_OK) {
const auto message = sqlite3_errmsg(db);
+ sqlite3_close(db);
return Exception { error, message };
}
return Database(std::make_unique<DatabaseImpl>(db));
diff --git a/platform/default/src/mbgl/util/format_number.cpp b/platform/default/src/mbgl/util/format_number.cpp
index 7cc863818a..f58d6e100a 100644
--- a/platform/default/src/mbgl/util/format_number.cpp
+++ b/platform/default/src/mbgl/util/format_number.cpp
@@ -23,7 +23,11 @@ std::string formatNumber(double number, const std::string& localeId, const std::
.toString();
} else {
ustr = icu::number::NumberFormatter::with()
+#if U_ICU_VERSION_MAJOR_NUM >= 62
.precision(icu::number::Precision::minMaxFraction(minFractionDigits, maxFractionDigits))
+#else
+ .rounding(icu::number::Rounder::minMaxFraction(minFractionDigits, maxFractionDigits))
+#endif
.locale(locale)
.formatDouble(number, status)
.toString();
diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md
index 47da8ac53e..8515fd467f 100644
--- a/platform/ios/CHANGELOG.md
+++ b/platform/ios/CHANGELOG.md
@@ -2,7 +2,45 @@
Mapbox welcomes participation and contributions from everyone. Please read [CONTRIBUTING.md](../../CONTRIBUTING.md) to get started.
-## 5.3.0
+## master
+
+### Styles and rendering
+* Added an `-[MGLMapSnapshotter startWithOverlayHandler:completionHandler:]` method to provide the snapshot's current `CGContext` in order to perform custom drawing on `MGLMapSnapShot` objects. ([#15530](https://github.com/mapbox/mapbox-gl-native/pull/15530))
+
+### Performance improvements
+
+* Newly loaded labels appear faster on the screen. ([#15308](https://github.com/mapbox/mapbox-gl-native/pull/15308))
+
+## 5.4.0
+
+### Styles and rendering
+
+* Fixed crashes triggered when `MGLSource` and `MGLStyleLayer` objects are accessed after having been invalidated after a style change. ([#15539](https://github.com/mapbox/mapbox-gl-native/pull/15539))
+* Fixed a rendering issue of `collisionBox` when `MGLSymbolStyleLayer.textTranslate` or `MGLSymbolStyleLayer.iconTranslate` is enabled. ([#15467](https://github.com/mapbox/mapbox-gl-native/pull/15467))
+* Fixed an issue where the scale bar text would become illegible if iOS 13 dark mode was enabled. ([#15524](https://github.com/mapbox/mapbox-gl-native/pull/15524))
+* Enabled use of `MGLSymbolStyleLayer.textOffset` option together with `MGLSymbolStyleLayer.textVariableAnchor` (if `MGLSymbolStyleLayer.textRadialOffset` option is not provided). ([#15542](https://github.com/mapbox/mapbox-gl-native/pull/15542))
+* Fixed an issue with the appearance of the compass text in iOS 13. ([#15547](https://github.com/mapbox/mapbox-gl-native/pull/15547))
+* Fixed a bug where the completion block passed to `-[MGLMapView flyToCamera:completionHandler:` (and related methods) wouldn't be called. ([#15473](https://github.com/mapbox/mapbox-gl-native/pull/15473))
+
+### User interaction
+
+* Fixed an issue that caused the tilt gesture to trigger too easily and conflict with pinch or pan gestures. ([#15349](https://github.com/mapbox/mapbox-gl-native/pull/15349))
+* Fixed an issue that caused the map to rotate too easily during a pinch gesture. [(#15562)](https://github.com/mapbox/mapbox-gl-native/pull/15562)
+
+### Performance improvements
+
+* Improved offline region download performance by batching certain database activities. ([#15521](https://github.com/mapbox/mapbox-gl-native/pull/15521))
+* Newly loaded labels appear faster on the screen. ([#15308](https://github.com/mapbox/mapbox-gl-native/pull/15308))
+
+### Other changes
+
+* Fixed a potential integer overflow at high zoom levels. ([#15560](https://github.com/mapbox/mapbox-gl-native/pull/15560))
+* Fixed a bug with annotation view positions after camera transitions. ([#15122](https://github.com/mapbox/mapbox-gl-native/pull/15122/))
+* Fixed constant repainting for the sources with invisible layers, caused by `RenderSource::hasFadingTiles()` returning `true` all the time. ([#15600](https://github.com/mapbox/mapbox-gl-native/pull/15600))
+
+## 5.3.0 - August 28, 2019
+
+This release changes how offline tile requests are billed — they are now billed on a pay-as-you-go basis and all developers are able raise the offline tile limit for their users. Offline requests were previously exempt from monthly active user (MAU) billing and increasing the offline per-user tile limit to more than 6,000 tiles required the purchase of an enterprise license. By upgrading to this release, you are opting into the changes outlined in [this blog post](https://blog.mapbox.com/offline-maps-for-all-bb0fc51827be) and [#15380](https://github.com/mapbox/mapbox-gl-native/pull/15380).
### Styles and rendering
@@ -11,11 +49,18 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT
* Fixed an issue where animated camera transitions zoomed in or out too dramatically. ([#15281](https://github.com/mapbox/mapbox-gl-native/pull/15281))
* Enabled variable label placement when `MGLSymbolStyleLayer.textAllowsOverlap` is set to true. ([#15354](https://github.com/mapbox/mapbox-gl-native/pull/15354))
* Added the `MGLSymbolStyleLayer.textWritingModes` layout property. This property can be set to `MGLTextWritingModeHorizontal` or `MGLTextWritingModeVertical`. ([#14932](https://github.com/mapbox/mapbox-gl-native/pull/14932))
+* Fixed rendering and collision detection issues with using `MGLSymbolStyleLayer.textVariableAnchor` and `MGLSymbolStyleLayer.iconTextFit` properties on the same layer. ([#15367](https://github.com/mapbox/mapbox-gl-native/pull/15367))
+* Fixed symbol overlap when zooming out quickly. ([#15416](https://github.com/mapbox/mapbox-gl-native/pull/15416))
+* Fixed a rendering issue where non-SDF icons would be treated as SDF icons if they are in the same layer. ([#15456](https://github.com/mapbox/mapbox-gl-native/pull/15456))
### Other changes
+* Fixed a bug where glyphs generated through the LocalGlyphRasterizer interface were changing fonts during some zoom changes. ([#15407](https://github.com/mapbox/mapbox-gl-native/pull/15407))
+* Fixed use of objects after moving, potentially causing crashes. ([#15408](https://github.com/mapbox/mapbox-gl-native/pull/15408))
+* Fixed a possible crash that could be caused by invoking the wrong layer implementation casting function. ([#15398](https://github.com/mapbox/mapbox-gl-native/pull/15398))
* Fixed a rare crash when tile download requests returned “404 Not Found” errors. ([#15313](https://github.com/mapbox/mapbox-gl-native/pull/15313))
* `MGLLoggingLevel` has been updated to better match core log levels. You can now use `MGLLoggingConfiguration.loggingLevel` to filter logs from core. ([#15120](https://github.com/mapbox/mapbox-gl-native/pull/15120))
+* Fixed an issue where the scale bar could show `0 mm` instead of `0`. ([#15381](https://github.com/mapbox/mapbox-gl-native/pull/15381))
## 4.11.2 - July 30, 2019
diff --git a/platform/ios/INSTALL.md b/platform/ios/INSTALL.md
index eee75b9993..1d0d7dc647 100644
--- a/platform/ios/INSTALL.md
+++ b/platform/ios/INSTALL.md
@@ -108,7 +108,7 @@ For instructions on installing stable release versions of the Mapbox Maps SDK fo
##### Testing pre-releases with CocoaPods
-To test pre-releases of the dynamic framework, directly specify the version in your Podfile:
+To test pre-releases of the dynamic framework, directly specify the version in your `Podfile`:
```rb
pod 'Mapbox-iOS-SDK', '~> x.x.x-alpha.1'
@@ -126,10 +126,20 @@ pod 'Mapbox-iOS-SDK-snapshot-dynamic', podspec: 'https://raw.githubusercontent.c
1. Build from source manually, per above.
-1. Update your app’s `Podfile` to point to `Mapbox-iOS-SDK.podspec`.
+1. Edit [`Mapbox-iOS-SDK.podspec`](./Mapbox-iOS-SDK.podspec) to point to the local build output:
+
+ ```diff
+ m.source = {
+ - :http => "https://mapbox.s3.amazonaws.com/mapbox-gl-native/ios/builds/mapbox-ios-sdk-#{m.version.to_s}-dynamic.zip",
+ + :path => "../../build/ios/pkg/dynamic/",
+ :flatten => true
+ }
+ ```
+
+1. Update your app’s `Podfile` to point to the edited `Mapbox-iOS-SDK.podspec`.
```rb
- pod 'Mapbox-iOS-SDK', :path => '{...}/build/ios/pkg/{dynamic|static}/Mapbox-iOS-SDK.podspec'
+ pod 'Mapbox-iOS-SDK', :path => '{...}/platform/ios/Mapbox-iOS-SDK.podspec'
```
1. Run `pod update` to grab the newly-built library.
@@ -138,10 +148,12 @@ If using the static framework, add `$(inherited)` to your target’s Other Linke
##### Using pre-stripped releases with CocoaPods
-If you choose to commit the contents of your `Pods` directory to source control and are encountering file size limitations, you may wish to use builds that have been pre-stripped of debug symbols.
+If you choose to commit the contents of your `Pods` directory to source control and are encountering file size limitations, you may wish to use builds that have been pre-stripped of debug symbols. We publish these to [our public podspecs repository](https://github.com/mapbox/pod-specs/), which should be added as an additional `source` in your app’s `Podfile`.
```rb
-pod 'Mapbox-iOS-SDK-stripped', podspec: 'https://raw.githubusercontent.com/mapbox/mapbox-gl-native/ios-v{x.x.x}/platform/ios/Mapbox-iOS-SDK-stripped.podspec'
+source 'https://github.com/mapbox/pod-specs.git'
+
+pod 'Mapbox-iOS-SDK-stripped', '~> x.x.x'
```
Note that these builds lack some debugging information, which could make development more difficult and result in less useful crash reports. Though initially smaller on disk, using these builds has no effect on the ultimate size of your application — see our [Understanding iOS Framework Size guide](https://www.mapbox.com/help/ios-framework-size/) for more information.
diff --git a/platform/ios/Integration Tests/Annotation Tests/MGLAnnotationViewIntegrationTests.m b/platform/ios/Integration Tests/Annotation Tests/MGLAnnotationViewIntegrationTests.mm
index f129277e87..1b3603419e 100644
--- a/platform/ios/Integration Tests/Annotation Tests/MGLAnnotationViewIntegrationTests.m
+++ b/platform/ios/Integration Tests/Annotation Tests/MGLAnnotationViewIntegrationTests.mm
@@ -4,6 +4,13 @@
#import "MGLTestLocationManager.h"
#import "MGLCompactCalloutView.h"
+#import "MGLGeometry_Private.h"
+#import "MGLMapView_Private.h"
+
+#include <mbgl/util/geo.hpp>
+#include <mbgl/map/camera.hpp>
+#include <mbgl/map/map.hpp>
+
@interface MGLTestCalloutView : MGLCompactCalloutView
@property (nonatomic) BOOL implementsMarginHints;
@end
@@ -21,6 +28,10 @@
@interface MGLMapView (Tests)
- (MGLAnnotationTag)annotationTagAtPoint:(CGPoint)point persistingResults:(BOOL)persist;
+- (id <MGLAnnotation>)annotationWithTag:(MGLAnnotationTag)tag;
+- (MGLMapCamera *)cameraByRotatingToDirection:(CLLocationDirection)degrees aroundAnchorPoint:(CGPoint)anchorPoint;
+- (MGLMapCamera *)cameraByZoomingToZoomLevel:(double)zoom aroundAnchorPoint:(CGPoint)anchorPoint;
+- (MGLMapCamera *)cameraForCameraOptions:(const mbgl::CameraOptions &)cameraOptions;
@property (nonatomic) UIView<MGLCalloutView> *calloutViewForSelectedAnnotation;
@end
@@ -502,6 +513,267 @@ static const CGPoint kAnnotationRelativeScale = { 0.05f, 0.125f };
XCTAssertEqual(originalFrame.origin.y + offset.y, offsetFrame.origin.y);
}
+#pragma mark - Rotating/zooming
+
+- (void)testSelectingAnnotationWhenMapIsRotated {
+
+ CLLocationCoordinate2D coordinates[] = {
+ { 40.0, 40.0 },
+ { NAN, NAN }
+ };
+
+ NSArray *annotations = [self internalAddAnnotationsAtCoordinates:coordinates];
+ MGLPointAnnotation *annotation = annotations.firstObject;
+
+ // Rotate
+ CLLocationDirection lastAngle = 0.0;
+
+ srand48(0);
+ for (NSInteger iter = 0; iter < 10; iter++ ) {
+
+ CLLocationDirection angle = (CLLocationDirection)((drand48()*1080.0) - 540.0);
+
+ CGPoint anchor = CGPointMake(drand48()*CGRectGetWidth(self.mapView.bounds), drand48()*CGRectGetHeight(self.mapView.bounds));
+
+ NSString *activityTitle = [NSString stringWithFormat:@"Rotate to: %0.1f from: %0.1f", angle, lastAngle];
+ [XCTContext runActivityNamed:activityTitle
+ block:^(id<XCTActivity> _Nonnull activity) {
+
+ MGLMapCamera *toCamera = [self.mapView cameraByRotatingToDirection:angle aroundAnchorPoint:anchor];
+ [self internalTestSelecting:annotation withCamera:toCamera];
+ }];
+
+ lastAngle = angle;
+ }
+}
+
+- (void)testSelectingAnnotationWhenMapIsScaled {
+
+ CLLocationCoordinate2D coordinates[] = {
+ { 0.005, 0.005 },
+ { NAN, NAN }
+ };
+
+ NSArray *annotations = [self internalAddAnnotationsAtCoordinates:coordinates];
+ MGLPointAnnotation *annotation = annotations.firstObject;
+
+ CGPoint anchor = CGPointMake(CGRectGetMidX(self.mapView.bounds), CGRectGetMidY(self.mapView.bounds));
+
+ srand48(0);
+ for (NSInteger iter = 0; iter < 10; iter++ ) {
+
+ double zoom = (double)(drand48()*14.0);
+
+ NSString *activityTitle = [NSString stringWithFormat:@"Zoom to %0.1f", zoom];
+ [XCTContext runActivityNamed:activityTitle
+ block:^(id<XCTActivity> _Nonnull activity) {
+ MGLMapCamera *toCamera = [self.mapView cameraByZoomingToZoomLevel:zoom aroundAnchorPoint:anchor];
+ [self internalTestSelecting:annotation withCamera:toCamera];
+ }];
+ }
+}
+
+- (void)testSelectingAnnotationWhenMapIsScaledAndRotated {
+
+ CLLocationCoordinate2D coordinates[] = {
+ { 0.005, 0.005 },
+ { NAN, NAN }
+ };
+
+ NSArray *annotations = [self internalAddAnnotationsAtCoordinates:coordinates];
+ MGLPointAnnotation *annotation = annotations.firstObject;
+
+ srand48(0);
+ for (NSInteger iter = 0; iter < 10; iter++ ) {
+
+ double zoom = (double)(7.0 + drand48()*7.0);
+ CLLocationDirection angle = (CLLocationDirection)((drand48()*1080.0) - 540.0);
+
+ CGPoint anchor = CGPointMake(drand48()*CGRectGetWidth(self.mapView.bounds), drand48()*CGRectGetHeight(self.mapView.bounds));
+
+ NSString *activityTitle = [NSString stringWithFormat:@"Zoom to %0.1f", zoom];
+ [XCTContext runActivityNamed:activityTitle
+ block:^(id<XCTActivity> _Nonnull activity)
+ {
+ mbgl::CameraOptions currentCameraOptions;
+
+ currentCameraOptions.bearing = angle;
+ currentCameraOptions.anchor = mbgl::ScreenCoordinate { anchor.x, anchor.y };
+ currentCameraOptions.zoom = zoom;
+ MGLMapCamera *toCamera = [self.mapView cameraForCameraOptions:currentCameraOptions];
+
+ [self internalTestSelecting:annotation withCamera:toCamera];
+ }];
+ }
+}
+
+
+- (void)testShowingAnnotationsThenSelectingAnimated {
+ [self internalTestShowingAnnotationsThenSelectingAnimated:YES];
+}
+
+- (void)testShowingAnnotationsThenSelecting {
+ [self internalTestShowingAnnotationsThenSelectingAnimated:NO];
+}
+
+- (void)internalTestShowingAnnotationsThenSelectingAnimated:(BOOL)animated {
+ srand48(0);
+
+ CGFloat maxXPadding = std::max(CGRectGetWidth(self.mapView.bounds)/5.0, 100.0);
+ CGFloat maxYPadding = std::max(CGRectGetHeight(self.mapView.bounds)/5.0, 100.0);
+
+ for (int i = 0; i < 10; i++) {
+ UIEdgeInsets edgePadding;
+ edgePadding.top = floor(drand48()*maxYPadding);
+ edgePadding.bottom = floor(drand48()*maxYPadding);
+ edgePadding.left = floor(drand48()*maxXPadding);
+ edgePadding.right = floor(drand48()*maxXPadding);
+
+ UIEdgeInsets contentInsets;
+ contentInsets.top = floor(drand48()*maxYPadding);
+ contentInsets.bottom = floor(drand48()*maxYPadding);
+ contentInsets.left = floor(drand48()*maxXPadding);
+ contentInsets.right = floor(drand48()*maxXPadding);
+
+ [self internalTestShowingAnnotationsThenSelectingAnimated:animated edgePadding:edgePadding contentInsets:contentInsets];
+ }
+}
+
+- (void)internalTestShowingAnnotationsThenSelectingAnimated:(BOOL)animated edgePadding:(UIEdgeInsets)edgeInsets contentInsets:(UIEdgeInsets)contentInsets {
+ CLLocationCoordinate2D coordinates[21];
+
+ for (int i = 0; i < (int)(sizeof(coordinates)/sizeof(coordinates[0])); i++)
+ {
+ coordinates[i].latitude = drand48();
+ coordinates[i].longitude = drand48();
+ }
+ coordinates[20] = CLLocationCoordinate2DMake(NAN, NAN);
+
+ NSArray *annotations = [self internalAddAnnotationsAtCoordinates:coordinates];
+
+ XCTestExpectation *showCompleted = [self expectationWithDescription:@"showCompleted"];
+
+ self.mapView.contentInset = contentInsets;
+ [self.mapView showAnnotations:annotations
+ edgePadding:edgeInsets
+ animated:animated
+ completionHandler:^{
+ [showCompleted fulfill];
+ }];
+
+ [self waitForExpectations:@[showCompleted] timeout:3.5];
+
+ // These tests will fail if this isn't here. But this isn't quite what we're
+ // seeing in https://github.com/mapbox/mapbox-gl-native/issues/15106
+ [self waitForCollisionDetectionToRun];
+
+ for (MGLPointAnnotation *point in annotations) {
+ [self internalSelectDeselectAnnotation:point];
+ }
+
+ [self.mapView removeAnnotations:annotations];
+ self.mapView.contentInset = UIEdgeInsetsZero;
+ [self waitForCollisionDetectionToRun];
+}
+
+- (NSArray*)internalAddAnnotationsAtCoordinates:(CLLocationCoordinate2D*)coordinates
+{
+ __block NSMutableArray *annotations = [NSMutableArray array];
+
+ [XCTContext runActivityNamed:@"Map setup"
+ block:^(id<XCTActivity> _Nonnull activity)
+ {
+
+ NSString * const MGLTestAnnotationReuseIdentifer = @"MGLTestAnnotationReuseIdentifer";
+
+ CGSize annotationSize = CGSizeMake(40.0, 40.0);
+
+ self.viewForAnnotation = ^MGLAnnotationView*(MGLMapView *view, id<MGLAnnotation> annotation2) {
+
+ if (![annotation2 isKindOfClass:[MGLPointAnnotation class]]) {
+ return nil;
+ }
+
+ // No dequeue
+ MGLAnnotationView *annotationView = [[MGLAnnotationView alloc] initWithAnnotation:annotation2 reuseIdentifier:MGLTestAnnotationReuseIdentifer];
+ annotationView.bounds = (CGRect){ .origin = CGPointZero, .size = annotationSize };
+ annotationView.backgroundColor = UIColor.redColor;
+ annotationView.enabled = YES;
+
+ return annotationView;
+ };
+
+ CLLocationCoordinate2D *coordinatePtr = coordinates;
+ while (!isnan(coordinatePtr->latitude)) {
+ CLLocationCoordinate2D coordinate = *coordinatePtr++;
+
+ MGLPointAnnotation *annotation = [[MGLPointAnnotation alloc] init];
+ annotation.title = NSStringFromSelector(_cmd);
+ annotation.coordinate = coordinate;
+ [annotations addObject:annotation];
+ }
+
+ [self.mapView addAnnotations:annotations];
+
+ }];
+
+ NSArray *copiedAnnotations = [annotations copy];
+ annotations = nil;
+
+ return copiedAnnotations;
+}
+
+- (void)internalTestSelecting:(MGLPointAnnotation*)point withCamera:(MGLMapCamera*)camera {
+
+ // Rotate
+ XCTestExpectation *rotationCompleted = [self expectationWithDescription:@"rotationCompleted"];
+ [self.mapView setCamera:camera withDuration:0.1 animationTimingFunction:nil completionHandler:^{
+ [rotationCompleted fulfill];
+ }];
+
+ [self waitForExpectations:@[rotationCompleted] timeout:1.5];
+
+ // Collision detection may not have completed, if not we may not get our annotation.
+ [self waitForCollisionDetectionToRun];
+
+ // Look up annotation at point
+ [self internalSelectDeselectAnnotation:point];
+}
+
+- (void)internalSelectDeselectAnnotation:(MGLPointAnnotation*)point {
+ [XCTContext runActivityNamed:[NSString stringWithFormat:@"Select annotation: %@", point]
+ block:^(id<XCTActivity> _Nonnull activity)
+ {
+ CGPoint annotationPoint = [self.mapView convertCoordinate:point.coordinate toPointToView:self.mapView];
+
+ MGLAnnotationTag tagAtPoint = [self.mapView annotationTagAtPoint:annotationPoint persistingResults:YES];
+ if (tagAtPoint != UINT32_MAX)
+ {
+ id <MGLAnnotation> annotation = [self.mapView annotationWithTag:tagAtPoint];
+ XCTAssertNotNil(annotation);
+
+ // Select
+ XCTestExpectation *selectionCompleted = [self expectationWithDescription:@"Selection completed"];
+ [self.mapView selectAnnotation:annotation moveIntoView:NO animateSelection:NO completionHandler:^{
+ [selectionCompleted fulfill];
+ }];
+
+ [self waitForExpectations:@[selectionCompleted] timeout:0.05];
+
+ XCTAssert(self.mapView.selectedAnnotations.count == 1, @"There should only be 1 selected annotation");
+ XCTAssertEqualObjects(self.mapView.selectedAnnotations.firstObject, annotation, @"The annotation should be selected");
+
+ // Deselect
+ [self.mapView deselectAnnotation:annotation animated:NO];
+ }
+ else
+ {
+ XCTFail(@"Should be an annotation at this point: %@", NSStringFromCGPoint(annotationPoint));
+ }
+ }];
+
+}
+
#pragma mark - Utilities
- (void)runRunLoop {
@@ -529,6 +801,7 @@ static const CGPoint kAnnotationRelativeScale = { 0.05f, 0.125f };
- (void)waitForCollisionDetectionToRun {
XCTAssertNil(self.renderFinishedExpectation, @"Incorrect test setup");
+ [self.mapView setNeedsRerender];
self.renderFinishedExpectation = [self expectationWithDescription:@"Map view should be rendered"];
XCTestExpectation *timerExpired = [self expectationWithDescription:@"Timer expires"];
diff --git a/platform/ios/Integration Tests/Camera Tests/MGLCameraTransitionFinishTests.mm b/platform/ios/Integration Tests/Camera Tests/MGLCameraTransitionFinishTests.mm
new file mode 100644
index 0000000000..1527e8dbe5
--- /dev/null
+++ b/platform/ios/Integration Tests/Camera Tests/MGLCameraTransitionFinishTests.mm
@@ -0,0 +1,109 @@
+#import "MGLMapViewIntegrationTest.h"
+#import "MGLTestUtility.h"
+#import "../../darwin/src/MGLGeometry_Private.h"
+
+#include <mbgl/map/camera.hpp>
+
+@interface MGLCameraTransitionFinishTests : MGLMapViewIntegrationTest
+@end
+
+@implementation MGLCameraTransitionFinishTests
+
+- (void)testEaseToCompletionHandler {
+
+ MGLCoordinateBounds bounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(0.0, 0.0),
+ CLLocationCoordinate2DMake(1.0, 1.0));
+ MGLMapCamera *camera = [self.mapView cameraThatFitsCoordinateBounds:bounds];
+
+ XCTestExpectation *expectation = [self expectationWithDescription:@"Completion block should be called"];
+
+ [self.mapView setCamera:camera
+ withDuration:0.0
+ animationTimingFunction:nil
+ completionHandler:^{
+ [expectation fulfill];
+ }];
+
+ [self waitForExpectations:@[expectation] timeout:0.5];
+}
+
+- (void)testEaseToCompletionHandlerAnimated {
+
+ MGLCoordinateBounds bounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(0.0, 0.0),
+ CLLocationCoordinate2DMake(1.0, 1.0));
+ MGLMapCamera *camera = [self.mapView cameraThatFitsCoordinateBounds:bounds];
+
+ XCTestExpectation *expectation = [self expectationWithDescription:@"Completion block should be called"];
+
+ [self.mapView setCamera:camera
+ withDuration:0.3
+ animationTimingFunction:nil
+ completionHandler:^{
+ [expectation fulfill];
+ }];
+
+ [self waitForExpectations:@[expectation] timeout:0.5];
+}
+
+- (void)testFlyToCompletionHandler {
+
+ MGLCoordinateBounds bounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(0.0, 0.0),
+ CLLocationCoordinate2DMake(1.0, 1.0));
+ MGLMapCamera *camera = [self.mapView cameraThatFitsCoordinateBounds:bounds];
+
+ XCTestExpectation *expectation = [self expectationWithDescription:@"Completion block should be called"];
+
+ [self.mapView flyToCamera:camera
+ withDuration:0.0
+ completionHandler:^{
+ [expectation fulfill];
+ }];
+
+ [self waitForExpectations:@[expectation] timeout:0.5];
+}
+
+- (void)testFlyToCompletionHandlerAnimated {
+
+ MGLCoordinateBounds bounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(0.0, 0.0),
+ CLLocationCoordinate2DMake(1.0, 1.0));
+ MGLMapCamera *camera = [self.mapView cameraThatFitsCoordinateBounds:bounds];
+
+ XCTestExpectation *expectation = [self expectationWithDescription:@"Completion block should be called"];
+
+ [self.mapView flyToCamera:camera
+ withDuration:0.3
+ completionHandler:^{
+ [expectation fulfill];
+ }];
+
+ [self waitForExpectations:@[expectation] timeout:0.5];
+}
+@end
+
+#pragma mark - camera transitions with NaN values
+
+@interface MGLMapView (MGLCameraTransitionFinishNaNTests)
+- (mbgl::CameraOptions)cameraOptionsObjectForAnimatingToCamera:(MGLMapCamera *)camera edgePadding:(UIEdgeInsets)insets;
+@end
+
+@interface MGLCameraTransitionNaNZoomMapView: MGLMapView
+@end
+
+@implementation MGLCameraTransitionNaNZoomMapView
+- (mbgl::CameraOptions)cameraOptionsObjectForAnimatingToCamera:(MGLMapCamera *)camera edgePadding:(UIEdgeInsets)insets {
+ mbgl::CameraOptions options = [super cameraOptionsObjectForAnimatingToCamera:camera edgePadding:insets];
+ options.zoom = NAN;
+ return options;
+}
+@end
+
+// Subclass the entire test suite, but with a different MGLMapView subclass
+@interface MGLCameraTransitionFinishNaNTests : MGLCameraTransitionFinishTests
+@end
+
+@implementation MGLCameraTransitionFinishNaNTests
+- (MGLMapView *)mapViewForTestWithFrame:(CGRect)rect styleURL:(NSURL *)styleURL {
+ return [[MGLCameraTransitionNaNZoomMapView alloc] initWithFrame:rect styleURL:styleURL];
+}
+@end
+
diff --git a/platform/ios/Integration Tests/MGLCameraTransitionTests.mm b/platform/ios/Integration Tests/Camera Tests/MGLCameraTransitionTests.mm
index 9679c4c11f..27ab7964c1 100644
--- a/platform/ios/Integration Tests/MGLCameraTransitionTests.mm
+++ b/platform/ios/Integration Tests/Camera Tests/MGLCameraTransitionTests.mm
@@ -2,10 +2,10 @@
#import "MGLTestUtility.h"
#import "../../darwin/src/MGLGeometry_Private.h"
-@interface MBCameraTransitionTests : MGLMapViewIntegrationTest
+@interface MGLCameraTransitionTests : MGLMapViewIntegrationTest
@end
-@implementation MBCameraTransitionTests
+@implementation MGLCameraTransitionTests
- (void)testSetAndResetNorthWithDispatchAsyncInDelegateMethod {
@@ -17,7 +17,7 @@
self.regionDidChange = ^(MGLMapView *mapView, MGLCameraChangeReason reason, BOOL animated) {
- MBCameraTransitionTests *strongSelf = weakself;
+ MGLCameraTransitionTests *strongSelf = weakself;
if (!strongSelf) return;
@@ -48,7 +48,7 @@
self.regionDidChange = ^(MGLMapView *mapView, MGLCameraChangeReason reason, BOOL animated) {
- MBCameraTransitionTests *strongSelf = weakself;
+ MGLCameraTransitionTests *strongSelf = weakself;
if (!strongSelf) return;
@@ -79,7 +79,7 @@
__block BOOL finishedReset = NO;
self.regionIsChanging = ^(MGLMapView *mapView) {
- MBCameraTransitionTests *strongSelf = weakself;
+ MGLCameraTransitionTests *strongSelf = weakself;
if (!strongSelf) return;
if (!startedReset) {
@@ -91,7 +91,7 @@
};
self.regionDidChange = ^(MGLMapView *mapView, MGLCameraChangeReason reason, BOOL animated) {
- MBCameraTransitionTests *strongSelf = weakself;
+ MGLCameraTransitionTests *strongSelf = weakself;
if (!strongSelf) return;
MGLTestAssert(strongSelf, startedReset);
@@ -127,7 +127,7 @@
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.15 * NSEC_PER_SEC),
dispatch_get_main_queue(),
^{
- MBCameraTransitionTests *strongSelf = weakself;
+ MGLCameraTransitionTests *strongSelf = weakself;
[strongSelf.mapView setCenterCoordinate:dc zoomLevel:zoomLevel animated:NO];
MGLTestAssertEqualWithAccuracy(strongSelf,
@@ -160,7 +160,7 @@
self.regionDidChange = ^(MGLMapView *mapView, MGLCameraChangeReason reason, BOOL animated) {
- MBCameraTransitionTests *strongSelf = weakself;
+ MGLCameraTransitionTests *strongSelf = weakself;
if (!strongSelf) return;
@@ -248,7 +248,7 @@
self.regionDidChange = ^(MGLMapView *mapView, MGLCameraChangeReason reason, BOOL animated) {
- MBCameraTransitionTests *strongSelf = weakself;
+ MGLCameraTransitionTests *strongSelf = weakself;
if (!strongSelf) return;
@@ -333,7 +333,7 @@
#pragma mark - Pending tests
-- (void)testContinuallyResettingNorthInIsChangingPENDING {
+- (void)testContinuallyResettingNorthInIsChanging🙁{
// See https://github.com/mapbox/mapbox-gl-native/pull/11614
// This test currently fails, unsurprisingly, since we're continually
// setting the camera to the same parameters during its update.
@@ -365,8 +365,8 @@
XCTAssertEqualWithAccuracy(self.mapView.direction, 0.0, 0.001, @"Camera should have reset to north. %0.3f", self.mapView.direction);
}
-- (void)testContinuallySettingCoordinateInIsChangingPENDING {
- // See above comment in `-testContinuallyResettingNorthInIsChangingPENDING`
+- (void)testContinuallySettingCoordinateInIsChanging🙁 {
+ // See above comment in `-testContinuallyResettingNorthInIsChanging🙁`
// Reset to non-zero, prior to testing
[self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(0.0, 0.0) animated:NO];
diff --git a/platform/ios/Integration Tests/MGLMapViewIntegrationTest.h b/platform/ios/Integration Tests/MGLMapViewIntegrationTest.h
index dedafdb83a..08576e884a 100644
--- a/platform/ios/Integration Tests/MGLMapViewIntegrationTest.h
+++ b/platform/ios/Integration Tests/MGLMapViewIntegrationTest.h
@@ -26,6 +26,7 @@
@interface MGLMapViewIntegrationTest : XCTestCase <MGLMapViewDelegate>
@property (nonatomic) MGLMapView *mapView;
+@property (nonatomic) UIWindow *window;
@property (nonatomic) MGLStyle *style;
@property (nonatomic) XCTestExpectation *styleLoadingExpectation;
@property (nonatomic) XCTestExpectation *renderFinishedExpectation;
@@ -38,7 +39,7 @@
@property (nonatomic) id<MGLCalloutView> (^mapViewCalloutViewForAnnotation)(MGLMapView *mapView, id<MGLAnnotation> annotation);
// Utility methods
-- (NSString*)validAccessToken;
- (void)waitForMapViewToFinishLoadingStyleWithTimeout:(NSTimeInterval)timeout;
- (void)waitForMapViewToBeRenderedWithTimeout:(NSTimeInterval)timeout;
+- (MGLMapView *)mapViewForTestWithFrame:(CGRect)rect styleURL:(NSURL *)styleURL;
@end
diff --git a/platform/ios/Integration Tests/MGLMapViewIntegrationTest.m b/platform/ios/Integration Tests/MGLMapViewIntegrationTest.m
index 2c89bb1c77..4095b4620b 100644
--- a/platform/ios/Integration Tests/MGLMapViewIntegrationTest.m
+++ b/platform/ios/Integration Tests/MGLMapViewIntegrationTest.m
@@ -2,50 +2,76 @@
@interface MGLMapView (MGLMapViewIntegrationTest)
- (void)updateFromDisplayLink:(CADisplayLink *)displayLink;
+- (void)setNeedsRerender;
@end
@implementation MGLMapViewIntegrationTest
-- (void)invokeTest {
- NSString *selector = NSStringFromSelector(self.invocation.selector);
- BOOL isPendingTest = [selector hasSuffix:@"PENDING"];
++ (XCTestSuite*)defaultTestSuite {
- if (isPendingTest) {
- NSString *runPendingTests = [[NSProcessInfo processInfo] environment][@"MAPBOX_RUN_PENDING_TESTS"];
- if (![runPendingTests boolValue]) {
- printf("warning: '%s' is a pending test - skipping\n", selector.UTF8String);
- return;
+ XCTestSuite *defaultTestSuite = [super defaultTestSuite];
+
+ NSArray *tests = defaultTestSuite.tests;
+
+ XCTestSuite *newTestSuite = [XCTestSuite testSuiteWithName:defaultTestSuite.name];
+
+ BOOL runPendingTests = [[[NSProcessInfo processInfo] environment][@"MAPBOX_RUN_PENDING_TESTS"] boolValue];
+ NSString *accessToken = [[NSProcessInfo processInfo] environment][@"MAPBOX_ACCESS_TOKEN"];
+
+ for (XCTest *test in tests) {
+
+ // Check for pending tests
+ if ([test.name containsString:@"PENDING"] ||
+ [test.name containsString:@"🙁"]) {
+ if (!runPendingTests) {
+ printf("warning: '%s' is a pending test - skipping\n", test.name.UTF8String);
+ continue;
+ }
+ }
+
+ // Check for tests that require a valid access token
+ if ([test.name containsString:@"🔒"]) {
+ if (!accessToken) {
+ printf("warning: MAPBOX_ACCESS_TOKEN env var is required for test '%s' - skipping.\n", test.name.UTF8String);
+ continue;
+ }
}
- }
-
- [super invokeTest];
-}
-- (NSString*)validAccessToken {
- NSString *accessToken = [[NSProcessInfo processInfo] environment][@"MAPBOX_ACCESS_TOKEN"];
- if (!accessToken) {
- printf("warning: MAPBOX_ACCESS_TOKEN env var is required for this test - skipping.\n");
- return nil;
+ [newTestSuite addTest:test];
}
+
+ return newTestSuite;
+}
- [MGLAccountManager setAccessToken:accessToken];
- return accessToken;
+- (MGLMapView *)mapViewForTestWithFrame:(CGRect)rect styleURL:(NSURL *)styleURL {
+ return [[MGLMapView alloc] initWithFrame:UIScreen.mainScreen.bounds styleURL:styleURL];
}
- (void)setUp {
[super setUp];
- [MGLAccountManager setAccessToken:@"pk.feedcafedeadbeefbadebede"];
+ NSString *accessToken;
+
+ if ([self.name containsString:@"🔒"]) {
+ accessToken = [[NSProcessInfo processInfo] environment][@"MAPBOX_ACCESS_TOKEN"];
+
+ if (!accessToken) {
+ printf("warning: MAPBOX_ACCESS_TOKEN env var is required for test '%s' - trying anyway.\n", self.name.UTF8String);
+ }
+ }
+
+ [MGLAccountManager setAccessToken:accessToken ?: @"pk.feedcafedeadbeefbadebede"];
+
NSURL *styleURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"one-liner" withExtension:@"json"];
- self.mapView = [[MGLMapView alloc] initWithFrame:UIScreen.mainScreen.bounds styleURL:styleURL];
+ self.mapView = [self mapViewForTestWithFrame:UIScreen.mainScreen.bounds styleURL:styleURL];
self.mapView.delegate = self;
UIView *superView = [[UIView alloc] initWithFrame:UIScreen.mainScreen.bounds];
[superView addSubview:self.mapView];
- UIWindow *window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
- [window addSubview:superView];
- [window makeKeyAndVisible];
+ self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
+ [self.window addSubview:superView];
+ [self.window makeKeyAndVisible];
if (!self.mapView.style) {
[self waitForMapViewToFinishLoadingStyleWithTimeout:10];
@@ -57,6 +83,7 @@
self.renderFinishedExpectation = nil;
self.mapView = nil;
self.style = nil;
+ self.window = nil;
[MGLAccountManager setAccessToken:nil];
[super tearDown];
@@ -129,13 +156,15 @@
XCTAssertNil(self.styleLoadingExpectation);
self.styleLoadingExpectation = [self expectationWithDescription:@"Map view should finish loading style."];
[self waitForExpectations:@[self.styleLoadingExpectation] timeout:timeout];
+ self.styleLoadingExpectation = nil;
}
- (void)waitForMapViewToBeRenderedWithTimeout:(NSTimeInterval)timeout {
XCTAssertNil(self.renderFinishedExpectation);
- [self.mapView setNeedsDisplay];
+ [self.mapView setNeedsRerender];
self.renderFinishedExpectation = [self expectationWithDescription:@"Map view should be rendered"];
[self waitForExpectations:@[self.renderFinishedExpectation] timeout:timeout];
+ self.renderFinishedExpectation = nil;
}
- (void)waitForExpectations:(NSArray<XCTestExpectation *> *)expectations timeout:(NSTimeInterval)seconds {
diff --git a/platform/ios/Integration Tests/MGLMapViewPendingBlockTests.m b/platform/ios/Integration Tests/MGLMapViewPendingBlockTests.m
new file mode 100644
index 0000000000..c7925d7896
--- /dev/null
+++ b/platform/ios/Integration Tests/MGLMapViewPendingBlockTests.m
@@ -0,0 +1,366 @@
+#import "MGLMapViewIntegrationTest.h"
+#import "MGLTestUtility.h"
+
+@interface MGLMapView (MGLMapViewPendingBlockTests)
+@property (nonatomic) NSMutableArray *pendingCompletionBlocks;
+- (void)pauseRendering:(__unused NSNotification *)notification;
+@end
+
+@interface MGLMapViewPendingBlockTests : MGLMapViewIntegrationTest
+@property (nonatomic, copy) void (^observation)(NSDictionary*);
+@property (nonatomic) BOOL completionHandlerCalled;
+@end
+
+@implementation MGLMapViewPendingBlockTests
+
+- (void)testSetCenterCoordinate {
+ __typeof__(self) weakSelf = self;
+
+ void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) {
+ __typeof__(self) strongSelf = weakSelf;
+
+ if (strongSelf) {
+ [strongSelf.mapView setCenterCoordinate:CLLocationCoordinate2DMake(10.0, 10.0)
+ zoomLevel:10.0
+ direction:0
+ animated:NO
+ completionHandler:completion];
+ }
+ else {
+ completion();
+ }
+ };
+
+ [self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd)
+ transition:transition
+ addToPendingCallback:nil];
+}
+
+- (void)testSetCenterCoordinateAnimated {
+ __typeof__(self) weakSelf = self;
+
+ void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) {
+ __typeof__(self) strongSelf = weakSelf;
+
+ if (strongSelf) {
+ [strongSelf.mapView setCenterCoordinate:CLLocationCoordinate2DMake(10.0, 10.0)
+ zoomLevel:10.0
+ direction:0
+ animated:YES
+ completionHandler:completion];
+ }
+ else {
+ completion();
+ }
+ };
+
+ [self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd)
+ transition:transition
+ addToPendingCallback:nil];
+}
+
+- (void)testSetVisibleCoordinateBounds {
+ __typeof__(self) weakSelf = self;
+
+ void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) {
+ __typeof__(self) strongSelf = weakSelf;
+
+ if (strongSelf) {
+ MGLCoordinateBounds unitBounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(1, 1));
+ [strongSelf.mapView setVisibleCoordinateBounds:unitBounds
+ edgePadding:UIEdgeInsetsZero
+ animated:NO
+ completionHandler:completion];
+ }
+ else {
+ completion();
+ }
+ };
+
+ [self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd)
+ transition:transition
+ addToPendingCallback:nil];
+}
+
+- (void)testSetVisibleCoordinateBoundsAnimated {
+ __typeof__(self) weakSelf = self;
+
+ void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) {
+ __typeof__(self) strongSelf = weakSelf;
+
+ if (strongSelf) {
+ MGLCoordinateBounds unitBounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(1, 1));
+ [strongSelf.mapView setVisibleCoordinateBounds:unitBounds
+ edgePadding:UIEdgeInsetsZero
+ animated:YES
+ completionHandler:completion];
+ }
+ else {
+ completion();
+ }
+ };
+
+ [self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd)
+ transition:transition
+ addToPendingCallback:nil];
+}
+
+- (void)testSetCamera {
+ __typeof__(self) weakSelf = self;
+
+ void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) {
+ __typeof__(self) strongSelf = weakSelf;
+
+ if (strongSelf) {
+ MGLCoordinateBounds unitBounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(1, 1));
+ MGLMapCamera *camera = [strongSelf.mapView cameraThatFitsCoordinateBounds:unitBounds];
+
+ [strongSelf.mapView setCamera:camera withDuration:0.0 animationTimingFunction:nil completionHandler:completion];
+ }
+ else {
+ completion();
+ }
+ };
+
+ [self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd)
+ transition:transition
+ addToPendingCallback:nil];
+}
+
+- (void)testSetCameraAnimated {
+ __typeof__(self) weakSelf = self;
+
+ void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) {
+ __typeof__(self) strongSelf = weakSelf;
+
+ if (strongSelf) {
+ MGLCoordinateBounds unitBounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(1, 1));
+ MGLMapCamera *camera = [strongSelf.mapView cameraThatFitsCoordinateBounds:unitBounds];
+
+ [strongSelf.mapView setCamera:camera withDuration:0.3 animationTimingFunction:nil completionHandler:completion];
+ }
+ else {
+ completion();
+ }
+ };
+
+ [self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd)
+ transition:transition
+ addToPendingCallback:nil];
+}
+
+- (void)testFlyToCamera {
+ __typeof__(self) weakSelf = self;
+
+ void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) {
+ __typeof__(self) strongSelf = weakSelf;
+
+ if (strongSelf) {
+ MGLCoordinateBounds unitBounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(1, 1));
+ MGLMapCamera *camera = [strongSelf.mapView cameraThatFitsCoordinateBounds:unitBounds];
+
+ [strongSelf.mapView flyToCamera:camera withDuration:0.0 completionHandler:completion];
+ }
+ else {
+ completion();
+ }
+ };
+
+ [self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd)
+ transition:transition
+ addToPendingCallback:nil];
+}
+
+- (void)testFlyToCameraAnimated {
+
+ __typeof__(self) weakSelf = self;
+
+ void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) {
+ __typeof__(self) strongSelf = weakSelf;
+
+ if (strongSelf) {
+ MGLCoordinateBounds unitBounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(1, 1));
+ MGLMapCamera *camera = [strongSelf.mapView cameraThatFitsCoordinateBounds:unitBounds];
+
+ [strongSelf.mapView flyToCamera:camera withDuration:0.3 completionHandler:completion];
+ }
+ else {
+ completion();
+ }
+ };
+
+ [self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd)
+ transition:transition
+ addToPendingCallback:nil];
+}
+
+
+#pragma mark - test interrupting regular rendering
+
+- (void)testSetCenterCoordinateSetHidden {
+
+ __typeof__(self) weakSelf = self;
+
+ void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) {
+ __typeof__(self) strongSelf = weakSelf;
+
+ if (strongSelf) {
+ [strongSelf.mapView setCenterCoordinate:CLLocationCoordinate2DMake(10.0, 10.0)
+ zoomLevel:10.0
+ direction:0
+ animated:NO
+ completionHandler:completion];
+ }
+ else {
+ completion();
+ }
+ };
+
+ dispatch_block_t addedToPending = ^{
+ __typeof__(self) strongSelf = weakSelf;
+
+ MGLTestAssert(strongSelf, !strongSelf.completionHandlerCalled);
+
+ // Now hide the mapview
+ strongSelf.mapView.hidden = YES;
+
+ MGLTestAssert(strongSelf, strongSelf.completionHandlerCalled);
+ };
+
+ [self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd)
+ transition:transition
+ addToPendingCallback:addedToPending];
+}
+
+- (void)testSetCenterCoordinatePauseRendering {
+
+ __typeof__(self) weakSelf = self;
+
+ void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) {
+ __typeof__(self) strongSelf = weakSelf;
+
+ if (strongSelf) {
+ [strongSelf.mapView setCenterCoordinate:CLLocationCoordinate2DMake(10.0, 10.0)
+ zoomLevel:10.0
+ direction:0
+ animated:NO
+ completionHandler:completion];
+ }
+ else {
+ completion();
+ }
+ };
+
+ dispatch_block_t addedToPending = ^{
+ __typeof__(self) strongSelf = weakSelf;
+
+ MGLTestAssert(strongSelf, !strongSelf.completionHandlerCalled);
+
+ // Pause rendering, stopping display link
+ [strongSelf.mapView pauseRendering:nil];
+
+ MGLTestAssert(strongSelf, strongSelf.completionHandlerCalled);
+ };
+
+ [self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd)
+ transition:transition
+ addToPendingCallback:addedToPending];
+}
+
+- (void)testSetCenterCoordinateRemoveFromSuperview {
+
+ __typeof__(self) weakSelf = self;
+
+ void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) {
+ __typeof__(self) strongSelf = weakSelf;
+
+ if (strongSelf) {
+ [strongSelf.mapView setCenterCoordinate:CLLocationCoordinate2DMake(10.0, 10.0)
+ zoomLevel:10.0
+ direction:0
+ animated:NO
+ completionHandler:completion];
+ }
+ else {
+ completion();
+ }
+ };
+
+ dispatch_block_t addedToPending = ^{
+ __typeof__(self) strongSelf = weakSelf;
+
+ MGLTestAssert(strongSelf, !strongSelf.completionHandlerCalled);
+
+ // Remove from window, triggering validateDisplayLink
+ [strongSelf.mapView removeFromSuperview];
+
+ MGLTestAssert(strongSelf, strongSelf.completionHandlerCalled);
+ };
+
+ [self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd)
+ transition:transition
+ addToPendingCallback:addedToPending];
+}
+
+#pragma mark - Shared utility methods
+
+- (void)internalTestCompletionBlockAddedToPendingForTestName:(NSString *)testName
+ transition:(void (^)(dispatch_block_t))transition
+ addToPendingCallback:(dispatch_block_t)addToPendingCallback {
+
+ XCTestExpectation *expectation = [self expectationWithDescription:testName];
+
+ __weak __typeof__(self) myself = self;
+
+ dispatch_block_t block = ^{
+ myself.completionHandlerCalled = YES;
+ [expectation fulfill];
+ };
+
+ XCTAssertNotNil(transition);
+ transition(block);
+
+ XCTAssert(!self.completionHandlerCalled);
+ XCTAssert(self.mapView.pendingCompletionBlocks.count == 0);
+
+ __block BOOL blockAddedToPendingBlocks = NO;
+
+ // Observes changes to pendingCompletionBlocks (including additions)
+ self.observation = ^(NSDictionary *change){
+
+ NSLog(@"change = %@ count = %lu", change, myself.mapView.pendingCompletionBlocks.count);
+
+ NSArray *value = change[NSKeyValueChangeNewKey];
+
+ MGLTestAssert(myself, [value isKindOfClass:[NSArray class]]);
+
+ if (value.count > 0) {
+ MGLTestAssert(myself, [value containsObject:block]);
+ MGLTestAssert(myself, !blockAddedToPendingBlocks);
+ if ([myself.mapView.pendingCompletionBlocks containsObject:block]) {
+ blockAddedToPendingBlocks = YES;
+
+ if (addToPendingCallback) {
+ addToPendingCallback();
+ }
+ }
+ }
+ };
+
+ [self.mapView addObserver:self forKeyPath:@"pendingCompletionBlocks" options:NSKeyValueObservingOptionNew context:_cmd];
+
+ [self waitForExpectations:@[expectation] timeout:0.5];
+
+ XCTAssert(blockAddedToPendingBlocks);
+ XCTAssert(self.completionHandlerCalled);
+ XCTAssert(self.mapView.pendingCompletionBlocks.count == 0);
+
+ [self.mapView removeObserver:self forKeyPath:@"pendingCompletionBlocks" context:_cmd];
+}
+
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
+ if (self.observation) {
+ self.observation(change);
+ }
+}
+@end
diff --git a/platform/ios/Integration Tests/MGLSourceTests.swift b/platform/ios/Integration Tests/MGLSourceTests.swift
new file mode 100644
index 0000000000..69fa0182b5
--- /dev/null
+++ b/platform/ios/Integration Tests/MGLSourceTests.swift
@@ -0,0 +1,45 @@
+import XCTest
+
+class MGLSourceTests: MGLMapViewIntegrationTest {
+
+ // See testForRaisingExceptionsOnStaleStyleObjects for Obj-C sibling.
+ func testForRaisingExceptionsOnStaleStyleObjectsOnRemoveFromMapView() {
+
+ guard
+ let configURL = URL(string: "mapbox://examples.2uf7qges") else {
+ XCTFail()
+ return
+ }
+
+ let source = MGLVectorTileSource(identifier: "trees", configurationURL: configURL)
+ mapView.style?.addSource(source)
+
+ let bundle = Bundle(for: type(of: self))
+
+ guard let styleURL = bundle.url(forResource: "one-liner", withExtension: "json") else {
+ XCTFail()
+ return
+ }
+
+ styleLoadingExpectation = nil;
+
+ mapView.centerCoordinate = CLLocationCoordinate2D(latitude : 38.897, longitude : -77.039)
+ mapView.zoomLevel = 10.5
+ mapView.styleURL = styleURL
+
+ waitForMapViewToFinishLoadingStyle(withTimeout: 10.0)
+
+ let expect = expectation(description: "Remove source should error")
+
+ do {
+ try mapView.style?.removeSource(source, error: ())
+ }
+ catch let error as NSError {
+ XCTAssertEqual(error.domain, MGLErrorDomain)
+ XCTAssertEqual(error.code, MGLErrorCode.sourceCannotBeRemovedFromStyle.rawValue)
+ expect.fulfill()
+ }
+
+ wait(for: [expect], timeout: 0.1)
+ }
+}
diff --git a/platform/ios/Integration Tests/MGLStyleLayerIntegrationTests.m b/platform/ios/Integration Tests/MGLStyleLayerIntegrationTests.m
index 4501294f72..c018c457b9 100644
--- a/platform/ios/Integration Tests/MGLStyleLayerIntegrationTests.m
+++ b/platform/ios/Integration Tests/MGLStyleLayerIntegrationTests.m
@@ -58,4 +58,55 @@
[self waitForMapViewToBeRenderedWithTimeout:10];
}
+- (void)testForRaisingExceptionsOnStaleStyleObjects {
+ self.mapView.centerCoordinate = CLLocationCoordinate2DMake(38.897,-77.039);
+ self.mapView.zoomLevel = 10.5;
+
+ MGLVectorTileSource *source = [[MGLVectorTileSource alloc] initWithIdentifier:@"trees" configurationURL:[NSURL URLWithString:@"mapbox://examples.2uf7qges"]];
+ [self.mapView.style addSource:source];
+
+ self.styleLoadingExpectation = nil;
+ [self.mapView setStyleURL:[[NSBundle bundleForClass:[self class]] URLForResource:@"one-liner" withExtension:@"json"]];
+ [self waitForMapViewToFinishLoadingStyleWithTimeout:10];
+
+ XCTAssertNotNil(source.description);
+ XCTAssertThrowsSpecificNamed(source.configurationURL, NSException, MGLInvalidStyleSourceException, @"MGLSource should raise an exception if its core peer got invalidated");
+}
+
+- (void)testForRaisingExceptionsOnStaleLayerObject {
+ self.mapView.centerCoordinate = CLLocationCoordinate2DMake(38.897,-77.039);
+ self.mapView.zoomLevel = 10.5;
+
+ MGLPointFeature *feature = [[MGLPointFeature alloc] init];
+ MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
+
+ // Testing generated layers
+ MGLLineStyleLayer *lineLayer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"lineLayerID" source:source];
+ MGLRasterStyleLayer *rasterLayer = [[MGLRasterStyleLayer alloc] initWithIdentifier:@"rasterLayerID" source:source];
+
+ [self.mapView.style addSource:source];
+ [self.mapView.style addLayer:lineLayer];
+ [self.mapView.style addLayer:rasterLayer];
+
+ XCTAssertNoThrow(lineLayer.isVisible);
+ XCTAssertNoThrow(rasterLayer.isVisible);
+
+ XCTAssert(![source.description containsString:@"<unknown>"]);
+ XCTAssert(![lineLayer.description containsString:@"<unknown>"]);
+ XCTAssert(![rasterLayer.description containsString:@"<unknown>"]);
+
+ self.styleLoadingExpectation = nil;
+ [self.mapView setStyleURL:[[NSBundle bundleForClass:[self class]] URLForResource:@"one-liner" withExtension:@"json"]];
+ [self waitForMapViewToFinishLoadingStyleWithTimeout:10];
+
+ XCTAssert([source.description containsString:@"<unknown>"]);
+ XCTAssert([lineLayer.description containsString:@"<unknown>"]);
+ XCTAssert([rasterLayer.description containsString:@"<unknown>"]);
+
+ XCTAssertThrowsSpecificNamed(lineLayer.isVisible, NSException, MGLInvalidStyleLayerException, @"Layer should raise an exception if its core peer got invalidated");
+ XCTAssertThrowsSpecificNamed(rasterLayer.isVisible, NSException, MGLInvalidStyleLayerException, @"Layer should raise an exception if its core peer got invalidated");
+
+ XCTAssertThrowsSpecificNamed([self.mapView.style removeLayer:lineLayer], NSException, NSInvalidArgumentException, @"Style should raise an exception when attempting to remove an invalid layer (e.g. if its core peer got invalidated)");
+ XCTAssertThrowsSpecificNamed([self.mapView.style removeLayer:rasterLayer], NSException, NSInvalidArgumentException, @"Style should raise an exception when attempting to remove an invalid layer (e.g. if its core peer got invalidated)");
+}
@end
diff --git a/platform/ios/Integration Tests/MGLStyleURLIntegrationTest.m b/platform/ios/Integration Tests/MGLStyleURLIntegrationTest.m
index f9217bae5f..22de4c6aa5 100644
--- a/platform/ios/Integration Tests/MGLStyleURLIntegrationTest.m
+++ b/platform/ios/Integration Tests/MGLStyleURLIntegrationTest.m
@@ -6,36 +6,32 @@
@implementation MGLStyleURLIntegrationTest
- (void)internalTestWithStyleSelector:(SEL)selector {
- if (![self validAccessToken]) {
- return;
- }
-
self.mapView.styleURL = [MGLStyle performSelector:selector];
[self waitForMapViewToFinishLoadingStyleWithTimeout:5];
}
-- (void)testLoadingStreetsStyleURL {
+- (void)testLoadingStreetsStyleURL🔒 {
[self internalTestWithStyleSelector:@selector(streetsStyleURL)];
}
-- (void)testLoadingOutdoorsStyleURL {
+- (void)testLoadingOutdoorsStyleURL🔒 {
[self internalTestWithStyleSelector:@selector(outdoorsStyleURL)];
}
-- (void)testLoadingLightStyleURL {
+- (void)testLoadingLightStyleURL🔒 {
[self internalTestWithStyleSelector:@selector(lightStyleURL)];
}
-- (void)testLoadingDarkStyleURL {
+- (void)testLoadingDarkStyleURL🔒 {
[self internalTestWithStyleSelector:@selector(darkStyleURL)];
}
-- (void)testLoadingSatelliteStyleURL {
+- (void)testLoadingSatelliteStyleURL🔒 {
[self internalTestWithStyleSelector:@selector(satelliteStyleURL)];
}
-- (void)testLoadingSatelliteStreetsStyleURL {
+- (void)testLoadingSatelliteStreetsStyleURL🔒 {
[self internalTestWithStyleSelector:@selector(satelliteStreetsStyleURL)];
}
diff --git a/platform/ios/Integration Tests/Snapshotter Tests/MGLMapSnapshotterSwiftTests.swift b/platform/ios/Integration Tests/Snapshotter Tests/MGLMapSnapshotterSwiftTests.swift
index 0f2034b6b8..c3400b1fa2 100644
--- a/platform/ios/Integration Tests/Snapshotter Tests/MGLMapSnapshotterSwiftTests.swift
+++ b/platform/ios/Integration Tests/Snapshotter Tests/MGLMapSnapshotterSwiftTests.swift
@@ -15,12 +15,9 @@ class MGLMapSnapshotterSwiftTests: MGLMapViewIntegrationTest {
return options
}
- func testCapturingSnapshotterInSnapshotCompletion() {
+ func testCapturingSnapshotterInSnapshotCompletion🔒() {
// See the Obj-C testDeallocatingSnapshotterDuringSnapshot
// This Swift test, is essentially the same except for capturing the snapshotter
- guard validAccessToken() != nil else {
- return
- }
let timeout: TimeInterval = 10.0
let expectation = self.expectation(description: "snapshot")
diff --git a/platform/ios/Integration Tests/Snapshotter Tests/MGLMapSnapshotterTest.m b/platform/ios/Integration Tests/Snapshotter Tests/MGLMapSnapshotterTest.m
index 32e5fc782d..7707896203 100644
--- a/platform/ios/Integration Tests/Snapshotter Tests/MGLMapSnapshotterTest.m
+++ b/platform/ios/Integration Tests/Snapshotter Tests/MGLMapSnapshotterTest.m
@@ -26,11 +26,7 @@ MGLMapSnapshotter* snapshotterWithCoordinates(CLLocationCoordinate2D coordinates
@implementation MGLMapSnapshotterTest
-- (void)testMultipleSnapshotsWithASingleSnapshotter {
- if (![self validAccessToken]) {
- return;
- }
-
+- (void)testMultipleSnapshotsWithASingleSnapshotter🔒 {
CGSize size = self.mapView.bounds.size;
XCTestExpectation *expectation = [self expectationWithDescription:@"snapshots"];
@@ -60,11 +56,8 @@ MGLMapSnapshotter* snapshotterWithCoordinates(CLLocationCoordinate2D coordinates
[self waitForExpectations:@[expectation] timeout:10.0];
}
-- (void)testDeallocatingSnapshotterDuringSnapshot {
+- (void)testDeallocatingSnapshotterDuringSnapshot🔒 {
// See also https://github.com/mapbox/mapbox-gl-native/issues/12336
- if (![self validAccessToken]) {
- return;
- }
NSTimeInterval timeout = 10.0;
XCTestExpectation *expectation = [self expectationWithDescription:@"snapshot"];
@@ -108,16 +101,12 @@ MGLMapSnapshotter* snapshotterWithCoordinates(CLLocationCoordinate2D coordinates
[self waitForExpectations:@[expectation] timeout:timeout];
}
-- (void)testSnapshotterUsingNestedDispatchQueues {
+- (void)testSnapshotterUsingNestedDispatchQueues🔒 {
// This is the opposite pair to the above test `testDeallocatingSnapshotterDuringSnapshot`
// The only significant difference is that the snapshotter is a `__block` variable, so
// its lifetime should continue until it's set to nil in the completion block.
// See also https://github.com/mapbox/mapbox-gl-native/issues/12336
- if (![self validAccessToken]) {
- return;
- }
-
NSTimeInterval timeout = 10.0;
XCTestExpectation *expectation = [self expectationWithDescription:@"snapshot"];
CGSize size = self.mapView.bounds.size;
@@ -156,11 +145,7 @@ MGLMapSnapshotter* snapshotterWithCoordinates(CLLocationCoordinate2D coordinates
[self waitForExpectations:@[expectation] timeout:timeout];
}
-- (void)testCancellingSnapshot {
- if (![self validAccessToken]) {
- return;
- }
-
+- (void)testCancellingSnapshot🔒 {
XCTestExpectation *expectation = [self expectationWithDescription:@"snapshots"];
expectation.assertForOverFulfill = YES;
expectation.expectedFulfillmentCount = 1;
@@ -189,11 +174,7 @@ MGLMapSnapshotter* snapshotterWithCoordinates(CLLocationCoordinate2D coordinates
[self waitForExpectations:@[expectation] timeout:5.0];
}
-- (void)testAllocatingSnapshotOnBackgroundQueue {
- if (![self validAccessToken]) {
- return;
- }
-
+- (void)testAllocatingSnapshotOnBackgroundQueue🔒 {
XCTestExpectation *expectation = [self expectationWithDescription:@"snapshots"];
CGSize size = self.mapView.bounds.size;
@@ -226,11 +207,7 @@ MGLMapSnapshotter* snapshotterWithCoordinates(CLLocationCoordinate2D coordinates
[self waitForExpectations:@[expectation] timeout:2.0];
}
-- (void)testSnapshotterFromBackgroundQueueShouldFail {
- if (![self validAccessToken]) {
- return;
- }
-
+- (void)testSnapshotterFromBackgroundQueueShouldFail🔒 {
CGSize size = self.mapView.bounds.size;
CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(30.0, 30.0);
@@ -281,12 +258,7 @@ MGLMapSnapshotter* snapshotterWithCoordinates(CLLocationCoordinate2D coordinates
[self waitForExpectations:@[expectation] timeout:60.0];
}
-- (void)testMultipleSnapshottersPENDING {
-
- if (![self validAccessToken]) {
- return;
- }
-
+- (void)testMultipleSnapshotters🔒🙁 {
NSUInteger numSnapshots = 8;
CGSize size = self.mapView.bounds.size;
@@ -340,11 +312,7 @@ MGLMapSnapshotter* snapshotterWithCoordinates(CLLocationCoordinate2D coordinates
[self waitForExpectations:@[expectation] timeout:60.0];
}
-- (void)testSnapshotPointConversion {
- if (![self validAccessToken]) {
- return;
- }
-
+- (void)testSnapshotPointConversion🔒 {
CGSize size = self.mapView.bounds.size;
XCTestExpectation *expectation = [self expectationWithDescription:@"snapshot"];
@@ -382,11 +350,7 @@ MGLMapSnapshotter* snapshotterWithCoordinates(CLLocationCoordinate2D coordinates
[self waitForExpectations:@[expectation] timeout:10.0];
}
-- (void)testSnapshotPointConversionCoordinateOrdering {
- if (![self validAccessToken]) {
- return;
- }
-
+- (void)testSnapshotPointConversionCoordinateOrdering🔒 {
CGSize size = self.mapView.bounds.size;
XCTestExpectation *expectation = [self expectationWithDescription:@"snapshot"];
@@ -429,5 +393,62 @@ MGLMapSnapshotter* snapshotterWithCoordinates(CLLocationCoordinate2D coordinates
[self waitForExpectations:@[expectation] timeout:10.0];
}
+- (void)testSnapshotWithOverlayHandlerFailure {
+ if (![self validAccessToken]) {
+ return;
+ }
+
+ CGSize size = self.mapView.bounds.size;
+
+ XCTestExpectation *expectation = [self expectationWithDescription:@"snapshot with overlay fails"];
+ expectation.expectedFulfillmentCount = 2;
+
+ CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(30.0, 30.0);
+
+ MGLMapSnapshotter *snapshotter = snapshotterWithCoordinates(coord, size);
+ XCTAssertNotNil(snapshotter);
+
+ [snapshotter startWithOverlayHandler:^(MGLMapSnapshotOverlay * _Nullable snapshotOverlay) {
+ UIGraphicsEndImageContext();
+ [expectation fulfill];
+ } completionHandler:^(MGLMapSnapshot * _Nullable snapshot, NSError * _Nullable error) {
+ XCTAssertNil(snapshot);
+ XCTAssertNotNil(error);
+ [expectation fulfill];
+ }];
+
+ [self waitForExpectations:@[expectation] timeout:10.0];
+}
+
+- (void)testSnapshotWithOverlayHandlerSuccess {
+ if (![self validAccessToken]) {
+ return;
+ }
+
+ CGSize size = self.mapView.bounds.size;
+ CGRect snapshotRect = CGRectMake(0, 0, size.width, size.height);
+
+ XCTestExpectation *expectation = [self expectationWithDescription:@"snapshot with overlay succeeds"];
+ expectation.expectedFulfillmentCount = 2;
+
+ CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(30.0, 30.0);
+
+ MGLMapSnapshotter *snapshotter = snapshotterWithCoordinates(coord, size);
+ XCTAssertNotNil(snapshotter);
+
+ [snapshotter startWithOverlayHandler:^(MGLMapSnapshotOverlay * _Nullable snapshotOverlay) {
+ CGContextSetFillColorWithColor(snapshotOverlay.context, [UIColor.greenColor CGColor]);
+ CGContextSetAlpha(snapshotOverlay.context, 0.2);
+ CGContextAddRect(snapshotOverlay.context, snapshotRect);
+ CGContextFillRect(snapshotOverlay.context, snapshotRect);
+ [expectation fulfill];
+ } completionHandler:^(MGLMapSnapshot * _Nullable snapshot, NSError * _Nullable error) {
+ XCTAssertNil(error);
+ XCTAssertNotNil(snapshot);
+ [expectation fulfill];
+ }];
+
+ [self waitForExpectations:@[expectation] timeout:10.0];
+}
@end
diff --git a/platform/ios/Mapbox-iOS-SDK-snapshot-dynamic.podspec b/platform/ios/Mapbox-iOS-SDK-snapshot-dynamic.podspec
index 77ff18c104..52dbe44428 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 = '5.3.0-alpha.3'
+ version = '5.4.0-alpha.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 5c8b30220a..a86ef2aef3 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 = '5.3.0-alpha.3'
+ version = '5.4.0-alpha.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 c356a3c12d..b0e71ef5e6 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 = '5.3.0-alpha.3'
+ version = '5.4.0-alpha.2'
m.name = 'Mapbox-iOS-SDK'
m.version = version
diff --git a/platform/ios/Mapbox.playground/Contents.swift b/platform/ios/Mapbox.playground/Contents.swift
index f31c9b6171..3bdb870fb5 100644
--- a/platform/ios/Mapbox.playground/Contents.swift
+++ b/platform/ios/Mapbox.playground/Contents.swift
@@ -121,10 +121,9 @@ class MapDelegate: NSObject, MGLMapViewDelegate {
let isRecognized = press.state == .recognized
if (isRecognized) {
- let coordinate: CLLocationCoordinate2D = mapView.convert(press.location(in: mapView), toCoordinateFrom: mapView)
let annotation = MGLPointAnnotation()
annotation.title = "Dropped Marker"
- annotation.coordinate = coordinate
+ annotation.coordinate = mapView.convert(press.location(in: mapView), toCoordinateFrom: mapView)
mapView.addAnnotation(annotation)
mapView.showAnnotations([annotation], animated: true)
}
@@ -134,8 +133,6 @@ class MapDelegate: NSObject, MGLMapViewDelegate {
//: Create a map and its delegate
-let centerCoordinate = CLLocationCoordinate2D(latitude: 37.174057, longitude: -104.490984)
-
let mapView = MGLMapView(frame: CGRect(x: 0, y: 0, width: width, height: height))
mapView.frame = CGRect(x: 0, y: 0, width: width, height: height)
@@ -150,7 +147,7 @@ mapView.addGestureRecognizer(tapGesture)
//: Zoom in to a location
-mapView.setCenter(centerCoordinate, zoomLevel: 12, animated: false)
+mapView.setCenter(CLLocationCoordinate2D(latitude: 37.174057, longitude: -104.490984), zoomLevel: 12, animated: false)
//: Add control panel
diff --git a/platform/ios/Mapbox.playground/contents.xcplayground b/platform/ios/Mapbox.playground/contents.xcplayground
index 35968656f5..c8659f26e4 100644
--- a/platform/ios/Mapbox.playground/contents.xcplayground
+++ b/platform/ios/Mapbox.playground/contents.xcplayground
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<playground version='5.0' target-platform='ios' display-mode='raw'>
+<playground version='5.0' target-platform='ios' display-mode='raw' last-migration='1100'>
<timeline fileName='timeline.xctimeline'/>
</playground> \ No newline at end of file
diff --git a/platform/ios/app/MBXState.h b/platform/ios/app/MBXState.h
index 7cf064acd8..346c31d586 100644
--- a/platform/ios/app/MBXState.h
+++ b/platform/ios/app/MBXState.h
@@ -12,7 +12,6 @@ FOUNDATION_EXTERN NSString *const MBXShowsZoomLevelOrnament;
FOUNDATION_EXTERN NSString *const MBXShowsTimeFrameGraph;
FOUNDATION_EXTERN NSString *const MBXMapFramerateMeasurementEnabled;
FOUNDATION_EXTERN NSString *const MBXDebugMaskValue;
-FOUNDATION_EXTERN NSString *const MBXDebugLoggingEnabled;
FOUNDATION_EXTERN NSString *const MBXReuseQueueStatsEnabled;
@interface MBXState : NSObject <NSSecureCoding>
@@ -26,7 +25,6 @@ FOUNDATION_EXTERN NSString *const MBXReuseQueueStatsEnabled;
@property (nonatomic) BOOL showsTimeFrameGraph;
@property (nonatomic) BOOL framerateMeasurementEnabled;
@property (nonatomic) MGLMapDebugMaskOptions debugMask;
-@property (nonatomic) BOOL debugLoggingEnabled;
@property (nonatomic) BOOL reuseQueueStatsEnabled;
@property (nonatomic, readonly) NSString *debugDescription;
diff --git a/platform/ios/app/MBXState.m b/platform/ios/app/MBXState.m
index 0365306637..455961e88a 100644
--- a/platform/ios/app/MBXState.m
+++ b/platform/ios/app/MBXState.m
@@ -6,7 +6,6 @@ NSString *const MBXShowsUserLocation = @"MBXShowsUserLocation";
NSString *const MBXDebugMaskValue = @"MBXDebugMaskValue";
NSString *const MBXShowsZoomLevelOrnament = @"MBXShowsZoomLevelOrnament";
NSString *const MBXShowsTimeFrameGraph = @"MBXShowsFrameTimeGraph";
-NSString *const MBXDebugLoggingEnabled = @"MGLMapboxMetricsDebugLoggingEnabled";
NSString *const MBXShowsMapScale = @"MBXMapShowsScale";
NSString *const MBXMapShowsHeadingIndicator = @"MBXMapShowsHeadingIndicator";
NSString *const MBXMapFramerateMeasurementEnabled = @"MBXMapFramerateMeasurementEnabled";
@@ -26,7 +25,6 @@ NSString *const MBXReuseQueueStatsEnabled = @"MBXReuseQueueStatsEnabled";
[coder encodeObject:[NSNumber numberWithUnsignedInteger:_debugMask] forKey:MBXDebugMaskValue];
[coder encodeBool:_showsZoomLevelOrnament forKey:MBXShowsZoomLevelOrnament];
[coder encodeBool:_showsTimeFrameGraph forKey:MBXShowsTimeFrameGraph];
- [coder encodeBool:_debugLoggingEnabled forKey:MBXDebugLoggingEnabled];
[coder encodeBool:_showsMapScale forKey:MBXShowsMapScale];
[coder encodeBool:_showsUserHeadingIndicator forKey:MBXMapShowsHeadingIndicator];
[coder encodeBool:_framerateMeasurementEnabled forKey:MBXMapFramerateMeasurementEnabled];
@@ -41,7 +39,6 @@ NSString *const MBXReuseQueueStatsEnabled = @"MBXReuseQueueStatsEnabled";
NSNumber *decodedDebugMaskOptions = [decoder decodeObjectForKey:MBXDebugMaskValue];
BOOL decodedZoomLevelOrnament = [decoder decodeBoolForKey:MBXShowsZoomLevelOrnament];
BOOL decodedShowsTimeFrameGraph = [decoder decodeBoolForKey:MBXShowsTimeFrameGraph];
- BOOL decodedDebugLoggingEnabled = [decoder decodeBoolForKey:MBXDebugLoggingEnabled];
BOOL decodedShowsMapScale = [decoder decodeBoolForKey:MBXShowsMapScale];
BOOL decodedShowsUserHeadingIndicator = [decoder decodeBoolForKey:MBXMapShowsHeadingIndicator];
BOOL decodedFramerateMeasurementEnabled = [decoder decodeBoolForKey:MBXMapFramerateMeasurementEnabled];
@@ -53,7 +50,6 @@ NSString *const MBXReuseQueueStatsEnabled = @"MBXReuseQueueStatsEnabled";
_debugMask = decodedDebugMaskOptions.intValue;
_showsZoomLevelOrnament = decodedZoomLevelOrnament;
_showsTimeFrameGraph = decodedShowsTimeFrameGraph;
- _debugLoggingEnabled = decodedDebugLoggingEnabled;
_showsMapScale = decodedShowsMapScale;
_showsUserHeadingIndicator = decodedShowsUserHeadingIndicator;
_framerateMeasurementEnabled = decodedFramerateMeasurementEnabled;
@@ -67,15 +63,14 @@ NSString *const MBXReuseQueueStatsEnabled = @"MBXReuseQueueStatsEnabled";
return YES;
}
-- (NSString*) debugDescription {
- return [NSString stringWithFormat:@"Camera: %@\nTracking mode: %lu\nShows user location: %@\nDebug mask value: %lu\nShows zoom level ornament: %@\nShows time frame graph: %@\nDebug logging enabled: %@\nShows map scale: %@\nShows user heading indicator: %@\nFramerate measurement enabled: %@\nReuse queue stats enabled: %@",
+- (NSString *)debugDescription {
+ return [NSString stringWithFormat:@"Camera: %@\nTracking mode: %lu\nShows user location: %@\nDebug mask value: %lu\nShows zoom level ornament: %@\nShows time frame graph: %@\nShows map scale: %@\nShows user heading indicator: %@\nFramerate measurement enabled: %@\nReuse queue stats enabled: %@",
self.camera,
(unsigned long)self.userTrackingMode,
self.showsUserLocation ? @"YES" : @"NO",
(unsigned long)self.debugMask,
self.showsZoomLevelOrnament ? @"YES" : @"NO",
self.showsTimeFrameGraph ? @"YES" : @"NO",
- self.debugLoggingEnabled ? @"YES" : @"NO",
self.showsMapScale ? @"YES" : @"NO",
self.showsUserHeadingIndicator ? @"YES" : @"NO",
self.framerateMeasurementEnabled ? @"YES" : @"NO",
diff --git a/platform/ios/app/MBXViewController.m b/platform/ios/app/MBXViewController.m
index 2fb95e1b17..346a182a88 100644
--- a/platform/ios/app/MBXViewController.m
+++ b/platform/ios/app/MBXViewController.m
@@ -211,7 +211,6 @@ CLLocationCoordinate2D randomWorldCoordinate() {
@property (nonatomic) BOOL shouldLimitCameraChanges;
@property (nonatomic) BOOL randomWalk;
@property (nonatomic) BOOL zoomLevelOrnamentEnabled;
-@property (nonatomic) BOOL debugLoggingEnabled;
@property (nonatomic) NSMutableArray<UIWindow *> *helperWindows;
@property (nonatomic) NSMutableArray<UIView *> *contentInsetsOverlays;
@@ -246,7 +245,6 @@ CLLocationCoordinate2D randomWorldCoordinate() {
self.mapView.showsScale = YES;
self.zoomLevelOrnamentEnabled = NO;
self.frameTimeGraphEnabled = NO;
- self.debugLoggingEnabled = YES;
} else {
// Revert to the previously saved state
[self restoreMapState:nil];
@@ -441,14 +439,6 @@ CLLocationCoordinate2D randomWorldCoordinate() {
@"Ornaments Placement",
]];
- if (self.currentState.debugLoggingEnabled)
- {
- [settingsTitles addObjectsFromArray:@[
- @"Print Telemetry Logfile",
- @"Delete Telemetry Logfile",
- ]];
- };
-
break;
default:
NSAssert(NO, @"All settings sections should be implemented");
@@ -558,15 +548,12 @@ CLLocationCoordinate2D randomWorldCoordinate() {
case MBXSettingsAnnotationSelectRandomOffscreenPointAnnotation:
[self selectAnOffscreenPointAnnotation];
break;
-
case MBXSettingsAnnotationCenterSelectedAnnotation:
[self centerSelectedAnnotation];
break;
-
case MBXSettingsAnnotationAddVisibleAreaPolyline:
[self addVisibleAreaPolyline];
break;
-
default:
NSAssert(NO, @"All annotations setting rows should be implemented");
break;
@@ -667,13 +654,6 @@ CLLocationCoordinate2D randomWorldCoordinate() {
case MBXSettingsMiscellaneousRandomTour:
[self randomWorldTour];
break;
-
- case MBXSettingsMiscellaneousPrintLogFile:
- [self printTelemetryLogFile];
- break;
- case MBXSettingsMiscellaneousDeleteLogFile:
- [self deleteTelemetryLogFile];
- break;
case MBXSettingsMiscellaneousScrollView:
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
@@ -1734,37 +1714,6 @@ CLLocationCoordinate2D randomWorldCoordinate() {
return backupImage;
}
-- (void)printTelemetryLogFile
-{
- NSString *fileContents = [NSString stringWithContentsOfFile:[self telemetryDebugLogFilePath] encoding:NSUTF8StringEncoding error:nil];
- NSLog(@"%@", fileContents);
-}
-
-- (void)deleteTelemetryLogFile
-{
- NSString *filePath = [self telemetryDebugLogFilePath];
- if ([[NSFileManager defaultManager] isDeletableFileAtPath:filePath])
- {
- NSError *error;
- BOOL success = [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error];
- if (success) {
- NSLog(@"Deleted telemetry log.");
- } else {
- NSLog(@"Error deleting telemetry log: %@", error.localizedDescription);
- }
- }
-}
-
-- (NSString *)telemetryDebugLogFilePath
-{
- NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
- [dateFormatter setDateFormat:@"yyyy'-'MM'-'dd"];
- [dateFormatter setTimeZone:[NSTimeZone systemTimeZone]];
- NSString *filePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject] stringByAppendingPathComponent:[NSString stringWithFormat:@"telemetry_log-%@.json", [dateFormatter stringFromDate:[NSDate date]]]];
-
- return filePath;
-}
-
#pragma mark - Random World Tour
- (void)addAnnotations:(NSInteger)numAnnotations aroundCoordinate:(CLLocationCoordinate2D)coordinate radius:(CLLocationDistance)radius {
@@ -2396,7 +2345,6 @@ CLLocationCoordinate2D randomWorldCoordinate() {
self.currentState.showsZoomLevelOrnament = self.zoomLevelOrnamentEnabled;
self.currentState.showsTimeFrameGraph = self.frameTimeGraphEnabled;
self.currentState.debugMask = self.mapView.debugMask;
- self.currentState.debugLoggingEnabled = self.debugLoggingEnabled;
self.currentState.reuseQueueStatsEnabled = self.reuseQueueStatsEnabled;
[[MBXStateManager sharedManager] saveState:self.currentState];
@@ -2413,7 +2361,6 @@ CLLocationCoordinate2D randomWorldCoordinate() {
self.zoomLevelOrnamentEnabled = currentState.showsZoomLevelOrnament;
self.frameTimeGraphEnabled = currentState.showsTimeFrameGraph;
self.mapView.debugMask = currentState.debugMask;
- self.debugLoggingEnabled = currentState.debugLoggingEnabled;
self.reuseQueueStatsEnabled = currentState.reuseQueueStatsEnabled;
self.currentState = currentState;
diff --git a/platform/ios/app/Main.storyboard b/platform/ios/app/Main.storyboard
index 28316745a1..ac83bd968f 100644
--- a/platform/ios/app/Main.storyboard
+++ b/platform/ios/app/Main.storyboard
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14810.11" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="PSe-Ot-7Ff">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14865.1" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="PSe-Ot-7Ff">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
- <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14766.13"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14819.2"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
@@ -13,11 +13,11 @@
<objects>
<viewController id="WaX-pd-UZQ" userLabel="Map View Controller" customClass="MBXViewController" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Z9X-fc-PUC">
- <rect key="frame" x="0.0" y="0.0" width="203" height="33"/>
+ <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="kNe-zV-9ha" customClass="MGLMapView">
- <rect key="frame" x="0.0" y="0.0" width="203" height="33"/>
+ <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<subviews>
<button hidden="YES" opaque="NO" userInteractionEnabled="NO" alpha="0.69999999999999996" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="tailTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="58y-pX-YyB">
<rect key="frame" x="8" y="82" width="40" height="20"/>
@@ -38,7 +38,7 @@
</userDefinedRuntimeAttributes>
</button>
<view hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="BHE-Wn-x69" customClass="MBXFrameTimeGraphView">
- <rect key="frame" x="0.0" y="-167" width="203" height="200"/>
+ <rect key="frame" x="0.0" y="467" width="375" height="200"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<accessibility key="accessibilityConfiguration">
<accessibilityTraits key="traits" notEnabled="YES"/>
@@ -84,7 +84,7 @@
</connections>
</barButtonItem>
<button key="titleView" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" id="KsN-ny-Hou">
- <rect key="frame" x="65" y="5.5" width="203" height="33"/>
+ <rect key="frame" x="89" y="5.5" width="148" height="33"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
<state key="normal" title="Streets"/>
@@ -198,7 +198,7 @@
<action selector="addCurrentRegion:" destination="7q0-lI-zqb" id="G2O-3V-aEA"/>
</connections>
</barButtonItem>
- <barButtonItem style="plain" systemItem="refresh" id="2fx-iS-Veb">
+ <barButtonItem systemItem="refresh" id="2fx-iS-Veb">
<connections>
<action selector="invalidatePacks:" destination="7q0-lI-zqb" id="5lx-FY-aTt"/>
</connections>
diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj
index de2bec5d99..7712c332c4 100644
--- a/platform/ios/ios.xcodeproj/project.pbxproj
+++ b/platform/ios/ios.xcodeproj/project.pbxproj
@@ -388,7 +388,7 @@
9680274022653B84006BA4A1 /* MBXSKUToken.h in Headers */ = {isa = PBXBuildFile; fileRef = 9680273E22653B84006BA4A1 /* MBXSKUToken.h */; };
9680276422655696006BA4A1 /* libmbxaccounts.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9680274122653C3E006BA4A1 /* libmbxaccounts.a */; };
96802766226556C5006BA4A1 /* libmbxaccounts.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9680274122653C3E006BA4A1 /* libmbxaccounts.a */; };
- 9686D1BD22D9357700194EA0 /* MGLMapViewZoomTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 9686D1BC22D9357700194EA0 /* MGLMapViewZoomTests.m */; };
+ 9686D1BD22D9357700194EA0 /* MGLMapViewZoomTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9686D1BC22D9357700194EA0 /* MGLMapViewZoomTests.mm */; };
968F36B51E4D128D003A5522 /* MGLDistanceFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 3557F7AE1E1D27D300CCA5E6 /* MGLDistanceFormatter.h */; settings = {ATTRIBUTES = (Public, ); }; };
96E027231E57C76E004B8E66 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 96E027251E57C76E004B8E66 /* Localizable.strings */; };
96E516DC2000547000A02306 /* MGLPolyline_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 9654C1251FFC1AB900DB6A19 /* MGLPolyline_Private.h */; };
@@ -481,6 +481,8 @@
9C6E284522A982670056B7BE /* MMEUINavigation.h in Headers */ = {isa = PBXBuildFile; fileRef = 406E99B31FFEFED600D9FFCC /* MMEUINavigation.h */; };
9C6E284622A982670056B7BE /* MMEUniqueIdentifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 40834BBF1FE05D6E00C1BD0D /* MMEUniqueIdentifier.h */; };
9C6E284722A982670056B7BE /* MMEDispatchManager.h in Headers */ = {isa = PBXBuildFile; fileRef = ACA65F552140696B00537748 /* MMEDispatchManager.h */; };
+ A4DE3DCB23038C98005B3473 /* MGLMockGestureRecognizers.h in Sources */ = {isa = PBXBuildFile; fileRef = A4DE3DCA23038A7F005B3473 /* MGLMockGestureRecognizers.h */; };
+ A4DE3DCC23038CCA005B3473 /* MGLMockGestureRecognizers.m in Sources */ = {isa = PBXBuildFile; fileRef = A4DE3DC823038A07005B3473 /* MGLMockGestureRecognizers.m */; };
A4F3FB1D2254865900A30170 /* missing_icon.json in Resources */ = {isa = PBXBuildFile; fileRef = A4F3FB1C2254865900A30170 /* missing_icon.json */; };
AC46EB59225E600A0039C013 /* MMECertPin.h in Headers */ = {isa = PBXBuildFile; fileRef = AC46EB57225E60090039C013 /* MMECertPin.h */; };
AC46EB5A225E600A0039C013 /* MMECertPin.h in Headers */ = {isa = PBXBuildFile; fileRef = AC46EB57225E60090039C013 /* MMECertPin.h */; };
@@ -504,13 +506,16 @@
CA0C27922076C804001CE5B7 /* MGLShapeSourceTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CA0C27912076C804001CE5B7 /* MGLShapeSourceTests.m */; };
CA0C27942076CA19001CE5B7 /* MGLMapViewIntegrationTest.m in Sources */ = {isa = PBXBuildFile; fileRef = CA0C27932076CA19001CE5B7 /* MGLMapViewIntegrationTest.m */; };
CA1B4A512099FB2200EDD491 /* MGLMapSnapshotterTest.m in Sources */ = {isa = PBXBuildFile; fileRef = CA1B4A502099FB2200EDD491 /* MGLMapSnapshotterTest.m */; };
- CA34C9C3207FD272005C1A06 /* MGLCameraTransitionTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CA34C9C2207FD272005C1A06 /* MGLCameraTransitionTests.mm */; };
+ CA4C54FE2324948100A81659 /* MGLSourceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA4C54FD2324948100A81659 /* MGLSourceTests.swift */; };
CA4EB8C720863487006AB465 /* MGLStyleLayerIntegrationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CA4EB8C620863487006AB465 /* MGLStyleLayerIntegrationTests.m */; };
+ CA4F3BDE230F74C3008BAFEA /* MGLMapViewPendingBlockTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CA4F3BDD230F74C3008BAFEA /* MGLMapViewPendingBlockTests.m */; };
+ CA4F3BE223107793008BAFEA /* MGLCameraTransitionTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CA4F3BE123107793008BAFEA /* MGLCameraTransitionTests.mm */; };
+ CA4F3BE4231077B9008BAFEA /* MGLCameraTransitionFinishTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CA4F3BE3231077B9008BAFEA /* MGLCameraTransitionFinishTests.mm */; };
CA55CD41202C16AA00CE7095 /* MGLCameraChangeReason.h in Headers */ = {isa = PBXBuildFile; fileRef = CA55CD3E202C16AA00CE7095 /* MGLCameraChangeReason.h */; settings = {ATTRIBUTES = (Public, ); }; };
CA55CD42202C16AA00CE7095 /* MGLCameraChangeReason.h in Headers */ = {isa = PBXBuildFile; fileRef = CA55CD3E202C16AA00CE7095 /* MGLCameraChangeReason.h */; settings = {ATTRIBUTES = (Public, ); }; };
CA65C4F821E9BB080068B0D4 /* MGLCluster.h in Headers */ = {isa = PBXBuildFile; fileRef = CA65C4F721E9BB080068B0D4 /* MGLCluster.h */; settings = {ATTRIBUTES = (Public, ); }; };
CA65C4F921E9BB080068B0D4 /* MGLCluster.h in Headers */ = {isa = PBXBuildFile; fileRef = CA65C4F721E9BB080068B0D4 /* MGLCluster.h */; settings = {ATTRIBUTES = (Public, ); }; };
- CA6914B520E67F50002DB0EE /* MGLAnnotationViewIntegrationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CA6914B420E67F50002DB0EE /* MGLAnnotationViewIntegrationTests.m */; };
+ CA6914B520E67F50002DB0EE /* MGLAnnotationViewIntegrationTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CA6914B420E67F50002DB0EE /* MGLAnnotationViewIntegrationTests.mm */; };
CA7766832229C10E0008DE9E /* MGLCompactCalloutView.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8848451CBAFB9800AB86E3 /* MGLCompactCalloutView.m */; };
CA7766842229C11A0008DE9E /* SMCalloutView.m in Sources */ = {isa = PBXBuildFile; fileRef = DA88488A1CBB037E00AB86E3 /* SMCalloutView.m */; };
CA86FF0E22D8D5A0009EB14A /* MGLNetworkConfigurationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CA86FF0D22D8D5A0009EB14A /* MGLNetworkConfigurationTests.m */; };
@@ -572,8 +577,8 @@
DA5DB12A1FABF1EE001C2326 /* MGLMapAccessibilityElementTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5DB1291FABF1EE001C2326 /* MGLMapAccessibilityElementTests.m */; };
DA6408DB1DA4E7D300908C90 /* MGLVectorStyleLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = DA6408D91DA4E7D300908C90 /* MGLVectorStyleLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
DA6408DC1DA4E7D300908C90 /* MGLVectorStyleLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = DA6408D91DA4E7D300908C90 /* MGLVectorStyleLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
- DA6408DD1DA4E7D300908C90 /* MGLVectorStyleLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = DA6408DA1DA4E7D300908C90 /* MGLVectorStyleLayer.m */; };
- DA6408DE1DA4E7D300908C90 /* MGLVectorStyleLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = DA6408DA1DA4E7D300908C90 /* MGLVectorStyleLayer.m */; };
+ DA6408DD1DA4E7D300908C90 /* MGLVectorStyleLayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA6408DA1DA4E7D300908C90 /* MGLVectorStyleLayer.mm */; };
+ DA6408DE1DA4E7D300908C90 /* MGLVectorStyleLayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA6408DA1DA4E7D300908C90 /* MGLVectorStyleLayer.mm */; };
DA695426215B1E76002041A4 /* MGLMapCameraTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DA695425215B1E75002041A4 /* MGLMapCameraTests.m */; };
DA704CC21F65A475004B3F28 /* MGLMapAccessibilityElement.h in Headers */ = {isa = PBXBuildFile; fileRef = DA704CC01F65A475004B3F28 /* MGLMapAccessibilityElement.h */; };
DA704CC31F65A475004B3F28 /* MGLMapAccessibilityElement.h in Headers */ = {isa = PBXBuildFile; fileRef = DA704CC01F65A475004B3F28 /* MGLMapAccessibilityElement.h */; };
@@ -1129,7 +1134,7 @@
967C864A210A9D3C004DF794 /* UIDevice+MGLAdditions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIDevice+MGLAdditions.m"; sourceTree = "<group>"; };
9680273E22653B84006BA4A1 /* MBXSKUToken.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MBXSKUToken.h; path = "../vendor/mapbox-accounts-ios/MBXSKUToken.h"; sourceTree = "<group>"; };
9680274122653C3E006BA4A1 /* libmbxaccounts.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libmbxaccounts.a; path = "vendor/mapbox-accounts-ios/libmbxaccounts.a"; sourceTree = SOURCE_ROOT; };
- 9686D1BC22D9357700194EA0 /* MGLMapViewZoomTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLMapViewZoomTests.m; sourceTree = "<group>"; };
+ 9686D1BC22D9357700194EA0 /* MGLMapViewZoomTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLMapViewZoomTests.mm; sourceTree = "<group>"; };
968F36B41E4D0FC6003A5522 /* ja */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = "<group>"; };
96E027241E57C76E004B8E66 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = "<group>"; };
96E027271E57C77A004B8E66 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = "<group>"; };
@@ -1173,6 +1178,8 @@
9C6E286522A9849E0056B7BE /* release-notes-jazzy.md.ejs */ = {isa = PBXFileReference; lastKnownFileType = text; path = "release-notes-jazzy.md.ejs"; sourceTree = "<group>"; };
9C6E286622A9849E0056B7BE /* deploy-snapshot.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "deploy-snapshot.sh"; sourceTree = "<group>"; };
9C6E286722A9849E0056B7BE /* release-notes.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = "release-notes.js"; sourceTree = "<group>"; };
+ A4DE3DC823038A07005B3473 /* MGLMockGestureRecognizers.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLMockGestureRecognizers.m; sourceTree = "<group>"; };
+ A4DE3DCA23038A7F005B3473 /* MGLMockGestureRecognizers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLMockGestureRecognizers.h; sourceTree = "<group>"; };
A4F3FB1C2254865900A30170 /* missing_icon.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = missing_icon.json; sourceTree = "<group>"; };
AC46EB57225E60090039C013 /* MMECertPin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MMECertPin.h; sourceTree = "<group>"; };
AC46EB58225E60090039C013 /* MMECertPin.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MMECertPin.m; sourceTree = "<group>"; };
@@ -1192,12 +1199,15 @@
CA0C27932076CA19001CE5B7 /* MGLMapViewIntegrationTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLMapViewIntegrationTest.m; sourceTree = "<group>"; wrapsLines = 0; };
CA0C27952076CA50001CE5B7 /* MGLMapViewIntegrationTest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLMapViewIntegrationTest.h; sourceTree = "<group>"; };
CA1B4A502099FB2200EDD491 /* MGLMapSnapshotterTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLMapSnapshotterTest.m; sourceTree = "<group>"; };
- CA34C9C2207FD272005C1A06 /* MGLCameraTransitionTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLCameraTransitionTests.mm; sourceTree = "<group>"; };
+ CA4C54FD2324948100A81659 /* MGLSourceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MGLSourceTests.swift; sourceTree = "<group>"; };
CA4EB8C620863487006AB465 /* MGLStyleLayerIntegrationTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLStyleLayerIntegrationTests.m; sourceTree = "<group>"; };
+ CA4F3BDD230F74C3008BAFEA /* MGLMapViewPendingBlockTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLMapViewPendingBlockTests.m; sourceTree = "<group>"; };
+ CA4F3BE123107793008BAFEA /* MGLCameraTransitionTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLCameraTransitionTests.mm; sourceTree = "<group>"; };
+ CA4F3BE3231077B9008BAFEA /* MGLCameraTransitionFinishTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLCameraTransitionFinishTests.mm; sourceTree = "<group>"; };
CA55CD3E202C16AA00CE7095 /* MGLCameraChangeReason.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLCameraChangeReason.h; sourceTree = "<group>"; };
CA5E5042209BDC5F001A8A81 /* MGLTestUtility.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MGLTestUtility.h; path = ../../darwin/test/MGLTestUtility.h; sourceTree = "<group>"; };
CA65C4F721E9BB080068B0D4 /* MGLCluster.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLCluster.h; sourceTree = "<group>"; };
- CA6914B420E67F50002DB0EE /* MGLAnnotationViewIntegrationTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = MGLAnnotationViewIntegrationTests.m; path = "Annotation Tests/MGLAnnotationViewIntegrationTests.m"; sourceTree = "<group>"; };
+ CA6914B420E67F50002DB0EE /* MGLAnnotationViewIntegrationTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLAnnotationViewIntegrationTests.mm; path = "Annotation Tests/MGLAnnotationViewIntegrationTests.mm"; sourceTree = "<group>"; };
CA86FF0D22D8D5A0009EB14A /* MGLNetworkConfigurationTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLNetworkConfigurationTests.m; sourceTree = "<group>"; };
CA88DC2F21C85D900059ED5A /* MGLStyleURLIntegrationTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLStyleURLIntegrationTest.m; sourceTree = "<group>"; };
CA8FBC0821A47BB100D1203C /* MGLRendererConfigurationTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLRendererConfigurationTests.mm; path = ../../darwin/test/MGLRendererConfigurationTests.mm; sourceTree = "<group>"; };
@@ -1277,7 +1287,7 @@
DA618B261E68920D00CB7F44 /* lt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = lt; path = lt.lproj/Foundation.stringsdict; sourceTree = "<group>"; };
DA618B2B1E68932D00CB7F44 /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/Localizable.strings; sourceTree = "<group>"; };
DA6408D91DA4E7D300908C90 /* MGLVectorStyleLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLVectorStyleLayer.h; sourceTree = "<group>"; };
- DA6408DA1DA4E7D300908C90 /* MGLVectorStyleLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLVectorStyleLayer.m; sourceTree = "<group>"; };
+ DA6408DA1DA4E7D300908C90 /* MGLVectorStyleLayer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLVectorStyleLayer.mm; sourceTree = "<group>"; };
DA695425215B1E75002041A4 /* MGLMapCameraTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLMapCameraTests.m; path = ../../darwin/test/MGLMapCameraTests.m; sourceTree = "<group>"; };
DA704CBB1F637311004B3F28 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Foundation.strings; sourceTree = "<group>"; };
DA704CBC1F637405004B3F28 /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = uk; path = uk.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
@@ -1537,12 +1547,12 @@
16376B081FFD9DAF0000563E /* Integration Tests */ = {
isa = PBXGroup;
children = (
+ CA4F3BE023107793008BAFEA /* Camera Tests */,
CA6914B320E67F07002DB0EE /* Annotations */,
CAE7AD5320F46EF5003B6782 /* integration-Bridging-Header.h */,
CA1B4A4F2099FA2800EDD491 /* Snapshotter Tests */,
16376B091FFD9DAF0000563E /* MBGLIntegrationTests.mm */,
16376B0B1FFD9DAF0000563E /* Info.plist */,
- CA34C9C2207FD272005C1A06 /* MGLCameraTransitionTests.mm */,
CA0C27912076C804001CE5B7 /* MGLShapeSourceTests.m */,
CA0C27932076CA19001CE5B7 /* MGLMapViewIntegrationTest.m */,
CA0C27952076CA50001CE5B7 /* MGLMapViewIntegrationTest.h */,
@@ -1550,6 +1560,8 @@
CA88DC2F21C85D900059ED5A /* MGLStyleURLIntegrationTest.m */,
077061DB215DA11F000FEF62 /* MGLTestLocationManager.h */,
077061D9215DA00E000FEF62 /* MGLTestLocationManager.m */,
+ CA4F3BDD230F74C3008BAFEA /* MGLMapViewPendingBlockTests.m */,
+ CA4C54FD2324948100A81659 /* MGLSourceTests.swift */,
);
path = "Integration Tests";
sourceTree = "<group>";
@@ -1637,7 +1649,7 @@
353933FD1D3FB7DD003F57D7 /* MGLSymbolStyleLayer.h */,
35136D441D42275100C20EFD /* MGLSymbolStyleLayer.mm */,
DA6408D91DA4E7D300908C90 /* MGLVectorStyleLayer.h */,
- DA6408DA1DA4E7D300908C90 /* MGLVectorStyleLayer.m */,
+ DA6408DA1DA4E7D300908C90 /* MGLVectorStyleLayer.mm */,
);
name = Layers;
sourceTree = "<group>";
@@ -1744,6 +1756,8 @@
children = (
CA5E5042209BDC5F001A8A81 /* MGLTestUtility.h */,
4031ACFE1E9FD29F00A3EA26 /* MGLSDKTestHelpers.swift */,
+ A4DE3DCA23038A7F005B3473 /* MGLMockGestureRecognizers.h */,
+ A4DE3DC823038A07005B3473 /* MGLMockGestureRecognizers.m */,
);
name = "Test Helpers";
sourceTree = "<group>";
@@ -1917,10 +1931,19 @@
path = "Snapshotter Tests";
sourceTree = "<group>";
};
+ CA4F3BE023107793008BAFEA /* Camera Tests */ = {
+ isa = PBXGroup;
+ children = (
+ CA4F3BE123107793008BAFEA /* MGLCameraTransitionTests.mm */,
+ CA4F3BE3231077B9008BAFEA /* MGLCameraTransitionFinishTests.mm */,
+ );
+ path = "Camera Tests";
+ sourceTree = "<group>";
+ };
CA6914B320E67F07002DB0EE /* Annotations */ = {
isa = PBXGroup;
children = (
- CA6914B420E67F50002DB0EE /* MGLAnnotationViewIntegrationTests.m */,
+ CA6914B420E67F50002DB0EE /* MGLAnnotationViewIntegrationTests.mm */,
);
name = Annotations;
sourceTree = "<group>";
@@ -2057,7 +2080,7 @@
96381C0122C6F3950053497D /* MGLMapViewPitchTests.m */,
9658C154204761FC00D8A674 /* MGLMapViewScaleBarTests.m */,
076171C22139C70900668A35 /* MGLMapViewTests.m */,
- 9686D1BC22D9357700194EA0 /* MGLMapViewZoomTests.m */,
+ 9686D1BC22D9357700194EA0 /* MGLMapViewZoomTests.mm */,
1F95931C1E6DE2E900D5B294 /* MGLNSDateAdditionsTests.mm */,
96036A0520059BBA00510F3D /* MGLNSOrthographyAdditionsTests.m */,
DAE7DEC11E245455007505A6 /* MGLNSStringAdditionsTests.m */,
@@ -3188,16 +3211,19 @@
files = (
CA4EB8C720863487006AB465 /* MGLStyleLayerIntegrationTests.m in Sources */,
CA7766842229C11A0008DE9E /* SMCalloutView.m in Sources */,
- CA34C9C3207FD272005C1A06 /* MGLCameraTransitionTests.mm in Sources */,
16376B0A1FFD9DAF0000563E /* MBGLIntegrationTests.mm in Sources */,
+ CA4F3BDE230F74C3008BAFEA /* MGLMapViewPendingBlockTests.m in Sources */,
CA88DC3021C85D900059ED5A /* MGLStyleURLIntegrationTest.m in Sources */,
CA0C27942076CA19001CE5B7 /* MGLMapViewIntegrationTest.m in Sources */,
CA7766832229C10E0008DE9E /* MGLCompactCalloutView.m in Sources */,
CAE7AD5520F46EF5003B6782 /* MGLMapSnapshotterSwiftTests.swift in Sources */,
CA0C27922076C804001CE5B7 /* MGLShapeSourceTests.m in Sources */,
077061DA215DA00E000FEF62 /* MGLTestLocationManager.m in Sources */,
- CA6914B520E67F50002DB0EE /* MGLAnnotationViewIntegrationTests.m in Sources */,
+ CA6914B520E67F50002DB0EE /* MGLAnnotationViewIntegrationTests.mm in Sources */,
+ CA4F3BE223107793008BAFEA /* MGLCameraTransitionTests.mm in Sources */,
+ CA4C54FE2324948100A81659 /* MGLSourceTests.swift in Sources */,
CA1B4A512099FB2200EDD491 /* MGLMapSnapshotterTest.m in Sources */,
+ CA4F3BE4231077B9008BAFEA /* MGLCameraTransitionFinishTests.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -3236,6 +3262,8 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ A4DE3DCC23038CCA005B3473 /* MGLMockGestureRecognizers.m in Sources */,
+ A4DE3DCB23038C98005B3473 /* MGLMockGestureRecognizers.h in Sources */,
6407D6701E0085FD00F6A9C3 /* MGLDocumentationExampleTests.swift in Sources */,
DA2E88631CC0382C00F24E7B /* MGLOfflineRegionTests.m in Sources */,
409F43FD1E9E781C0048729D /* MGLMapViewDelegateIntegrationTests.swift in Sources */,
@@ -3273,7 +3301,7 @@
3575798B1D502B0C000B822E /* MGLBackgroundStyleLayerTests.mm in Sources */,
9658C155204761FC00D8A674 /* MGLMapViewScaleBarTests.m in Sources */,
409D0A0D1ED614CE00C95D0C /* MGLAnnotationViewIntegrationTests.swift in Sources */,
- 9686D1BD22D9357700194EA0 /* MGLMapViewZoomTests.m in Sources */,
+ 9686D1BD22D9357700194EA0 /* MGLMapViewZoomTests.mm in Sources */,
DA2E88621CC0382C00F24E7B /* MGLOfflinePackTests.m in Sources */,
55E2AD131E5B125400E8C587 /* MGLOfflineStorageTests.mm in Sources */,
07D8C6FF1F67562C00381808 /* MGLComputedShapeSourceTests.m in Sources */,
@@ -3321,7 +3349,7 @@
35136D3C1D42272500C20EFD /* MGLCircleStyleLayer.mm in Sources */,
DD9BE4F81EB263C50079A3AF /* UIViewController+MGLAdditions.m in Sources */,
350098DE1D484E60004B2AF0 /* NSValue+MGLStyleAttributeAdditions.mm in Sources */,
- DA6408DD1DA4E7D300908C90 /* MGLVectorStyleLayer.m in Sources */,
+ DA6408DD1DA4E7D300908C90 /* MGLVectorStyleLayer.mm in Sources */,
40834BF71FE05E1800C1BD0D /* MMEUniqueIdentifier.m in Sources */,
3566C7681D4A77BA008152BC /* MGLShapeSource.mm in Sources */,
967C864D210A9D3C004DF794 /* UIDevice+MGLAdditions.m in Sources */,
@@ -3445,7 +3473,7 @@
DD9BE4FA1EB263F40079A3AF /* UIViewController+MGLAdditions.m in Sources */,
AC46EB60225E60510039C013 /* MMEPinningConfigurationProvider.m in Sources */,
350098DF1D484E60004B2AF0 /* NSValue+MGLStyleAttributeAdditions.mm in Sources */,
- DA6408DE1DA4E7D300908C90 /* MGLVectorStyleLayer.m in Sources */,
+ DA6408DE1DA4E7D300908C90 /* MGLVectorStyleLayer.mm in Sources */,
3566C7691D4A77BA008152BC /* MGLShapeSource.mm in Sources */,
9C6E282722A980AC0056B7BE /* UIKit+MMEMobileEvents.m in Sources */,
40834C0B1FE05E1800C1BD0D /* MMEUniqueIdentifier.m in Sources */,
diff --git a/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/CI.xcscheme b/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/CI.xcscheme
index 7d59c4edee..ebe96ef82d 100644
--- a/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/CI.xcscheme
+++ b/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/CI.xcscheme
@@ -54,6 +54,8 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ language = "en"
+ region = "US"
codeCoverageEnabled = "YES"
onlyGenerateCoverageForSpecifiedTargets = "YES"
shouldUseLaunchSchemeArgsEnv = "NO">
diff --git a/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/dynamic.xcscheme b/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/dynamic.xcscheme
index 65d4b059e8..4fdd896401 100644
--- a/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/dynamic.xcscheme
+++ b/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/dynamic.xcscheme
@@ -40,7 +40,18 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- shouldUseLaunchSchemeArgsEnv = "YES">
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ language = "en"
+ region = "US">
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "DA8847D11CBAF91600AB86E3"
+ BuildableName = "Mapbox.framework"
+ BlueprintName = "dynamic"
+ ReferencedContainer = "container:ios.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
<Testables>
<TestableReference
skipped = "NO"
@@ -54,17 +65,6 @@
</BuildableReference>
</TestableReference>
</Testables>
- <MacroExpansion>
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "DA8847D11CBAF91600AB86E3"
- BuildableName = "Mapbox.framework"
- BlueprintName = "dynamic"
- ReferencedContainer = "container:ios.xcodeproj">
- </BuildableReference>
- </MacroExpansion>
- <AdditionalOptions>
- </AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
@@ -85,8 +85,6 @@
ReferencedContainer = "container:ios.xcodeproj">
</BuildableReference>
</MacroExpansion>
- <AdditionalOptions>
- </AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
diff --git a/platform/ios/scripts/deploy-packages.sh b/platform/ios/scripts/deploy-packages.sh
index a0efbd622e..b33a25df86 100755
--- a/platform/ios/scripts/deploy-packages.sh
+++ b/platform/ios/scripts/deploy-packages.sh
@@ -7,12 +7,10 @@ set -u
# dynamic environment variables:
# VERSION_TAG={determined automatically}: Version tag in format ios-vX.X.X-pre.X
# GITHUB_RELEASE=true: Upload to github
-# BINARY_DIRECTORY=build/ios/deploy: Directory in which to save test packages
# environment variables and dependencies:
# - You must run "mbx auth ..." before running
# - Set GITHUB_TOKEN to a GitHub API access token in your environment to use GITHUB_RELEASE
-# - "wget" is required for downloading the zip files from s3
# - The "github-release" command is required to use GITHUB_RELEASE
function step { >&2 echo -e "\033[1m\033[36m* $@\033[0m"; }
@@ -36,8 +34,6 @@ buildPackageStyle() {
./platform/ios/scripts/publish.sh "${PUBLISH_VERSION}" ${style}
file_name=mapbox-ios-sdk-${PUBLISH_VERSION}-${style}.zip
fi
- step "Downloading ${file_name} from s3 to ${BINARY_DIRECTORY}"
- wget -O ${BINARY_DIRECTORY}/${file_name} http://mapbox.s3.amazonaws.com/mapbox-gl-native/ios/builds/${file_name}
if [[ "${GITHUB_RELEASE}" == true ]]; then
step "Uploading ${file_name} to GitHub"
github-release upload \
@@ -54,7 +50,7 @@ export BUILDTYPE=Release
VERSION_TAG=${VERSION_TAG:-''}
PUBLISH_VERSION=
-BINARY_DIRECTORY=${BINARY_DIRECTORY:-build/ios/deploy}
+BINARY_DIRECTORY='build/ios'
GITHUB_RELEASE=${GITHUB_RELEASE:-true}
PUBLISH_PRE_FLAG=''
diff --git a/platform/ios/scripts/install-packaging-dependencies.sh b/platform/ios/scripts/install-packaging-dependencies.sh
index 3d87a93f20..3d7f2fa4ea 100755
--- a/platform/ios/scripts/install-packaging-dependencies.sh
+++ b/platform/ios/scripts/install-packaging-dependencies.sh
@@ -22,15 +22,6 @@ else
fi
##
-## wget
-##
-if [ -z `which wget` ]; then
- brew install wget
-else
- echo "Found brew"
-fi
-
-##
## cocoapods
##
if [[ -z `which pod` || $(pod --version) != "${COCOAPODS_VERSION}" ]]; then
diff --git a/platform/ios/scripts/publish.sh b/platform/ios/scripts/publish.sh
index b4e6f30257..1a4652a509 100755
--- a/platform/ios/scripts/publish.sh
+++ b/platform/ios/scripts/publish.sh
@@ -24,18 +24,19 @@ GITHUB_REPO=${GITHUB_REPO:-'mapbox-gl-native'}
# zip
#
cd build/ios/pkg
-SNAPSHOT_FILENAME="mapbox-ios-sdk-${PUBLISH_VERSION}${PUBLISH_STYLE}.zip"
-step "Compressing ${SNAPSHOT_FILENAME}…"
-rm -f ../${SNAPSHOT_FILENAME}
-zip -yr ../${SNAPSHOT_FILENAME} *
+ZIP_FILENAME="mapbox-ios-sdk-${PUBLISH_VERSION}${PUBLISH_STYLE}.zip"
+step "Compressing ${ZIP_FILENAME}…"
+rm -f ../${ZIP_FILENAME}
+zip -yr ../${ZIP_FILENAME} *
+cd ..
#
# report file sizes
#
step "Echoing file sizes…"
-du -sh ../${SNAPSHOT_FILENAME}
-du -sch *
-du -sch dynamic/*
+du -sh ${ZIP_FILENAME}
+du -sch pkg/*
+du -sch pkg/dynamic/*
#
# upload
@@ -45,17 +46,34 @@ if [ -n "${CI:-}" ]; then
PROGRESS="--no-progress"
fi
-step "Uploading ${SNAPSHOT_FILENAME} to s3…"
-aws s3 cp ../${SNAPSHOT_FILENAME} s3://mapbox/$GITHUB_REPO/ios/builds/ --acl public-read ${PROGRESS}
-echo "URL: https://mapbox.s3.amazonaws.com/$GITHUB_REPO/ios/builds/${SNAPSHOT_FILENAME}"
+step "Uploading ${ZIP_FILENAME} to s3…"
+aws s3 cp ${ZIP_FILENAME} s3://mapbox/${GITHUB_REPO}/ios/builds/ --acl public-read ${PROGRESS}
+S3_URL=https://mapbox.s3.amazonaws.com/${GITHUB_REPO}/ios/builds/${ZIP_FILENAME}
+echo "URL: ${S3_URL}"
#
# upload & update snapshot
#
if [[ ${PUBLISH_VERSION} =~ "snapshot" ]]; then
step "Updating ${PUBLISH_VERSION} to ${PUBLISH_STYLE}…"
- GENERIC_SNAPSHOT_FILENAME="mapbox-ios-sdk-${PUBLISH_VERSION}.zip"
+ GENERIC_ZIP_FILENAME="mapbox-ios-sdk-${PUBLISH_VERSION}.zip"
aws s3 cp \
- s3://mapbox/$GITHUB_REPO/ios/builds/${SNAPSHOT_FILENAME} \
- s3://mapbox/$GITHUB_REPO/ios/builds/${GENERIC_SNAPSHOT_FILENAME} --acl public-read ${PROGRESS}
+ s3://mapbox/$GITHUB_REPO/ios/builds/${ZIP_FILENAME} \
+ s3://mapbox/$GITHUB_REPO/ios/builds/${GENERIC_ZIP_FILENAME} --acl public-read ${PROGRESS}
+fi
+
+#
+# verify upload integrity
+#
+
+step "Validating local and remote checksums…"
+curl --output remote-${ZIP_FILENAME} ${S3_URL}
+LOCAL_CHECKSUM=$( shasum -a 256 -b ${ZIP_FILENAME} | cut -d ' ' -f 1 )
+REMOTE_CHECKSUM=$( shasum -a 256 -b remote-${ZIP_FILENAME} | cut -d ' ' -f 1 )
+
+if [ "${LOCAL_CHECKSUM}" == "${REMOTE_CHECKSUM}" ]; then
+ echo "Checksums match: ${LOCAL_CHECKSUM}"
+else
+ echo "Checksums did not match: ${LOCAL_CHECKSUM} != ${REMOTE_CHECKSUM}"
+ exit 1
fi
diff --git a/platform/ios/sdk-files.json b/platform/ios/sdk-files.json
index 4a28116550..0df4b381ba 100644
--- a/platform/ios/sdk-files.json
+++ b/platform/ios/sdk-files.json
@@ -25,7 +25,7 @@
"platform/darwin/src/MGLCircleStyleLayer.mm",
"platform/ios/src/UIViewController+MGLAdditions.m",
"platform/darwin/src/NSValue+MGLStyleAttributeAdditions.mm",
- "platform/darwin/src/MGLVectorStyleLayer.m",
+ "platform/darwin/src/MGLVectorStyleLayer.mm",
"platform/ios/vendor/mapbox-events-ios/MapboxMobileEvents/MMEUniqueIdentifier.m",
"platform/darwin/src/MGLShapeSource.mm",
"platform/ios/src/UIDevice+MGLAdditions.m",
diff --git a/platform/ios/src/MGLCompassButton.mm b/platform/ios/src/MGLCompassButton.mm
index 94a6820a74..acb25a560c 100644
--- a/platform/ios/src/MGLCompassButton.mm
+++ b/platform/ios/src/MGLCompassButton.mm
@@ -63,9 +63,16 @@
UIImage *scaleImage = [UIImage mgl_resourceImageNamed:@"Compass"];
UIGraphicsBeginImageContextWithOptions(scaleImage.size, NO, UIScreen.mainScreen.scale);
[scaleImage drawInRect:{CGPointZero, scaleImage.size}];
+
+ UIFont *northFont;
+ if (@available(iOS 13.0, *)) {
+ northFont = [UIFont systemFontOfSize:11 weight:UIFontWeightLight];
+ } else {
+ northFont = [UIFont systemFontOfSize:11 weight:UIFontWeightUltraLight];
+ }
NSAttributedString *north = [[NSAttributedString alloc] initWithString:NSLocalizedStringWithDefaultValue(@"COMPASS_NORTH", nil, nil, @"N", @"Compass abbreviation for north") attributes:@{
- NSFontAttributeName: [UIFont systemFontOfSize:11 weight:UIFontWeightUltraLight],
+ NSFontAttributeName: northFont,
NSForegroundColorAttributeName: [UIColor whiteColor],
}];
CGRect stringRect = CGRectMake((scaleImage.size.width - north.size.width) / 2,
diff --git a/platform/ios/src/MGLMapView+Impl.h b/platform/ios/src/MGLMapView+Impl.h
index 0a62b7da82..232215bd1b 100644
--- a/platform/ios/src/MGLMapView+Impl.h
+++ b/platform/ios/src/MGLMapView+Impl.h
@@ -62,7 +62,7 @@ public:
void onDidFinishLoadingMap() override;
void onDidFailLoadingMap(mbgl::MapLoadError mapError, const std::string& what) override;
void onWillStartRenderingFrame() override;
- void onDidFinishRenderingFrame(mbgl::MapObserver::RenderMode) override;
+ void onDidFinishRenderingFrame(mbgl::MapObserver::RenderFrameStatus) override;
void onWillStartRenderingMap() override;
void onDidFinishRenderingMap(mbgl::MapObserver::RenderMode) override;
void onDidFinishLoadingStyle() override;
diff --git a/platform/ios/src/MGLMapView+Impl.mm b/platform/ios/src/MGLMapView+Impl.mm
index 7b4277d407..0b9ab75699 100644
--- a/platform/ios/src/MGLMapView+Impl.mm
+++ b/platform/ios/src/MGLMapView+Impl.mm
@@ -75,8 +75,8 @@ void MGLMapViewImpl::onWillStartRenderingFrame() {
[mapView mapViewWillStartRenderingFrame];
}
-void MGLMapViewImpl::onDidFinishRenderingFrame(mbgl::MapObserver::RenderMode mode) {
- bool fullyRendered = mode == mbgl::MapObserver::RenderMode::Full;
+void MGLMapViewImpl::onDidFinishRenderingFrame(mbgl::MapObserver::RenderFrameStatus status) {
+ bool fullyRendered = status.mode == mbgl::MapObserver::RenderMode::Full;
[mapView mapViewDidFinishRenderingFrameFullyRendered:fullyRendered];
}
diff --git a/platform/ios/src/MGLMapView.h b/platform/ios/src/MGLMapView.h
index e6f66e39ae..017ba525c4 100644
--- a/platform/ios/src/MGLMapView.h
+++ b/platform/ios/src/MGLMapView.h
@@ -748,7 +748,8 @@ MGL_EXPORT
Changes the center coordinate of the map and optionally animates the change.
Changing the center coordinate centers the map on the new coordinate without
- changing the current zoom level.
+ changing the current zoom level. For animated changes, wait until the map view has
+ finished loading before calling this method.
@param coordinate The new center coordinate for the map.
@param animated Specify `YES` if you want the map view to scroll to the new
@@ -762,7 +763,8 @@ MGL_EXPORT
/**
Changes the center coordinate and zoom level of the map and optionally animates
- the change.
+ the change. For animated changes, wait until the map view has
+ finished loading before calling this method.
@param centerCoordinate The new center coordinate for the map.
@param zoomLevel The new zoom level for the map.
@@ -777,7 +779,8 @@ MGL_EXPORT
/**
Changes the center coordinate, zoom level, and direction of the map and
- optionally animates the change.
+ optionally animates the change. For animated changes, wait until the map view has
+ finished loading before calling this method.
@param centerCoordinate The new center coordinate for the map.
@param zoomLevel The new zoom level for the map.
@@ -794,7 +797,8 @@ MGL_EXPORT
/**
Changes the center coordinate, zoom level, and direction of the map, calling a
- completion handler at the end of an optional animation.
+ completion handler at the end of an optional animation. For animated changes,
+ wait until the map view has finished loading before calling this method.
@param centerCoordinate The new center coordinate for the map.
@param zoomLevel The new zoom level for the map.
@@ -1065,7 +1069,8 @@ MGL_EXPORT
/**
Moves the viewpoint to a different location with respect to the map with an
- optional transition animation.
+ optional transition animation. For animated changes, wait until the map view has
+ finished loading before calling this method.
@param camera The new viewpoint.
@param animated Specify `YES` if you want the map view to animate the change to
@@ -1081,7 +1086,8 @@ MGL_EXPORT
/**
Moves the viewpoint to a different location with respect to the map with an
- optional transition duration and timing function.
+ optional transition duration and timing function. For animated changes, wait
+ until the map view has finished loading before calling this method.
@param camera The new viewpoint.
@param duration The amount of time, measured in seconds, that the transition
@@ -1100,7 +1106,8 @@ MGL_EXPORT
/**
Moves the viewpoint to a different location with respect to the map with an
- optional transition duration and timing function.
+ optional transition duration and timing function. For animated changes, wait
+ until the map view has finished loading before calling this method.
@param camera The new viewpoint.
@param duration The amount of time, measured in seconds, that the transition
@@ -1116,7 +1123,8 @@ MGL_EXPORT
/**
Moves the viewpoint to a different location with respect to the map with an
optional transition duration and timing function, and optionally some additional
- padding on each side.
+ padding on each side. For animated changes, wait until the map view has
+ finished loading before calling this method.
@param camera The new viewpoint.
@param duration The amount of time, measured in seconds, that the transition
@@ -1306,8 +1314,8 @@ MGL_EXPORT
property may be overridden at any time.
Changing the value of this property updates the map view immediately. If you
- want to animate the change, use the `-setContentInset:animated:` method
- instead.
+ want to animate the change, use the `-setContentInset:animated:completionHandler:`
+ method instead.
*/
@property (nonatomic, assign) UIEdgeInsets contentInset;
diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm
index d77f94d8ba..62b943fd3d 100644
--- a/platform/ios/src/MGLMapView.mm
+++ b/platform/ios/src/MGLMapView.mm
@@ -128,6 +128,9 @@ const CLLocationDirection MGLToleranceForSnappingToNorth = 7;
/// Distance threshold to stop the camera while animating.
const CLLocationDistance MGLDistanceThresholdForCameraPause = 500;
+/// Rotation threshold while a pinch gesture is occurring.
+static NSString * const MGLRotationThresholdWhileZoomingKey = @"MGLRotationThresholdWhileZooming";
+
/// Reuse identifier and file name of the default point annotation image.
static NSString * const MGLDefaultStyleMarkerSymbolName = @"default_marker";
@@ -154,6 +157,9 @@ static const NSUInteger MGLPresentsWithTransactionAnnotationCount = 0;
/// An indication that the requested annotation was not found or is nonexistent.
enum { MGLAnnotationTagNotFound = UINT32_MAX };
+/// The threshold used to consider when a tilt gesture should start.
+const CLLocationDegrees MGLHorizontalTiltToleranceDegrees = 45.0;
+
/// Mapping from an annotation tag to metadata about that annotation, including
/// the annotation itself.
typedef std::unordered_map<MGLAnnotationTag, MGLAnnotationContext> MGLAnnotationTagContextMap;
@@ -240,6 +246,10 @@ public:
@property (nonatomic) CGFloat quickZoomStart;
@property (nonatomic, getter=isDormant) BOOL dormant;
@property (nonatomic, readonly, getter=isRotationAllowed) BOOL rotationAllowed;
+@property (nonatomic) CGFloat rotationThresholdWhileZooming;
+@property (nonatomic) CGFloat rotationBeforeThresholdMet;
+@property (nonatomic) BOOL isZooming;
+@property (nonatomic) BOOL isRotating;
@property (nonatomic) BOOL shouldTriggerHapticFeedbackForCompass;
@property (nonatomic) MGLMapViewProxyAccessibilityElement *mapViewProxyAccessibilityElement;
@property (nonatomic) MGLAnnotationContainerView *annotationContainerView;
@@ -247,6 +257,7 @@ public:
@property (nonatomic) NSMutableDictionary<NSString *, NSMutableArray<MGLAnnotationView *> *> *annotationViewReuseQueueByIdentifier;
@property (nonatomic, readonly) BOOL enablePresentsWithTransaction;
@property (nonatomic) UIImage *lastSnapshotImage;
+@property (nonatomic) NSMutableArray *pendingCompletionBlocks;
/// Experimental rendering performance measurement.
@property (nonatomic) BOOL experimental_enableFrameRateMeasurement;
@@ -260,6 +271,9 @@ public:
@property (nonatomic) MGLMapDebugMaskOptions residualDebugMask;
@property (nonatomic, copy) NSURL *residualStyleURL;
+/// Tilt gesture recognizer helper
+@property (nonatomic, assign) CGPoint dragGestureMiddlePoint;
+
- (mbgl::Map &)mbglMap;
@end
@@ -457,7 +471,7 @@ public:
// setup mbgl map
MGLRendererConfiguration *config = [MGLRendererConfiguration currentConfiguration];
- auto renderer = std::make_unique<mbgl::Renderer>(_mbglView->getRendererBackend(), config.scaleFactor, config.cacheDir, config.localFontFamilyName);
+ auto renderer = std::make_unique<mbgl::Renderer>(_mbglView->getRendererBackend(), config.scaleFactor, config.localFontFamilyName);
BOOL enableCrossSourceCollisions = !config.perSourceCollisions;
_rendererFrontend = std::make_unique<MGLRenderFrontend>(std::move(renderer), self, _mbglView->getRendererBackend());
@@ -569,6 +583,7 @@ public:
_rotate.delegate = self;
[self addGestureRecognizer:_rotate];
_rotateEnabled = YES;
+ _rotationThresholdWhileZooming = 3;
_doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTapGesture:)];
_doubleTap.numberOfTapsRequired = 2;
@@ -612,6 +627,11 @@ public:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willEnterForeground:) name:UIApplicationWillEnterForegroundNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil];
+
+ // Pending completion blocks are called *after* annotation views have been updated
+ // in updateFromDisplayLink.
+ _pendingCompletionBlocks = [NSMutableArray array];
+
// As of 3.7.5, we intentionally do not listen for `UIApplicationWillResignActiveNotification` or call `pauseRendering:` in response to it, as doing
// so causes a loop when asking for location permission. See: https://github.com/mapbox/mapbox-gl-native/issues/11225
@@ -1033,6 +1053,34 @@ public:
return CGPointMake(CGRectGetMidX(contentFrame), CGRectGetMidY(contentFrame));
}
+#pragma mark - Pending completion blocks
+
+- (void)processPendingBlocks
+{
+ NSArray *blocks = self.pendingCompletionBlocks;
+ self.pendingCompletionBlocks = [NSMutableArray array];
+
+ for (dispatch_block_t block in blocks)
+ {
+ block();
+ }
+}
+
+- (BOOL)scheduleTransitionCompletion:(dispatch_block_t)block
+{
+ // Only add a block if the display link (that calls processPendingBlocks) is
+ // running, otherwise fall back to calling immediately.
+ if (_displayLink && !_displayLink.isPaused)
+ {
+ [self willChangeValueForKey:@"pendingCompletionBlocks"];
+ [self.pendingCompletionBlocks addObject:block];
+ [self didChangeValueForKey:@"pendingCompletionBlocks"];
+ return YES;
+ }
+
+ return NO;
+}
+
#pragma mark - Life Cycle -
- (void)updateFromDisplayLink:(CADisplayLink *)displayLink
@@ -1057,7 +1105,7 @@ public:
return;
}
- if (_needsDisplayRefresh)
+ if (_needsDisplayRefresh || (self.pendingCompletionBlocks.count > 0))
{
_needsDisplayRefresh = NO;
@@ -1066,6 +1114,13 @@ public:
[self updateAnnotationViews];
[self updateCalloutView];
+ // Call any pending completion blocks. This is primarily to ensure
+ // that annotations are in the expected position after core rendering
+ // and map update.
+ //
+ // TODO: Consider using this same mechanism for delegate callbacks.
+ [self processPendingBlocks];
+
_mbglView->display();
}
@@ -1132,6 +1187,7 @@ public:
{
[_displayLink invalidate];
_displayLink = nil;
+ [self processPendingBlocks];
}
}
@@ -1415,6 +1471,7 @@ public:
[MGLMapboxEvents flush];
_displayLink.paused = YES;
+ [self processPendingBlocks];
if ( ! self.glSnapshotView)
{
@@ -1467,6 +1524,11 @@ public:
{
super.hidden = hidden;
_displayLink.paused = hidden;
+
+ if (hidden)
+ {
+ [self processPendingBlocks];
+ }
}
- (void)tintColorDidChange
@@ -1622,6 +1684,9 @@ public:
{
self.scale = powf(2, [self zoomLevel]);
+ if (abs(pinch.velocity) > abs(self.rotate.velocity)) {
+ self.isZooming = YES;
+ }
[self notifyGestureDidBegin];
}
else if (pinch.state == UIGestureRecognizerStateChanged)
@@ -1697,6 +1762,7 @@ public:
}
}
+ self.isZooming = NO;
[self notifyGestureDidEndWithDrift:drift];
[self unrotateIfNeededForGesture];
}
@@ -1716,20 +1782,30 @@ public:
self.cameraChangeReasonBitmask |= MGLCameraChangeReasonGestureRotate;
- if (rotate.state == UIGestureRecognizerStateBegan)
+ if ([[NSUserDefaults standardUserDefaults] objectForKey:MGLRotationThresholdWhileZoomingKey]) {
+ self.rotationThresholdWhileZooming = [[[NSUserDefaults standardUserDefaults] objectForKey:MGLRotationThresholdWhileZoomingKey] floatValue];
+ }
+ // Check whether a zoom triggered by a pinch gesture is occurring and if the rotation threshold has been met.
+ if (MGLDegreesFromRadians(self.rotationBeforeThresholdMet) < self.rotationThresholdWhileZooming && self.isZooming && !self.isRotating) {
+ self.rotationBeforeThresholdMet += fabs(rotate.rotation);
+ rotate.rotation = 0;
+ return;
+ }
+
+ if (rotate.state == UIGestureRecognizerStateBegan || ! self.isRotating)
{
self.angle = MGLRadiansFromDegrees(*self.mbglMap.getCameraOptions().bearing) * -1;
+ self.isRotating = YES;
if (self.userTrackingMode != MGLUserTrackingModeNone)
{
self.userTrackingMode = MGLUserTrackingModeFollow;
}
self.shouldTriggerHapticFeedbackForCompass = NO;
-
[self notifyGestureDidBegin];
}
- else if (rotate.state == UIGestureRecognizerStateChanged)
+ if (rotate.state == UIGestureRecognizerStateChanged)
{
CGFloat newDegrees = MGLDegreesFromRadians(self.angle + rotate.rotation) * -1;
@@ -1740,14 +1816,14 @@ public:
newDegrees = fminf(newDegrees, 30);
newDegrees = fmaxf(newDegrees, -30);
}
-
+
MGLMapCamera *toCamera = [self cameraByRotatingToDirection:newDegrees aroundAnchorPoint:centerPoint];
if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera])
{
- self.mbglMap.jumpTo(mbgl::CameraOptions()
- .withBearing(newDegrees)
- .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y}));
+ self.mbglMap.jumpTo(mbgl::CameraOptions()
+ .withBearing(newDegrees)
+ .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y}));
}
[self cameraIsChanging];
@@ -1768,8 +1844,12 @@ public:
}
}
}
- else if (rotate.state == UIGestureRecognizerStateEnded || rotate.state == UIGestureRecognizerStateCancelled)
+ else if ((rotate.state == UIGestureRecognizerStateEnded || rotate.state == UIGestureRecognizerStateCancelled))
{
+ self.rotationBeforeThresholdMet = 0;
+ if (! self.isRotating) { return; }
+ self.isRotating = NO;
+
CGFloat velocity = rotate.velocity;
CGFloat decelerationRate = self.decelerationRate;
if (decelerationRate != MGLMapViewDecelerationRateImmediate && fabs(velocity) > 3)
@@ -1783,14 +1863,13 @@ public:
if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera])
{
self.mbglMap.easeTo(mbgl::CameraOptions()
- .withBearing(newDegrees)
- .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }),
+ .withBearing(newDegrees)
+ .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }),
MGLDurationFromTimeInterval(decelerationRate));
[self notifyGestureDidEndWithDrift:YES];
-
__weak MGLMapView *weakSelf = self;
-
+
[self animateWithDelay:decelerationRate animations:^
{
[weakSelf unrotateIfNeededForGesture];
@@ -2016,6 +2095,14 @@ public:
if (twoFingerDrag.state == UIGestureRecognizerStateBegan)
{
+ CGPoint midPoint = [twoFingerDrag translationInView:twoFingerDrag.view];
+ // In the following if and for the first execution middlePoint
+ // will be equal to dragGestureMiddlePoint and the resulting
+ // gestureSlopeAngle will be 0º causing a small delay,
+ // initializing dragGestureMiddlePoint with the current midPoint
+ // but substracting one point from 'y' forces an initial 90º angle
+ // making the gesture avoid the delay
+ self.dragGestureMiddlePoint = CGPointMake(midPoint.x, midPoint.y-1);
initialPitch = *self.mbglMap.getCameraOptions().pitch;
[self notifyGestureDidBegin];
}
@@ -2027,30 +2114,45 @@ public:
twoFingerDrag.state = UIGestureRecognizerStateEnded;
return;
}
-
- CGFloat gestureDistance = CGPoint([twoFingerDrag translationInView:twoFingerDrag.view]).y;
- CGFloat slowdown = 2.0;
-
- CGFloat pitchNew = initialPitch - (gestureDistance / slowdown);
-
- CGPoint centerPoint = [self anchorPointForGesture:twoFingerDrag];
-
- MGLMapCamera *oldCamera = self.camera;
- MGLMapCamera *toCamera = [self cameraByTiltingToPitch:pitchNew];
-
- if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera])
- {
- self.mbglMap.jumpTo(mbgl::CameraOptions()
+
+ CGPoint leftTouchPoint = [twoFingerDrag locationOfTouch:0 inView:twoFingerDrag.view];
+ CGPoint rightTouchPoint = [twoFingerDrag locationOfTouch:1 inView:twoFingerDrag.view];
+ CLLocationDegrees fingerSlopeAngle = [self angleBetweenPoints:leftTouchPoint endPoint:rightTouchPoint];
+
+ CGPoint middlePoint = [twoFingerDrag translationInView:twoFingerDrag.view];
+
+ CLLocationDegrees gestureSlopeAngle = [self angleBetweenPoints:self.dragGestureMiddlePoint endPoint:middlePoint];
+ self.dragGestureMiddlePoint = middlePoint;
+ if (fabs(fingerSlopeAngle) < MGLHorizontalTiltToleranceDegrees && fabs(gestureSlopeAngle) > 60.0 ) {
+
+ CGFloat gestureDistance = middlePoint.y;
+ CGFloat slowdown = 2.0;
+
+ CGFloat pitchNew = initialPitch - (gestureDistance / slowdown);
+
+ CGPoint centerPoint = [self anchorPointForGesture:twoFingerDrag];
+
+ MGLMapCamera *oldCamera = self.camera;
+ MGLMapCamera *toCamera = [self cameraByTiltingToPitch:pitchNew];
+
+ if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera])
+ {
+ self.mbglMap.jumpTo(mbgl::CameraOptions()
.withPitch(pitchNew)
.withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }));
+ }
+
+ [self cameraIsChanging];
+
}
- [self cameraIsChanging];
+
}
else if (twoFingerDrag.state == UIGestureRecognizerStateEnded || twoFingerDrag.state == UIGestureRecognizerStateCancelled)
{
[self notifyGestureDidEndWithDrift:NO];
[self unrotateIfNeededForGesture];
+ self.dragGestureMiddlePoint = CGPointZero;
}
}
@@ -2173,23 +2275,17 @@ public:
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
- if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]])
+ if (gestureRecognizer == _twoFingerDrag)
{
UIPanGestureRecognizer *panGesture = (UIPanGestureRecognizer *)gestureRecognizer;
if (panGesture.minimumNumberOfTouches == 2)
{
- CGPoint west = [panGesture locationOfTouch:0 inView:panGesture.view];
- CGPoint east = [panGesture locationOfTouch:1 inView:panGesture.view];
-
- if (west.x > east.x) {
- CGPoint swap = west;
- west = east;
- east = swap;
- }
+ CGPoint leftTouchPoint = [panGesture locationOfTouch:0 inView:panGesture.view];
+ CGPoint rightTouchPoint = [panGesture locationOfTouch:1 inView:panGesture.view];
- CLLocationDegrees horizontalToleranceDegrees = 60.0;
- if ([self angleBetweenPoints:west east:east] > horizontalToleranceDegrees) {
+ CLLocationDegrees degrees = [self angleBetweenPoints:leftTouchPoint endPoint:rightTouchPoint];
+ if (fabs(degrees) > MGLHorizontalTiltToleranceDegrees) {
return NO;
}
}
@@ -2211,18 +2307,24 @@ public:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
NSArray *validSimultaneousGestures = @[ self.pan, self.pinch, self.rotate ];
-
return ([validSimultaneousGestures containsObject:gestureRecognizer] && [validSimultaneousGestures containsObject:otherGestureRecognizer]);
}
-- (CLLocationDegrees)angleBetweenPoints:(CGPoint)west east:(CGPoint)east
+- (CLLocationDegrees)angleBetweenPoints:(CGPoint)originPoint endPoint:(CGPoint)endPoint
{
- CGFloat slope = (west.y - east.y) / (west.x - east.x);
+ if (originPoint.x > endPoint.x) {
+ CGPoint swap = originPoint;
+ originPoint = endPoint;
+ endPoint = swap;
+ }
+
+ CGFloat x = (endPoint.x - originPoint.x);
+ CGFloat y = (endPoint.y - originPoint.y);
- CGFloat angle = atan(fabs(slope));
- CLLocationDegrees degrees = MGLDegreesFromRadians(angle);
+ CGFloat angleInRadians = atan2(y, x);
+ CLLocationDegrees angleInDegrees = MGLDegreesFromRadians(angleInRadians);
- return degrees;
+ return angleInDegrees;
}
#pragma mark - Attribution -
@@ -2302,7 +2404,7 @@ public:
NSString *message;
NSString *participateTitle;
NSString *declineTitle;
- if ([[NSUserDefaults standardUserDefaults] boolForKey:@"MGLMapboxMetricsEnabled"])
+ if ([[NSUserDefaults standardUserDefaults] boolForKey:MGLMapboxMetricsEnabledKey])
{
message = NSLocalizedStringWithDefaultValue(@"TELEMETRY_ENABLED_MSG", nil, nil, @"You are helping to make OpenStreetMap and Mapbox maps better by contributing anonymous usage data.", @"Telemetry prompt message");
participateTitle = NSLocalizedStringWithDefaultValue(@"TELEMETRY_ENABLED_ON", nil, nil, @"Keep Participating", @"Telemetry prompt button");
@@ -2330,14 +2432,14 @@ public:
UIAlertAction *declineAction = [UIAlertAction actionWithTitle:declineTitle
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * _Nonnull action) {
- [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"MGLMapboxMetricsEnabled"];
+ [[NSUserDefaults standardUserDefaults] setBool:NO forKey:MGLMapboxMetricsEnabledKey];
}];
[alertController addAction:declineAction];
UIAlertAction *participateAction = [UIAlertAction actionWithTitle:participateTitle
style:UIAlertActionStyleCancel
handler:^(UIAlertAction * _Nonnull action) {
- [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"MGLMapboxMetricsEnabled"];
+ [[NSUserDefaults standardUserDefaults] setBool:YES forKey:MGLMapboxMetricsEnabledKey];
}];
[alertController addAction:participateAction];
@@ -3188,26 +3290,35 @@ public:
animationOptions.duration.emplace(MGLDurationFromTimeInterval(duration));
animationOptions.easing.emplace(MGLUnitBezierForMediaTimingFunction(function));
}
+
+ dispatch_block_t pendingCompletion;
+
if (completion)
{
- animationOptions.transitionFinishFn = [completion]() {
+ __weak __typeof__(self) weakSelf = self;
+
+ pendingCompletion = ^{
+ if (![weakSelf scheduleTransitionCompletion:completion])
+ {
+ completion();
+ }
+ };
+
+ animationOptions.transitionFinishFn = [pendingCompletion]() {
// Must run asynchronously after the transition is completely over.
// Otherwise, a call to -setCenterCoordinate: within the completion
// handler would reenter the completion handler’s caller.
- dispatch_async(dispatch_get_main_queue(), ^{
- completion();
- });
+
+ dispatch_async(dispatch_get_main_queue(), pendingCompletion);
};
}
MGLMapCamera *camera = [self cameraForCameraOptions:cameraOptions];
if ([self.camera isEqualToMapCamera:camera] && UIEdgeInsetsEqualToEdgeInsets(_contentInset, insets))
{
- if (completion)
+ if (pendingCompletion)
{
- [self animateWithDelay:duration animations:^{
- completion();
- }];
+ [self animateWithDelay:duration animations:pendingCompletion];
}
return;
}
@@ -3374,12 +3485,22 @@ public:
animationOptions.duration.emplace(MGLDurationFromTimeInterval(duration));
animationOptions.easing.emplace(MGLUnitBezierForMediaTimingFunction(function));
}
+
+ dispatch_block_t pendingCompletion;
+
if (completion)
{
- animationOptions.transitionFinishFn = [completion]() {
- dispatch_async(dispatch_get_main_queue(), ^{
+ __weak __typeof__(self) weakSelf = self;
+
+ pendingCompletion = ^{
+ if (![weakSelf scheduleTransitionCompletion:completion])
+ {
completion();
- });
+ }
+ };
+
+ animationOptions.transitionFinishFn = [pendingCompletion]() {
+ dispatch_async(dispatch_get_main_queue(), pendingCompletion);
};
}
@@ -3389,11 +3510,9 @@ public:
MGLMapCamera *camera = [self cameraForCameraOptions:cameraOptions];
if ([self.camera isEqualToMapCamera:camera])
{
- if (completion)
+ if (pendingCompletion)
{
- [self animateWithDelay:duration animations:^{
- completion();
- }];
+ [self animateWithDelay:duration animations:pendingCompletion];
}
return;
}
@@ -3534,22 +3653,30 @@ public:
animationOptions.duration.emplace(MGLDurationFromTimeInterval(duration));
animationOptions.easing.emplace(MGLUnitBezierForMediaTimingFunction(function));
}
+
+ dispatch_block_t pendingCompletion;
+
if (completion)
{
- animationOptions.transitionFinishFn = [completion]() {
- dispatch_async(dispatch_get_main_queue(), ^{
+ __weak __typeof__(self) weakSelf = self;
+
+ pendingCompletion = ^{
+ if (![weakSelf scheduleTransitionCompletion:completion])
+ {
completion();
- });
+ }
+ };
+
+ animationOptions.transitionFinishFn = [pendingCompletion]() {
+ dispatch_async(dispatch_get_main_queue(), pendingCompletion);
};
}
if ([self.camera isEqualToMapCamera:camera] && UIEdgeInsetsEqualToEdgeInsets(_contentInset, edgePadding))
{
- if (completion)
+ if (pendingCompletion)
{
- [self animateWithDelay:duration animations:^{
- completion();
- }];
+ [self animateWithDelay:duration animations:pendingCompletion];
}
return;
}
@@ -3605,22 +3732,30 @@ public:
animationOptions.minZoom = MGLZoomLevelForAltitude(peakAltitude, peakPitch,
peakLatitude, self.frame.size);
}
+
+ dispatch_block_t pendingCompletion;
+
if (completion)
{
- animationOptions.transitionFinishFn = [completion]() {
- dispatch_async(dispatch_get_main_queue(), ^{
+ __weak __typeof__(self) weakSelf = self;
+
+ pendingCompletion = ^{
+ if (![weakSelf scheduleTransitionCompletion:completion])
+ {
completion();
- });
+ }
+ };
+
+ animationOptions.transitionFinishFn = [pendingCompletion]() {
+ dispatch_async(dispatch_get_main_queue(), pendingCompletion);
};
}
if ([self.camera isEqualToMapCamera:camera] && UIEdgeInsetsEqualToEdgeInsets(_contentInset, insets))
{
- if (completion)
+ if (pendingCompletion)
{
- [self animateWithDelay:duration animations:^{
- completion();
- }];
+ [self animateWithDelay:duration animations:pendingCompletion];
}
return;
}
@@ -5168,35 +5303,29 @@ public:
if (shouldEnableLocationServices)
{
- if (self.locationManager.authorizationStatus == kCLAuthorizationStatusNotDetermined)
- {
- BOOL requiresWhenInUseUsageDescription = [NSProcessInfo.processInfo isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){11,0,0}];
+ if (self.locationManager.authorizationStatus == kCLAuthorizationStatusNotDetermined) {
BOOL hasWhenInUseUsageDescription = !![[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"];
- BOOL hasAlwaysUsageDescription;
- if (requiresWhenInUseUsageDescription)
- {
- hasAlwaysUsageDescription = !![[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysAndWhenInUseUsageDescription"] && hasWhenInUseUsageDescription;
- }
- else
- {
- hasAlwaysUsageDescription = !![[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"];
- }
- if (hasAlwaysUsageDescription)
- {
- [self.locationManager requestAlwaysAuthorization];
- }
- else if (hasWhenInUseUsageDescription)
- {
- [self.locationManager requestWhenInUseAuthorization];
- }
- else
- {
- NSString *suggestedUsageKeys = requiresWhenInUseUsageDescription ?
- @"NSLocationWhenInUseUsageDescription and (optionally) NSLocationAlwaysAndWhenInUseUsageDescription" :
- @"NSLocationWhenInUseUsageDescription and/or NSLocationAlwaysUsageDescription";
- [NSException raise:MGLMissingLocationServicesUsageDescriptionException
- format:@"This app must have a value for %@ in its Info.plist.", suggestedUsageKeys];
+ if (@available(iOS 11.0, *)) {
+ // A WhenInUse string is required in iOS 11+ and the map never has any need for Always, so it's enough to just ask for WhenInUse.
+ if (hasWhenInUseUsageDescription) {
+ [self.locationManager requestWhenInUseAuthorization];
+ } else {
+ [NSException raise:MGLMissingLocationServicesUsageDescriptionException
+ format:@"To use location services this app must have a NSLocationWhenInUseUsageDescription string in its Info.plist."];
+ }
+ } else {
+ // We might have to ask for Always if the app does not provide a WhenInUse string.
+ BOOL hasAlwaysUsageDescription = !![[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"];
+
+ if (hasWhenInUseUsageDescription) {
+ [self.locationManager requestWhenInUseAuthorization];
+ } else if (hasAlwaysUsageDescription) {
+ [self.locationManager requestAlwaysAuthorization];
+ } else {
+ [NSException raise:MGLMissingLocationServicesUsageDescriptionException
+ format:@"To use location services this app must have a NSLocationWhenInUseUsageDescription and/or NSLocationAlwaysUsageDescription string in its Info.plist."];
+ }
}
}
diff --git a/platform/ios/src/MGLMapView_Private.h b/platform/ios/src/MGLMapView_Private.h
index e53dc8519c..155527000f 100644
--- a/platform/ios/src/MGLMapView_Private.h
+++ b/platform/ios/src/MGLMapView_Private.h
@@ -52,8 +52,6 @@ FOUNDATION_EXTERN MGL_EXPORT MGLExceptionName const _Nonnull MGLUnderlyingMapUna
/// Synchronously render a frame of the map.
- (void)renderSync;
-- (nonnull mbgl::Map *)mbglMap;
-
- (nonnull mbgl::Renderer *)renderer;
/** Returns whether the map view is currently loading or processing any assets required to render the map */
diff --git a/platform/ios/src/MGLMapboxEvents.h b/platform/ios/src/MGLMapboxEvents.h
index cb3132656f..a7d316cc06 100644
--- a/platform/ios/src/MGLMapboxEvents.h
+++ b/platform/ios/src/MGLMapboxEvents.h
@@ -3,6 +3,9 @@
NS_ASSUME_NONNULL_BEGIN
+/// NSUserDefaults key that controls telemetry user opt-out status
+FOUNDATION_EXTERN NSString * const MGLMapboxMetricsEnabledKey;
+
@interface MGLMapboxEvents : NSObject
+ (nullable instancetype)sharedInstance;
diff --git a/platform/ios/src/MGLMapboxEvents.m b/platform/ios/src/MGLMapboxEvents.m
index cc7390ac61..808c3a88bf 100644
--- a/platform/ios/src/MGLMapboxEvents.m
+++ b/platform/ios/src/MGLMapboxEvents.m
@@ -3,14 +3,16 @@
#import "NSBundle+MGLAdditions.h"
#import "MGLAccountManager_Private.h"
+// NSUserDefaults and Info.plist keys
+NSString * const MGLMapboxMetricsEnabledKey = @"MGLMapboxMetricsEnabled";
+static NSString * const MGLMapboxMetricsDebugLoggingEnabledKey = @"MGLMapboxMetricsDebugLoggingEnabled";
+static NSString * const MGLMapboxMetricsEnabledSettingShownInAppKey = @"MGLMapboxMetricsEnabledSettingShownInApp";
+static NSString * const MGLTelemetryAccessTokenKey = @"MGLTelemetryAccessToken";
+static NSString * const MGLTelemetryBaseURLKey = @"MGLTelemetryBaseURL";
+static NSString * const MGLEventsProfileKey = @"MMEEventsProfile";
+static NSString * const MGLVariableGeofenceKey = @"VariableGeofence";
+
static NSString * const MGLAPIClientUserAgentBase = @"mapbox-maps-ios";
-static NSString * const MGLMapboxAccountType = @"MGLMapboxAccountType";
-static NSString * const MGLMapboxMetricsEnabled = @"MGLMapboxMetricsEnabled";
-static NSString * const MGLMapboxMetricsDebugLoggingEnabled = @"MGLMapboxMetricsDebugLoggingEnabled";
-static NSString * const MGLTelemetryAccessToken = @"MGLTelemetryAccessToken";
-static NSString * const MGLTelemetryBaseURL = @"MGLTelemetryBaseURL";
-static NSString * const MGLEventsProfile = @"MMEEventsProfile";
-static NSString * const MGLVariableGeofence = @"VariableGeofence";
@interface MGLMapboxEvents ()
@@ -19,16 +21,16 @@ static NSString * const MGLVariableGeofence = @"VariableGeofence";
@property (nonatomic, copy) NSString *accessToken;
@end
-@implementation MGLMapboxEvents
+@implementation MGLMapboxEvents
+ (void)initialize {
if (self == [MGLMapboxEvents class]) {
NSBundle *bundle = [NSBundle mainBundle];
- NSNumber *accountTypeNumber = [bundle objectForInfoDictionaryKey:MGLMapboxAccountType];
- [[NSUserDefaults standardUserDefaults] registerDefaults:@{MGLMapboxAccountType: accountTypeNumber ?: @0,
- MGLMapboxMetricsEnabled: @YES,
- MGLMapboxMetricsDebugLoggingEnabled: @NO}];
+ NSNumber *accountTypeNumber = [bundle objectForInfoDictionaryKey:MGLMapboxAccountTypeKey];
+ [[NSUserDefaults standardUserDefaults] registerDefaults:@{MGLMapboxAccountTypeKey: accountTypeNumber ?: @0,
+ MGLMapboxMetricsEnabledKey: @YES,
+ MGLMapboxMetricsDebugLoggingEnabledKey: @NO}];
}
}
@@ -46,9 +48,9 @@ static NSString * const MGLVariableGeofence = @"VariableGeofence";
self = [super init];
if (self) {
_eventsManager = MMEEventsManager.sharedManager;
- _eventsManager.debugLoggingEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:MGLMapboxMetricsDebugLoggingEnabled];
- _eventsManager.accountType = [[NSUserDefaults standardUserDefaults] integerForKey:MGLMapboxAccountType];
- _eventsManager.metricsEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:MGLMapboxMetricsEnabled];
+ _eventsManager.debugLoggingEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:MGLMapboxMetricsDebugLoggingEnabledKey];
+ _eventsManager.accountType = [[NSUserDefaults standardUserDefaults] integerForKey:MGLMapboxAccountTypeKey];
+ _eventsManager.metricsEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:MGLMapboxMetricsEnabledKey];
// It is possible for the shared instance of this class to be created because of a call to
// +[MGLAccountManager load] early on in the app lifecycle of the host application.
@@ -57,11 +59,11 @@ static NSString * const MGLVariableGeofence = @"VariableGeofence";
// (once -[MMEEventsManager initializeWithAccessToken:userAgentBase:hostSDKVersion:] is called.
// Normally, the telem access token and base URL are not set this way. However, overriding these values
// with user defaults can be useful for testing with an alternative (test) backend system.
- if ([[[[NSUserDefaults standardUserDefaults] dictionaryRepresentation] allKeys] containsObject:MGLTelemetryAccessToken]) {
- self.accessToken = [[NSUserDefaults standardUserDefaults] objectForKey:MGLTelemetryAccessToken];
+ if ([[[[NSUserDefaults standardUserDefaults] dictionaryRepresentation] allKeys] containsObject:MGLTelemetryAccessTokenKey]) {
+ self.accessToken = [[NSUserDefaults standardUserDefaults] objectForKey:MGLTelemetryAccessTokenKey];
}
- if ([[[[NSUserDefaults standardUserDefaults] dictionaryRepresentation] allKeys] containsObject:MGLTelemetryBaseURL]) {
- self.baseURL = [NSURL URLWithString:[[NSUserDefaults standardUserDefaults] objectForKey:MGLTelemetryBaseURL]];
+ if ([[[[NSUserDefaults standardUserDefaults] dictionaryRepresentation] allKeys] containsObject:MGLTelemetryBaseURLKey]) {
+ self.baseURL = [NSURL URLWithString:[[NSUserDefaults standardUserDefaults] objectForKey:MGLTelemetryBaseURLKey]];
}
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(userDefaultsDidChange:) name:NSUserDefaultsDidChangeNotification object:nil];
@@ -81,22 +83,22 @@ static NSString * const MGLVariableGeofence = @"VariableGeofence";
}
- (void)updateNonDisablingConfigurationValues {
- self.eventsManager.debugLoggingEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:@"MGLMapboxMetricsDebugLoggingEnabled"];
+ self.eventsManager.debugLoggingEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:MGLMapboxMetricsDebugLoggingEnabledKey];
- // It is possible for `MGLTelemetryAccessToken` to have been set yet `userDefaultsDidChange:`
+ // It is possible for the telemetry access token key to have been set yet `userDefaultsDidChange:`
// is called before `setupWithAccessToken:` is called.
// In that case, setting the access token here will have no effect. In practice, that's fine
// because the access token value will be resolved when `setupWithAccessToken:` is called eventually
- if ([[[[NSUserDefaults standardUserDefaults] dictionaryRepresentation] allKeys] containsObject:MGLTelemetryAccessToken]) {
- self.eventsManager.accessToken = [[NSUserDefaults standardUserDefaults] objectForKey:MGLTelemetryAccessToken];
+ if ([[[[NSUserDefaults standardUserDefaults] dictionaryRepresentation] allKeys] containsObject:MGLTelemetryAccessTokenKey]) {
+ self.eventsManager.accessToken = [[NSUserDefaults standardUserDefaults] objectForKey:MGLTelemetryAccessTokenKey];
}
- // It is possible for `MGLTelemetryBaseURL` to have been set yet `userDefaultsDidChange:`
+ // It is possible for the telemetry base URL key to have been set yet `userDefaultsDidChange:`
// is called before setupWithAccessToken: is called.
// In that case, setting the base URL here will have no effect. In practice, that's fine
// because the base URL value will be resolved when `setupWithAccessToken:` is called eventually
- if ([[[[NSUserDefaults standardUserDefaults] dictionaryRepresentation] allKeys] containsObject:MGLTelemetryBaseURL]) {
- NSURL *baseURL = [NSURL URLWithString:[[NSUserDefaults standardUserDefaults] objectForKey:MGLTelemetryBaseURL]];
+ if ([[[[NSUserDefaults standardUserDefaults] dictionaryRepresentation] allKeys] containsObject:MGLTelemetryBaseURLKey]) {
+ NSURL *baseURL = [NSURL URLWithString:[[NSUserDefaults standardUserDefaults] objectForKey:MGLTelemetryBaseURLKey]];
self.eventsManager.baseURL = baseURL;
}
}
@@ -109,8 +111,8 @@ static NSString * const MGLVariableGeofence = @"VariableGeofence";
if ([[notification object] respondsToSelector:@selector(objectForKey:)]) {
NSUserDefaults *userDefaults = [notification object];
- NSInteger accountType = [userDefaults integerForKey:MGLMapboxAccountType];
- BOOL metricsEnabled = [userDefaults boolForKey:MGLMapboxMetricsEnabled];
+ NSInteger accountType = [userDefaults integerForKey:MGLMapboxAccountTypeKey];
+ BOOL metricsEnabled = [userDefaults boolForKey:MGLMapboxMetricsEnabledKey];
if (accountType != self.eventsManager.accountType || metricsEnabled != self.eventsManager.metricsEnabled) {
self.eventsManager.accountType = accountType;
@@ -124,7 +126,7 @@ static NSString * const MGLVariableGeofence = @"VariableGeofence";
+ (void)setupWithAccessToken:(NSString *)accessToken {
int64_t delayTime = 0;
- if ([[[NSBundle mainBundle] objectForInfoDictionaryKey:MGLEventsProfile] isEqualToString:MGLVariableGeofence]) {
+ if ([[[NSBundle mainBundle] objectForInfoDictionaryKey:MGLEventsProfileKey] isEqualToString:MGLVariableGeofenceKey]) {
delayTime = 10;
}
@@ -164,11 +166,11 @@ static NSString * const MGLVariableGeofence = @"VariableGeofence";
}
+ (void)ensureMetricsOptoutExists {
- NSNumber *shownInAppNumber = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"MGLMapboxMetricsEnabledSettingShownInApp"];
+ NSNumber *shownInAppNumber = [[NSBundle mainBundle] objectForInfoDictionaryKey:MGLMapboxMetricsEnabledSettingShownInAppKey];
BOOL metricsEnabledSettingShownInAppFlag = [shownInAppNumber boolValue];
if (!metricsEnabledSettingShownInAppFlag &&
- [[NSUserDefaults standardUserDefaults] integerForKey:MGLMapboxAccountType] == 0) {
+ [[NSUserDefaults standardUserDefaults] integerForKey:MGLMapboxAccountTypeKey] == 0) {
// Opt-out is not configured in UI, so check for Settings.bundle
id defaultEnabledValue;
NSString *appSettingsBundle = [[NSBundle mainBundle] pathForResource:@"Settings" ofType:@"bundle"];
@@ -178,7 +180,7 @@ static NSString * const MGLVariableGeofence = @"VariableGeofence";
NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[appSettingsBundle stringByAppendingPathComponent:@"Root.plist"]];
NSArray *preferences = settings[@"PreferenceSpecifiers"];
for (NSDictionary *prefSpecification in preferences) {
- if ([prefSpecification[@"Key"] isEqualToString:MGLMapboxMetricsEnabled]) {
+ if ([prefSpecification[@"Key"] isEqualToString:MGLMapboxMetricsEnabledKey]) {
defaultEnabledValue = prefSpecification[@"DefaultValue"];
}
}
diff --git a/platform/ios/src/MGLScaleBar.mm b/platform/ios/src/MGLScaleBar.mm
index 9590a99438..cd8bc1d030 100644
--- a/platform/ios/src/MGLScaleBar.mm
+++ b/platform/ios/src/MGLScaleBar.mm
@@ -84,7 +84,7 @@ static const MGLRow MGLImperialTable[] ={
@property (nonatomic) UIColor *secondaryColor;
@property (nonatomic) CALayer *borderLayer;
@property (nonatomic, assign) CGFloat borderWidth;
-@property (nonatomic) NSCache* labelImageCache;
+@property (nonatomic) NSMutableDictionary* labelImageCache;
@property (nonatomic) MGLScaleBarLabel* prototypeLabel;
@property (nonatomic) CGFloat lastLabelWidth;
@@ -101,7 +101,6 @@ static const CGFloat MGLFeetPerMeter = 3.28084;
- (void)drawTextInRect:(CGRect)rect {
CGSize shadowOffset = self.shadowOffset;
- UIColor *textColor = self.textColor;
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 2);
@@ -112,7 +111,7 @@ static const CGFloat MGLFeetPerMeter = 3.28084;
[super drawTextInRect:rect];
CGContextSetTextDrawingMode(context, kCGTextFill);
- self.textColor = textColor;
+ self.textColor = [UIColor blackColor];
self.shadowOffset = CGSizeMake(0, 0);
[super drawTextInRect:rect];
@@ -159,7 +158,7 @@ static const CGFloat MGLFeetPerMeter = 3.28084;
_formatter = [[MGLDistanceFormatter alloc] init];
// Image labels are now images
- _labelImageCache = [[NSCache alloc] init];
+ _labelImageCache = [[NSMutableDictionary alloc] init];
_prototypeLabel = [[MGLScaleBarLabel alloc] init];
_prototypeLabel.font = [UIFont systemFontOfSize:8 weight:UIFontWeightMedium];
_prototypeLabel.clipsToBounds = NO;
@@ -180,6 +179,17 @@ static const CGFloat MGLFeetPerMeter = 3.28084;
// Zero is a special case (no formatting)
[self addZeroLabel];
+
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resetLabelImageCache) name:NSCurrentLocaleDidChangeNotification object:nil];
+}
+
+- (void)dealloc {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+}
+
+- (void)resetLabelImageCache {
+ self.labelImageCache = [[NSMutableDictionary alloc] init];
+ [self addZeroLabel];
}
#pragma mark - Dimensions
diff --git a/platform/ios/test/MGLMapAccessibilityElementTests.m b/platform/ios/test/MGLMapAccessibilityElementTests.m
index 2312d1d406..916461e708 100644
--- a/platform/ios/test/MGLMapAccessibilityElementTests.m
+++ b/platform/ios/test/MGLMapAccessibilityElementTests.m
@@ -8,11 +8,6 @@
@implementation MGLMapAccessibilityElementTests
-- (void)setUp {
- // FIXME: https://github.com/mapbox/mapbox-gl-native/issues/14908
- XCTAssertEqualObjects(NSLocale.currentLocale.localeIdentifier, @"en_US", @"Device locale must be en_US for these tests to pass.");
-}
-
- (void)testFeatureLabels {
MGLPointFeature *feature = [[MGLPointFeature alloc] init];
feature.attributes = @{
diff --git a/platform/ios/test/MGLMapViewDirectionTests.mm b/platform/ios/test/MGLMapViewDirectionTests.mm
index 8a724a06bc..81e169432b 100644
--- a/platform/ios/test/MGLMapViewDirectionTests.mm
+++ b/platform/ios/test/MGLMapViewDirectionTests.mm
@@ -1,5 +1,6 @@
#import <Mapbox/Mapbox.h>
#import <XCTest/XCTest.h>
+#import "MGLMockGestureRecognizers.h"
#import <mbgl/math/wrap.hpp>
@@ -8,12 +9,6 @@
- (void)resetNorthAnimated:(BOOL)animated;
@end
-@interface UIRotationGestureRecognizerMock : UIRotationGestureRecognizer
-@end
-
-@implementation UIRotationGestureRecognizerMock
-- (CGPoint)locationInView:(nullable UIView*)view { return view.center; }
-@end
@interface MGLMapViewDirectionTests : XCTestCase
@property (nonatomic) MGLMapView *mapView;
diff --git a/platform/ios/test/MGLMapViewPitchTests.m b/platform/ios/test/MGLMapViewPitchTests.m
index b7b18973a1..3e9311dbd4 100644
--- a/platform/ios/test/MGLMapViewPitchTests.m
+++ b/platform/ios/test/MGLMapViewPitchTests.m
@@ -2,23 +2,35 @@
#import <XCTest/XCTest.h>
@interface MockUIPanGestureRecognizer : UIPanGestureRecognizer
-@property CGFloat mbx_tiltGestureYTranslation;
@property NSUInteger mbx_numberOfFingersForGesture;
+@property CGPoint mbx_middlePoint;
+@property CGPoint mbx_westPoint;
+@property CGPoint mbx_eastPoint;
@end
@implementation MockUIPanGestureRecognizer
- (instancetype)initWithTarget:(id)target action:(SEL)action {
if (self = [super initWithTarget:target action:action]) {
- self.mbx_tiltGestureYTranslation = 0;
self.mbx_numberOfFingersForGesture = 2;
+ self.mbx_westPoint = CGPointMake(100, 0);
+ self.mbx_eastPoint = CGPointMake(200, 0);
}
return self;
}
- (NSUInteger)numberOfTouches { return self.mbx_numberOfFingersForGesture; }
-- (CGPoint)translationInView:(UIView *)view { return CGPointMake(0, self.mbx_tiltGestureYTranslation); }
+- (CGPoint)translationInView:(UIView *)view { return self.mbx_middlePoint; }
+- (CGPoint)locationOfTouch:(NSUInteger)touchIndex inView:(UIView *)view {
+ if (touchIndex == 0) {
+ return self.mbx_westPoint;
+ }
+ return self.mbx_eastPoint;
+}
- (void)setTiltGestureYTranslationForPitchDegrees:(CGFloat)degrees {
// The tilt gesture takes the number of screen points the fingers have moved and then divides them by a "slowdown" factor, which happens to be set to 2.0 in -[MGLMapView handleTwoFingerDragGesture:].
- self.mbx_tiltGestureYTranslation = -(degrees * 2.0);
+ CGFloat mbx_tiltGestureYTranslation = -(degrees * 2.0);
+ self.mbx_westPoint = CGPointMake(self.mbx_westPoint.x, mbx_tiltGestureYTranslation);
+ self.mbx_eastPoint = CGPointMake(self.mbx_eastPoint.x, mbx_tiltGestureYTranslation);
+ self.mbx_middlePoint = CGPointMake(self.mbx_middlePoint.x, mbx_tiltGestureYTranslation);
}
@end
@@ -112,6 +124,25 @@
}
}
+- (void)testHorizontalTiltGesture {
+ MockUIPanGestureRecognizer *gesture = [[MockUIPanGestureRecognizer alloc] initWithTarget:self.mapView action:nil];
+ gesture.state = UIGestureRecognizerStateBegan;
+ [self.mapView handleTwoFingerDragGesture:gesture];
+ XCTAssertEqual(self.mapView.camera.pitch, 0, @"Pitch should initially be set to 0°.");
+
+ // Tilt gestures should not be triggered on horizontal dragging.
+ for (NSInteger deltaX = 0; deltaX < 5; deltaX++) {
+ gesture.mbx_westPoint = CGPointMake(100 - deltaX, 100);
+ gesture.mbx_eastPoint = CGPointMake(100 - deltaX, 50);
+ gesture.mbx_middlePoint = CGPointMake((gesture.mbx_westPoint.x + gesture.mbx_westPoint.x)/2, (gesture.mbx_westPoint.y + gesture.mbx_westPoint.y)/2);
+
+ gesture.state = UIGestureRecognizerStateChanged;
+
+ [self.mapView handleTwoFingerDragGesture:gesture];
+ XCTAssertEqual(self.mapView.camera.pitch, 0, @"Horizontal dragging should not tilt the map.");
+ }
+}
+
- (void)testTiltGestureFromInitialTilt {
CGFloat initialTilt = 20;
CGFloat additionalTilt = 30;
diff --git a/platform/ios/test/MGLMapViewZoomTests.m b/platform/ios/test/MGLMapViewZoomTests.mm
index bd617857fd..360af72d02 100644
--- a/platform/ios/test/MGLMapViewZoomTests.m
+++ b/platform/ios/test/MGLMapViewZoomTests.mm
@@ -1,16 +1,14 @@
#import <Mapbox/Mapbox.h>
#import <XCTest/XCTest.h>
+#import "MGLMockGestureRecognizers.h"
+
+#import <mbgl/math/wrap.hpp>
@interface MGLMapView (MGLMapViewZoomTests)
+@property (nonatomic) BOOL isZooming;
+@property (nonatomic) CGFloat rotationThresholdWhileZooming;
- (void)handlePinchGesture:(UIPinchGestureRecognizer *)pinch;
-@end
-
-@interface UIPinchGestureRecognizerMock : UIPinchGestureRecognizer
-@property (nonatomic) CGPoint locationInViewOverride;
-@end
-
-@implementation UIPinchGestureRecognizerMock
-- (CGPoint)locationInView:(nullable UIView *)view { return self.locationInViewOverride; }
+- (void)handleRotateGesture:(UIRotationGestureRecognizer *)rotate;
@end
@interface MGLMapViewZoomTests : XCTestCase
@@ -129,6 +127,60 @@
XCTAssertEqualWithAccuracy(centerCoordinateBeforeReset.longitude, self.mapView.centerCoordinate.longitude, 0.0000001, @"Map center coordinate longitude should remain constant after resetting to north.");
}
+- (void)testPinchAndZoom {
+
+ [[NSUserDefaults standardUserDefaults] setObject:@3 forKey:@"MGLRotationThresholdWhileZooming"];
+ self.mapView.rotationThresholdWhileZooming = 3;
+ self.mapView.zoomLevel = 15;
+ UIPinchGestureRecognizerMock *pinch = [[UIPinchGestureRecognizerMock alloc] initWithTarget:self.mapView action:nil];
+ [self.mapView addGestureRecognizer:pinch];
+ pinch.state = UIGestureRecognizerStateBegan;
+ pinch.velocity = 5.0;
+ pinch.locationInViewOverride = CGPointMake(0, 0);
+ [self.mapView handlePinchGesture:pinch];
+
+ XCTAssertTrue(self.mapView.isZooming);
+
+ UIRotationGestureRecognizerMock *rotate = [[UIRotationGestureRecognizerMock alloc] initWithTarget:self.mapView action:nil];
+ rotate.state = UIGestureRecognizerStateBegan;
+ rotate.rotation = MGLRadiansFromDegrees(1);
+ [self.mapView addGestureRecognizer:rotate];
+ [self.mapView handleRotateGesture:rotate];
+
+ // Both the rotation and direction should be zero since the rotation threshold hasn't been met.
+ XCTAssertEqual(rotate.rotation, 0);
+ XCTAssertEqual(self.mapView.direction, 0);
+
+ // The direction should be `0`. The default rotation threshold is `3`.
+ XCTAssertEqual(self.mapView.direction, 0);
+ rotate.state = UIGestureRecognizerStateChanged;
+ rotate.rotation = MGLRadiansFromDegrees(2);
+ [self.mapView handleRotateGesture:rotate];
+
+ // The direction should be `0`. The default rotation threshold is `3`.
+ XCTAssertEqual(self.mapView.direction, 0);
+
+ for (NSNumber *degrees in @[@-90, @-10, @10, @10, @30, @90, @180, @240, @460, @500, @590, @800]) {
+ rotate.state = UIGestureRecognizerStateChanged;
+ rotate.rotation = MGLRadiansFromDegrees([degrees doubleValue]);
+ [self.mapView handleRotateGesture:rotate];
+
+ CGFloat wrappedRotation = mbgl::util::wrap(-MGLDegreesFromRadians(rotate.rotation), 0., 360.);
+
+
+ // Check that the direction property now matches the gesture's rotation.
+ XCTAssertEqualWithAccuracy(self.mapView.direction, wrappedRotation, 0.001, @"Map direction should match gesture rotation for input of %@°.", degrees);
+ }
+
+ rotate.state = UIGestureRecognizerStateEnded;
+ pinch.state = UIGestureRecognizerStateEnded;
+
+ [self.mapView handleRotateGesture:rotate];
+ [self.mapView handlePinchGesture:pinch];
+
+ XCTAssertFalse(self.mapView.isZooming);
+}
+
NS_INLINE CGFloat MGLScaleFromZoomLevel(double zoom) {
return pow(2, zoom);
}
diff --git a/platform/ios/test/MGLMockGestureRecognizers.h b/platform/ios/test/MGLMockGestureRecognizers.h
new file mode 100644
index 0000000000..aa5fbec494
--- /dev/null
+++ b/platform/ios/test/MGLMockGestureRecognizers.h
@@ -0,0 +1,10 @@
+
+#import <UIKit/UIKit.h>
+
+@interface UIPinchGestureRecognizerMock : UIPinchGestureRecognizer
+@property (nonatomic, readwrite) CGFloat velocity;
+@property (nonatomic) CGPoint locationInViewOverride;
+@end
+
+@interface UIRotationGestureRecognizerMock : UIRotationGestureRecognizer
+@end
diff --git a/platform/ios/test/MGLMockGestureRecognizers.m b/platform/ios/test/MGLMockGestureRecognizers.m
new file mode 100644
index 0000000000..89df6750a9
--- /dev/null
+++ b/platform/ios/test/MGLMockGestureRecognizers.m
@@ -0,0 +1,11 @@
+
+#import "MGLMockGestureRecognizers.h"
+
+@implementation UIPinchGestureRecognizerMock
+@synthesize velocity;
+- (CGPoint)locationInView:(nullable UIView *)view { return self.locationInViewOverride; }
+@end
+
+@implementation UIRotationGestureRecognizerMock
+- (CGPoint)locationInView:(nullable UIView*)view { return view.center; }
+@end
diff --git a/platform/linux/README.md b/platform/linux/README.md
index e1a231dd28..4dc951f12e 100644
--- a/platform/linux/README.md
+++ b/platform/linux/README.md
@@ -66,10 +66,10 @@ Set an access token as described below, and then run:
### Test
-- `make test-*` Builds and runs all tests. You can specify individual tests by replacing * with their name (e.g. `make test-Sprite.CustomSpriteImages`).
+- `make run-test-*` Builds and runs all tests. You can specify individual tests by replacing * with their name (e.g. `make run-test-Sprite.CustomSpriteImages`).
The `zsh` will treat the * in this command as a glob, so you'll need to run
-`make "test-*"` instead.
+`make "run-test-*"` instead.
### Usage
diff --git a/platform/linux/config.cmake b/platform/linux/config.cmake
index aa65ddb606..d7bfad0011 100644
--- a/platform/linux/config.cmake
+++ b/platform/linux/config.cmake
@@ -101,14 +101,6 @@ macro(mbgl_platform_core)
PRIVATE nunicode
PUBLIC -lz
)
-
- if(WITH_CXX11ABI)
- # Statically link libstdc++ when we're using the new STL ABI
- target_link_libraries(mbgl-core
- PUBLIC -static-libstdc++
- PUBLIC -Wl,-Bsymbolic-functions
- )
- endif()
endmacro()
diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md
index d5092be1db..da9a179ad3 100644
--- a/platform/macos/CHANGELOG.md
+++ b/platform/macos/CHANGELOG.md
@@ -2,6 +2,7 @@
## master
+* Fixed crashes triggered when `MGLSource` and `MGLStyleLayer` objects are accessed after having been invalidated after a style change. ([#15539](https://github.com/mapbox/mapbox-gl-native/pull/15539))
* Fixed an issue where it was possible to set the map’s content insets then tilt the map enough to see the horizon, causing performance issues. ([#15195](https://github.com/mapbox/mapbox-gl-native/pull/15195))
* Added an `MGLMapView.prefetchesTiles` property to configure lower-resolution tile prefetching behavior. ([#14816](https://github.com/mapbox/mapbox-gl-native/pull/14816))
* Fixed queryRenderedFeatues bug caused by incorrect sort feature index calculation. ([#14884](https://github.com/mapbox/mapbox-gl-native/pull/14884))
@@ -9,8 +10,14 @@
* The `MGLIdeographicFontFamilyName` Info.plist key now also accepts an array of font family names, to customize font fallback behavior. It can also be set to a Boolean value of `NO` to force the SDK to typeset CJK characters in a remote font specified by `MGLSymbolStyleLayer.textFontNames`. ([#14862](https://github.com/mapbox/mapbox-gl-native/pull/14862))
* Performance improvements for queryRenderedFeatures API and optimization that allocates containers based on a number of rendered layers. ([#14930](https://github.com/mapbox/mapbox-gl-native/pull/14930))
* Fixed rendering layers after fill-extrusion regression caused by optimization of fill-extrusion rendering. ([#15065](https://github.com/mapbox/mapbox-gl-native/pull/15065))
-* `MGLLoggingLevel` has been updated for better matching core log levels. Now can use `[MGLLoggingConfiguration sharedConfiguration].loggingLevel` to filter logs from core . [#15120](https://github.com/mapbox/mapbox-gl-native/pull/15120)
-* Fixed an issue where animated camera transitions zoomed in or out too dramatically. [#15281](https://github.com/mapbox/mapbox-gl-native/pull/15281)
+* `MGLLoggingLevel` has been updated for better matching core log levels. Now can use `[MGLLoggingConfiguration sharedConfiguration].loggingLevel` to filter logs from core . ([#15120](https://github.com/mapbox/mapbox-gl-native/pull/15120))
+* Fixed an issue where animated camera transitions zoomed in or out too dramatically. ([#15281](https://github.com/mapbox/mapbox-gl-native/pull/15281))
+* Fixed rendering and collision detection issues with using `text-variable-anchor` and `icon-text-fit` properties on the same layer. ([#15367](https://github.com/mapbox/mapbox-gl-native/pull/15367))
+* Fixed symbol overlap when zooming out quickly. ([15416](https://github.com/mapbox/mapbox-gl-native/pull/15416))
+* Fixed a rendering issue that non-SDF icon would be treated as SDF icon if they are in the same layer. ([#15456](https://github.com/mapbox/mapbox-gl-native/pull/15456))
+* Fixed a rendering issue of `collisionBox` when `text-translate` or `icon-translate` is enabled. ([#15467](https://github.com/mapbox/mapbox-gl-native/pull/15467))
+* Fixed an issue of integer overflow when converting `tileCoordinates` to `LatLon`, which caused issues such as `queryRenderedFeatures` and `querySourceFeatures` returning incorrect coordinates at zoom levels 20 and higher. ([#15560](https://github.com/mapbox/mapbox-gl-native/pull/15560))
+* Added an `-[MGLMapSnapshotter startWithOverlayHandler:completionHandler:]` method to provide the snapshot's current `CGContext` in order to perform custom drawing on `MGLMapSnapShot` objects. ([#15530](https://github.com/mapbox/mapbox-gl-native/pull/15530))
### Styles and rendering
diff --git a/platform/macos/macos.xcodeproj/project.pbxproj b/platform/macos/macos.xcodeproj/project.pbxproj
index 45e5a6d653..d290d97012 100644
--- a/platform/macos/macos.xcodeproj/project.pbxproj
+++ b/platform/macos/macos.xcodeproj/project.pbxproj
@@ -156,7 +156,7 @@
DA5589771D320C41006B7F64 /* wms.json in Resources */ = {isa = PBXBuildFile; fileRef = DA5589761D320C41006B7F64 /* wms.json */; };
DA57D4B11EBC699800793288 /* MGLDocumentationGuideTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA57D4B01EBC699800793288 /* MGLDocumentationGuideTests.swift */; };
DA6408D71DA4E5DA00908C90 /* MGLVectorStyleLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = DA6408D51DA4E5DA00908C90 /* MGLVectorStyleLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
- DA6408D81DA4E5DA00908C90 /* MGLVectorStyleLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = DA6408D61DA4E5DA00908C90 /* MGLVectorStyleLayer.m */; };
+ DA6408D81DA4E5DA00908C90 /* MGLVectorStyleLayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA6408D61DA4E5DA00908C90 /* MGLVectorStyleLayer.mm */; };
DA695424215B1E6C002041A4 /* MGLMapCameraTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DA695423215B1E6C002041A4 /* MGLMapCameraTests.m */; };
DA7262071DEEDD460043BB89 /* MGLOpenGLStyleLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = DA7262051DEEDD460043BB89 /* MGLOpenGLStyleLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
DA7262081DEEDD460043BB89 /* MGLOpenGLStyleLayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA7262061DEEDD460043BB89 /* MGLOpenGLStyleLayer.mm */; };
@@ -516,7 +516,7 @@
DA618B271E68926E00CB7F44 /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/Localizable.strings; sourceTree = "<group>"; };
DA618B2A1E6892B500CB7F44 /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/Localizable.strings; sourceTree = "<group>"; };
DA6408D51DA4E5DA00908C90 /* MGLVectorStyleLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLVectorStyleLayer.h; sourceTree = "<group>"; };
- DA6408D61DA4E5DA00908C90 /* MGLVectorStyleLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLVectorStyleLayer.m; sourceTree = "<group>"; };
+ DA6408D61DA4E5DA00908C90 /* MGLVectorStyleLayer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLVectorStyleLayer.mm; sourceTree = "<group>"; };
DA695423215B1E6C002041A4 /* MGLMapCameraTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = MGLMapCameraTests.m; path = ../../darwin/test/MGLMapCameraTests.m; sourceTree = "<group>"; };
DA704CBA1F6372E8004B3F28 /* ru */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Foundation.strings; sourceTree = "<group>"; };
DA704CBE1F637531004B3F28 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/Localizable.strings; sourceTree = "<group>"; };
@@ -799,7 +799,7 @@
DA8F25911D51CA750010E6B5 /* MGLSymbolStyleLayer.h */,
DA8F25921D51CA750010E6B5 /* MGLSymbolStyleLayer.mm */,
DA6408D51DA4E5DA00908C90 /* MGLVectorStyleLayer.h */,
- DA6408D61DA4E5DA00908C90 /* MGLVectorStyleLayer.m */,
+ DA6408D61DA4E5DA00908C90 /* MGLVectorStyleLayer.mm */,
);
name = Layers;
sourceTree = "<group>";
@@ -1695,7 +1695,7 @@
DA35A2A61CC9EB2700E826B2 /* MGLCoordinateFormatter.m in Sources */,
352742821D4C243B00A1ECE6 /* MGLSource.mm in Sources */,
DAE6C3881CC31E2A00DB3429 /* MGLMapCamera.mm in Sources */,
- DA6408D81DA4E5DA00908C90 /* MGLVectorStyleLayer.m in Sources */,
+ DA6408D81DA4E5DA00908C90 /* MGLVectorStyleLayer.mm in Sources */,
1FF4858D2237235300F19727 /* MGLAttributedExpression.m in Sources */,
DA8F25B31D51CB270010E6B5 /* NSValue+MGLStyleAttributeAdditions.mm in Sources */,
DAE6C3911CC31E2A00DB3429 /* MGLPolygon.mm in Sources */,
diff --git a/platform/macos/macos.xcodeproj/xcshareddata/xcschemes/CI.xcscheme b/platform/macos/macos.xcodeproj/xcshareddata/xcschemes/CI.xcscheme
index 5f1cf773ae..cfb1eca382 100644
--- a/platform/macos/macos.xcodeproj/xcshareddata/xcschemes/CI.xcscheme
+++ b/platform/macos/macos.xcodeproj/xcshareddata/xcschemes/CI.xcscheme
@@ -56,7 +56,7 @@
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
- BlueprintIdentifier = "9EEBD19ABEE247CF8D3CF4C5"
+ BlueprintIdentifier = "9771D7F76DA54F52A89268C6"
BuildableName = "mbgl-test"
BlueprintName = "mbgl-test"
ReferencedContainer = "container:../../build/macos/mbgl.xcodeproj">
@@ -70,7 +70,7 @@
buildForAnalyzing = "NO">
<BuildableReference
BuildableIdentifier = "primary"
- BlueprintIdentifier = "B328AB16ECE141AAAE2A72C8"
+ BlueprintIdentifier = "D87DA13F4A80489CB4508EBD"
BuildableName = "mbgl-benchmark"
BlueprintName = "mbgl-benchmark"
ReferencedContainer = "container:../../build/macos/mbgl.xcodeproj">
@@ -82,7 +82,18 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- shouldUseLaunchSchemeArgsEnv = "YES">
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ language = "en"
+ region = "US">
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "DA839E911CC2E3400062CAFB"
+ BuildableName = "Mapbox GL.app"
+ BlueprintName = "macosapp"
+ ReferencedContainer = "container:macos.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
<Testables>
<TestableReference
skipped = "NO">
@@ -95,17 +106,6 @@
</BuildableReference>
</TestableReference>
</Testables>
- <MacroExpansion>
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "DA839E911CC2E3400062CAFB"
- BuildableName = "Mapbox GL.app"
- BlueprintName = "macosapp"
- ReferencedContainer = "container:macos.xcodeproj">
- </BuildableReference>
- </MacroExpansion>
- <AdditionalOptions>
- </AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
@@ -126,8 +126,6 @@
ReferencedContainer = "container:macos.xcodeproj">
</BuildableReference>
</MacroExpansion>
- <AdditionalOptions>
- </AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
diff --git a/platform/macos/macos.xcodeproj/xcshareddata/xcschemes/dynamic.xcscheme b/platform/macos/macos.xcodeproj/xcshareddata/xcschemes/dynamic.xcscheme
index fc623b22fa..55a36344d5 100644
--- a/platform/macos/macos.xcodeproj/xcshareddata/xcschemes/dynamic.xcscheme
+++ b/platform/macos/macos.xcodeproj/xcshareddata/xcschemes/dynamic.xcscheme
@@ -40,7 +40,18 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- shouldUseLaunchSchemeArgsEnv = "YES">
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ language = "en"
+ region = "US">
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "DAE6C3271CC30DB200DB3429"
+ BuildableName = "Mapbox.framework"
+ BlueprintName = "dynamic"
+ ReferencedContainer = "container:macos.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
<Testables>
<TestableReference
skipped = "NO">
@@ -53,17 +64,6 @@
</BuildableReference>
</TestableReference>
</Testables>
- <MacroExpansion>
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "DAE6C3271CC30DB200DB3429"
- BuildableName = "Mapbox.framework"
- BlueprintName = "dynamic"
- ReferencedContainer = "container:macos.xcodeproj">
- </BuildableReference>
- </MacroExpansion>
- <AdditionalOptions>
- </AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
@@ -84,8 +84,6 @@
ReferencedContainer = "container:macos.xcodeproj">
</BuildableReference>
</MacroExpansion>
- <AdditionalOptions>
- </AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
diff --git a/platform/macos/macos.xcodeproj/xcshareddata/xcschemes/macosapp.xcscheme b/platform/macos/macos.xcodeproj/xcshareddata/xcschemes/macosapp.xcscheme
index ce62359388..98e6c54a33 100644
--- a/platform/macos/macos.xcodeproj/xcshareddata/xcschemes/macosapp.xcscheme
+++ b/platform/macos/macos.xcodeproj/xcshareddata/xcschemes/macosapp.xcscheme
@@ -26,8 +26,18 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES"
language = "en"
- shouldUseLaunchSchemeArgsEnv = "YES">
+ region = "US">
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "DA839E911CC2E3400062CAFB"
+ BuildableName = "Mapbox GL.app"
+ BlueprintName = "macosapp"
+ ReferencedContainer = "container:macos.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
<Testables>
<TestableReference
skipped = "NO">
@@ -40,17 +50,6 @@
</BuildableReference>
</TestableReference>
</Testables>
- <MacroExpansion>
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "DA839E911CC2E3400062CAFB"
- BuildableName = "Mapbox GL.app"
- BlueprintName = "macosapp"
- ReferencedContainer = "container:macos.xcodeproj">
- </BuildableReference>
- </MacroExpansion>
- <AdditionalOptions>
- </AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
@@ -72,8 +71,6 @@
ReferencedContainer = "container:macos.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
- <AdditionalOptions>
- </AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
diff --git a/platform/macos/sdk-files.json b/platform/macos/sdk-files.json
index 022f679b4a..13760da70f 100644
--- a/platform/macos/sdk-files.json
+++ b/platform/macos/sdk-files.json
@@ -49,7 +49,7 @@
"platform/darwin/src/MGLCoordinateFormatter.m",
"platform/darwin/src/MGLSource.mm",
"platform/darwin/src/MGLMapCamera.mm",
- "platform/darwin/src/MGLVectorStyleLayer.m",
+ "platform/darwin/src/MGLVectorStyleLayer.mm",
"platform/darwin/src/MGLAttributedExpression.m",
"platform/darwin/src/NSValue+MGLStyleAttributeAdditions.mm",
"platform/darwin/src/MGLPolygon.mm",
diff --git a/platform/macos/src/MGLMapView+Impl.h b/platform/macos/src/MGLMapView+Impl.h
index 2d523716d4..d33a19dbab 100644
--- a/platform/macos/src/MGLMapView+Impl.h
+++ b/platform/macos/src/MGLMapView+Impl.h
@@ -30,7 +30,7 @@ public:
void onDidFinishLoadingMap() override;
void onDidFailLoadingMap(mbgl::MapLoadError mapError, const std::string& what) override;
void onWillStartRenderingFrame() override;
- void onDidFinishRenderingFrame(mbgl::MapObserver::RenderMode) override;
+ void onDidFinishRenderingFrame(mbgl::MapObserver::RenderFrameStatus) override;
void onWillStartRenderingMap() override;
void onDidFinishRenderingMap(mbgl::MapObserver::RenderMode) override;
void onDidFinishLoadingStyle() override;
diff --git a/platform/macos/src/MGLMapView+Impl.mm b/platform/macos/src/MGLMapView+Impl.mm
index 2354f67a6d..c00f858153 100644
--- a/platform/macos/src/MGLMapView+Impl.mm
+++ b/platform/macos/src/MGLMapView+Impl.mm
@@ -67,8 +67,8 @@ void MGLMapViewImpl::onWillStartRenderingFrame() {
[mapView mapViewWillStartRenderingFrame];
}
-void MGLMapViewImpl::onDidFinishRenderingFrame(mbgl::MapObserver::RenderMode mode) {
- bool fullyRendered = mode == mbgl::MapObserver::RenderMode::Full;
+void MGLMapViewImpl::onDidFinishRenderingFrame(mbgl::MapObserver::RenderFrameStatus status) {
+ bool fullyRendered = status.mode == mbgl::MapObserver::RenderMode::Full;
[mapView mapViewDidFinishRenderingFrameFullyRendered:fullyRendered];
}
diff --git a/platform/macos/src/MGLMapView.h b/platform/macos/src/MGLMapView.h
index 7617063430..374d4eeab7 100644
--- a/platform/macos/src/MGLMapView.h
+++ b/platform/macos/src/MGLMapView.h
@@ -620,8 +620,8 @@ MGL_EXPORT IB_DESIGNABLE
the value of this property may be overridden at any time.
Changing the value of this property updates the map view immediately. If you
- want to animate the change, use the `-setContentInsets:animated:` method
- instead.
+ want to animate the change, use the `-setContentInset:animated:completionHandler:`
+ method instead.
*/
@property (nonatomic, assign) NSEdgeInsets contentInsets;
diff --git a/platform/macos/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm
index 3c9647571e..9a7cb437ec 100644
--- a/platform/macos/src/MGLMapView.mm
+++ b/platform/macos/src/MGLMapView.mm
@@ -276,7 +276,7 @@ public:
MGLRendererConfiguration *config = [MGLRendererConfiguration currentConfiguration];
- auto renderer = std::make_unique<mbgl::Renderer>(_mbglView->getRendererBackend(), config.scaleFactor, config.cacheDir, config.localFontFamilyName);
+ auto renderer = std::make_unique<mbgl::Renderer>(_mbglView->getRendererBackend(), config.scaleFactor, config.localFontFamilyName);
BOOL enableCrossSourceCollisions = !config.perSourceCollisions;
_rendererFrontend = std::make_unique<MGLRenderFrontend>(std::move(renderer), self, _mbglView->getRendererBackend(), true);
diff --git a/platform/node/CHANGELOG.md b/platform/node/CHANGELOG.md
index 8271e5fcfb..519f30aaad 100644
--- a/platform/node/CHANGELOG.md
+++ b/platform/node/CHANGELOG.md
@@ -1,14 +1,19 @@
-# master
+# 4.3.0
* Introduce `text-writing-mode` layout property for symbol layer ([#14932](https://github.com/mapbox/mapbox-gl-native/pull/14932)). The `text-writing-mode` layout property allows control over symbol's preferred writing mode. The new property value is an array, whose values are enumeration values from a ( `horizontal` | `vertical` ) set.
+* Fixed rendering and collision detection issues with using `text-variable-anchor` and `icon-text-fit` properties on the same layer ([#15367](https://github.com/mapbox/mapbox-gl-native/pull/15367)).
+* Fixed a rendering issue that non-SDF icon would be treated as SDF icon if they are in the same layer. ([#15456](https://github.com/mapbox/mapbox-gl-native/pull/15456))
+* Fixed a rendering issue of `collisionBox` when `text-translate` or `icon-translate` is enabled. ([#15467](https://github.com/mapbox/mapbox-gl-native/pull/15467))
+* Fixed an issue of integer overflow when converting `tileCoordinates` to `LatLon`, which caused issues such as `queryRenderedFeatures` and `querySourceFeatures` returning incorrect coordinates at zoom levels 20 and higher. ([#15560](https://github.com/mapbox/mapbox-gl-native/pull/15560))
+* Add typechecking while constructing legacy filter to prevent converting an unexpected filter type [#15389](https://github.com/mapbox/mapbox-gl-native/pull/15389).
# 4.2.0
- Add an option to set whether or not an image should be treated as a SDF ([#15054](https://github.com/mapbox/mapbox-gl-native/issues/15054))
-- Fix problems associated with node 10 and NAN [#14847](https://github.com/mapbox/mapbox-gl-native/pull/14847)
+- Fix problems associated with node 10 and NAN ([#14847](https://github.com/mapbox/mapbox-gl-native/pull/14847))
# 4.1.0
-- Add `symbol-z-order` symbol layout property to style spec [#12783](https://github.com/mapbox/mapbox-gl-native/pull/12783)
-- Add `crossSourceCollisions` map option, with default of `true`. When set to `false`, cross-source collision detection is disabled. ([#12820] (https://github.com/mapbox/mapbox-gl-native/issues/12820))
-- Fixed bugs in coercion expression operators ("to-array" applied to empty arrays, "to-color" applied to colors, and "to-number" applied to null) [#12864](https://github.com/mapbox/mapbox-gl-native/pull/12864)
+- Add `symbol-z-order` symbol layout property to style spec ([#12783](https://github.com/mapbox/mapbox-gl-native/pull/12783))
+- Add `crossSourceCollisions` map option, with default of `true`. When set to `false`, cross-source collision detection is disabled. ([#12820](https://github.com/mapbox/mapbox-gl-native/issues/12820))
+- Fixed bugs in coercion expression operators ("to-array" applied to empty arrays, "to-color" applied to colors, and "to-number" applied to null) ([#12864](https://github.com/mapbox/mapbox-gl-native/pull/12864))
- Fixed an issue where fill and line layers would occasionally flicker on zoom ([#12982](https://github.com/mapbox/mapbox-gl-native/pull/12982))
# 4.0.0
diff --git a/platform/node/DEVELOPING.md b/platform/node/DEVELOPING.md
index 066448c08e..3d07253ee3 100644
--- a/platform/node/DEVELOPING.md
+++ b/platform/node/DEVELOPING.md
@@ -43,7 +43,7 @@ To publish a new version of the package:
- [ ] an updated version number in [`package.json`](../../package.json#L3)
- [ ] an entry in [`platform/node/CHANGELOG.md`](CHANGELOG.md) describing the changes in the release
- [ ] run `git tag node-v{VERSION}` where `{VERSION}` matches the version in `package.json`, e.g. `git tag node-v3.3.2`
-- [ ] run `git push && git push --gs`
+- [ ] run `git push && git push --tags`
The CI builds for tag pushes will check if the tag matches the version listed in `package.json`, and if so, will run with `BUILDTYPE=Release` and publish a binary with `node-pre-gyp`.
diff --git a/platform/node/test/ignores.json b/platform/node/test/ignores.json
index 7665972aad..d0ae1d0b35 100644
--- a/platform/node/test/ignores.json
+++ b/platform/node/test/ignores.json
@@ -40,12 +40,9 @@
"render-tests/custom-layer-js/tent-3d": "skip - js specific",
"render-tests/regressions/mapbox-gl-js#7708": "skip - js specific",
"render-tests/debug/collision": "https://github.com/mapbox/mapbox-gl-native/issues/3841",
- "render-tests/debug/collision-lines": "https://github.com/mapbox/mapbox-gl-native/issues/10412",
- "render-tests/debug/collision-lines-overscaled": "https://github.com/mapbox/mapbox-gl-native/issues/10412",
- "render-tests/debug/collision-lines-pitched": "https://github.com/mapbox/mapbox-gl-native/issues/10412",
- "render-tests/debug/collision-pitched-wrapped": "https://github.com/mapbox/mapbox-gl-native/issues/10412",
"render-tests/debug/tile": "https://github.com/mapbox/mapbox-gl-native/issues/3841",
"render-tests/debug/tile-overscaled": "https://github.com/mapbox/mapbox-gl-native/issues/3841",
+ "render-tests/debug/raster": "https://github.com/mapbox/mapbox-gl-native/issues/15510",
"render-tests/extent/1024-circle": "needs investigation",
"render-tests/fill-extrusion-pattern/@2x": "https://github.com/mapbox/mapbox-gl-js/issues/3327",
"render-tests/fill-extrusion-pattern/function": "https://github.com/mapbox/mapbox-gl-js/issues/3327",
@@ -73,19 +70,12 @@
"render-tests/regressions/mapbox-gl-js#7302": "skip - js specific",
"render-tests/regressions/mapbox-gl-native#7357": "https://github.com/mapbox/mapbox-gl-native/issues/7357",
"render-tests/symbol-cross-fade/chinese": "https://github.com/mapbox/mapbox-gl-native/issues/10619",
- "render-tests/symbol-visibility/visible": "https://github.com/mapbox/mapbox-gl-native/issues/10409",
- "render-tests/text-pitch-alignment/auto-text-rotation-alignment-map": "https://github.com/mapbox/mapbox-gl-native/issues/9732",
- "render-tests/text-pitch-alignment/map-text-rotation-alignment-map": "https://github.com/mapbox/mapbox-gl-native/issues/9732",
- "render-tests/text-pitch-alignment/viewport-text-rotation-alignment-map": "https://github.com/mapbox/mapbox-gl-native/issues/9732",
"render-tests/video/default": "skip - https://github.com/mapbox/mapbox-gl-native/issues/601",
"render-tests/background-color/colorSpace-hcl": "needs issue",
"render-tests/feature-state/composite-expression": "https://github.com/mapbox/mapbox-gl-native/issues/12613",
"render-tests/feature-state/data-expression": "https://github.com/mapbox/mapbox-gl-native/issues/12613",
"render-tests/feature-state/vector-source": "https://github.com/mapbox/mapbox-gl-native/issues/12613",
- "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",
"render-tests/remove-feature-state/vector-source": "https://github.com/mapbox/mapbox-gl-native/issues/12413",
@@ -103,17 +93,5 @@
"query-tests/fill-extrusion/sort-rotated": "https://github.com/mapbox/mapbox-gl-native/issues/13139",
"query-tests/fill-extrusion/sort": "https://github.com/mapbox/mapbox-gl-native/issues/13139",
"query-tests/fill-extrusion/top-in": "https://github.com/mapbox/mapbox-gl-native/issues/13139",
- "query-tests/regressions/mapbox-gl-js#7883": "https://github.com/mapbox/mapbox-gl-native/issues/14585",
- "render-tests/icon-text-fit/both-padding": "https://github.com/mapbox/mapbox-gl-native/issues/15346",
- "render-tests/icon-text-fit/both": "https://github.com/mapbox/mapbox-gl-native/issues/15346",
- "render-tests/icon-text-fit/height-padding": "https://github.com/mapbox/mapbox-gl-native/issues/15346",
- "render-tests/icon-text-fit/height": "https://github.com/mapbox/mapbox-gl-native/issues/15346",
- "render-tests/icon-text-fit/placement-line": "https://github.com/mapbox/mapbox-gl-native/issues/15346",
- "render-tests/icon-text-fit/width-padding": "https://github.com/mapbox/mapbox-gl-native/issues/15346",
- "render-tests/icon-text-fit/width": "https://github.com/mapbox/mapbox-gl-native/issues/15346",
- "render-tests/regressions/mapbox-gl-js#5631": "https://github.com/mapbox/mapbox-gl-native/issues/15346",
- "render-tests/text-variable-anchor/all-anchors-icon-text-fit": "https://github.com/mapbox/mapbox-gl-native/issues/15346",
- "render-tests/text-variable-anchor/icon-text-fit-collision-box": "https://github.com/mapbox/mapbox-gl-native/issues/15346",
- "render-tests/text-writing-mode/point_label/cjk-variable-anchors-vertical-horizontal-mode-icon-text-fit": "https://github.com/mapbox/mapbox-gl-native/issues/15346",
- "render-tests/text-writing-mode/point_label/mixed-multiline-vertical-horizontal-mode-icon-text-fit": "https://github.com/mapbox/mapbox-gl-native/issues/15346"
+ "query-tests/regressions/mapbox-gl-js#7883": "https://github.com/mapbox/mapbox-gl-native/issues/14585"
}
diff --git a/platform/qt/src/local_glyph_rasterizer.cpp b/platform/qt/src/local_glyph_rasterizer.cpp
index 3f8df5d876..f62975b377 100644
--- a/platform/qt/src/local_glyph_rasterizer.cpp
+++ b/platform/qt/src/local_glyph_rasterizer.cpp
@@ -1,5 +1,6 @@
#include <mbgl/text/local_glyph_rasterizer.hpp>
#include <mbgl/util/i18n.hpp>
+#include <mbgl/util/constants.hpp>
#include <QtCore/QFile>
#include <QtGui/QFont>
@@ -17,13 +18,15 @@ public:
optional<std::string> fontFamily;
QFont font;
+ optional<QFontMetrics> metrics;
};
LocalGlyphRasterizer::Impl::Impl(const optional<std::string> fontFamily_)
: fontFamily(fontFamily_) {
if (isConfigured()) {
font.setFamily(QString::fromStdString(*fontFamily));
- font.setPixelSize(24);
+ font.setPixelSize(util::ONE_EM);
+ metrics = QFontMetrics(font);
}
}
@@ -39,29 +42,33 @@ LocalGlyphRasterizer::~LocalGlyphRasterizer() {
}
bool LocalGlyphRasterizer::canRasterizeGlyph(const FontStack&, GlyphID glyphID) {
- return util::i18n::allowsFixedWidthGlyphGeneration(glyphID) && impl->isConfigured();
+ return impl->isConfigured() && impl->metrics->inFont(glyphID) && util::i18n::allowsFixedWidthGlyphGeneration(glyphID);
}
Glyph LocalGlyphRasterizer::rasterizeGlyph(const FontStack&, GlyphID glyphID) {
Glyph glyph;
glyph.id = glyphID;
- QFontMetrics metrics(impl->font);
- Size size(metrics.width(glyphID), metrics.height());
+ if (!impl->isConfigured()) {
+ assert(false);
+ return glyph;
+ }
- glyph.metrics.width = size.width;
- glyph.metrics.height = size.height;
+ glyph.metrics.width = impl->metrics->width(glyphID);
+ glyph.metrics.height = impl->metrics->height();
glyph.metrics.left = 3;
glyph.metrics.top = -8;
- glyph.metrics.advance = metrics.width(glyphID);
+ glyph.metrics.advance = glyph.metrics.width;
+ // Set width of a glyph's backing image to be util::ONE_EM.
+ Size size(util::ONE_EM, glyph.metrics.height);
QImage image(QSize(size.width, size.height), QImage::Format_Alpha8);
image.fill(qRgba(0, 0, 0, 0));
-
QPainter painter(&image);
painter.setFont(impl->font);
painter.setRenderHints(QPainter::TextAntialiasing);
- painter.drawText(QPointF(0, metrics.ascent()), QString(QChar(glyphID)));
+ // Render at constant baseline, to align with glyphs that are rendered by node-fontnik.
+ painter.drawText(QPointF(0, 20), QString(QChar(glyphID)));
auto img = std::make_unique<uint8_t[]>(image.byteCount());
memcpy(img.get(), image.constBits(), image.byteCount());
diff --git a/platform/qt/src/qmapboxgl_map_observer.cpp b/platform/qt/src/qmapboxgl_map_observer.cpp
index 4a842026cd..00af666b0f 100644
--- a/platform/qt/src/qmapboxgl_map_observer.cpp
+++ b/platform/qt/src/qmapboxgl_map_observer.cpp
@@ -77,9 +77,9 @@ void QMapboxGLMapObserver::onWillStartRenderingFrame()
emit mapChanged(QMapboxGL::MapChangeWillStartRenderingFrame);
}
-void QMapboxGLMapObserver::onDidFinishRenderingFrame(mbgl::MapObserver::RenderMode mode)
+void QMapboxGLMapObserver::onDidFinishRenderingFrame(mbgl::MapObserver::RenderFrameStatus status)
{
- if (mode == mbgl::MapObserver::RenderMode::Partial) {
+ if (status.mode == mbgl::MapObserver::RenderMode::Partial) {
emit mapChanged(QMapboxGL::MapChangeDidFinishRenderingFrame);
} else {
emit mapChanged(QMapboxGL::MapChangeDidFinishRenderingFrameFullyRendered);
diff --git a/platform/qt/src/qmapboxgl_map_observer.hpp b/platform/qt/src/qmapboxgl_map_observer.hpp
index a12e5e9c70..d9e51db28f 100644
--- a/platform/qt/src/qmapboxgl_map_observer.hpp
+++ b/platform/qt/src/qmapboxgl_map_observer.hpp
@@ -28,7 +28,7 @@ public:
void onDidFinishLoadingMap() final;
void onDidFailLoadingMap(mbgl::MapLoadError, const std::string&) final;
void onWillStartRenderingFrame() final;
- void onDidFinishRenderingFrame(mbgl::MapObserver::RenderMode) final;
+ void onDidFinishRenderingFrame(mbgl::MapObserver::RenderFrameStatus) final;
void onWillStartRenderingMap() final;
void onDidFinishRenderingMap(mbgl::MapObserver::RenderMode) final;
void onDidFinishLoadingStyle() final;
diff --git a/platform/qt/src/qmapboxgl_map_renderer.cpp b/platform/qt/src/qmapboxgl_map_renderer.cpp
index eba50af6bf..8423470323 100644
--- a/platform/qt/src/qmapboxgl_map_renderer.cpp
+++ b/platform/qt/src/qmapboxgl_map_renderer.cpp
@@ -28,7 +28,7 @@ static auto *getScheduler() {
QMapboxGLMapRenderer::QMapboxGLMapRenderer(qreal pixelRatio, QMapboxGLSettings::GLContextMode mode, const QString &localFontFamily)
: m_backend(static_cast<mbgl::gfx::ContextMode>(mode)),
- m_renderer(std::make_unique<mbgl::Renderer>(m_backend, pixelRatio, mbgl::optional<std::string> {},
+ m_renderer(std::make_unique<mbgl::Renderer>(m_backend, pixelRatio,
localFontFamily.isEmpty() ? mbgl::nullopt : mbgl::optional<std::string> { localFontFamily.toStdString() }))
, m_forceScheduler(needsToForceScheduler())
{
diff --git a/platform/qt/src/qmapboxgl_renderer_observer.hpp b/platform/qt/src/qmapboxgl_renderer_observer.hpp
index ee340113ff..78dd6b91d6 100644
--- a/platform/qt/src/qmapboxgl_renderer_observer.hpp
+++ b/platform/qt/src/qmapboxgl_renderer_observer.hpp
@@ -37,8 +37,8 @@ public:
delegate.invoke(&mbgl::RendererObserver::onWillStartRenderingFrame);
}
- void onDidFinishRenderingFrame(RenderMode mode, bool repaintNeeded) final {
- delegate.invoke(&mbgl::RendererObserver::onDidFinishRenderingFrame, mode, repaintNeeded);
+ void onDidFinishRenderingFrame(RenderMode mode, bool repaintNeeded, bool placementChanged) final {
+ delegate.invoke(&mbgl::RendererObserver::onDidFinishRenderingFrame, mode, repaintNeeded, placementChanged);
}
void onDidFinishRenderingMap() final {