summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--platform/android/CHANGELOG.md42
-rw-r--r--platform/android/MapboxGLAndroidSDK/build.gradle4
-rw-r--r--platform/android/MapboxGLAndroidSDK/gradle-checkstyle.gradle1
-rw-r--r--platform/android/MapboxGLAndroidSDK/proguard-rules.pro89
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java29
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Icon.java67
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyBearingTracking.java4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyLocationTracking.java4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/Style.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationSource.java63
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java22
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java67
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/FocalPointChangeListener.java3
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java148
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java52
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java10
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java115
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java4
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java16
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java6
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java57
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java28
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java1
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java65
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/Resource.java6
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/CompositeFunction.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Filter.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java21
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/TransitionOptions.java28
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java181
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Position.java81
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/light.java.ejs121
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/package-info.java4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/AnimatorUtils.java59
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java3
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/IconTest.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/build.gradle3
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/proguard-rules.pro1
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LightTest.java162
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/light.junit.ejs128
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraPositionActivity.java31
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java10
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/BuildingFillExtrusionActivity.java88
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/FillExtrusionStyleTestActivity.java78
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MockLocationEngine.java4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_paint.xml9
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_building_layer.xml30
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_extrusion_test.xml18
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_press_for_marker.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_building.xml12
-rw-r--r--platform/android/build.gradle1
-rw-r--r--platform/android/config.cmake4
-rw-r--r--platform/android/dependencies.gradle14
-rw-r--r--platform/android/gradle/wrapper/gradle-wrapper.properties2
-rw-r--r--platform/android/scripts/generate-style-code.js93
-rw-r--r--platform/android/scripts/release.py48
-rwxr-xr-xplatform/android/src/jni.cpp3
-rw-r--r--platform/android/src/map/camera_position.cpp7
-rwxr-xr-xplatform/android/src/native_map_view.cpp23
-rwxr-xr-xplatform/android/src/native_map_view.hpp3
-rw-r--r--platform/android/src/style/conversion/position.hpp37
-rw-r--r--platform/android/src/style/conversion/types.hpp7
-rw-r--r--platform/android/src/style/conversion/types_string_values.hpp14
-rw-r--r--platform/android/src/style/light.cpp146
-rw-r--r--platform/android/src/style/light.cpp.ejs123
-rw-r--r--platform/android/src/style/light.hpp57
-rw-r--r--platform/android/src/style/light.hpp.ejs59
-rw-r--r--platform/android/src/style/position.cpp34
-rw-r--r--platform/android/src/style/position.hpp29
-rw-r--r--platform/darwin/docs/guides/Tile URL Templates.md.ejs109
-rw-r--r--platform/darwin/scripts/generate-style-code.js13
-rw-r--r--platform/darwin/src/MGLAttributionInfo.mm31
-rw-r--r--platform/darwin/src/MGLAttributionInfo_Private.h18
-rw-r--r--platform/darwin/src/MGLFillExtrusionStyleLayer.h2
-rw-r--r--platform/darwin/src/MGLGeometry_Private.h64
-rw-r--r--platform/darwin/src/MGLLight.h125
-rw-r--r--platform/darwin/src/MGLLight.mm113
-rw-r--r--platform/darwin/src/MGLLight_Private.h23
-rw-r--r--platform/darwin/src/MGLOfflineStorage.mm14
-rw-r--r--platform/darwin/src/MGLPolygon.mm20
-rw-r--r--platform/darwin/src/MGLPolyline.mm65
-rw-r--r--platform/darwin/src/MGLRasterSource.h91
-rw-r--r--platform/darwin/src/MGLStyle.h9
-rw-r--r--platform/darwin/src/MGLStyle.mm17
-rw-r--r--platform/darwin/src/MGLStyleValue.h6
-rw-r--r--platform/darwin/src/MGLStyleValue.mm6
-rw-r--r--platform/darwin/src/MGLStyleValue_Private.h14
-rw-r--r--platform/darwin/src/MGLTypes.h1
-rw-r--r--platform/darwin/src/MGLVectorSource.h91
-rw-r--r--platform/darwin/src/NSBundle+MGLAdditions.h4
-rw-r--r--platform/darwin/src/NSBundle+MGLAdditions.m33
-rw-r--r--platform/darwin/src/NSValue+MGLAdditions.h29
-rw-r--r--platform/darwin/src/NSValue+MGLAdditions.m23
-rw-r--r--platform/darwin/src/NSValue+MGLStyleAttributeAdditions.h1
-rw-r--r--platform/darwin/src/NSValue+MGLStyleAttributeAdditions.mm15
-rw-r--r--platform/darwin/test/MGLAttributionInfoTests.m12
-rw-r--r--platform/darwin/test/MGLCodingTests.m119
-rw-r--r--platform/darwin/test/MGLDocumentationExampleTests.swift2
-rw-r--r--platform/darwin/test/MGLLightTest.mm217
-rw-r--r--platform/ios/CHANGELOG.md22
-rw-r--r--platform/ios/Mapbox-iOS-SDK-symbols.podspec2
-rw-r--r--platform/ios/Mapbox-iOS-SDK.podspec2
-rw-r--r--platform/ios/app/MBXViewController.m21
-rw-r--r--platform/ios/docs/guides/Tile URL Templates.md99
-rw-r--r--platform/ios/ios.xcodeproj/project.pbxproj116
-rw-r--r--platform/ios/jazzy.yml2
-rw-r--r--platform/ios/originals/compass.sketchbin0 -> 4881 bytes
-rw-r--r--platform/ios/resources/Compass.pngbin1139 -> 0 bytes
-rw-r--r--platform/ios/resources/Compass@2x.pngbin1892 -> 0 bytes
-rw-r--r--platform/ios/resources/Compass@3x.pngbin3398 -> 0 bytes
-rw-r--r--platform/ios/resources/Images.xcassets/Compass.imageset/Contents.json12
-rw-r--r--platform/ios/resources/Images.xcassets/Compass.imageset/compass.pdfbin0 -> 4574 bytes
-rw-r--r--platform/ios/resources/Images.xcassets/Contents.json6
-rw-r--r--platform/ios/resources/Images.xcassets/default_marker.imageset/Contents.json12
-rw-r--r--platform/ios/resources/Images.xcassets/default_marker.imageset/default_marker.pdfbin0 -> 2601 bytes
-rw-r--r--platform/ios/resources/Images.xcassets/mapbox.imageset/Contents.json12
-rw-r--r--platform/ios/resources/Images.xcassets/mapbox.imageset/mapbox.pdfbin0 -> 8823 bytes
-rw-r--r--platform/ios/resources/default_marker.pngbin1010 -> 0 bytes
-rw-r--r--platform/ios/resources/default_marker@2x.pngbin1995 -> 0 bytes
-rw-r--r--platform/ios/resources/default_marker@3x.pngbin2998 -> 0 bytes
-rw-r--r--platform/ios/resources/mapbox.pngbin2347 -> 0 bytes
-rw-r--r--platform/ios/resources/mapbox@2x.pngbin5290 -> 0 bytes
-rw-r--r--platform/ios/resources/mapbox@3x.pngbin8245 -> 0 bytes
-rw-r--r--platform/ios/src/MGLAPIClient.m2
-rw-r--r--platform/ios/src/MGLAnnotationView.h43
-rw-r--r--platform/ios/src/MGLAnnotationView.mm57
-rw-r--r--platform/ios/src/MGLMapView.mm253
-rw-r--r--platform/ios/src/MGLMapboxEvents.m7
-rw-r--r--platform/ios/src/MGLScaleBar.mm6
-rw-r--r--platform/ios/src/Mapbox.h1
-rw-r--r--platform/ios/test/MGLAnnotationViewIntegrationTests.swift23
-rw-r--r--platform/ios/test/MGLAnnotationViewTests.m23
-rw-r--r--platform/macos/CHANGELOG.md15
-rw-r--r--platform/macos/app/MGLVectorSource+MBXAdditions.h2
-rw-r--r--platform/macos/app/MGLVectorSource+MBXAdditions.m18
-rw-r--r--platform/macos/app/MapDocument.m8
-rw-r--r--platform/macos/docs/guides/Tile URL Templates.md98
-rw-r--r--platform/macos/jazzy.yml2
-rw-r--r--platform/macos/macos.xcodeproj/project.pbxproj36
-rw-r--r--platform/macos/src/MGLMapView.mm15
-rw-r--r--platform/macos/src/Mapbox.h1
-rw-r--r--scripts/config.xcconfig.in1
148 files changed, 4058 insertions, 855 deletions
diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md
index 7807334c14..a9d31426c3 100644
--- a/platform/android/CHANGELOG.md
+++ b/platform/android/CHANGELOG.md
@@ -3,11 +3,51 @@
Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started.
## 5.1.0 - TBA
+* Fix tracking mode + camera race condition [#9133](https://github.com/mapbox/mapbox-gl-native/pull/9133)
+* Harden orientation changes [#9128](https://github.com/mapbox/mapbox-gl-native/pull/9128)
+
+## 5.1.0-beta.3 - May 26, 2017
+
+* Add binding support for Light [#9013](https://github.com/mapbox/mapbox-gl-native/pull/9013)
* Update attribution with new Mapbox wordmark [#8774](https://github.com/mapbox/mapbox-gl-native/pull/8774)
+* LatLngBounds bearing default value [#9102](https://github.com/mapbox/mapbox-gl-native/pull/9102)
+* Stop location updates when toggling MyLocationView [#9099](https://github.com/mapbox/mapbox-gl-native/pull/9099)
+* Horizontally rotated in snapshot [#9083](https://github.com/mapbox/mapbox-gl-native/pull/9083)
+* Disable letter spacing for Arabic text [#9071](https://github.com/mapbox/mapbox-gl-native/pull/9071)
+* Correct bearing conversion when animating the map [#9050](https://github.com/mapbox/mapbox-gl-native/pull/9050)
+* Don't leak selected markers when removing [#9047](https://github.com/mapbox/mapbox-gl-native/pull/9047)
+* Bump tools and support lib version [#9046](https://github.com/mapbox/mapbox-gl-native/pull/9046)
+* MarkerView deselect events with OnMarkerViewClickListener [#9047](https://github.com/mapbox/mapbox-gl-native/pull/9047)
+* LOST update to v3.0.0 [#9112](https://github.com/mapbox/mapbox-gl-native/pull/9112)
+* Convert dp to pixels for meters per pixel at latitude [#9048](https://github.com/mapbox/mapbox-gl-native/pull/9048)
+
+## 5.1.0-beta.2 - May 12, 2017
+
+5.1.0-beta.2 builds further on 5.1.0-beta.1 and adds:
+
+* When a layer is added, reload its source's tiles [#8963](https://github.com/mapbox/mapbox-gl-native/pull/8963)
+* Update release script to support CircleCI builds [#8950](https://github.com/mapbox/mapbox-gl-native/pull/8950)
+* URL getter on Sources [#8959](https://github.com/mapbox/mapbox-gl-native/pull/8959)
+* Build SNAPSHOT from release branch CI configuration [#8958](https://github.com/mapbox/mapbox-gl-native/pull/8958)
+* Fix UI test filter in Makefile [#8960](https://github.com/mapbox/mapbox-gl-native/pull/8960)
+* Bump & fixup dependencies [#8921](https://github.com/mapbox/mapbox-gl-native/pull/8921)
+* Ignore already deleted region [#8920](https://github.com/mapbox/mapbox-gl-native/pull/8920)
+* Keep offline observer when timeout occurs [#8919](https://github.com/mapbox/mapbox-gl-native/pull/8919)
+* Show error message when no browser installed [#8920](https://github.com/mapbox/mapbox-gl-native/pull/8920)
+* Reset observers of removed Sources and Layers [#8900](https://github.com/mapbox/mapbox-gl-native/pull/8900)
+* Only build custom layer .so for debug builds [#8885](https://github.com/mapbox/mapbox-gl-native/pull/8885)
+* Update localizations [#8883](https://github.com/mapbox/mapbox-gl-native/pull/8883)
+* Reset observers of removed Sources and Layers [#8862](https://github.com/mapbox/mapbox-gl-native/pull/8862)
+* Remove force style cascade [#8866](https://github.com/mapbox/mapbox-gl-native/pull/8866)
+* Update proguard config [#8944](https://github.com/mapbox/mapbox-gl-native/pull/8944)
+* Update LOST to 2.3.0-SNAPSHOT [#8872](https://github.com/mapbox/mapbox-gl-native/pull/8872)
+* Update logo [#8774](https://github.com/mapbox/mapbox-gl-native/pull/8774)
+* Camera change listener v2.0 [#8644](https://github.com/mapbox/mapbox-gl-native/pull/8644)
+* Allow filesource url transform reset [#8957](https://github.com/mapbox/mapbox-gl-native/pull/8957)
## 5.1.0-beta.1 - May 2, 2017
-5.1.0 builds further on 5.0.2 and adds:
+5.1.0-beta.1 builds further on 5.0.2 and adds:
* Support for FillExtrusionLayer [#8431](https://github.com/mapbox/mapbox-gl-native/pull/8431)
* Limit Viewport [#8622](https://github.com/mapbox/mapbox-gl-native/pull/8622)
diff --git a/platform/android/MapboxGLAndroidSDK/build.gradle b/platform/android/MapboxGLAndroidSDK/build.gradle
index 40712da065..adbc7cad7f 100644
--- a/platform/android/MapboxGLAndroidSDK/build.gradle
+++ b/platform/android/MapboxGLAndroidSDK/build.gradle
@@ -95,6 +95,9 @@ android {
}
}
}
+
+ // proguard config for .aar
+ consumerProguardFiles 'proguard-rules.pro'
}
// avoid naming conflicts, force usage of prefix
@@ -126,7 +129,6 @@ android {
release {
// aar proguard configuration
- consumerProguardFiles 'proguard-rules.pro'
jniDebuggable false
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/gradle-checkstyle.gradle b/platform/android/MapboxGLAndroidSDK/gradle-checkstyle.gradle
index 05037c6be7..e0bc076d3d 100644
--- a/platform/android/MapboxGLAndroidSDK/gradle-checkstyle.gradle
+++ b/platform/android/MapboxGLAndroidSDK/gradle-checkstyle.gradle
@@ -15,6 +15,7 @@ task checkstyle(type: Checkstyle) {
exclude '**/style/layers/Property.java'
exclude '**/style/layers/PropertyFactory.java'
exclude '**/style/layers/*Layer.java'
+ exclude '**/style/light/Light.java'
classpath = files()
ignoreFailures = false
}
diff --git a/platform/android/MapboxGLAndroidSDK/proguard-rules.pro b/platform/android/MapboxGLAndroidSDK/proguard-rules.pro
index baecd80e50..8e47815451 100644
--- a/platform/android/MapboxGLAndroidSDK/proguard-rules.pro
+++ b/platform/android/MapboxGLAndroidSDK/proguard-rules.pro
@@ -2,89 +2,8 @@
# in ../sdk/tools/proguard/proguard-android.txt,
# contents of this file will be appended into proguard-android.txt
-keepattributes Signature, *Annotation*, EnclosingMethod
-
-# Square okio, ignoring warnings,
-# see https://github.com/square/okio/issues/60
--dontwarn okhttp3.**
--dontwarn okio.**
-
-# Gesture package
-keep class almeros.android.multitouch.gesturedetectors.** { *; }
-
-# Package annotations
--keep class com.mapbox.mapboxsdk.annotations.** { *; }
-
-# Package camera
--keep class com.mapbox.mapboxsdk.camera.** { *; }
-
-# Package geometry
--keep class com.mapbox.mapboxsdk.geometry.** { *; }
-
-# Package http
--keep class com.mapbox.mapboxsdk.http.** { *; }
-
-# Package maps
--keep class com.mapbox.mapboxsdk.maps.** { *; }
-
-# Package net
--keep class com.mapbox.mapboxsdk.net.** { *; }
-
-# Package offline
--keep class com.mapbox.mapboxsdk.offline.** { *; }
-
-# Package storage
--keep class com.mapbox.mapboxsdk.storage.** { *; }
-
-# Package style
--keep class com.mapbox.mapboxsdk.style.layers.** { *; }
--keep class com.mapbox.mapboxsdk.style.sources.** { *; }
--keep class com.mapbox.mapboxsdk.style.functions.** { *; }
-
-# Package telemetry
--keep class com.mapbox.mapboxsdk.telemetry.** { *; }
-
-#
-# Mapbox-java Proguard rules
-# We include these rules since libjava is a Jar file not AAR
-#
-
-# Retrofit 2
-# Platform calls Class.forName on types which do not exist on Android to determine platform.
--dontnote retrofit2.Platform
-# Platform used when running on RoboVM on iOS. Will not be used at runtime.
--dontnote retrofit2.Platform$IOS$MainThreadExecutor
-# Platform used when running on Java 8 VMs. Will not be used at runtime.
--dontwarn retrofit2.Platform$Java8
-# Retain generic type information for use by reflection by converters and adapters.
--keepattributes Signature
-# Retain declared checked exceptions for use by a Proxy instance.
--keepattributes Exceptions
-
-# For using GSON @Expose annotation
--keepattributes *Annotation*
-# Gson specific classes
--dontwarn sun.misc.**
-
-# Prevent proguard from stripping interface information from TypeAdapterFactory,
-# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
--keep class * implements com.google.gson.TypeAdapterFactory
--keep class * implements com.google.gson.JsonSerializer
--keep class * implements com.google.gson.JsonDeserializer
-
-# MAS Data Models
--keep class com.mapbox.services.commons.geojson.** { *; }
--keep class com.mapbox.services.mapmatching.v4.models.** { *; }
--keep class com.mapbox.services.distance.v1.models.** { *; }
--keep class com.mapbox.services.directions.v4.models.** { *; }
--keep class com.mapbox.services.directions.v5.models.** { *; }
--keep class com.mapbox.services.geocoding.v5.models.** { *; }
-
--dontwarn javax.annotation.**
-
--keepclassmembers class rx.internal.util.unsafe.** {
- long producerIndex;
- long consumerIndex;
-}
-
--keep class com.google.** { *; }
--dontwarn com.google.** \ No newline at end of file
+-keep class com.mapbox.mapboxsdk.** { *; }
+-keep interface com.mapbox.mapboxsdk.** { *; }
+-keep class com.mapbox.services.android.telemetry.** { *; }
+-keep class com.mapbox.services.commons.** { *;} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java
index 8098ee4d86..81134e9497 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java
@@ -1,5 +1,6 @@
package com.mapbox.mapboxsdk;
+import android.app.Application;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
@@ -15,6 +16,14 @@ import com.mapbox.services.android.telemetry.MapboxTelemetry;
import com.mapbox.services.android.telemetry.location.LocationEngine;
import com.mapbox.services.android.telemetry.location.LocationEnginePriority;
+/**
+ * The entry point of the Mapbox Android SDK.
+ * <p>
+ * Obtain a reference by calling {@link #getInstance(Context, String)}. Usually this class is configured in
+ * {@link Application#onCreate()} and is responsible for the active access token, application context, and
+ * connectivity state.
+ * </p>
+ */
public final class Mapbox {
private static Mapbox INSTANCE;
@@ -25,7 +34,7 @@ public final class Mapbox {
/**
* Get an instance of Mapbox.
* <p>
- * This class manages the active access token, application context and connectivity state.
+ * This class manages the active access token, application context, and connectivity state.
* </p>
*
* @param context Android context which holds or is an application context
@@ -52,9 +61,9 @@ public final class Mapbox {
}
/**
- * Access Token for this application.
+ * Access token for this application.
*
- * @return Mapbox Access Token
+ * @return Mapbox access token
*/
public static String getAccessToken() {
validateMapbox();
@@ -72,7 +81,7 @@ public final class Mapbox {
}
/**
- * Runtime validation of Access Token.
+ * Runtime validation of access token.
*
* @throws MapboxConfigurationException exception thrown when not using a valid accessToken
*/
@@ -92,11 +101,11 @@ public final class Mapbox {
}
/**
- * Manually sets the connectivity state of the app. This is useful for apps that control their
+ * Manually sets the connectivity state of the app. This is useful for apps which control their
* own connectivity state and want to bypass any checks to the ConnectivityManager.
*
* @param connected flag to determine the connectivity state, true for connected, false for
- * disconnected, null for ConnectivityManager to determine.
+ * disconnected, and null for ConnectivityManager to determine.
*/
public static synchronized void setConnected(Boolean connected) {
// Connectivity state overridden by app
@@ -104,10 +113,10 @@ public final class Mapbox {
}
/**
- * Determines whether we have an Internet connection available. Please do not rely on this
- * method in your apps, this method is used internally by the SDK.
+ * Determines whether we have an internet connection available. Please do not rely on this
+ * method in your apps. This method is used internally by the SDK.
*
- * @return true if there is an Internet connection, false otherwise
+ * @return true if there is an internet connection, false otherwise
*/
public static synchronized Boolean isConnected() {
if (INSTANCE.connected != null) {
@@ -119,4 +128,4 @@ public final class Mapbox {
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
return (activeNetwork != null && activeNetwork.isConnected());
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Icon.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Icon.java
index b1a05ec436..2ee17c227d 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Icon.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Icon.java
@@ -1,15 +1,18 @@
package com.mapbox.mapboxsdk.annotations;
import android.graphics.Bitmap;
+import android.util.DisplayMetrics;
-import com.mapbox.mapboxsdk.maps.MapView;
+import java.nio.ByteBuffer;
/**
- * Icon is the visual representation of a {@link Marker} on a {@link MapView}.
+ * Icon is the visual representation of a Marker on a MapView.
*
* @see Marker
+ * @see IconFactory
*/
public class Icon {
+
private Bitmap mBitmap;
private String mId;
@@ -19,29 +22,67 @@ public class Icon {
}
/**
- * {@link String} identifier for this {@link Icon}.
+ * String identifier for this icon.
*
- * @return {@link String} identifier for this {@link Icon}.
+ * @return String identifier for this icon.
*/
public String getId() {
return mId;
}
/**
- * Get the {@link Bitmap} being used for this {@link Icon}.
+ * Get the bitmap being used for this icon.
*
- * @return The {@link Bitmap} being used for the {@link Icon}.
+ * @return The bitmap being used for the icon.
*/
public Bitmap getBitmap() {
+ if (mBitmap.getConfig() != Bitmap.Config.ARGB_8888) {
+ mBitmap = mBitmap.copy(Bitmap.Config.ARGB_8888, false);
+ }
return mBitmap;
}
/**
- * Compares this {@link Icon} object with another {@link Icon} and determines if they match.
+ * Get the icon bitmap scale.
+ * <p>
+ * Requires the bitmap to be set before calling this method.
+ * </p>
+ *
+ * @return the scale of the bitmap
+ */
+ public float getScale() {
+ if (mBitmap == null) {
+ throw new IllegalStateException("Required to set a Icon before calling getScale");
+ }
+ float density = mBitmap.getDensity();
+ if (density == Bitmap.DENSITY_NONE) {
+ density = DisplayMetrics.DENSITY_DEFAULT;
+ }
+ return density / DisplayMetrics.DENSITY_DEFAULT;
+ }
+
+ /**
+ * Get the icon bitmap bytes.
+ * <p>
+ * Requires the bitmap to be set before calling this method.
+ * </p>
*
- * @param object Another {@link Icon} to compare with this object.
- * @return True if the {@link Icon} being passed in matches this {@link Icon} object. Else,
- * false.
+ * @return the bytes of the bitmap
+ */
+ public byte[] toBytes() {
+ if (mBitmap == null) {
+ throw new IllegalStateException("Required to set a Icon before calling toBytes");
+ }
+ ByteBuffer buffer = ByteBuffer.allocate(mBitmap.getRowBytes() * mBitmap.getHeight());
+ mBitmap.copyPixelsToBuffer(buffer);
+ return buffer.array();
+ }
+
+ /**
+ * Compares this icon object with another icon and determines if they match.
+ *
+ * @param object Another iconi to compare with this object.
+ * @return True if the icon being passed in matches this icon object. Else, false.
*/
@Override
public boolean equals(Object object) {
@@ -53,11 +94,7 @@ public class Icon {
}
Icon icon = (Icon) object;
-
- if (!mBitmap.equals(icon.mBitmap)) {
- return false;
- }
- return mId.equals(icon.mId);
+ return mBitmap.equals(icon.mBitmap) && mId.equals(icon.mId);
}
/**
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java
index 30336d4ebd..56e8cc4ce2 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java
@@ -3,6 +3,7 @@ package com.mapbox.mapboxsdk.annotations;
import android.support.annotation.FloatRange;
import android.support.annotation.Nullable;
+import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapboxMap;
@@ -361,6 +362,9 @@ public class MarkerView extends Marker {
*/
@Override
public Icon getIcon() {
+ if (markerViewIcon == null) {
+ setIcon(IconFactory.getInstance(Mapbox.getApplicationContext()).defaultMarkerView());
+ }
return markerViewIcon;
}
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 5e958ff565..66c261f1d0 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
@@ -156,7 +156,7 @@ public final class CameraPosition implements Parcelable {
}
/**
- * Builder for composing {@link CameraPosition} objects.
+ * Builder for composing CameraPosition objects.
*/
public static final class Builder {
@@ -190,7 +190,7 @@ public final class CameraPosition implements Parcelable {
/**
* Create Builder with an existing CameraPosition data.
*
- * @param typedArray TypedArray containgin attribute values
+ * @param typedArray TypedArray containing attribute values
*/
public Builder(TypedArray typedArray) {
super();
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 64b86054a0..8e1411e273 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
@@ -15,7 +15,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
- * Factory for creating {@link CameraUpdate} objects.
+ * Factory for creating CameraUpdate objects.
*/
public final class CameraUpdateFactory {
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyBearingTracking.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyBearingTracking.java
index f53c65d055..88c3bef673 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyBearingTracking.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyBearingTracking.java
@@ -16,7 +16,7 @@ import java.lang.annotation.RetentionPolicy;
public class MyBearingTracking {
/**
- * Indicates the parameter accepts one of the values from {@link MyBearingTracking}.
+ * Indicates that the parameter accepts one of the values from MyBearingTracking.
*/
@IntDef( {NONE, COMPASS, GPS, /**COMBINED**/})
@Retention(RetentionPolicy.SOURCE)
@@ -38,6 +38,4 @@ public class MyBearingTracking {
*/
public static final int GPS = 0x00000008;
- // public static final int COMBINED = 0x00000012;
-
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyLocationTracking.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyLocationTracking.java
index 39f653596f..a1744d701f 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyLocationTracking.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyLocationTracking.java
@@ -17,7 +17,7 @@ import java.lang.annotation.RetentionPolicy;
public class MyLocationTracking {
/**
- * Indicates the parameter accepts one of the values from {@link MyLocationTracking}.
+ * Indicates the parameter accepts one of the values from MyLocationTracking.
*/
@IntDef( {TRACKING_NONE, TRACKING_FOLLOW})
@Retention(RetentionPolicy.SOURCE)
@@ -30,7 +30,7 @@ public class MyLocationTracking {
public static final int TRACKING_NONE = 0x00000000;
/**
- * Tracking the location of the user, {@link MapView} will reposition to center of {@link MyLocationView}
+ * Tracking the location of the user. {@link MapView} will reposition to center of {@link MyLocationView}
*/
public static final int TRACKING_FOLLOW = 0x00000004;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/Style.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/Style.java
index 77d0929df3..31e6313509 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/Style.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/Style.java
@@ -19,7 +19,7 @@ public class Style {
/**
- * Indicates the parameter accepts one of the values from {@link Style}. Using one of these
+ * Indicates the parameter accepts one of the values from Style. Using one of these
* constants means your map style will always use the latest version and may change as we
* improve the style
*/
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationSource.java
index b795cf1d5b..4e934fa3cc 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationSource.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationSource.java
@@ -2,7 +2,7 @@ package com.mapbox.mapboxsdk.location;
import android.content.Context;
import android.location.Location;
-import android.util.Log;
+import android.support.annotation.NonNull;
import com.mapbox.services.android.telemetry.location.LocationEngine;
import com.mapbox.services.android.telemetry.location.LocationEngineListener;
@@ -15,6 +15,8 @@ import com.mapzen.android.lost.api.LostApiClient;
import java.lang.ref.WeakReference;
+import timber.log.Timber;
+
/**
* Manages locational updates. Contains methods to register and unregister location listeners.
* <ul>
@@ -33,8 +35,6 @@ import java.lang.ref.WeakReference;
public class LocationSource extends LocationEngine implements
LostApiClient.ConnectionCallbacks, LocationListener {
- private static final String LOG_TAG = LocationSource.class.getSimpleName();
-
private static LocationEngine instance;
private WeakReference<Context> context;
@@ -48,7 +48,13 @@ public class LocationSource extends LocationEngine implements
.build();
}
- public static synchronized LocationEngine getLocationEngine(Context context) {
+ /**
+ * Get the LocationEngine instance.
+ *
+ * @param context a Context from which the application context is derived
+ * @return the LocationEngine instance
+ */
+ public static synchronized LocationEngine getLocationEngine(@NonNull Context context) {
if (instance == null) {
instance = new LocationSource(context.getApplicationContext());
}
@@ -56,6 +62,10 @@ public class LocationSource extends LocationEngine implements
return instance;
}
+ /**
+ * Activate the location engine which will connect whichever location provider you are using. You'll need to call
+ * this before requesting user location updates using {@link LocationEngine#requestLocationUpdates()}.
+ */
@Override
public void activate() {
if (lostApiClient != null && !lostApiClient.isConnected()) {
@@ -63,6 +73,11 @@ public class LocationSource extends LocationEngine implements
}
}
+ /**
+ * Disconnect the location engine which is useful when you no longer need location updates or requesting the users
+ * {@link LocationEngine#getLastLocation()}. Before deactivating, you'll need to stop request user location updates
+ * using {@link LocationEngine#removeLocationUpdates()}.
+ */
@Override
public void deactivate() {
if (lostApiClient != null && lostApiClient.isConnected()) {
@@ -70,11 +85,20 @@ public class LocationSource extends LocationEngine implements
}
}
+ /**
+ * Check if your location provider has been activated/connected. This is mainly used internally but is also useful in
+ * the rare case when you'd like to know if your location engine is connected or not.
+ *
+ * @return boolean true if the location engine has been activated/connected, else false.
+ */
@Override
public boolean isConnected() {
return lostApiClient.isConnected();
}
+ /**
+ * Invoked when the location provider has connected.
+ */
@Override
public void onConnected() {
for (LocationEngineListener listener : locationListeners) {
@@ -82,11 +106,19 @@ public class LocationSource extends LocationEngine implements
}
}
+ /**
+ * Invoked when the location provider connection has been suspended.
+ */
@Override
public void onConnectionSuspended() {
- Log.d(LOG_TAG, "Connection suspended.");
+ Timber.d("Connection suspended.");
}
+ /**
+ * Returns the Last known location is the location provider is connected and location permissions are granted.
+ *
+ * @return the last known location
+ */
@Override
public Location getLastLocation() {
if (lostApiClient.isConnected() && PermissionsManager.areLocationPermissionsGranted(context.get())) {
@@ -97,6 +129,9 @@ public class LocationSource extends LocationEngine implements
return null;
}
+ /**
+ * Request location updates to the location provider.
+ */
@Override
public void requestLocationUpdates() {
// Common params
@@ -122,6 +157,9 @@ public class LocationSource extends LocationEngine implements
}
}
+ /**
+ * Dismiss ongoing location update to the location provider.
+ */
@Override
public void removeLocationUpdates() {
if (lostApiClient.isConnected()) {
@@ -129,20 +167,15 @@ public class LocationSource extends LocationEngine implements
}
}
+ /**
+ * Invoked when the Location has changed.
+ *
+ * @param location the new location
+ */
@Override
public void onLocationChanged(Location location) {
for (LocationEngineListener listener : locationListeners) {
listener.onLocationChanged(location);
}
}
-
- @Override
- public void onProviderDisabled(String provider) {
- Log.d(LOG_TAG, "Provider disabled: " + provider);
- }
-
- @Override
- public void onProviderEnabled(String provider) {
- Log.d(LOG_TAG, "Provider enabled: " + provider);
- }
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java
index 9b6706b90c..7e7947047e 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java
@@ -100,6 +100,10 @@ class AnnotationManager {
if (annotation instanceof Marker) {
Marker marker = (Marker) annotation;
marker.hideInfoWindow();
+ if (selectedMarkers.contains(marker)) {
+ selectedMarkers.remove(marker);
+ }
+
if (marker instanceof MarkerView) {
markerViewManager.removeMarkerView((MarkerView) marker);
}
@@ -112,6 +116,10 @@ class AnnotationManager {
if (annotation instanceof Marker) {
Marker marker = (Marker) annotation;
marker.hideInfoWindow();
+ if (selectedMarkers.contains(marker)) {
+ selectedMarkers.remove(marker);
+ }
+
if (marker instanceof MarkerView) {
markerViewManager.removeMarkerView((MarkerView) marker);
}
@@ -124,6 +132,7 @@ class AnnotationManager {
Annotation annotation;
int count = annotationsArray.size();
long[] ids = new long[count];
+ selectedMarkers.clear();
for (int i = 0; i < count; i++) {
ids[i] = annotationsArray.keyAt(i);
annotation = annotationsArray.get(ids[i]);
@@ -383,12 +392,15 @@ class AnnotationManager {
for (Marker nearbyMarker : nearbyMarkers) {
for (Marker selectedMarker : selectedMarkers) {
if (nearbyMarker.equals(selectedMarker)) {
- if (onMarkerClickListener != null) {
- // end developer has provided a custom click listener
+ if (nearbyMarker instanceof MarkerView) {
+ handledDefaultClick = markerViewManager.onClickMarkerView((MarkerView) nearbyMarker);
+ } else if (onMarkerClickListener != null) {
handledDefaultClick = onMarkerClickListener.onMarkerClick(nearbyMarker);
- if (!handledDefaultClick) {
- deselectMarker(nearbyMarker);
- }
+ }
+
+ if (!handledDefaultClick) {
+ // only deselect marker if user didn't handle the click event themselves
+ deselectMarker(nearbyMarker);
}
return true;
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java
new file mode 100644
index 0000000000..bd028aecb6
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java
@@ -0,0 +1,67 @@
+package com.mapbox.mapboxsdk.maps;
+
+import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraIdleListener;
+import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveCanceledListener;
+import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveStartedListener;
+import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveListener;
+
+class CameraChangeDispatcher implements MapboxMap.OnCameraMoveStartedListener, MapboxMap.OnCameraMoveListener,
+ MapboxMap.OnCameraMoveCanceledListener, OnCameraIdleListener {
+
+ private boolean idle = true;
+
+ private OnCameraMoveStartedListener onCameraMoveStartedListener;
+ private OnCameraMoveCanceledListener onCameraMoveCanceledListener;
+ private OnCameraMoveListener onCameraMoveListener;
+ private OnCameraIdleListener onCameraIdleListener;
+
+ void setOnCameraMoveStartedListener(OnCameraMoveStartedListener onCameraMoveStartedListener) {
+ this.onCameraMoveStartedListener = onCameraMoveStartedListener;
+ }
+
+ void setOnCameraMoveCanceledListener(OnCameraMoveCanceledListener onCameraMoveCanceledListener) {
+ this.onCameraMoveCanceledListener = onCameraMoveCanceledListener;
+ }
+
+ void setOnCameraMoveListener(OnCameraMoveListener onCameraMoveListener) {
+ this.onCameraMoveListener = onCameraMoveListener;
+ }
+
+ void setOnCameraIdleListener(OnCameraIdleListener onCameraIdleListener) {
+ this.onCameraIdleListener = onCameraIdleListener;
+ }
+
+ @Override
+ public void onCameraMoveStarted(int reason) {
+ if (!idle) {
+ return;
+ }
+
+ idle = false;
+ if (onCameraMoveStartedListener != null) {
+ onCameraMoveStartedListener.onCameraMoveStarted(reason);
+ }
+ }
+
+ @Override
+ public void onCameraMove() {
+ if (onCameraMoveListener != null && !idle) {
+ onCameraMoveListener.onCameraMove();
+ }
+ }
+
+ @Override
+ public void onCameraMoveCanceled() {
+ if (onCameraMoveCanceledListener != null && !idle) {
+ onCameraMoveCanceledListener.onCameraMoveCanceled();
+ }
+ }
+
+ @Override
+ public void onCameraIdle() {
+ if (onCameraIdleListener != null && !idle) {
+ idle = true;
+ onCameraIdleListener.onCameraIdle();
+ }
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/FocalPointChangeListener.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/FocalPointChangeListener.java
index 006122a4e2..aec9a848b7 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/FocalPointChangeListener.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/FocalPointChangeListener.java
@@ -2,6 +2,9 @@ package com.mapbox.mapboxsdk.maps;
import android.graphics.PointF;
+/**
+ * Interface definition of a callback that is invoked when the focal point will change.
+ */
public interface FocalPointChangeListener {
void onFocalPointChanged(PointF pointF);
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java
index c9d81a88bc..9f4171aee8 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java
@@ -1,15 +1,14 @@
package com.mapbox.mapboxsdk.maps;
import android.graphics.Bitmap;
-import android.util.DisplayMetrics;
+import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.annotations.Icon;
import com.mapbox.mapboxsdk.annotations.IconFactory;
import com.mapbox.mapboxsdk.annotations.Marker;
import com.mapbox.mapboxsdk.annotations.MarkerView;
import com.mapbox.mapboxsdk.exceptions.IconBitmapChangedException;
-import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
@@ -41,118 +40,109 @@ class IconManager {
Icon loadIconForMarker(Marker marker) {
Icon icon = marker.getIcon();
-
- // calculating average before adding
- int iconSize = icons.size() + 1;
-
- // TODO replace former if case with anchor implementation,
- // current workaround for having extra pixels is diving height by 2
if (icon == null) {
- icon = IconFactory.getInstance(nativeMapView.getContext()).defaultMarker();
- Bitmap bitmap = icon.getBitmap();
- averageIconHeight = averageIconHeight + (bitmap.getHeight() / 2 - averageIconHeight) / iconSize;
- averageIconWidth = averageIconWidth + (bitmap.getWidth() - averageIconWidth) / iconSize;
- marker.setIcon(icon);
- } else {
- Bitmap bitmap = icon.getBitmap();
- averageIconHeight = averageIconHeight + (bitmap.getHeight() - averageIconHeight) / iconSize;
- averageIconWidth = averageIconWidth + (bitmap.getWidth() - averageIconWidth) / iconSize;
- }
-
- if (!icons.contains(icon)) {
- icons.add(icon);
- loadIcon(icon);
+ // TODO replace with anchor implementation, we are faking an anchor by adding extra pixels and diving height by 2
+ // TODO we can move this code afterwards to getIcon as with MarkerView.getIcon
+ icon = loadDefaultIconForMarker(marker);
} else {
- Icon oldIcon = icons.get(icons.indexOf(icon));
- if (!oldIcon.getBitmap().sameAs(icon.getBitmap())) {
- throw new IconBitmapChangedException();
- }
+ updateAverageIconSize(icon);
}
+ addIcon(icon);
return icon;
}
- Icon loadIconForMarkerView(MarkerView marker) {
+ void loadIconForMarkerView(MarkerView marker) {
Icon icon = marker.getIcon();
- int iconSize = icons.size() + 1;
- if (icon == null) {
- icon = IconFactory.getInstance(nativeMapView.getContext()).defaultMarkerView();
- marker.setIcon(icon);
- }
Bitmap bitmap = icon.getBitmap();
- averageIconHeight = averageIconHeight + (bitmap.getHeight() - averageIconHeight) / iconSize;
- averageIconWidth = averageIconWidth + (bitmap.getWidth() - averageIconWidth) / iconSize;
- if (!icons.contains(icon)) {
- icons.add(icon);
- } else {
- Icon oldIcon = icons.get(icons.indexOf(icon));
- if (!oldIcon.getBitmap().sameAs(icon.getBitmap())) {
- throw new IconBitmapChangedException();
- }
- }
- return icon;
+ updateAverageIconSize(bitmap);
+ addIcon(icon, false);
}
int getTopOffsetPixelsForIcon(Icon icon) {
return (int) (nativeMapView.getTopOffsetPixelsForAnnotationSymbol(icon.getId()) * nativeMapView.getPixelRatio());
}
- void loadIcon(Icon icon) {
+ int getAverageIconHeight() {
+ return averageIconHeight;
+ }
+
+ int getAverageIconWidth() {
+ return averageIconWidth;
+ }
+
+ private Icon loadDefaultIconForMarker(Marker marker) {
+ Icon icon = IconFactory.getInstance(Mapbox.getApplicationContext()).defaultMarker();
Bitmap bitmap = icon.getBitmap();
- String id = icon.getId();
- if (bitmap.getConfig() != Bitmap.Config.ARGB_8888) {
- bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, false);
- }
- ByteBuffer buffer = ByteBuffer.allocate(bitmap.getRowBytes() * bitmap.getHeight());
- bitmap.copyPixelsToBuffer(buffer);
+ updateAverageIconSize(bitmap.getWidth(), bitmap.getHeight() / 2);
+ marker.setIcon(icon);
+ return icon;
+ }
+
+ private void addIcon(Icon icon) {
+ addIcon(icon, true);
+ }
- float density = bitmap.getDensity();
- if (density == Bitmap.DENSITY_NONE) {
- density = DisplayMetrics.DENSITY_DEFAULT;
+ private void addIcon(Icon icon, boolean addIconToMap) {
+ if (!icons.contains(icon)) {
+ icons.add(icon);
+ if (addIconToMap) {
+ loadIcon(icon);
+ }
+ } else {
+ validateIconChanged(icon);
}
- float scale = density / DisplayMetrics.DENSITY_DEFAULT;
- nativeMapView.addAnnotationIcon(
- id,
+ }
+
+ private void updateAverageIconSize(Icon icon) {
+ updateAverageIconSize(icon.getBitmap());
+ }
+
+ private void updateAverageIconSize(Bitmap bitmap) {
+ updateAverageIconSize(bitmap.getWidth(), bitmap.getHeight());
+ }
+
+ private void updateAverageIconSize(int width, int height) {
+ int iconSize = icons.size() + 1;
+ averageIconHeight = averageIconHeight + (height - averageIconHeight) / iconSize;
+ averageIconWidth = averageIconWidth + (width - averageIconWidth) / iconSize;
+ }
+
+ private void loadIcon(Icon icon) {
+ Bitmap bitmap = icon.getBitmap();
+ nativeMapView.addAnnotationIcon(icon.getId(),
bitmap.getWidth(),
bitmap.getHeight(),
- scale, buffer.array());
+ icon.getScale(),
+ icon.toBytes());
}
void reloadIcons() {
- int count = icons.size();
- for (int i = 0; i < count; i++) {
- Icon icon = icons.get(i);
+ for (Icon icon : icons) {
loadIcon(icon);
}
}
+ private void validateIconChanged(Icon icon) {
+ Icon oldIcon = icons.get(icons.indexOf(icon));
+ if (!oldIcon.getBitmap().sameAs(icon.getBitmap())) {
+ throw new IconBitmapChangedException();
+ }
+ }
+
void ensureIconLoaded(Marker marker, MapboxMap mapboxMap) {
Icon icon = marker.getIcon();
if (icon == null) {
- icon = IconFactory.getInstance(nativeMapView.getContext()).defaultMarker();
- marker.setIcon(icon);
- }
- if (!icons.contains(icon)) {
- icons.add(icon);
- loadIcon(icon);
- } else {
- Icon oldIcon = icons.get(icons.indexOf(icon));
- if (!oldIcon.getBitmap().sameAs(icon.getBitmap())) {
- throw new IconBitmapChangedException();
- }
+ icon = loadDefaultIconForMarker(marker);
}
+ addIcon(icon);
+ setTopOffsetPixels(marker, mapboxMap, icon);
+ }
+ private void setTopOffsetPixels(Marker marker, MapboxMap mapboxMap, Icon icon) {
// this seems to be a costly operation according to the profiler so I'm trying to save some calls
Marker previousMarker = marker.getId() != -1 ? (Marker) mapboxMap.getAnnotation(marker.getId()) : null;
if (previousMarker == null || previousMarker.getIcon() == null || previousMarker.getIcon() != marker.getIcon()) {
marker.setTopOffsetPixels(getTopOffsetPixelsForIcon(icon));
}
}
-
- int getAverageIconHeight() {
- return averageIconHeight;
- }
-
- int getAverageIconWidth() {
- return averageIconWidth;
- }
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java
index 80fd6248bc..33e13c5ecc 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java
@@ -22,6 +22,8 @@ import com.mapbox.services.android.telemetry.MapboxTelemetry;
import com.mapbox.services.android.telemetry.utils.MathUtils;
import com.mapbox.services.android.telemetry.utils.TelemetryUtils;
+import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveStartedListener.REASON_API_GESTURE;
+
/**
* Manages gestures events on a MapView.
* <p>
@@ -35,6 +37,7 @@ final class MapGestureDetector {
private final UiSettings uiSettings;
private final TrackingSettings trackingSettings;
private final AnnotationManager annotationManager;
+ private final CameraChangeDispatcher cameraChangeDispatcher;
private final GestureDetectorCompat gestureDetector;
private final ScaleGestureDetector scaleGestureDetector;
@@ -56,12 +59,14 @@ final class MapGestureDetector {
private boolean scaleGestureOccurred = false;
MapGestureDetector(Context context, Transform transform, Projection projection, UiSettings uiSettings,
- TrackingSettings trackingSettings, AnnotationManager annotationManager) {
+ TrackingSettings trackingSettings, AnnotationManager annotationManager,
+ CameraChangeDispatcher cameraChangeDispatcher) {
this.annotationManager = annotationManager;
this.transform = transform;
this.projection = projection;
this.uiSettings = uiSettings;
this.trackingSettings = trackingSettings;
+ this.cameraChangeDispatcher = cameraChangeDispatcher;
// Touch gesture detectors
gestureDetector = new GestureDetectorCompat(context, new GestureListener());
@@ -187,6 +192,7 @@ final class MapGestureDetector {
MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapDragEndEvent(
getLocationFromGesture(event.getX(), event.getY()), transform));
scrollInProgress = false;
+ cameraChangeDispatcher.onCameraIdle();
}
twoTap = false;
@@ -273,6 +279,9 @@ final class MapGestureDetector {
break;
}
+ // notify camera change listener
+ cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE);
+
// Single finger double tap
if (focalPoint != null) {
// User provided focal point
@@ -337,6 +346,7 @@ final class MapGestureDetector {
// and ignore when a scale gesture has occurred
return false;
}
+ cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE);
float screenDensity = uiSettings.getPixelRatio();
@@ -362,9 +372,7 @@ final class MapGestureDetector {
long animationTime = (long) (velocityXY / 7 / tiltFactor + MapboxConstants.ANIMATION_DURATION_FLING_BASE);
// update transformation
- transform.setGestureInProgress(true);
transform.moveBy(offsetX, offsetY, animationTime);
- transform.setGestureInProgress(false);
if (onFlingListener != null) {
onFlingListener.onFling();
@@ -375,12 +383,6 @@ final class MapGestureDetector {
// Called for drags
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
- if (!scrollInProgress) {
- scrollInProgress = true;
- MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapClickEvent(
- getLocationFromGesture(e1.getX(), e1.getY()),
- MapboxEvent.GESTURE_PAN_START, transform));
- }
if (!trackingSettings.isScrollGestureCurrentlyEnabled()) {
return false;
}
@@ -389,10 +391,19 @@ final class MapGestureDetector {
return false;
}
+ if (!scrollInProgress) {
+ scrollInProgress = true;
+
+ // Cancel any animation
+ transform.cancelTransitions();
+ cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE);
+ MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapClickEvent(
+ getLocationFromGesture(e1.getX(), e1.getY()),
+ MapboxEvent.GESTURE_PAN_START, transform));
+ }
+
// reset tracking if needed
trackingSettings.resetTrackingModesIfRequired(true, false, false);
- // Cancel any animation
- transform.cancelTransitions();
// Scroll the map
transform.moveBy(-distanceX, -distanceY, 0 /*no duration*/);
@@ -446,6 +457,8 @@ final class MapGestureDetector {
// If scale is large enough ignore a tap
scaleFactor *= detector.getScaleFactor();
if ((scaleFactor > 1.05f) || (scaleFactor < 0.95f)) {
+ // notify camera change listener
+ cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE);
zoomStarted = true;
}
@@ -465,9 +478,6 @@ final class MapGestureDetector {
return false;
}
- // Cancel any animation
- transform.cancelTransitions();
-
// Gesture is a quickzoom if there aren't two fingers
quickZoom = !twoTap;
@@ -512,6 +522,9 @@ final class MapGestureDetector {
return false;
}
+ // notify camera change listener
+ cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE);
+
beginTime = detector.getEventTime();
MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapClickEvent(
getLocationFromGesture(detector.getFocusX(), detector.getFocusY()),
@@ -522,6 +535,7 @@ final class MapGestureDetector {
// Called when the fingers leave the screen
@Override
public void onRotateEnd(RotateGestureDetector detector) {
+ // notify camera change listener
beginTime = 0;
totalAngle = 0.0f;
started = false;
@@ -553,13 +567,8 @@ final class MapGestureDetector {
if (!started) {
return false;
}
-
- // Cancel any animation
- transform.cancelTransitions();
-
// rotation constitutes translation of anything except the center of
// rotation, so cancel both location and bearing tracking if required
-
trackingSettings.resetTrackingModesIfRequired(true, true, false);
// Get rotate value
@@ -593,6 +602,8 @@ final class MapGestureDetector {
return false;
}
+ // notify camera change listener
+ cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE);
beginTime = detector.getEventTime();
MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapClickEvent(
getLocationFromGesture(detector.getFocusX(), detector.getFocusY()),
@@ -633,9 +644,6 @@ final class MapGestureDetector {
return false;
}
- // Cancel any animation
- transform.cancelTransitions();
-
// Get tilt value (scale and clamp)
double pitch = transform.getTilt();
pitch -= 0.1 * detector.getShovePixelsDelta();
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 4f90b0a8fe..cf1841e180 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
@@ -131,6 +131,9 @@ public class MapView extends FrameLayout {
// callback for zooming in the camera
CameraZoomInvalidator zoomInvalidator = new CameraZoomInvalidator();
+ // callback for camera change events
+ CameraChangeDispatcher cameraChangeDispatcher = new CameraChangeDispatcher();
+
// setup components for MapboxMap creation
Projection proj = new Projection(nativeMapView);
UiSettings uiSettings = new UiSettings(proj, focalPoint, compassView, attrView, view.findViewById(R.id.logoView));
@@ -145,13 +148,14 @@ public class MapView extends FrameLayout {
Polylines polylines = new PolylineContainer(nativeMapView, annotationsArray);
AnnotationManager annotationManager = new AnnotationManager(nativeMapView, this, annotationsArray,
markerViewManager, iconManager, annotations, markers, polygons, polylines);
- Transform transform = new Transform(nativeMapView, annotationManager.getMarkerViewManager(), trackingSettings);
+ Transform transform = new Transform(nativeMapView, annotationManager.getMarkerViewManager(), trackingSettings,
+ cameraChangeDispatcher);
mapboxMap = new MapboxMap(nativeMapView, transform, uiSettings, trackingSettings, myLocationViewSettings, proj,
- registerTouchListener, annotationManager);
+ registerTouchListener, annotationManager, cameraChangeDispatcher);
// user input
mapGestureDetector = new MapGestureDetector(context, transform, proj, uiSettings, trackingSettings,
- annotationManager);
+ annotationManager, cameraChangeDispatcher);
mapKeyListener = new MapKeyListener(transform, trackingSettings, uiSettings);
MapZoomControllerListener zoomListener = new MapZoomControllerListener(mapGestureDetector, uiSettings, transform);
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 5f1ed0755c..f60ddf616a 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
@@ -41,6 +41,7 @@ import com.mapbox.mapboxsdk.location.LocationSource;
import com.mapbox.mapboxsdk.maps.widgets.MyLocationViewSettings;
import com.mapbox.mapboxsdk.style.layers.Filter;
import com.mapbox.mapboxsdk.style.layers.Layer;
+import com.mapbox.mapboxsdk.style.light.Light;
import com.mapbox.mapboxsdk.style.sources.Source;
import com.mapbox.services.android.telemetry.location.LocationEngine;
import com.mapbox.services.commons.geojson.Feature;
@@ -69,6 +70,7 @@ public final class MapboxMap {
private final Transform transform;
private final AnnotationManager annotationManager;
private final MyLocationViewSettings myLocationViewSettings;
+ private final CameraChangeDispatcher cameraChangeDispatcher;
private final OnRegisterTouchListener onRegisterTouchListener;
@@ -76,7 +78,7 @@ public final class MapboxMap {
MapboxMap(NativeMapView map, Transform transform, UiSettings ui, TrackingSettings tracking,
MyLocationViewSettings myLocationView, Projection projection, OnRegisterTouchListener listener,
- AnnotationManager annotations) {
+ AnnotationManager annotations, CameraChangeDispatcher cameraChangeDispatcher) {
this.nativeMapView = map;
this.uiSettings = ui;
this.trackingSettings = tracking;
@@ -85,6 +87,7 @@ public final class MapboxMap {
this.annotationManager = annotations.bind(this);
this.transform = transform;
this.onRegisterTouchListener = listener;
+ this.cameraChangeDispatcher = cameraChangeDispatcher;
}
void initialise(@NonNull Context context, @NonNull MapboxMapOptions options) {
@@ -566,6 +569,20 @@ public final class MapboxMap {
}
//
+ //
+ //
+
+ /**
+ * Get the global light source used to change lighting conditions on extruded fill layers.
+ *
+ * @return the global light source
+ */
+ @Nullable
+ public Light getLight() {
+ return nativeMapView.getLight();
+ }
+
+ //
// Camera API
//
@@ -1623,11 +1640,52 @@ public final class MapboxMap {
* To unset the callback, use null.
*/
@UiThread
+ @Deprecated
public void setOnCameraChangeListener(@Nullable OnCameraChangeListener listener) {
transform.setOnCameraChangeListener(listener);
}
/**
+ * Sets a callback that is invoked when camera movement has ended.
+ *
+ * @param listener the listener to notify
+ */
+ @UiThread
+ public void setOnCameraIdleListener(@Nullable OnCameraIdleListener listener) {
+ cameraChangeDispatcher.setOnCameraIdleListener(listener);
+ }
+
+ /**
+ * Sets a callback that is invoked when camera movement was cancelled.
+ *
+ * @param listener the listener to notify
+ */
+ @UiThread
+ public void setOnCameraMoveCancelListener(@Nullable OnCameraMoveCanceledListener listener) {
+ cameraChangeDispatcher.setOnCameraMoveCanceledListener(listener);
+ }
+
+ /**
+ * Sets a callback that is invoked when camera movement has started.
+ *
+ * @param listener the listener to notify
+ */
+ @UiThread
+ public void setOnCameraMoveStartedistener(@Nullable OnCameraMoveStartedListener listener) {
+ cameraChangeDispatcher.setOnCameraMoveStartedListener(listener);
+ }
+
+ /**
+ * Sets a callback that is invoked when camera position changes.
+ *
+ * @param listener the listener to notify
+ */
+ @UiThread
+ public void setOnCameraMoveListener(@Nullable OnCameraMoveListener listener) {
+ cameraChangeDispatcher.setOnCameraMoveListener(listener);
+ }
+
+ /**
* Sets a callback that's invoked on every frame rendered to the map view.
*
* @param listener The callback that's invoked on every frame rendered to the map view.
@@ -1941,7 +1999,12 @@ public final class MapboxMap {
/**
* Interface definition for a callback to be invoked when the camera changes position.
+ *
+ * @deprecated Replaced by {@link MapboxMap.OnCameraMoveStartedListener}, {@link MapboxMap.OnCameraMoveListener} and
+ * {@link MapboxMap.OnCameraIdleListener}. The order in which the deprecated onCameraChange method will be called in
+ * relation to the methods in the new camera change listeners is undefined.
*/
+ @Deprecated
public interface OnCameraChangeListener {
/**
* Called after the camera position has changed. During an animation,
@@ -1954,6 +2017,56 @@ public final class MapboxMap {
}
/**
+ * Interface definition for a callback to be invoked for when the camera motion starts.
+ */
+ public interface OnCameraMoveStartedListener {
+ int REASON_API_GESTURE = 1;
+ int REASON_DEVELOPER_ANIMATION = 2;
+ int REASON_API_ANIMATION = 3;
+
+ /**
+ * Called when the camera starts moving after it has been idle or when the reason for camera motion has changed.
+ *
+ * @param reason the reason for the camera change
+ */
+ void onCameraMoveStarted(int reason);
+ }
+
+ /**
+ * Interface definition for a callback to be invoked for when the camera changes position.
+ */
+ public interface OnCameraMoveListener {
+ /**
+ * Called repeatedly as the camera continues to move after an onCameraMoveStarted call.
+ * This may be called as often as once every frame and should not perform expensive operations.
+ */
+ void onCameraMove();
+ }
+
+ /**
+ * Interface definition for a callback to be invoked for when the camera's motion has been stopped or when the camera
+ * starts moving for a new reason.
+ */
+ public interface OnCameraMoveCanceledListener {
+ /**
+ * Called when the developer explicitly calls the cancelTransitions() method or if the reason for camera motion has
+ * changed before the onCameraIdle had a chance to fire after the previous animation.
+ * Do not update or animate the camera from within this method.
+ */
+ void onCameraMoveCanceled();
+ }
+
+ /**
+ * Interface definition for a callback to be invoked for when camera movement has ended.
+ */
+ public interface OnCameraIdleListener {
+ /**
+ * Called when camera movement has ended.
+ */
+ void onCameraIdle();
+ }
+
+ /**
* Interface definition for a callback to be invoked when a frame is rendered to the map view.
*
* @see MapboxMap#setOnFpsChangedListener(OnFpsChangedListener)
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 68603ab1a3..98f94ddb39 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
@@ -36,7 +36,7 @@ import java.util.Arrays;
public class MapboxMapOptions implements Parcelable {
private static final float FOUR_DP = 4f;
- private static final float EIGHTY_NINE_DP = 92f;
+ private static final float NINETY_TWO_DP = 92f;
private CameraPosition cameraPosition;
@@ -241,7 +241,7 @@ public class MapboxMapOptions implements Parcelable {
R.styleable.mapbox_MapView_mapbox_uiAttributionGravity, Gravity.BOTTOM));
mapboxMapOptions.attributionMargins(new int[] {
(int) (typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_uiAttributionMarginLeft,
- EIGHTY_NINE_DP * pxlRatio)),
+ NINETY_TWO_DP * pxlRatio)),
(int) (typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_uiAttributionMarginTop,
FOUR_DP * pxlRatio)),
(int) (typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_uiAttributionMarginRight,
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 ae4a8ee8d2..6d9df8aebd 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
@@ -27,6 +27,7 @@ import com.mapbox.mapboxsdk.storage.FileSource;
import com.mapbox.mapboxsdk.style.layers.CannotAddLayerException;
import com.mapbox.mapboxsdk.style.layers.Filter;
import com.mapbox.mapboxsdk.style.layers.Layer;
+import com.mapbox.mapboxsdk.style.light.Light;
import com.mapbox.mapboxsdk.style.sources.CannotAddSourceException;
import com.mapbox.mapboxsdk.style.sources.Source;
import com.mapbox.services.commons.geojson.Feature;
@@ -617,7 +618,7 @@ final class NativeMapView {
if (isDestroyedOn("getMetersPerPixelAtLatitude")) {
return 0;
}
- return nativeGetMetersPerPixelAtLatitude(lat, getZoom());
+ return nativeGetMetersPerPixelAtLatitude(lat, getZoom()) / pixelRatio;
}
public ProjectedMeters projectedMetersForLatLng(LatLng latLng) {
@@ -882,12 +883,15 @@ final class NativeMapView {
fileSource.setApiBaseUrl(baseUrl);
}
- public float getPixelRatio() {
- return pixelRatio;
+ public Light getLight() {
+ if (isDestroyedOn("getLight")) {
+ return null;
+ }
+ return nativeGetLight();
}
- public Context getContext() {
- return mapView.getContext();
+ public float getPixelRatio() {
+ return pixelRatio;
}
//
@@ -1117,6 +1121,8 @@ final class NativeMapView {
String[] layerIds,
Object[] filter);
+ private native Light nativeGetLight();
+
int getWidth() {
if (isDestroyedOn("")) {
return 0;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java
index 09213934ae..7dcd84de75 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java
@@ -282,8 +282,10 @@ public final class TrackingSettings {
*/
void resetTrackingModesIfRequired(CameraPosition currentCameraPosition, CameraPosition targetCameraPosition,
boolean isFromLocation) {
- resetTrackingModesIfRequired(!currentCameraPosition.target.equals(targetCameraPosition.target), false,
- isFromLocation);
+ if (currentCameraPosition.target != null) {
+ resetTrackingModesIfRequired(!currentCameraPosition.target.equals(targetCameraPosition.target), false,
+ isFromLocation);
+ }
}
Location getMyLocation() {
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 507bec270d..7f44e0de07 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
@@ -16,6 +16,7 @@ import com.mapbox.mapboxsdk.maps.widgets.MyLocationView;
import timber.log.Timber;
import static com.mapbox.mapboxsdk.maps.MapView.REGION_DID_CHANGE_ANIMATED;
+import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveStartedListener;
/**
* Resembles the current Map transformation.
@@ -33,13 +34,18 @@ final class Transform implements MapView.OnMapChangedListener {
private CameraPosition cameraPosition;
private MapboxMap.CancelableCallback cameraCancelableCallback;
+
private MapboxMap.OnCameraChangeListener onCameraChangeListener;
- Transform(NativeMapView mapView, MarkerViewManager markerViewManager, TrackingSettings trackingSettings) {
+ private CameraChangeDispatcher cameraChangeDispatcher;
+
+ Transform(NativeMapView mapView, MarkerViewManager markerViewManager, TrackingSettings trackingSettings,
+ CameraChangeDispatcher cameraChangeDispatcher) {
this.mapView = mapView;
this.markerViewManager = markerViewManager;
this.trackingSettings = trackingSettings;
this.myLocationView = trackingSettings.getMyLocationView();
+ this.cameraChangeDispatcher = cameraChangeDispatcher;
}
void initialise(@NonNull MapboxMap mapboxMap, @NonNull MapboxMapOptions options) {
@@ -79,6 +85,7 @@ final class Transform implements MapView.OnMapChangedListener {
cameraCancelableCallback.onFinish();
cameraCancelableCallback = null;
}
+ cameraChangeDispatcher.onCameraIdle();
mapView.removeOnMapChangedListener(this);
}
}
@@ -89,10 +96,12 @@ final class Transform implements MapView.OnMapChangedListener {
if (!cameraPosition.equals(this.cameraPosition)) {
trackingSettings.resetTrackingModesIfRequired(this.cameraPosition, cameraPosition, false);
cancelTransitions();
+ cameraChangeDispatcher.onCameraMoveStarted(OnCameraMoveStartedListener.REASON_API_ANIMATION);
mapView.jumpTo(cameraPosition.bearing, cameraPosition.target, cameraPosition.tilt, cameraPosition.zoom);
if (callback != null) {
callback.onFinish();
}
+ cameraChangeDispatcher.onCameraIdle();
}
}
@@ -103,6 +112,8 @@ final class Transform implements MapView.OnMapChangedListener {
if (!cameraPosition.equals(this.cameraPosition)) {
trackingSettings.resetTrackingModesIfRequired(this.cameraPosition, cameraPosition, isDismissable);
cancelTransitions();
+ cameraChangeDispatcher.onCameraMoveStarted(OnCameraMoveStartedListener.REASON_API_ANIMATION);
+
if (callback != null) {
cameraCancelableCallback = callback;
mapView.addOnMapChangedListener(this);
@@ -118,8 +129,9 @@ final class Transform implements MapView.OnMapChangedListener {
CameraPosition cameraPosition = update.getCameraPosition(mapboxMap);
if (!cameraPosition.equals(this.cameraPosition)) {
trackingSettings.resetTrackingModesIfRequired(this.cameraPosition, cameraPosition, false);
-
cancelTransitions();
+ cameraChangeDispatcher.onCameraMoveStarted(OnCameraMoveStartedListener.REASON_API_ANIMATION);
+
if (callback != null) {
cameraCancelableCallback = callback;
mapView.addOnMapChangedListener(this);
@@ -134,7 +146,12 @@ final class Transform implements MapView.OnMapChangedListener {
@Nullable
CameraPosition invalidateCameraPosition() {
if (mapView != null) {
- cameraPosition = mapView.getCameraPosition();
+ CameraPosition cameraPosition = mapView.getCameraPosition();
+ if (this.cameraPosition != null && !this.cameraPosition.equals(cameraPosition)) {
+ cameraChangeDispatcher.onCameraMove();
+ }
+
+ this.cameraPosition = cameraPosition;
if (onCameraChangeListener != null) {
onCameraChangeListener.onCameraChange(this.cameraPosition);
}
@@ -143,10 +160,17 @@ final class Transform implements MapView.OnMapChangedListener {
}
void cancelTransitions() {
+ // notify user about cancel
+ cameraChangeDispatcher.onCameraMoveCanceled();
+
+ // notify animateCamera and easeCamera about cancelling
if (cameraCancelableCallback != null) {
+ cameraChangeDispatcher.onCameraIdle();
cameraCancelableCallback.onCancel();
cameraCancelableCallback = null;
}
+
+ // cancel ongoing transitions
mapView.cancelTransitions();
}
@@ -156,6 +180,10 @@ final class Transform implements MapView.OnMapChangedListener {
mapView.resetNorth();
}
+ //
+ // Camera change listener API
+ //
+
void setOnCameraChangeListener(@Nullable MapboxMap.OnCameraChangeListener listener) {
this.onCameraChangeListener = listener;
}
@@ -171,9 +199,6 @@ final class Transform implements MapView.OnMapChangedListener {
}
void zoom(boolean zoomIn, @NonNull PointF focalPoint) {
- // Cancel any animation
- cancelTransitions();
-
CameraPosition cameraPosition = invalidateCameraPosition();
if (cameraPosition != null) {
int newZoom = (int) Math.round(cameraPosition.zoom + (zoomIn ? 1 : -1));
@@ -186,6 +211,15 @@ final class Transform implements MapView.OnMapChangedListener {
}
void setZoom(double zoom, @NonNull PointF focalPoint, long duration) {
+ mapView.addOnMapChangedListener(new MapView.OnMapChangedListener() {
+ @Override
+ public void onMapChanged(int change) {
+ if (change == MapView.REGION_DID_CHANGE_ANIMATED) {
+ mapView.removeOnMapChangedListener(this);
+ cameraChangeDispatcher.onCameraIdle();
+ }
+ }
+ });
mapView.setZoom(zoom, focalPoint, duration);
}
@@ -277,6 +311,17 @@ final class Transform implements MapView.OnMapChangedListener {
}
void moveBy(double offsetX, double offsetY, long duration) {
+ if (duration > 0) {
+ mapView.addOnMapChangedListener(new MapView.OnMapChangedListener() {
+ @Override
+ public void onMapChanged(int change) {
+ if (change == MapView.DID_FINISH_RENDERING_MAP_FULLY_RENDERED) {
+ mapView.removeOnMapChangedListener(this);
+ cameraChangeDispatcher.onCameraIdle();
+ }
+ }
+ });
+ }
mapView.moveBy(offsetX, offsetY, duration);
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java
index 1bcf8a70b9..5f7b6c571b 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
@@ -193,12 +193,16 @@ public final class UiSettings {
private void initialiseLogo(MapboxMapOptions options, Resources resources) {
setLogoEnabled(options.getLogoEnabled());
setLogoGravity(options.getLogoGravity());
- int[] logoMargins = options.getLogoMargins();
+ setLogoMargins(resources, options.getLogoMargins());
+ }
+
+ private void setLogoMargins(Resources resources, int[] logoMargins) {
if (logoMargins != null) {
setLogoMargins(logoMargins[0], logoMargins[1], logoMargins[2], logoMargins[3]);
} else {
- int twoDp = (int) resources.getDimension(R.dimen.mapbox_two_dp);
- setLogoMargins(twoDp, twoDp, twoDp, twoDp);
+ // user did not specify margins when programmatically creating a map
+ int fourDp = (int) resources.getDimension(R.dimen.mapbox_four_dp);
+ setLogoMargins(fourDp, fourDp, fourDp, fourDp);
}
}
@@ -223,15 +227,23 @@ public final class UiSettings {
private void initialiseAttribution(Context context, MapboxMapOptions options) {
setAttributionEnabled(options.getAttributionEnabled());
setAttributionGravity(options.getAttributionGravity());
- int[] attributionMargins = options.getAttributionMargins();
+ setAttributionMargins(context, options.getAttributionMargins());
+ int attributionTintColor = options.getAttributionTintColor();
+ setAttributionTintColor(attributionTintColor != -1
+ ? attributionTintColor : ColorUtils.getPrimaryColor(context));
+ }
+
+ private void setAttributionMargins(Context context, int[] attributionMargins) {
if (attributionMargins != null) {
setAttributionMargins(attributionMargins[0], attributionMargins[1],
attributionMargins[2], attributionMargins[3]);
+ } else {
+ // user did not specify margins when programmatically creating a map
+ Resources resources = context.getResources();
+ int margin = (int) resources.getDimension(R.dimen.mapbox_four_dp);
+ int leftMargin = (int) resources.getDimension(R.dimen.mapbox_ninety_two_dp);
+ setAttributionMargins(leftMargin, margin, margin, margin);
}
-
- int attributionTintColor = options.getAttributionTintColor();
- setAttributionTintColor(attributionTintColor != -1
- ? attributionTintColor : ColorUtils.getPrimaryColor(context));
}
private void saveAttribution(Bundle outState) {
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java
index db2a335453..f5ef46a5d3 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java
@@ -440,6 +440,7 @@ public class MyLocationView extends View {
} else {
// Disable location and user dot
location = null;
+ locationSource.removeLocationUpdates();
locationSource.removeLocationEngineListener(userLocationListener);
locationSource.deactivate();
}
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 50ae6716e6..ce498da8f5 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
@@ -47,7 +47,7 @@ public class OfflineManager {
/**
* This callback receives an asynchronous response containing a list of all
- * {@link OfflineRegion} in the database, or an error message otherwise.
+ * OfflineRegion in the database or an error message otherwise.
*/
public interface ListOfflineRegionsCallback {
/**
@@ -67,7 +67,7 @@ public class OfflineManager {
/**
* This callback receives an asynchronous response containing the newly created
- * {@link OfflineRegion} in the database, or an error message otherwise.
+ * OfflineRegion in the database or an error message otherwise.
*/
public interface CreateOfflineRegionCallback {
/**
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java
index 5ed6579e1c..fae53c2086 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java
@@ -4,6 +4,7 @@ import android.os.Handler;
import android.os.Looper;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import com.mapbox.mapboxsdk.LibraryLoader;
import com.mapbox.mapboxsdk.storage.FileSource;
@@ -37,6 +38,9 @@ public class OfflineRegion {
//Region id
private long id;
+ // delete status
+ private boolean isDeleted;
+
private OfflineRegionDefinition definition;
/**
@@ -95,7 +99,7 @@ public class OfflineRegion {
}
/**
- * This callback receives an asynchronous response containing the {@link OfflineRegionStatus}
+ * This callback receives an asynchronous response containing the OfflineRegionStatus
* of the offline region, or a {@link String} error message otherwise.
*/
public interface OfflineRegionStatusCallback {
@@ -248,7 +252,7 @@ public class OfflineRegion {
*
* @param observer the observer to be notified
*/
- public void setObserver(@NonNull final OfflineRegionObserver observer) {
+ public void setObserver(@Nullable final OfflineRegionObserver observer) {
setOfflineRegionObserver(new OfflineRegionObserver() {
@Override
public void onStatusChanged(final OfflineRegionStatus status) {
@@ -256,7 +260,9 @@ public class OfflineRegion {
getHandler().post(new Runnable() {
@Override
public void run() {
- observer.onStatusChanged(status);
+ if (observer != null) {
+ observer.onStatusChanged(status);
+ }
}
});
}
@@ -268,7 +274,9 @@ public class OfflineRegion {
getHandler().post(new Runnable() {
@Override
public void run() {
- observer.onError(error);
+ if (observer != null) {
+ observer.onError(error);
+ }
}
});
}
@@ -280,7 +288,9 @@ public class OfflineRegion {
getHandler().post(new Runnable() {
@Override
public void run() {
- observer.mapboxTileCountLimitExceeded(limit);
+ if (observer != null) {
+ observer.mapboxTileCountLimitExceeded(limit);
+ }
}
});
}
@@ -347,28 +357,31 @@ public class OfflineRegion {
* @param callback the callback to be invoked
*/
public void delete(@NonNull final OfflineRegionDeleteCallback callback) {
- deleteOfflineRegion(new OfflineRegionDeleteCallback() {
- @Override
- public void onDelete() {
- getHandler().post(new Runnable() {
- @Override
- public void run() {
- callback.onDelete();
- OfflineRegion.this.finalize();
- }
- });
- }
+ if (!isDeleted) {
+ deleteOfflineRegion(new OfflineRegionDeleteCallback() {
+ @Override
+ public void onDelete() {
+ isDeleted = true;
+ getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ callback.onDelete();
+ OfflineRegion.this.finalize();
+ }
+ });
+ }
- @Override
- public void onError(final String error) {
- getHandler().post(new Runnable() {
- @Override
- public void run() {
- callback.onError(error);
- }
- });
- }
- });
+ @Override
+ public void onError(final String error) {
+ getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ callback.onError(error);
+ }
+ });
+ }
+ });
+ }
}
/**
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/Resource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/Resource.java
index af98a46a9b..eae83e8c1f 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/Resource.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/Resource.java
@@ -5,9 +5,15 @@ import android.support.annotation.IntDef;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+/**
+ * Resource provides access to resource types.
+ */
public final class Resource {
// Note: Keep this in sync with include/mbgl/storage/resource.hpp
+ /**
+ * Resource type variants.
+ */
@IntDef( {UNKNOWN, STYLE, SOURCE, TILE, GLYPHS, SPRITE_IMAGE, SPRITE_JSON})
@Retention(RetentionPolicy.SOURCE)
public @interface Kind {
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/CompositeFunction.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/CompositeFunction.java
index 8ded7ecd34..15e4474105 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/CompositeFunction.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/CompositeFunction.java
@@ -13,7 +13,7 @@ import com.mapbox.mapboxsdk.style.layers.PropertyValue;
import java.util.Map;
/**
- * Composite functions combine {@link android.graphics.Camera} and {@link SourceFunction}s.
+ * Composite functions combine Camera and SourceFunctions.
* <p>
* Composite functions allow the appearance of a map feature to change with both its
* properties and zoom. Each stop is an array with two elements, the first is an object
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Filter.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Filter.java
index 643a126388..4dbb461e4c 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Filter.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Filter.java
@@ -11,7 +11,7 @@ import java.util.Collections;
public class Filter {
/**
- * Base {@link Filter} statement. Subclassed to provide concrete statements.
+ * Base Filter statement. Subclassed to provide concrete statements.
*/
public abstract static class Statement {
protected final String operator;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java
index 48e0ec5de3..5e345268f9 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java
@@ -467,6 +467,27 @@ public final class Property {
@Retention(RetentionPolicy.SOURCE)
public @interface FILL_EXTRUSION_TRANSLATE_ANCHOR {}
+ // ANCHOR: Whether extruded geometries are lit relative to the map or viewport.
+
+ /**
+ * The position of the light source is aligned to the rotation of the map.
+ */
+ public static final String ANCHOR_MAP = "map";
+ /**
+ * The position of the light source is aligned to the rotation of the viewport.
+ */
+ public static final String ANCHOR_VIEWPORT = "viewport";
+
+ /**
+ * Whether extruded geometries are lit relative to the map or viewport.
+ */
+ @StringDef({
+ ANCHOR_MAP,
+ ANCHOR_VIEWPORT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ANCHOR {}
+
private Property() {
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/TransitionOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/TransitionOptions.java
index a46c11b35c..6e6e4ca613 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/TransitionOptions.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/TransitionOptions.java
@@ -1,23 +1,51 @@
package com.mapbox.mapboxsdk.style.layers;
+/**
+ * Resembles transition property from the style specification.
+ *
+ * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#transition">Transition documentation</a>
+ */
public class TransitionOptions {
private long duration;
private long delay;
+ /**
+ * Create a transition property based on duration and a delay.
+ *
+ * @param duration the duration of the transition
+ * @param delay the delay to start the transition
+ */
public TransitionOptions(long duration, long delay) {
this.duration = duration;
this.delay = delay;
}
+ /**
+ * Create a transition property based on duration and a delay.
+ *
+ * @param duration the duration of the transition
+ * @param delay the delay to start the transition
+ * @return a new transition property object
+ */
public static TransitionOptions fromTransitionOptions(long duration, long delay) {
return new TransitionOptions(duration, delay);
}
+ /**
+ * Get the transition duration.
+ *
+ * @return the transition duration
+ */
public long getDuration() {
return duration;
}
+ /**
+ * Get the transition delay.
+ *
+ * @return the transition delay
+ */
public long getDelay() {
return delay;
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java
new file mode 100644
index 0000000000..b66a50b8a4
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java
@@ -0,0 +1,181 @@
+// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
+
+package com.mapbox.mapboxsdk.style.light;
+
+import android.support.annotation.ColorInt;
+import android.support.annotation.NonNull;
+import android.support.annotation.UiThread;
+
+import com.mapbox.mapboxsdk.style.layers.Property;
+import com.mapbox.mapboxsdk.style.layers.PropertyFactory;
+import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
+
+/**
+ * The global light source.
+ *
+ * @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#light>">The online documentation</a>
+ */
+@UiThread
+public class Light {
+
+ private long nativePtr;
+
+ /**
+ * Creates a Light.
+ *
+ * @param nativePtr pointer used by core
+ */
+ public Light(long nativePtr) {
+ this.nativePtr = nativePtr;
+ }
+
+ /**
+ * Set the Anchor property. Whether extruded geometries are lit relative to the map or viewport.
+ *
+ * @param anchor as String
+ */
+ public void setAnchor(@Property.ANCHOR String anchor) {
+ nativeSetAnchor(anchor);
+ }
+
+ /**
+ * Get the Anchor property. Whether extruded geometries are lit relative to the map or viewport.
+ *
+ * @return anchor as String
+ */
+ @Property.ANCHOR public String getAnchor() {
+ return nativeGetAnchor();
+ }
+
+ /**
+ * Set the Position property. Position of the light source relative to lit (extruded) geometries, in [r radial coordinate, a azimuthal angle, p polar angle] where r indicates the distance from the center of the base of an object to its light, a indicates the position of the light relative to 0° (0° when `light.anchor` is set to `viewport` corresponds to the top of the viewport, or 0° when `light.anchor` is set to `map` corresponds to due north, and degrees proceed clockwise), and p indicates the height of the light (from 0°, directly above, to 180°, directly below).
+ *
+ * @param position of the light
+ */
+ public void setPosition(@NonNull Position position) {
+ nativeSetPosition(position);
+ }
+
+ /**
+ * Get the Position property. Position of the light source relative to lit (extruded) geometries, in [r radial coordinate, a azimuthal angle, p polar angle] where r indicates the distance from the center of the base of an object to its light, a indicates the position of the light relative to 0° (0° when `light.anchor` is set to `viewport` corresponds to the top of the viewport, or 0° when `light.anchor` is set to `map` corresponds to due north, and degrees proceed clockwise), and p indicates the height of the light (from 0°, directly above, to 180°, directly below).
+ *
+ * @return position as Position
+ */
+ public Position getPosition() {
+ return nativeGetPosition();
+ }
+
+ /**
+ * Get the Position property transition options.
+ *
+ * @return transition options for position
+ */
+ public TransitionOptions getPositionTransition() {
+ return nativeGetPositionTransition();
+ }
+
+ /**
+ * Set the Position property transition options.
+ *
+ * @param options transition options for position
+ */
+ public void setPositionTransition(TransitionOptions options) {
+ nativeSetPositionTransition(options.getDuration(), options.getDelay());
+ }
+
+ /**
+ * Set the Color property. Color tint for lighting extruded geometries.
+ *
+ * @param color as int
+ */
+ public void setColor(@ColorInt int color) {
+ nativeSetColor(PropertyFactory.colorToRgbaString(color));
+ }
+
+ /**
+ * Set the Color property. Color tint for lighting extruded geometries.
+ *
+ * @param color as String
+ */
+ public void setColor(String color) {
+ nativeSetColor(color);
+ }
+
+ /**
+ * Get the Color property. Color tint for lighting extruded geometries.
+ *
+ * @return color as String
+ */
+ public String getColor() {
+ return nativeGetColor();
+ }
+
+ /**
+ * Get the Color property transition options.
+ *
+ * @return transition options for color
+ */
+ public TransitionOptions getColorTransition() {
+ return nativeGetColorTransition();
+ }
+
+ /**
+ * Set the Color property transition options.
+ *
+ * @param options transition options for color
+ */
+ public void setColorTransition(TransitionOptions options) {
+ nativeSetColorTransition(options.getDuration(), options.getDelay());
+ }
+
+ /**
+ * Set the Intensity property. Intensity of lighting (on a scale from 0 to 1). Higher numbers will present as more extreme contrast.
+ *
+ * @param intensity as Float
+ */
+ public void setIntensity(float intensity) {
+ nativeSetIntensity(intensity);
+ }
+
+ /**
+ * Get the Intensity property. Intensity of lighting (on a scale from 0 to 1). Higher numbers will present as more extreme contrast.
+ *
+ * @return intensity as Float
+ */
+ public float getIntensity() {
+ return nativeGetIntensity();
+ }
+
+ /**
+ * Get the Intensity property transition options.
+ *
+ * @return transition options for intensity
+ */
+ public TransitionOptions getIntensityTransition() {
+ return nativeGetIntensityTransition();
+ }
+
+ /**
+ * Set the Intensity property transition options.
+ *
+ * @param options transition options for intensity
+ */
+ public void setIntensityTransition(TransitionOptions options) {
+ nativeSetIntensityTransition(options.getDuration(), options.getDelay());
+ }
+
+ private native void nativeSetAnchor(String anchor);
+ private native String nativeGetAnchor();
+ private native void nativeSetPosition(Position position);
+ private native Position nativeGetPosition();
+ private native TransitionOptions nativeGetPositionTransition();
+ private native void nativeSetPositionTransition(long duration, long delay);
+ private native void nativeSetColor(String color);
+ private native String nativeGetColor();
+ private native TransitionOptions nativeGetColorTransition();
+ private native void nativeSetColorTransition(long duration, long delay);
+ private native void nativeSetIntensity(float intensity);
+ private native float nativeGetIntensity();
+ private native TransitionOptions nativeGetIntensityTransition();
+ private native void nativeSetIntensityTransition(long duration, long delay);
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Position.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Position.java
new file mode 100644
index 0000000000..215db03ad2
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Position.java
@@ -0,0 +1,81 @@
+package com.mapbox.mapboxsdk.style.light;
+
+/**
+ * Position of the light source relative to lit (extruded) geometries.
+ * <p>
+ * The position is constructed out of a radial coordinate, an azimuthal angle and a polar angle.
+ * where the radial coordinate indicates the distance from the center of the base of an object to its light, the
+ * azimuthal angle indicates the position of the light relative to 0° (0° when
+ * {@link com.mapbox.mapboxsdk.style.layers.Property.ANCHOR} is set to viewport corresponds to the top of the
+ * viewport, or 0° when {@link com.mapbox.mapboxsdk.style.layers.Property.ANCHOR} is set to map corresponds to due
+ * north, and degrees proceed clockwise), and polar indicates the height of the light
+ * (from 0°, directly above, to 180°, directly below).
+ */
+public class Position {
+
+ private float radialCoordinate;
+ private float azimuthalAngle;
+ private float polarAngle;
+
+ /**
+ * Creates a Position from a radial coordinate, an azimuthal angle & a polar angle.
+ *
+ * @param radialCoordinate the distance from the center of the base of an object to its light
+ * @param azimuthalAngle the position of the light relative to 0°
+ * @param polarAngle the height of the light
+ */
+ public Position(float radialCoordinate, float azimuthalAngle, float polarAngle) {
+ this.radialCoordinate = radialCoordinate;
+ this.azimuthalAngle = azimuthalAngle;
+ this.polarAngle = polarAngle;
+ }
+
+ /**
+ * Returns a Position from a radial coordinate, an azimuthal angle & a polar angle
+ *
+ * @param radialCoordinate the radial coordinate
+ * @param azimuthalAngle the azimuthal angle
+ * @param polarAngle the polar angle
+ * @return the created Position object
+ */
+ public static Position fromPosition(float radialCoordinate, float azimuthalAngle, float polarAngle) {
+ return new Position(radialCoordinate, azimuthalAngle, polarAngle);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ Position position = (Position) o;
+
+ if (Float.compare(position.radialCoordinate, radialCoordinate) != 0) {
+ return false;
+ }
+ if (Float.compare(position.azimuthalAngle, azimuthalAngle) != 0) {
+ return false;
+ }
+ return Float.compare(position.polarAngle, polarAngle) == 0;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = (radialCoordinate != +0.0f ? Float.floatToIntBits(radialCoordinate) : 0);
+ result = 31 * result + (azimuthalAngle != +0.0f ? Float.floatToIntBits(azimuthalAngle) : 0);
+ result = 31 * result + (polarAngle != +0.0f ? Float.floatToIntBits(polarAngle) : 0);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "Position{"
+ + "radialCoordinate=" + radialCoordinate
+ + ", azimuthalAngle=" + azimuthalAngle
+ + ", polarAngle=" + polarAngle
+ + '}';
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/light.java.ejs b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/light.java.ejs
new file mode 100644
index 0000000000..067efe1092
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/light.java.ejs
@@ -0,0 +1,121 @@
+<%
+ const properties = locals.properties;
+ const doc = locals.doc;
+-%>
+// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
+
+package com.mapbox.mapboxsdk.style.light;
+
+import android.support.annotation.ColorInt;
+import android.support.annotation.NonNull;
+import android.support.annotation.UiThread;
+
+import com.mapbox.mapboxsdk.style.layers.Property;
+import com.mapbox.mapboxsdk.style.layers.PropertyFactory;
+import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
+
+/**
+ * The global light source.
+ *
+ * @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#light>">The online documentation</a>
+ */
+@UiThread
+public class Light {
+
+ private long nativePtr;
+
+ /**
+ * Creates a Light.
+ *
+ * @param nativePtr pointer used by core
+ */
+ public Light(long nativePtr) {
+ this.nativePtr = nativePtr;
+ }
+<% for (const property of properties) { -%>
+<% if (property.name == "position") {-%>
+
+ /**
+ * Set the <%- camelize(property.name) %> property. <%- property.doc %>
+ *
+ * @param position of the light
+ */
+ public void set<%- camelize(property.name) %>(@NonNull Position position) {
+ nativeSet<%- camelize(property.name) %>(position);
+ }
+
+ /**
+ * Get the <%- camelize(property.name) %> property. <%- property.doc %>
+ *
+ * @return <%- property.name %> as Position
+ */
+ public Position get<%- camelize(property.name) %>() {
+ return nativeGet<%- camelize(property.name) %>();
+ }
+<% } else { -%>
+<% if (property.name == "color") {-%>
+
+ /**
+ * Set the <%- camelize(property.name) %> property. <%- property.doc %>
+ *
+ * @param <%- property.name %> as int
+ */
+ public void set<%- camelize(property.name) %>(@ColorInt int <%- property.name %>) {
+ nativeSet<%- camelize(property.name) %>(PropertyFactory.colorToRgbaString(<%- property.name %>));
+ }
+<% } -%>
+
+ /**
+ * Set the <%- camelize(property.name) %> property. <%- property.doc %>
+ *
+ * @param <%- property.name %> as <%- propertyType(property) %>
+ */
+ public void set<%- camelize(property.name) %>(<%- propertyTypeAnnotation(property) %><%- iff(() => propertyTypeAnnotation(property), " ") %><%- propertyJavaType(property) %> <%- property.name %>) {
+ nativeSet<%- camelize(property.name) %>(<%- property.name %>);
+ }
+
+ /**
+ * Get the <%- camelize(property.name) %> property. <%- property.doc %>
+ *
+ * @return <%- property.name %> as <%- propertyType(property) %>
+ */
+ <%- propertyTypeAnnotation(property) %> public <%- propertyJavaType(property) %> get<%- camelize(property.name) %>() {
+ return nativeGet<%- camelize(property.name) %>();
+ }
+<% } -%>
+<% if (property.transition) { -%>
+
+ /**
+ * Get the <%- camelize(property.name) %> property transition options.
+ *
+ * @return transition options for <%- property.name %>
+ */
+ public TransitionOptions get<%- camelize(property.name) %>Transition() {
+ return nativeGet<%- camelize(property.name) %>Transition();
+ }
+
+ /**
+ * Set the <%- camelize(property.name) %> property transition options.
+ *
+ * @param options transition options for <%- property.name %>
+ */
+ public void set<%- camelize(property.name) %>Transition(TransitionOptions options) {
+ nativeSet<%- camelize(property.name) %>Transition(options.getDuration(), options.getDelay());
+ }
+<% } -%>
+<% } -%>
+
+<% for (const property of properties) { -%>
+<% if (property.name == "position") {-%>
+ private native void nativeSet<%- camelize(property.name) %>(Position position);
+ private native Position nativeGet<%- camelize(property.name) %>();
+<% } else { -%>
+ private native void nativeSet<%- camelize(property.name) %>(<%- propertyJavaType(property) -%> <%- property.name %>);
+ private native <%- propertyJavaType(property) -%> nativeGet<%- camelize(property.name) %>();
+<% } -%>
+<% if (property.transition) { -%>
+ private native TransitionOptions nativeGet<%- camelize(property.name) %>Transition();
+ private native void nativeSet<%- camelize(property.name) %>Transition(long duration, long delay);
+<% } -%>
+<% } -%>
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/package-info.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/package-info.java
new file mode 100644
index 0000000000..a613bf9587
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Contains the Mapbox Maps Android Style Light API classes.
+ */
+package com.mapbox.mapboxsdk.style.light;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/AnimatorUtils.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/AnimatorUtils.java
index 7694604d9f..34c52c829b 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/AnimatorUtils.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/AnimatorUtils.java
@@ -10,13 +10,31 @@ import android.support.annotation.Nullable;
import android.support.v4.view.animation.FastOutSlowInInterpolator;
import android.view.View;
+/**
+ * Animator utility class.
+ */
public class AnimatorUtils {
+ /**
+ * Animate a view from an animator resource.
+ *
+ * @param view the view to be animated
+ * @param animatorRes the animator resource to be loaded
+ * @param listener the animator end listener
+ */
public static void animate(@NonNull final View view, @AnimatorRes int animatorRes,
@Nullable OnAnimationEndListener listener) {
animate(view, animatorRes, -1, listener);
}
+ /**
+ * Animate a view from an animator resource.
+ *
+ * @param view the view to be animated
+ * @param animatorRes the animator resource to be loaded
+ * @param duration the duration of the animator
+ * @param listener the animator end listener
+ */
public static void animate(final View view, @AnimatorRes int animatorRes, int duration,
@Nullable final OnAnimationEndListener listener) {
if (view == null) {
@@ -43,14 +61,33 @@ public class AnimatorUtils {
animator.start();
}
+ /**
+ * Animate a view from an animator resource.
+ *
+ * @param view the view to be animated
+ * @param animatorRes the animator resource to be loaded
+ */
public static void animate(@NonNull final View view, @AnimatorRes int animatorRes) {
animate(view, animatorRes, -1);
}
+ /**
+ * Animate a view from an animator resource.
+ *
+ * @param view the view to be animated
+ * @param animatorRes the animator resource to be loaded
+ * @param duration the duration of the animator
+ */
public static void animate(@NonNull final View view, @AnimatorRes int animatorRes, int duration) {
animate(view, animatorRes, duration, null);
}
+ /**
+ * Animate a view rotation property to a value.
+ *
+ * @param view the view to be rotated
+ * @param rotation the value to animate to
+ */
public static void rotate(@NonNull final View view, float rotation) {
view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
ObjectAnimator rotateAnimator = ObjectAnimator.ofFloat(view, View.ROTATION, view.getRotation(), rotation);
@@ -64,6 +101,12 @@ public class AnimatorUtils {
rotateAnimator.start();
}
+ /**
+ * Animate a view rotation property by a value.
+ *
+ * @param view the view to be rotated
+ * @param rotationBy the value to animate by
+ */
public static void rotateBy(@NonNull final View view, float rotationBy) {
view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
view.animate().rotationBy(rotationBy).setInterpolator(new FastOutSlowInInterpolator()).setListener(
@@ -76,6 +119,13 @@ public class AnimatorUtils {
});
}
+ /**
+ * Animate a view alpha property to a value.
+ *
+ * @param convertView the view to be animated
+ * @param alpha the value to animate to
+ * @param listener the animator end listener
+ */
public static void alpha(@NonNull final View convertView, float alpha,
@Nullable final OnAnimationEndListener listener) {
convertView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
@@ -99,10 +149,19 @@ public class AnimatorUtils {
rotateAnimator.start();
}
+ /**
+ * Animate a view alpha property to a value.
+ *
+ * @param convertView the view to be animated
+ * @param alpha the value to animate to
+ */
public static void alpha(@NonNull final View convertView, float alpha) {
alpha(convertView, alpha, null);
}
+ /**
+ * An interface definition that is invoked when an animation ends.
+ */
public interface OnAnimationEndListener {
void onAnimationEnd();
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java
index 2da2472d69..24c76243d9 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java
@@ -17,6 +17,9 @@ import com.mapbox.mapboxsdk.exceptions.ConversionException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+/**
+ * Color utility class.
+ */
public class ColorUtils {
/**
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml
index ce20cb9a8b..8edbd47c29 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml
@@ -13,6 +13,6 @@
<dimen name="mapbox_eight_dp">8dp</dimen>
<dimen name="mapbox_ten_dp">10dp</dimen>
<dimen name="mapbox_sixteen_dp">16dp</dimen>
- <dimen name="mapbox_ninety_five_dp">95dp</dimen>
+ <dimen name="mapbox_ninety_two_dp">92dp</dimen>
<dimen name="mapbox_my_locationview_outer_circle">18dp</dimen>
</resources>
diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/IconTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/IconTest.java
index 5f6f6b6c6d..1c259af2d0 100644
--- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/IconTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/IconTest.java
@@ -9,6 +9,7 @@ import org.mockito.MockitoAnnotations;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotSame;
+import static org.mockito.Mockito.when;
public class IconTest {
@@ -18,6 +19,7 @@ public class IconTest {
@Before
public void beforeTest() {
MockitoAnnotations.initMocks(this);
+ when(bitmap.getConfig()).thenReturn(Bitmap.Config.ARGB_8888);
}
@Test
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle
index 7c263652af..656789fcdb 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle
+++ b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle
@@ -57,10 +57,7 @@ dependencies {
}
// Support libraries
- compile rootProject.ext.dep.supportAnnotations
- compile rootProject.ext.dep.supportV4
compile rootProject.ext.dep.supportAppcompatV7
- compile rootProject.ext.dep.supportDesign
compile rootProject.ext.dep.supportRecyclerView
// Leak Canary
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/proguard-rules.pro b/platform/android/MapboxGLAndroidSDKTestApp/proguard-rules.pro
index 5d944b5dd4..f8243ca44f 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/proguard-rules.pro
+++ b/platform/android/MapboxGLAndroidSDKTestApp/proguard-rules.pro
@@ -4,5 +4,6 @@
-dontwarn org.codehaus.**
-keep class com.google.**
-dontwarn com.google.**
+-dontwarn java.nio.**
-keep class com.mapbox.mapboxsdk.testapp.model.customlayer.ExampleCustomLayer { *; }
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LightTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LightTest.java
new file mode 100644
index 0000000000..36833fb4ee
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LightTest.java
@@ -0,0 +1,162 @@
+package com.mapbox.mapboxsdk.testapp.style;
+
+import android.graphics.Color;
+import android.support.test.espresso.UiController;
+import android.support.test.espresso.ViewAction;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.View;
+
+import com.mapbox.mapboxsdk.style.light.Light;
+import com.mapbox.mapboxsdk.style.functions.Function;
+import com.mapbox.mapboxsdk.style.functions.stops.IdentityStops;
+import com.mapbox.mapboxsdk.style.layers.FillExtrusionLayer;
+import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
+import com.mapbox.mapboxsdk.style.light.Position;
+import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest;
+import com.mapbox.mapboxsdk.testapp.activity.style.FillExtrusionStyleTestActivity;
+
+import timber.log.Timber;
+
+import org.hamcrest.Matcher;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static com.mapbox.mapboxsdk.style.layers.Filter.eq;
+import static com.mapbox.mapboxsdk.style.layers.Property.ANCHOR_MAP;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillExtrusionBase;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillExtrusionColor;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillExtrusionHeight;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillExtrusionOpacity;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+
+@RunWith(AndroidJUnit4.class)
+public class LightTest extends BaseActivityTest {
+
+ private Light light;
+
+ @Test
+ public void testAnchor() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("anchor");
+ assertNotNull(light);
+ // Set and Get
+ light.setAnchor(ANCHOR_MAP);
+ assertEquals("Anchor should match", ANCHOR_MAP, light.getAnchor());
+ }
+
+ @Test
+ public void testPositionTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("positionTransitionOptions");
+ assertNotNull(light);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ light.setPositionTransition(options);
+ assertEquals("Transition options should match", options, light.getPositionTransition());
+ }
+
+ @Test
+ public void testPosition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("position");
+ assertNotNull(light);
+
+ // Set and Get
+ Position position = new Position(1,2,3);
+ light.setPosition(position);
+ assertEquals("Position should match", position, light.getPosition());
+ }
+
+ @Test
+ public void testColorTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("colorTransitionOptions");
+ assertNotNull(light);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ light.setColorTransition(options);
+ assertEquals("Transition options should match", options, light.getColorTransition());
+ }
+
+ @Test
+ public void testColor() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("color");
+ assertNotNull(light);
+ // Set and Get
+ light.setColor("rgba(0, 0, 0, 1)");
+ assertEquals("Color should match", "rgba(0, 0, 0, 1)".replaceAll("\\s+",""), light.getColor());
+ }
+
+ @Test
+ public void testIntensityTransition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("intensityTransitionOptions");
+ assertNotNull(light);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ light.setIntensityTransition(options);
+ assertEquals("Transition options should match", options, light.getIntensityTransition());
+ }
+
+ @Test
+ public void testIntensity() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("intensity");
+ assertNotNull(light);
+ // Set and Get
+ light.setIntensity(0.3f);
+ assertEquals("Intensity should match", 0.3f, light.getIntensity());
+ }
+
+ private void setupLayer() {
+ onView(withId(R.id.mapView)).perform(new ViewAction() {
+ @Override
+ public Matcher<View> getConstraints() {
+ return isDisplayed();
+ }
+
+ @Override
+ public String getDescription() {
+ return getClass().getSimpleName();
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ light = mapboxMap.getLight();
+ FillExtrusionLayer fillExtrusionLayer = new FillExtrusionLayer("3d-buildings", "composite");
+ fillExtrusionLayer.setSourceLayer("building");
+ fillExtrusionLayer.setFilter(eq("extrude", "true"));
+ fillExtrusionLayer.setMinZoom(15);
+ fillExtrusionLayer.setProperties(
+ fillExtrusionColor(Color.LTGRAY),
+ fillExtrusionHeight(Function.property("height", new IdentityStops<Float>())),
+ fillExtrusionBase(Function.property("min_height", new IdentityStops<Float>())),
+ fillExtrusionOpacity(0.6f)
+ );
+ mapboxMap.addLayer(fillExtrusionLayer);
+ }
+ });
+ }
+
+ @Override
+ protected Class getActivityClass() {
+ return FillExtrusionStyleTestActivity.class;
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/light.junit.ejs b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/light.junit.ejs
new file mode 100644
index 0000000000..cb3ba58100
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/light.junit.ejs
@@ -0,0 +1,128 @@
+<%
+ const properties = locals.properties;
+-%>
+package com.mapbox.mapboxsdk.testapp.style;
+
+import android.graphics.Color;
+import android.support.test.espresso.UiController;
+import android.support.test.espresso.ViewAction;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.View;
+
+import com.mapbox.mapboxsdk.style.light.Light;
+import com.mapbox.mapboxsdk.style.functions.Function;
+import com.mapbox.mapboxsdk.style.functions.stops.IdentityStops;
+import com.mapbox.mapboxsdk.style.layers.FillExtrusionLayer;
+import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
+import com.mapbox.mapboxsdk.style.light.Position;
+import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest;
+import com.mapbox.mapboxsdk.testapp.activity.style.FillExtrusionStyleTestActivity;
+
+import timber.log.Timber;
+
+import org.hamcrest.Matcher;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static com.mapbox.mapboxsdk.style.layers.Filter.eq;
+import static com.mapbox.mapboxsdk.style.layers.Property.ANCHOR_MAP;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillExtrusionBase;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillExtrusionColor;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillExtrusionHeight;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillExtrusionOpacity;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+
+@RunWith(AndroidJUnit4.class)
+public class LightTest extends BaseActivityTest {
+
+ private Light light;
+<% for (const property of properties) { -%>
+<% if (property.transition) { -%>
+
+ @Test
+ public void test<%- camelize(property.name) %>Transition() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("<%- property.name %>TransitionOptions");
+ assertNotNull(light);
+
+ // Set and Get
+ TransitionOptions options = new TransitionOptions(300, 100);
+ light.set<%- camelize(property.name) %>Transition(options);
+ assertEquals("Transition options should match", options, light.get<%- camelize(property.name) %>Transition());
+ }
+<% } -%>
+<% if (property.name == "position") { -%>
+
+ @Test
+ public void test<%- camelize(property.name) %>() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("<%- property.name %>");
+ assertNotNull(light);
+
+ // Set and Get
+ Position position = new Position(1,2,3);
+ light.set<%- camelize(property.name) %>(position);
+ assertEquals("Position should match", position, light.get<%- camelize(property.name) %>());
+ }
+<% } else { -%>
+
+ @Test
+ public void test<%- camelize(property.name) %>() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("<%- property.name %>");
+ assertNotNull(light);
+ // Set and Get
+ light.set<%- camelize(property.name) %>(<%- defaultValueJava(property) %>);
+<% if (property.name == 'color') { -%>
+ assertEquals("<%- camelize(property.name) %> should match", <%- defaultValueJava(property) %>.replaceAll("\\s+",""), light.get<%- camelize(property.name) %>());
+<% } else { -%>
+ assertEquals("<%- camelize(property.name) %> should match", <%- defaultValueJava(property) %>, light.get<%- camelize(property.name) %>());
+<% } -%>
+ }
+<% } -%>
+<% } -%>
+
+ private void setupLayer() {
+ onView(withId(R.id.mapView)).perform(new ViewAction() {
+ @Override
+ public Matcher<View> getConstraints() {
+ return isDisplayed();
+ }
+
+ @Override
+ public String getDescription() {
+ return getClass().getSimpleName();
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ light = mapboxMap.getLight();
+ FillExtrusionLayer fillExtrusionLayer = new FillExtrusionLayer("3d-buildings", "composite");
+ fillExtrusionLayer.setSourceLayer("building");
+ fillExtrusionLayer.setFilter(eq("extrude", "true"));
+ fillExtrusionLayer.setMinZoom(15);
+ fillExtrusionLayer.setProperties(
+ fillExtrusionColor(Color.LTGRAY),
+ fillExtrusionHeight(Function.property("height", new IdentityStops<Float>())),
+ fillExtrusionBase(Function.property("min_height", new IdentityStops<Float>())),
+ fillExtrusionOpacity(0.6f)
+ );
+ mapboxMap.addLayer(fillExtrusionLayer);
+ }
+ });
+ }
+
+ @Override
+ protected Class getActivityClass() {
+ return FillExtrusionStyleTestActivity.class;
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
index 9ede763533..1a70e4548a 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
@@ -661,7 +661,9 @@
<activity
android:name=".activity.espresso.EspressoTestActivity"
android:screenOrientation="portrait"/>
-
+ <activity
+ android:name=".activity.style.FillExtrusionStyleTestActivity"
+ android:screenOrientation="portrait"/>
<!-- Configuration Settings -->
<meta-data
android:name="com.mapbox.TestEventsServer"
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 08399f3b3e..60518239c8 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
@@ -43,10 +43,35 @@ public class CameraPositionActivity extends AppCompatActivity implements OnMapRe
public void onMapReady(@NonNull final MapboxMap mapboxMap) {
this.mapboxMap = mapboxMap;
- mapboxMap.setOnCameraChangeListener(new MapboxMap.OnCameraChangeListener() {
+ mapboxMap.setOnCameraIdleListener(new MapboxMap.OnCameraIdleListener() {
@Override
- public void onCameraChange(CameraPosition position) {
- Timber.w("OnCameraChange: " + position);
+ public void onCameraIdle() {
+ Timber.e("OnCameraIdle");
+ }
+ });
+
+ mapboxMap.setOnCameraMoveCancelListener(new MapboxMap.OnCameraMoveCanceledListener() {
+ @Override
+ public void onCameraMoveCanceled() {
+ Timber.e("OnCameraMoveCanceled");
+ }
+ });
+
+ mapboxMap.setOnCameraMoveListener(new MapboxMap.OnCameraMoveListener() {
+ @Override
+ public void onCameraMove() {
+ Timber.e("OnCameraMove");
+ }
+ });
+
+ mapboxMap.setOnCameraMoveStartedistener(new MapboxMap.OnCameraMoveStartedListener() {
+
+ private final String[] REASONS = {"REASON_API_GESTURE", "REASON_DEVELOPER_ANIMATION", "REASON_API_ANIMATION"};
+
+ @Override
+ public void onCameraMoveStarted(int reason) {
+ // reason ranges from 1 <-> 3
+ Timber.e("OnCameraMoveStarted: %s", REASONS[reason - 1]);
}
});
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java
index be5d809457..344e9e140a 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java
@@ -274,22 +274,20 @@ public class OfflineActivity extends AppCompatActivity
}
// Debug
- Timber.d(String.format("%s/%s resources; %s bytes downloaded.",
+ Timber.d("%s/%s resources; %s bytes downloaded.",
String.valueOf(status.getCompletedResourceCount()),
String.valueOf(status.getRequiredResourceCount()),
- String.valueOf(status.getCompletedResourceSize())));
+ String.valueOf(status.getCompletedResourceSize()));
}
@Override
public void onError(OfflineRegionError error) {
- Timber.e("onError reason: " + error.getReason());
- Timber.e("onError message: " + error.getMessage());
- offlineRegion.setObserver(null);
+ Timber.e("onError: %s, %s", error.getReason(), error.getMessage());
}
@Override
public void mapboxTileCountLimitExceeded(long limit) {
- Timber.e("Mapbox tile count limit exceeded: " + limit);
+ Timber.e("Mapbox tile count limit exceeded: %s", limit);
}
});
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/BuildingFillExtrusionActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/BuildingFillExtrusionActivity.java
index f444aa40f0..def7d1678a 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/BuildingFillExtrusionActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/BuildingFillExtrusionActivity.java
@@ -4,6 +4,9 @@ import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
@@ -11,6 +14,10 @@ import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.style.functions.Function;
import com.mapbox.mapboxsdk.style.functions.stops.IdentityStops;
import com.mapbox.mapboxsdk.style.layers.FillExtrusionLayer;
+import com.mapbox.mapboxsdk.style.layers.Property;
+import com.mapbox.mapboxsdk.style.layers.PropertyFactory;
+import com.mapbox.mapboxsdk.style.light.Light;
+import com.mapbox.mapboxsdk.style.light.Position;
import com.mapbox.mapboxsdk.testapp.R;
import static com.mapbox.mapboxsdk.style.layers.Filter.eq;
@@ -25,6 +32,13 @@ import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillExtrusionOpa
public class BuildingFillExtrusionActivity extends AppCompatActivity {
private MapView mapView;
+ private MapboxMap mapboxMap;
+ private Light light;
+
+ private boolean isMapAnchorLight;
+ private boolean isLowIntensityLight;
+ private boolean isRedColor;
+ private boolean isInitPosition;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -35,21 +49,72 @@ public class BuildingFillExtrusionActivity extends AppCompatActivity {
mapView.getMapAsync(new OnMapReadyCallback() {
@Override
public void onMapReady(@NonNull final MapboxMap map) {
- FillExtrusionLayer fillExtrusionLayer = new FillExtrusionLayer("3d-buildings", "composite");
- fillExtrusionLayer.setSourceLayer("building");
- fillExtrusionLayer.setFilter(eq("extrude", "true"));
- fillExtrusionLayer.setMinZoom(15);
- fillExtrusionLayer.setProperties(
- fillExtrusionColor(Color.LTGRAY),
- fillExtrusionHeight(Function.property("height", new IdentityStops<Float>())),
- fillExtrusionBase(Function.property("min_height", new IdentityStops<Float>())),
- fillExtrusionOpacity(0.6f)
- );
- map.addLayer(fillExtrusionLayer);
+ mapboxMap = map;
+ setupBuildings();
+ setupLight();
}
});
}
+ private void setupBuildings() {
+ FillExtrusionLayer fillExtrusionLayer = new FillExtrusionLayer("3d-buildings", "composite");
+ fillExtrusionLayer.setSourceLayer("building");
+ fillExtrusionLayer.setFilter(eq("extrude", "true"));
+ fillExtrusionLayer.setMinZoom(15);
+ fillExtrusionLayer.setProperties(
+ fillExtrusionColor(Color.LTGRAY),
+ fillExtrusionHeight(Function.property("height", new IdentityStops<Float>())),
+ fillExtrusionBase(Function.property("min_height", new IdentityStops<Float>())),
+ fillExtrusionOpacity(0.9f)
+ );
+ mapboxMap.addLayer(fillExtrusionLayer);
+ }
+
+ private void setupLight() {
+ light = mapboxMap.getLight();
+
+ findViewById(R.id.fabLightPosition).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ isInitPosition = !isInitPosition;
+ if (isInitPosition) {
+ light.setPosition(new Position(1.5f, 90, 80));
+ } else {
+ light.setPosition(new Position(1.15f, 210, 30));
+ }
+ }
+ });
+
+ findViewById(R.id.fabLightColor).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ isRedColor = !isRedColor;
+ light.setColor(PropertyFactory.colorToRgbaString(isRedColor ? Color.RED : Color.BLUE));
+ }
+ });
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.menu_building, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (light != null) {
+ int id = item.getItemId();
+ if (id == R.id.menu_action_anchor) {
+ isMapAnchorLight = !isMapAnchorLight;
+ light.setAnchor(isMapAnchorLight ? Property.ANCHOR_MAP : Property.ANCHOR_VIEWPORT);
+ } else if (id == R.id.menu_action_intensity) {
+ isLowIntensityLight = !isLowIntensityLight;
+ light.setIntensity(isLowIntensityLight ? 0.35f : 1.0f);
+ }
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
@Override
protected void onStart() {
super.onStart();
@@ -91,5 +156,4 @@ public class BuildingFillExtrusionActivity extends AppCompatActivity {
super.onDestroy();
mapView.onDestroy();
}
-
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/FillExtrusionStyleTestActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/FillExtrusionStyleTestActivity.java
new file mode 100644
index 0000000000..1ff0b0e8e1
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/FillExtrusionStyleTestActivity.java
@@ -0,0 +1,78 @@
+package com.mapbox.mapboxsdk.testapp.activity.style;
+
+
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+
+import com.mapbox.mapboxsdk.maps.MapView;
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
+import com.mapbox.mapboxsdk.testapp.R;
+
+public class FillExtrusionStyleTestActivity extends AppCompatActivity {
+
+ public MapView mapView;
+ private MapboxMap mapboxMap;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_extrusion_test);
+
+ // Initialize map as normal
+ mapView = (MapView) findViewById(R.id.mapView);
+ mapView.onCreate(savedInstanceState);
+ mapView.getMapAsync(new OnMapReadyCallback() {
+ @Override
+ public void onMapReady(MapboxMap mapboxMap) {
+ FillExtrusionStyleTestActivity.this.mapboxMap = mapboxMap;
+ }
+ });
+ }
+
+ public MapboxMap getMapboxMap() {
+ return mapboxMap;
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ mapView.onStart();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mapView.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ mapView.onPause();
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ mapView.onStop();
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ mapView.onSaveInstanceState(outState);
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ mapView.onDestroy();
+ }
+
+ @Override
+ public void onLowMemory() {
+ super.onLowMemory();
+ mapView.onLowMemory();
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MockLocationEngine.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MockLocationEngine.java
index b87c723fda..b02b35b0d0 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MockLocationEngine.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MockLocationEngine.java
@@ -63,7 +63,9 @@ public class MockLocationEngine extends LocationEngine {
@Override
public void removeLocationUpdates() {
- handler.removeCallbacksAndMessages(null);
+ if (handler != null) {
+ handler.removeCallbacksAndMessages(null);
+ }
}
private Location getNextLocation() {
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_paint.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_paint.xml
new file mode 100644
index 0000000000..f9e55e1480
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_paint.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M18,4V3c0,-0.55 -0.45,-1 -1,-1H5c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1V6h1v4H9v11c0,0.55 0.45,1 1,1h2c0.55,0 1,-0.45 1,-1v-9h8V4h-3z"/>
+</vector>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_building_layer.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_building_layer.xml
index d9a10871b5..fa37c485d7 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_building_layer.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_building_layer.xml
@@ -1,9 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
+ android:layout_height="match_parent">
<com.mapbox.mapboxsdk.maps.MapView
android:id="@id/mapView"
@@ -13,6 +12,27 @@
app:mapbox_cameraTargetLng="-74.0066"
app:mapbox_cameraTilt="45"
app:mapbox_cameraZoom="15"
- app:mapbox_styleUrl="@string/mapbox_style_mapbox_streets"/>
+ app:mapbox_styleUrl="@string/mapbox_style_dark"/>
-</RelativeLayout>
+ <android.support.design.widget.FloatingActionButton
+ android:id="@+id/fabLightPosition"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end|bottom"
+ android:layout_marginBottom="82dp"
+ android:layout_marginRight="@dimen/fab_margin"
+ android:layout_marginEnd="@dimen/fab_margin"
+ android:src="@drawable/ic_my_location"
+ app:backgroundTint="@color/accent"
+ app:layout_anchorGravity="top"/>
+
+ <android.support.design.widget.FloatingActionButton
+ android:id="@+id/fabLightColor"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end|bottom"
+ android:layout_margin="@dimen/fab_margin"
+ android:src="@drawable/ic_paint"
+ app:backgroundTint="@color/primary"/>
+
+</FrameLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_extrusion_test.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_extrusion_test.xml
new file mode 100644
index 0000000000..d9a10871b5
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_extrusion_test.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <com.mapbox.mapboxsdk.maps.MapView
+ android:id="@id/mapView"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ app:mapbox_cameraTargetLat="40.7135"
+ app:mapbox_cameraTargetLng="-74.0066"
+ app:mapbox_cameraTilt="45"
+ app:mapbox_cameraZoom="15"
+ app:mapbox_styleUrl="@string/mapbox_style_mapbox_streets"/>
+
+</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_press_for_marker.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_press_for_marker.xml
index 9932803907..c2098b0f5b 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_press_for_marker.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_press_for_marker.xml
@@ -16,6 +16,6 @@
app:mapbox_styleUrl="@string/mapbox_style_mapbox_streets"
app:mapbox_uiAttributionGravity="top|end"
app:mapbox_uiLogoGravity="top|end"
- app:mapbox_uiLogoMarginRight="10dp"/>
+ app:mapbox_uiLogoMarginRight="28dp"/>
</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_building.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_building.xml
new file mode 100644
index 0000000000..92d1dd5380
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_building.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+ <item
+ android:id="@+id/menu_action_intensity"
+ android:title="Change intensity"
+ app:showAsAction="never"/>
+ <item
+ android:id="@+id/menu_action_anchor"
+ android:title="Change Anchor"
+ app:showAsAction="never"/>
+</menu>
diff --git a/platform/android/build.gradle b/platform/android/build.gradle
index 120c0219e4..bc90896812 100644
--- a/platform/android/build.gradle
+++ b/platform/android/build.gradle
@@ -12,6 +12,7 @@ buildscript {
allprojects {
repositories {
jcenter()
+ maven { url "http://oss.sonatype.org/content/repositories/snapshots/" }
}
}
diff --git a/platform/android/config.cmake b/platform/android/config.cmake
index c111744ed0..84591d644b 100644
--- a/platform/android/config.cmake
+++ b/platform/android/config.cmake
@@ -168,6 +168,10 @@ add_library(mbgl-android STATIC
platform/android/src/style/functions/identity_stops.hpp
platform/android/src/style/functions/interval_stops.cpp
platform/android/src/style/functions/interval_stops.hpp
+ platform/android/src/style/position.cpp
+ platform/android/src/style/position.hpp
+ platform/android/src/style/light.cpp
+ platform/android/src/style/light.hpp
# FileSource holder
platform/android/src/file_source.cpp
diff --git a/platform/android/dependencies.gradle b/platform/android/dependencies.gradle
index 738f571c09..5e80e344e4 100644
--- a/platform/android/dependencies.gradle
+++ b/platform/android/dependencies.gradle
@@ -7,21 +7,21 @@ ext {
versionCode = 11
versionName = "5.0.0"
+ mapboxServicesVersion = "2.1.1"
supportLibVersion = "25.3.1"
- leakCanaryVersion = '1.5'
wearableVersion = '2.0.0'
-
espressoVersion = '2.2.2'
testRunnerVersion = '0.5'
+ leakCanaryVersion = '1.5'
dep = [
// mapbox
- mapboxJavaServices : 'com.mapbox.mapboxsdk:mapbox-java-services:2.1.0@jar',
- mapboxJavaGeoJSON : 'com.mapbox.mapboxsdk:mapbox-java-geojson:2.1.0@jar',
- mapboxAndroidTelemetry : 'com.mapbox.mapboxsdk:mapbox-android-telemetry:2.1.0@aar',
+ mapboxJavaServices : "com.mapbox.mapboxsdk:mapbox-java-services:${mapboxServicesVersion}@jar",
+ mapboxJavaGeoJSON : "com.mapbox.mapboxsdk:mapbox-java-geojson:${mapboxServicesVersion}@jar",
+ mapboxAndroidTelemetry : "com.mapbox.mapboxsdk:mapbox-android-telemetry:${mapboxServicesVersion}@aar",
// mapzen lost
- lost : 'com.mapzen.android:lost:2.2.0',
+ lost : 'com.mapzen.android:lost:3.0.0',
// unit test
junit : 'junit:junit:4.12',
@@ -47,7 +47,7 @@ ext {
// square crew
timber : 'com.jakewharton.timber:timber:4.5.1',
- okhttp3 : 'com.squareup.okhttp3:okhttp:3.6.0',
+ okhttp3 : 'com.squareup.okhttp3:okhttp:3.7.0',
leakCanaryDebug : "com.squareup.leakcanary:leakcanary-android:${leakCanaryVersion}",
leakCanaryRelease : "com.squareup.leakcanary:leakcanary-android-no-op:${leakCanaryVersion}",
leakCanaryTest : "com.squareup.leakcanary:leakcanary-android-no-op:${leakCanaryVersion}"
diff --git a/platform/android/gradle/wrapper/gradle-wrapper.properties b/platform/android/gradle/wrapper/gradle-wrapper.properties
index c7ad166b13..1d35abd7b2 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-3.3-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip \ No newline at end of file
diff --git a/platform/android/scripts/generate-style-code.js b/platform/android/scripts/generate-style-code.js
index 5d8fc4cc6d..bb04e3ba2a 100644
--- a/platform/android/scripts/generate-style-code.js
+++ b/platform/android/scripts/generate-style-code.js
@@ -8,6 +8,13 @@ const _ = require('lodash');
require('../../../scripts/style-code');
// Specification parsing //
+const lightProperties = Object.keys(spec[`light`]).reduce((memo, name) => {
+ var property = spec[`light`][name];
+ property.name = name;
+ property['light-property'] = true;
+ memo.push(property);
+ return memo;
+}, []);
// Collect layer types from spec
var layers = Object.keys(spec.layer.type.values).map((type) => {
@@ -37,7 +44,7 @@ var layers = Object.keys(spec.layer.type.values).map((type) => {
// Process all layer properties
const layoutProperties = _(layers).map('layoutProperties').flatten().value();
const paintProperties = _(layers).map('paintProperties').flatten().value();
-const allProperties = _(layoutProperties).union(paintProperties).value();
+const allProperties = _(layoutProperties).union(paintProperties).union(lightProperties).value();
const enumProperties = _(allProperties).filter({'type': 'enum'}).value();
global.propertyType = function propertyType(property) {
@@ -59,12 +66,31 @@ global.propertyType = function propertyType(property) {
}
}
+global.propertyJavaType = function propertyType(property) {
+ switch (property.type) {
+ case 'boolean':
+ return 'boolean';
+ case 'number':
+ return 'float';
+ case 'string':
+ return 'String';
+ case 'enum':
+ return 'String';
+ case 'color':
+ return 'String';
+ case 'array':
+ return `${propertyJavaType({type:property.value})}[]`;
+ default:
+ throw new Error(`unknown type for ${property.name}`);
+ }
+ }
+
global.propertyJNIType = function propertyJNIType(property) {
switch (property.type) {
case 'boolean':
return 'jboolean';
- case 'jfloat':
- return 'Float';
+ case 'number':
+ return 'jfloat';
case 'String':
return 'String';
case 'enum':
@@ -93,6 +119,9 @@ global.propertyNativeType = function (property) {
case 'string':
return 'std::string';
case 'enum':
+ if(property['light-property']){
+ return `Light${camelize(property.name)}Type`;
+ }
return `${camelize(property.name)}Type`;
case 'color':
return `Color`;
@@ -215,6 +244,53 @@ global.propertyValueDoc = function (property, value) {
return doc;
};
+global.isDataDriven = function (property) {
+ return property['property-function'] === true;
+};
+
+global.isLightProperty = function (property) {
+ return property['light-property'] === true;
+};
+
+global.propertyValueType = function (property) {
+ if (isDataDriven(property)) {
+ return `DataDrivenPropertyValue<${evaluatedType(property)}>`;
+ } else {
+ return `PropertyValue<${evaluatedType(property)}>`;
+ }
+};
+
+global.evaluatedType = function (property) {
+ if (/-translate-anchor$/.test(property.name)) {
+ return 'TranslateAnchorType';
+ }
+ if (/-(rotation|pitch|illumination)-alignment$/.test(property.name)) {
+ return 'AlignmentType';
+ }
+ if (/position/.test(property.name)) {
+ return 'Position';
+ }
+ switch (property.type) {
+ case 'boolean':
+ return 'bool';
+ case 'number':
+ return 'float';
+ case 'string':
+ return 'std::string';
+ case 'enum':
+ return (isLightProperty(property) ? 'Light' : '') + `${camelize(property.name)}Type`;
+ case 'color':
+ return `Color`;
+ case 'array':
+ if (property.length) {
+ return `std::array<${evaluatedType({type: property.value})}, ${property.length}>`;
+ } else {
+ return `std::vector<${evaluatedType({type: property.value})}>`;
+ }
+ default: throw new Error(`unknown type for ${property.name}`)
+ }
+};
+
global.supportsZoomFunction = function (property) {
return property['zoom-function'] === true;
};
@@ -225,6 +301,16 @@ global.supportsPropertyFunction = function (property) {
// Template processing //
+// Java + JNI Light (Peer model)
+const lightHpp = ejs.compile(fs.readFileSync('platform/android/src/style/light.hpp.ejs', 'utf8'), {strict: true});;
+const lightCpp = ejs.compile(fs.readFileSync('platform/android/src/style/light.cpp.ejs', 'utf8'), {strict: true});;
+const lightJava = ejs.compile(fs.readFileSync('platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/light.java.ejs', 'utf8'), {strict: true});
+const lightJavaUnitTests = ejs.compile(fs.readFileSync('platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/light.junit.ejs', 'utf8'), {strict: true});
+writeIfModified(`platform/android/src/style/light.hpp`, lightHpp({properties: lightProperties}));
+writeIfModified(`platform/android/src/style/light.cpp`, lightCpp({properties: lightProperties}));
+writeIfModified(`platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java`, lightJava({properties: lightProperties}));
+writeIfModified(`platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LightTest.java`, lightJavaUnitTests({properties: lightProperties}));
+
// Java + JNI Layers (Peer model)
const layerHpp = ejs.compile(fs.readFileSync('platform/android/src/style/layers/layer.hpp.ejs', 'utf8'), {strict: true});
const layerCpp = ejs.compile(fs.readFileSync('platform/android/src/style/layers/layer.cpp.ejs', 'utf8'), {strict: true});
@@ -238,7 +324,6 @@ for (const layer of layers) {
writeIfModified(`platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/${camelize(layer.type)}LayerTest.java`, layerJavaUnitTests(layer));
}
-
// Java PropertyFactory
const propertiesTemplate = ejs.compile(fs.readFileSync('platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property_factory.java.ejs', 'utf8'), {strict: true});
writeIfModified(
diff --git a/platform/android/scripts/release.py b/platform/android/scripts/release.py
index 8abcccffdb..ce554d1362 100644
--- a/platform/android/scripts/release.py
+++ b/platform/android/scripts/release.py
@@ -1,5 +1,5 @@
'''
-Utility to schedule SDK builds in Bitrise.
+Utility to schedule SDK builds on CircleCI.
Examples:
@@ -33,7 +33,7 @@ Examples:
TODO:
-- Add a flag to wait until the release has been built (Bitrise) and published (Maven).
+- Add a flag to wait until the release has been built (CircleCI) and published (Maven).
'''
@@ -49,8 +49,8 @@ ALLOWED_STAGES = ['snapshot', 'beta', 'final']
# Get the version from GRADLE_PROPERTIES_PATH below
CURRENT_VERSION_TAG = 'current'
-# You can find the API token in https://www.bitrise.io/app/79cdcbdc42de4303#/code -> API token
-BITRISE_API_TOKEN_ENV_VAR = 'BITRISE_API_TOKEN'
+# You can add your API token on https://circleci.com/account/api
+CIRCLECI_API_TOKEN_ENV_VAR = 'CIRCLECI_API_TOKEN'
# In the future we might want to consider alpha, or rc.
ALLOWED_PRE_RELEASE = ['beta']
@@ -62,8 +62,8 @@ GRADLE_TOKEN = 'VERSION_NAME='
FABRIC_PROPERTIES_PATH = '%s/src/main/resources/fabric/com.mapbox.mapboxsdk.mapbox-android-sdk.properties' % MAPBOX_GL_ANDROID_SDK_PATH
FABRIC_TOKEN = 'fabric-version='
-# Bitrise
-URL_BITRISE = 'https://www.bitrise.io/app/79cdcbdc42de4303/build/start.json'
+# Triggers a new build, returns a summary of the build
+URL_CIRCLECI = 'https://circleci.com/api/v1.1/project/github/mapbox/mapbox-gl-native/tree/' # + :branch
# We support three parameters: stage, branch, and version
@click.command()
@@ -129,7 +129,7 @@ def publish_snapshot(branch, version):
if dirty_gradle:
git_add(path=GRADLE_PROPERTIES_PATH)
git_commit_and_push(branch=branch, version=version)
- do_bitrise_request(build_params={'branch': branch, 'workflow_id': 'scheduled'})
+ do_circleci_request(branch=branch)
def publish_beta(branch, version):
click.echo('Publishing beta from branch: %s (version: %s).' % (branch, version))
@@ -137,7 +137,7 @@ def publish_beta(branch, version):
if dirty_gradle:
git_add(path=GRADLE_PROPERTIES_PATH)
git_commit_and_push(branch=branch, version=version)
- do_bitrise_request(build_params={'branch': branch, 'workflow_id': 'scheduled'})
+ do_circleci_request(branch=branch)
def publish_final(branch, version):
click.echo('Publishing final release from branch: %s (version: %s).' % (branch, version))
@@ -149,7 +149,7 @@ def publish_final(branch, version):
git_add(path=FABRIC_PROPERTIES_PATH)
if dirty_gradle or dirty_fabric:
git_commit_and_push(branch=branch, version=version)
- do_bitrise_request(build_params={'branch': branch, 'workflow_id': 'scheduled'})
+ do_circleci_request(branch=branch)
#
# Utils
@@ -166,26 +166,24 @@ def execute_call(command):
abort_with_message('Command failed: %s' % command)
#
-# Bitrise
+# CircleCI
#
-def get_bitrise_api_token():
- bitrise_api_token = os.environ.get(BITRISE_API_TOKEN_ENV_VAR)
- if not bitrise_api_token:
- abort_with_message('You need to set the BITRISE_API_TOKEN environment variable.')
- click.echo('Found Bitrise API token.')
- return bitrise_api_token
-
-def do_bitrise_request(build_params):
- data = {
- 'hook_info': {'type': 'bitrise', 'api_token': get_bitrise_api_token()},
- 'build_params' : build_params}
- click.echo('Bitrise request data: %s' % json.dumps(data))
+def get_circleci_api_token():
+ circleci_api_token = os.environ.get(CIRCLECI_API_TOKEN_ENV_VAR)
+ if not circleci_api_token:
+ abort_with_message('You need to set the CIRCLECI_API_TOKEN environment variable.')
+ click.echo('Found CircleCI API token.')
+ return circleci_api_token
+
+def do_circleci_request(branch):
+ url = URL_CIRCLECI + branch
+ params = {'circle-token': get_circleci_api_token()}
+ click.echo('CircleCI request to %s (params: %s)' % (url, json.dumps(params)))
click.confirm('\nDo you want to start a build?', abort=True)
- r = requests.post(URL_BITRISE, data=json.dumps(data))
- click.echo('- Bitrise response code: %s' % r.status_code)
- click.echo('- Bitrise response content: %s' % r.text)
+ r = requests.post(url, params=params)
+ click.echo('- CircleCI response code: %s' % r.status_code)
#
# Git
diff --git a/platform/android/src/jni.cpp b/platform/android/src/jni.cpp
index 53691acb39..6c490fad5c 100755
--- a/platform/android/src/jni.cpp
+++ b/platform/android/src/jni.cpp
@@ -45,6 +45,7 @@
#include "style/functions/stop.hpp"
#include "style/layers/layers.hpp"
#include "style/sources/sources.hpp"
+#include "style/light.hpp"
namespace mbgl {
namespace android {
@@ -153,6 +154,8 @@ void registerNatives(JavaVM *vm) {
TransitionOptions::registerNative(env);
registerNativeLayers(env);
registerNativeSources(env);
+ Light::registerNative(env);
+ Position::registerNative(env);
Stop::registerNative(env);
CategoricalStops::registerNative(env);
ExponentialStops::registerNative(env);
diff --git a/platform/android/src/map/camera_position.cpp b/platform/android/src/map/camera_position.cpp
index aa5873b273..d6f2cb83e8 100644
--- a/platform/android/src/map/camera_position.cpp
+++ b/platform/android/src/map/camera_position.cpp
@@ -11,8 +11,9 @@ jni::Object<CameraPosition> CameraPosition::New(jni::JNIEnv &env, mbgl::CameraOp
auto center = options.center.value();
center.wrap();
- // convert bearing, core ranges from [−π rad, π rad], android from 0 to 360 degrees
- double bearing_degrees = options.angle.value_or(0) * 180.0 / M_PI;
+ // convert bearing, measured in radians counterclockwise from true north.
+ // Wrapped to [−π rad, π rad). Android binding from 0 to 360 degrees
+ double bearing_degrees = -options.angle.value_or(0) * util::RAD2DEG;
while (bearing_degrees > 360) {
bearing_degrees -= 360;
}
@@ -21,7 +22,7 @@ jni::Object<CameraPosition> CameraPosition::New(jni::JNIEnv &env, mbgl::CameraOp
}
// convert tilt, core ranges from [0 rad, 1,0472 rad], android ranges from 0 to 60
- double tilt_degrees = options.pitch.value_or(0) * 180 / M_PI;
+ double tilt_degrees = options.pitch.value_or(0) * util::RAD2DEG;
return CameraPosition::javaClass.New(env, constructor, LatLng::New(env, center), options.zoom.value_or(0), tilt_degrees, bearing_degrees);
}
diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp
index 51ce9c031d..73a4f96549 100755
--- a/platform/android/src/native_map_view.cpp
+++ b/platform/android/src/native_map_view.cpp
@@ -46,6 +46,7 @@
#include "java/util.hpp"
#include "geometry/lat_lng_bounds.hpp"
#include "map/camera_position.hpp"
+#include "style/light.hpp"
namespace mbgl {
namespace android {
@@ -385,12 +386,12 @@ void NativeMapView::moveBy(jni::JNIEnv&, jni::jdouble dx, jni::jdouble dy, jni::
void NativeMapView::jumpTo(jni::JNIEnv&, jni::jdouble angle, jni::jdouble latitude, jni::jdouble longitude, jni::jdouble pitch, jni::jdouble zoom) {
mbgl::CameraOptions options;
if (angle != -1) {
- options.angle = (-angle * M_PI) / 180;
+ options.angle = -angle * util::DEG2RAD;
}
options.center = mbgl::LatLng(latitude, longitude);
options.padding = insets;
if (pitch != -1) {
- options.pitch = pitch * M_PI / 180;
+ options.pitch = pitch * util::DEG2RAD;
}
if (zoom != -1) {
options.zoom = zoom;
@@ -402,12 +403,12 @@ void NativeMapView::jumpTo(jni::JNIEnv&, jni::jdouble angle, jni::jdouble latitu
void NativeMapView::easeTo(jni::JNIEnv&, jni::jdouble angle, jni::jdouble latitude, jni::jdouble longitude, jni::jlong duration, jni::jdouble pitch, jni::jdouble zoom, jni::jboolean easing) {
mbgl::CameraOptions cameraOptions;
if (angle != -1) {
- cameraOptions.angle = (-angle * M_PI) / 180;
+ cameraOptions.angle = -angle * util::DEG2RAD;
}
cameraOptions.center = mbgl::LatLng(latitude, longitude);
cameraOptions.padding = insets;
if (pitch != -1) {
- cameraOptions.pitch = pitch * M_PI / 180;
+ cameraOptions.pitch = pitch * util::DEG2RAD;
}
if (zoom != -1) {
cameraOptions.zoom = zoom;
@@ -426,12 +427,12 @@ void NativeMapView::easeTo(jni::JNIEnv&, jni::jdouble angle, jni::jdouble latitu
void NativeMapView::flyTo(jni::JNIEnv&, jni::jdouble angle, jni::jdouble latitude, jni::jdouble longitude, jni::jlong duration, jni::jdouble pitch, jni::jdouble zoom) {
mbgl::CameraOptions cameraOptions;
if (angle != -1) {
- cameraOptions.angle = (-angle * M_PI) / 180 ;
+ cameraOptions.angle = -angle * util::DEG2RAD;
}
cameraOptions.center = mbgl::LatLng(latitude, longitude);
cameraOptions.padding = insets;
if (pitch != -1) {
- cameraOptions.pitch = pitch * M_PI / 180;
+ cameraOptions.pitch = pitch * util::DEG2RAD;
}
if (zoom != -1) {
cameraOptions.zoom = zoom;
@@ -819,6 +820,15 @@ jni::Array<jni::Object<geojson::Feature>> NativeMapView::queryRenderedFeaturesFo
return *convert<jni::Array<jni::Object<Feature>>, std::vector<mbgl::Feature>>(env, map->queryRenderedFeatures(box, { layers, toFilter(env, jfilter) }));
}
+jni::Object<Light> NativeMapView::getLight(JNIEnv& env) {
+ mbgl::style::Light* light = map->getLight();
+ if (light) {
+ return jni::Object<Light>(Light::createJavaLightPeer(env, *map, *light));
+ } else {
+ return jni::Object<Light>();
+ }
+}
+
jni::Array<jni::Object<Layer>> NativeMapView::getLayers(JNIEnv& env) {
// Get the core layers
@@ -1535,6 +1545,7 @@ void NativeMapView::registerNative(jni::JNIEnv& env) {
METHOD(&NativeMapView::queryPointAnnotations, "nativeQueryPointAnnotations"),
METHOD(&NativeMapView::queryRenderedFeaturesForPoint, "nativeQueryRenderedFeaturesForPoint"),
METHOD(&NativeMapView::queryRenderedFeaturesForBox, "nativeQueryRenderedFeaturesForBox"),
+ METHOD(&NativeMapView::getLight, "nativeGetLight"),
METHOD(&NativeMapView::getLayers, "nativeGetLayers"),
METHOD(&NativeMapView::getLayer, "nativeGetLayer"),
METHOD(&NativeMapView::addLayer, "nativeAddLayer"),
diff --git a/platform/android/src/native_map_view.hpp b/platform/android/src/native_map_view.hpp
index e5fcb9badd..df43ad08b7 100755
--- a/platform/android/src/native_map_view.hpp
+++ b/platform/android/src/native_map_view.hpp
@@ -24,6 +24,7 @@
#include "style/sources/sources.hpp"
#include "geometry/lat_lng_bounds.hpp"
#include "map/camera_position.hpp"
+#include "style/light.hpp"
#include <exception>
#include <string>
@@ -230,6 +231,8 @@ public:
jni::jfloat, jni::Array<jni::String>,
jni::Array<jni::Object<>> jfilter);
+ jni::Object<Light> getLight(JNIEnv&);
+
jni::Array<jni::Object<Layer>> getLayers(JNIEnv&);
jni::Object<Layer> getLayer(JNIEnv&, jni::String);
diff --git a/platform/android/src/style/conversion/position.hpp b/platform/android/src/style/conversion/position.hpp
new file mode 100644
index 0000000000..f32a892c0c
--- /dev/null
+++ b/platform/android/src/style/conversion/position.hpp
@@ -0,0 +1,37 @@
+#pragma once
+
+#include "../../conversion/conversion.hpp"
+
+#include <jni/jni.hpp>
+#include <mbgl/style/position.hpp>
+#include "../../jni/local_object.hpp"
+#include "../position.hpp"
+
+namespace mbgl {
+namespace android {
+namespace conversion {
+
+template<>
+struct Converter<jni::Object<Position>, mbgl::style::Position> {
+ Result<jni::Object<Position>> operator()(jni::JNIEnv &env, const mbgl::style::Position &value) const {
+ std::array<float, 3> cartPosition = value.getSpherical();
+ return Position::fromPosition(env, cartPosition[0], cartPosition[1], cartPosition[2]);
+ }
+};
+
+template<>
+struct Converter<mbgl::style::Position, jni::Object<Position>> {
+ Result<mbgl::style::Position> operator()(jni::JNIEnv &env, const jni::Object<Position> &value) const {
+ float radialCoordinate = Position::getRadialCoordinate(env, value);
+ float azimuthalAngle = Position::getAzimuthalAngle(env, value);
+ float polarAngle = Position::getPolarAngle(env, value);
+ std::array<float, 3> cartPosition {{radialCoordinate, azimuthalAngle, polarAngle}};
+ mbgl::style::Position position{};
+ position.set(cartPosition);
+ return position;
+ }
+};
+
+}
+}
+} \ No newline at end of file
diff --git a/platform/android/src/style/conversion/types.hpp b/platform/android/src/style/conversion/types.hpp
index d9921e582e..a00f668c24 100644
--- a/platform/android/src/style/conversion/types.hpp
+++ b/platform/android/src/style/conversion/types.hpp
@@ -92,6 +92,13 @@ struct Converter<jni::jobject*, mbgl::style::CirclePitchScaleType> {
}
};
+template <>
+struct Converter<jni::jobject*, mbgl::style::LightAnchorType> {
+ Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::LightAnchorType& value) const {
+ return convert<jni::jobject*, std::string>(env, toString(value));
+ }
+};
+
} // namespace conversion
} // namespace android
diff --git a/platform/android/src/style/conversion/types_string_values.hpp b/platform/android/src/style/conversion/types_string_values.hpp
index e3108fdf5b..e96de3b01e 100644
--- a/platform/android/src/style/conversion/types_string_values.hpp
+++ b/platform/android/src/style/conversion/types_string_values.hpp
@@ -206,6 +206,20 @@ namespace conversion {
}
}
+ // anchor
+ inline std::string toString(mbgl::style::LightAnchorType value) {
+ switch (value) {
+ case mbgl::style::LightAnchorType::Map:
+ return "map";
+ break;
+ case mbgl::style::LightAnchorType::Viewport:
+ return "viewport";
+ break;
+ default:
+ throw std::runtime_error("Not implemented");
+ }
+ }
+
} // namespace conversion
} // namespace android
diff --git a/platform/android/src/style/light.cpp b/platform/android/src/style/light.cpp
new file mode 100644
index 0000000000..71f1cb076e
--- /dev/null
+++ b/platform/android/src/style/light.cpp
@@ -0,0 +1,146 @@
+// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
+
+#include <mbgl/map/map.hpp>
+#include "light.hpp"
+#include "conversion/transition_options.hpp"
+#include "conversion/position.hpp"
+
+namespace mbgl {
+namespace android {
+
+Light::Light(mbgl::Map& coreMap, mbgl::style::Light& coreLight)
+ : light(coreLight) , map(&coreMap) {
+}
+
+static Light* initializeLightPeer(mbgl::Map& map, mbgl::style::Light& coreLight) {
+ return new Light(map, coreLight);
+}
+
+jni::jobject* Light::createJavaLightPeer(jni::JNIEnv& env, Map& map, mbgl::style::Light& coreLight) {
+ std::unique_ptr<Light> peerLight = std::unique_ptr<Light>(initializeLightPeer(map, coreLight));
+ jni::jobject* result = peerLight->createJavaPeer(env);
+ peerLight.release();
+ return result;
+}
+
+jni::Class<Light> Light::javaClass;
+
+jni::jobject* Light::createJavaPeer(jni::JNIEnv& env) {
+ static auto constructor = Light::javaClass.template GetConstructor<jni::jlong>(env);
+ return Light::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this));
+}
+
+void Light::setAnchor(jni::JNIEnv& env, jni::String property) {
+ std::string anchorStr = jni::Make<std::string>(env, property);
+ if (anchorStr.compare("map") == 0) {
+ light.setAnchor(LightAnchorType::Map);
+ } else if (anchorStr.compare("viewport") == 0) {
+ light.setAnchor(LightAnchorType::Viewport);
+ }
+}
+
+jni::String Light::getAnchor(jni::JNIEnv& env) {
+ auto anchorType = light.getAnchor();
+ if (anchorType == LightAnchorType::Map) {
+ return jni::Make<jni::String>(env, "map");
+ } else {
+ return jni::Make<jni::String>(env, "viewport");
+ }
+}
+
+void Light::setPosition(jni::JNIEnv& env, jni::Object<Position> jposition) {
+ using namespace mbgl::android::conversion;
+ auto position = *convert<mbgl::style::Position>(env, jposition);
+ light.setPosition(position);
+}
+
+jni::Object<Position> Light::getPosition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::Position position = light.getPosition().asConstant();
+ return *convert<jni::Object<Position>>(env, position);
+}
+
+jni::Object<TransitionOptions> Light::getPositionTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = light.getPositionTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+}
+
+void Light::setPositionTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ light.setPositionTransition(options);
+}
+
+void Light::setColor(jni::JNIEnv& env, jni::String property) {
+ auto color = Color::parse(jni::Make<std::string>(env, property));
+ if (color) {
+ light.setColor(color.value());
+ }
+}
+
+jni::String Light::getColor(jni::JNIEnv &env) {
+ auto color = light.getColor().asConstant();
+ return jni::Make<jni::String>(env, color.stringify());
+}
+
+jni::Object<TransitionOptions> Light::getColorTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = light.getColorTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+}
+
+void Light::setColorTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ light.setColorTransition(options);
+}
+
+void Light::setIntensity(jni::JNIEnv&, jni::jfloat property) {
+ light.setIntensity(property);
+}
+
+jni::jfloat Light::getIntensity(jni::JNIEnv&) {
+ return light.getIntensity().asConstant();
+}
+
+jni::Object<TransitionOptions> Light::getIntensityTransition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = light.getIntensityTransition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+}
+
+void Light::setIntensityTransition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ light.setIntensityTransition(options);
+}
+
+void Light::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ Light::javaClass = *jni::Class<Light>::Find(env).NewGlobalRef(env).release();
+
+#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
+ // Register the peer
+ jni::RegisterNativePeer<Light>(env, Light::javaClass, "nativePtr",
+ METHOD(&Light::getAnchor, "nativeGetAnchor"),
+ METHOD(&Light::setAnchor, "nativeSetAnchor"),
+ METHOD(&Light::getPositionTransition, "nativeGetPositionTransition"),
+ METHOD(&Light::setPositionTransition, "nativeSetPositionTransition"),
+ METHOD(&Light::getPosition, "nativeGetPosition"),
+ METHOD(&Light::setPosition, "nativeSetPosition"),
+ METHOD(&Light::getColorTransition, "nativeGetColorTransition"),
+ METHOD(&Light::setColorTransition, "nativeSetColorTransition"),
+ METHOD(&Light::getColor, "nativeGetColor"),
+ METHOD(&Light::setColor, "nativeSetColor"),
+ METHOD(&Light::getIntensityTransition, "nativeGetIntensityTransition"),
+ METHOD(&Light::setIntensityTransition, "nativeSetIntensityTransition"),
+ METHOD(&Light::getIntensity, "nativeGetIntensity"),
+ METHOD(&Light::setIntensity, "nativeSetIntensity"));
+}
+
+} // namespace android
+} // namespace mb
diff --git a/platform/android/src/style/light.cpp.ejs b/platform/android/src/style/light.cpp.ejs
new file mode 100644
index 0000000000..17f0bba09d
--- /dev/null
+++ b/platform/android/src/style/light.cpp.ejs
@@ -0,0 +1,123 @@
+<%
+ const properties = locals.properties;
+-%>
+// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
+
+#include <mbgl/map/map.hpp>
+#include "light.hpp"
+#include "conversion/transition_options.hpp"
+#include "conversion/position.hpp"
+
+namespace mbgl {
+namespace android {
+
+Light::Light(mbgl::Map& coreMap, mbgl::style::Light& coreLight)
+ : light(coreLight) , map(&coreMap) {
+}
+
+static Light* initializeLightPeer(mbgl::Map& map, mbgl::style::Light& coreLight) {
+ return new Light(map, coreLight);
+}
+
+jni::jobject* Light::createJavaLightPeer(jni::JNIEnv& env, Map& map, mbgl::style::Light& coreLight) {
+ std::unique_ptr<Light> peerLight = std::unique_ptr<Light>(initializeLightPeer(map, coreLight));
+ jni::jobject* result = peerLight->createJavaPeer(env);
+ peerLight.release();
+ return result;
+}
+
+jni::Class<Light> Light::javaClass;
+
+jni::jobject* Light::createJavaPeer(jni::JNIEnv& env) {
+ static auto constructor = Light::javaClass.template GetConstructor<jni::jlong>(env);
+ return Light::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this));
+}
+
+<% for (const property of properties) { -%>
+<% if (property.name == "position") { -%>
+void Light::set<%- camelize(property.name) %>(jni::JNIEnv& env, jni::Object<<%- camelize(property.name) %>> j<%- property.name %>) {
+ using namespace mbgl::android::conversion;
+ auto position = *convert<mbgl::style::<%- camelize(property.name) %>>(env, jposition);
+ light.set<%- camelize(property.name) %>(<%- property.name %>);
+}
+
+jni::Object<Position> Light::get<%- camelize(property.name) %>(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::<%- camelize(property.name) %> <%- property.name %> = light.get<%- camelize(property.name) %>().asConstant();
+ return *convert<jni::Object<<%- camelize(property.name) %>>>(env, <%- property.name %>);
+}
+<% } else { -%>
+<% if(property.name == "color") {-%>
+void Light::set<%- camelize(property.name) %>(jni::JNIEnv& env, jni::<%- propertyJNIType(property) %> property) {
+ auto color = Color::parse(jni::Make<std::string>(env, property));
+ if (color) {
+ light.set<%- camelize(property.name) %>(color.value());
+ }
+}
+
+jni::String Light::get<%- camelize(property.name) %>(jni::JNIEnv &env) {
+ auto color = light.get<%- camelize(property.name) %>().asConstant();
+ return jni::Make<jni::String>(env, color.stringify());
+}
+<% } else if(property.name == "anchor"){ -%>
+void Light::set<%- camelize(property.name) %>(jni::JNIEnv& env, jni::<%- propertyJNIType(property) %> property) {
+ std::string anchorStr = jni::Make<std::string>(env, property);
+ if (anchorStr.compare("map") == 0) {
+ light.setAnchor(LightAnchorType::Map);
+ } else if (anchorStr.compare("viewport") == 0) {
+ light.setAnchor(LightAnchorType::Viewport);
+ }
+}
+
+jni::String Light::getAnchor(jni::JNIEnv& env) {
+ auto anchorType = light.getAnchor();
+ if (anchorType == LightAnchorType::Map) {
+ return jni::Make<jni::String>(env, "map");
+ } else {
+ return jni::Make<jni::String>(env, "viewport");
+ }
+}
+<% } else { -%>
+void Light::set<%- camelize(property.name) %>(jni::JNIEnv&, jni::<%- propertyJNIType(property) %> property) {
+ light.set<%- camelize(property.name) %>(property);
+}
+
+jni::<%- propertyJNIType(property) %> Light::get<%- camelize(property.name) %>(jni::JNIEnv&) {
+ return light.get<%- camelize(property.name) %>().asConstant();
+}
+<% } -%>
+<% } -%>
+
+<% if (property.transition) { -%>
+jni::Object<TransitionOptions> Light::get<%- camelize(property.name) %>Transition(jni::JNIEnv& env) {
+ using namespace mbgl::android::conversion;
+ mbgl::style::TransitionOptions options = light.get<%- camelize(property.name) %>Transition();
+ return *convert<jni::Object<TransitionOptions>>(env, options);
+}
+
+void Light::set<%- camelize(property.name) %>Transition(jni::JNIEnv&, jlong duration, jlong delay) {
+ mbgl::style::TransitionOptions options;
+ options.duration.emplace(mbgl::Milliseconds(duration));
+ options.delay.emplace(mbgl::Milliseconds(delay));
+ light.set<%- camelize(property.name) %>Transition(options);
+}
+
+<% } -%>
+<% } -%>
+void Light::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ Light::javaClass = *jni::Class<Light>::Find(env).NewGlobalRef(env).release();
+
+#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
+ // Register the peer
+ jni::RegisterNativePeer<Light>(env, Light::javaClass, "nativePtr",<% for(var i = 0; i < properties.length; i++) {%>
+<% if (properties[i].transition) { -%>
+ METHOD(&Light::get<%- camelize(properties[i].name) %>Transition, "nativeGet<%- camelize(properties[i].name) %>Transition"),
+ METHOD(&Light::set<%- camelize(properties[i].name) %>Transition, "nativeSet<%- camelize(properties[i].name) %>Transition"),
+<% } -%>
+ METHOD(&Light::get<%- camelize(properties[i].name) %>, "nativeGet<%- camelize(properties[i].name) %>"),
+ METHOD(&Light::set<%- camelize(properties[i].name) %>, "nativeSet<%- camelize(properties[i].name) %>")<% if(i != (properties.length -1)) {-%>,<% } -%><% } -%>);
+}
+
+} // namespace android
+} // namespace mb
diff --git a/platform/android/src/style/light.hpp b/platform/android/src/style/light.hpp
new file mode 100644
index 0000000000..2c314067be
--- /dev/null
+++ b/platform/android/src/style/light.hpp
@@ -0,0 +1,57 @@
+// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
+
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+
+#include <jni/jni.hpp>
+#include <mbgl/style/light.hpp>
+#include "transition_options.hpp"
+#include "position.hpp"
+#include <mbgl/style/types.hpp>
+#include <mbgl/style/property_value.hpp>
+
+namespace mbgl {
+namespace android {
+
+using namespace style;
+
+class Light : private mbgl::util::noncopyable {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/light/Light"; };
+
+ static jni::Class<Light> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+ static jni::jobject* createJavaLightPeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Light&);
+
+ Light(mbgl::Map&, mbgl::style::Light&);
+
+ void setAnchor(jni::JNIEnv&, jni::String);
+ jni::String getAnchor(jni::JNIEnv&);
+ void setPosition(jni::JNIEnv&, jni::Object<Position>);
+ jni::Object<Position> getPosition(jni::JNIEnv&);
+ void setPositionTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getPositionTransition(jni::JNIEnv&);
+ void setColor(jni::JNIEnv&, jni::String);
+ jni::String getColor(jni::JNIEnv&);
+ void setColorTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getColorTransition(jni::JNIEnv&);
+ void setIntensity(jni::JNIEnv&, jni::jfloat);
+ jni::jfloat getIntensity(jni::JNIEnv&);
+ void setIntensityTransition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> getIntensityTransition(jni::JNIEnv&);
+ jni::jobject* createJavaPeer(jni::JNIEnv&);
+
+protected:
+
+ // Raw reference to the light
+ mbgl::style::Light& light;
+
+ // Map is set when the light is retrieved
+ mbgl::Map* map;
+};
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/style/light.hpp.ejs b/platform/android/src/style/light.hpp.ejs
new file mode 100644
index 0000000000..18f961b9e0
--- /dev/null
+++ b/platform/android/src/style/light.hpp.ejs
@@ -0,0 +1,59 @@
+<%
+ const properties = locals.properties;
+-%>
+// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
+
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+
+#include <jni/jni.hpp>
+#include <mbgl/style/light.hpp>
+#include "transition_options.hpp"
+#include "position.hpp"
+#include <mbgl/style/types.hpp>
+#include <mbgl/style/property_value.hpp>
+
+namespace mbgl {
+namespace android {
+
+using namespace style;
+
+class Light : private mbgl::util::noncopyable {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/light/Light"; };
+
+ static jni::Class<Light> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+ static jni::jobject* createJavaLightPeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Light&);
+
+ Light(mbgl::Map&, mbgl::style::Light&);
+
+<% for (const property of properties) { -%>
+<% if (property.name=="position") {-%>
+ void set<%- camelize(property.name) %>(jni::JNIEnv&, jni::Object<Position>);
+ jni::Object<<%- camelize(property.name) %>> get<%- camelize(property.name) %>(jni::JNIEnv&);
+<% } else { -%>
+ void set<%- camelize(property.name) %>(jni::JNIEnv&, jni::<%- propertyJNIType(property) %>);
+ jni::<%- propertyJNIType(property) %> get<%- camelize(property.name) %>(jni::JNIEnv&);
+<% } -%>
+<% if (property.transition) { -%>
+ void set<%- camelize(property.name) %>Transition(jni::JNIEnv&, jlong duration, jlong delay);
+ jni::Object<TransitionOptions> get<%- camelize(property.name) %>Transition(jni::JNIEnv&);
+<% } -%>
+<% } -%>
+ jni::jobject* createJavaPeer(jni::JNIEnv&);
+
+protected:
+
+ // Raw reference to the light
+ mbgl::style::Light& light;
+
+ // Map is set when the light is retrieved
+ mbgl::Map* map;
+};
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/style/position.cpp b/platform/android/src/style/position.cpp
new file mode 100644
index 0000000000..0bbcefcbcd
--- /dev/null
+++ b/platform/android/src/style/position.cpp
@@ -0,0 +1,34 @@
+#include "position.hpp"
+
+namespace mbgl {
+namespace android {
+
+jni::Object<Position> Position::fromPosition(jni::JNIEnv& env, jfloat radialCoordinate, jfloat azimuthalAngle, jfloat polarAngle) {
+ static auto method = Position::javaClass.GetStaticMethod<jni::Object<Position> (jfloat, jfloat, jfloat)>(env, "fromPosition");
+ return Position::javaClass.Call(env, method, radialCoordinate, azimuthalAngle, polarAngle);
+}
+
+void Position::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ Position::javaClass = *jni::Class<Position>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<Position> Position::javaClass;
+
+float Position::getRadialCoordinate(jni::JNIEnv& env, jni::Object<Position> position){
+ static auto field = Position::javaClass.GetField<jfloat>(env, "radialCoordinate");
+ return position.Get(env, field);
+}
+
+float Position::getAzimuthalAngle(jni::JNIEnv& env, jni::Object<Position> position){
+ static auto field = Position::javaClass.GetField<jfloat>(env, "azimuthalAngle");
+ return position.Get(env, field);
+}
+
+float Position::getPolarAngle(jni::JNIEnv& env, jni::Object<Position> position){
+ static auto field = Position::javaClass.GetField<jfloat>(env, "polarAngle");
+ return position.Get(env, field);
+}
+
+} // namespace andr[oid
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/style/position.hpp b/platform/android/src/style/position.hpp
new file mode 100644
index 0000000000..4aafa853db
--- /dev/null
+++ b/platform/android/src/style/position.hpp
@@ -0,0 +1,29 @@
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class Position : private mbgl::util::noncopyable {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/light/Position"; };
+
+ static jni::Object<Position> fromPosition(jni::JNIEnv&, jfloat, jfloat, jfloat);
+
+ static jni::Class<Position> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+ static float getRadialCoordinate(jni::JNIEnv&, jni::Object<Position>);
+ static float getAzimuthalAngle(jni::JNIEnv&, jni::Object<Position>);
+ static float getPolarAngle(jni::JNIEnv&, jni::Object<Position>);
+
+};
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/darwin/docs/guides/Tile URL Templates.md.ejs b/platform/darwin/docs/guides/Tile URL Templates.md.ejs
new file mode 100644
index 0000000000..78fb297138
--- /dev/null
+++ b/platform/darwin/docs/guides/Tile URL Templates.md.ejs
@@ -0,0 +1,109 @@
+<%
+ const os = locals.os;
+ const iOS = os === 'iOS';
+ //const macOS = os === 'macOS';
+ //const cocoaPrefix = iOS ? 'UI' : 'NS';
+-%>
+<!--
+ This file is generated.
+ Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
+-->
+# Tile URL Templates
+
+`MGLTileSource` objects, specifically `MGLRasterSource` and `MGLVectorSource`
+objects, can be created using an initializer that accepts an array of tile URL
+templates. Tile URL templates are strings that specify the URLs of the vector
+tiles or raster tile images to load. A template resembles an absolute URL, but
+with any number of placeholder strings that the source evaluates based on the
+tile it needs to load. For example:
+
+* `http://www.example.com/tiles/{z}/{x}/{y}.pbf` could be
+ evaluated as `http://www.example.com/tiles/14/6/9.pbf`.
+* `http://www.example.com/tiles/{z}/{x}/{y}{ratio}.png` could be
+ evaluated as `http://www.example.com/tiles/14/6/9@2x.png`.
+
+Tile URL templates are also used to define tilesets in TileJSON manifests or
+[`raster`](https://www.mapbox.com/mapbox-gl-js/style-spec/#sources-raster-tiles)
+and
+[`vector`](https://www.mapbox.com/mapbox-gl-js/style-spec/#sources-vector-tiles)
+sources in style JSON files. See the
+[TileJSON specification](https://github.com/mapbox/tilejson-spec/tree/master/2.2.0)
+for information about tile URL templates in the context of a TileJSON or style
+JSON file.
+
+Tile sources support the following placeholder strings in tile URL templates,
+all of which are optional:
+
+<table>
+<thead>
+<tr><th>Placeholder string</th><th>Description</th></tr>
+</thead>
+<tbody>
+<tr>
+ <td><code>{x}</code></td>
+ <td>The index of the tile along the map’s x axis according to Spherical
+ Mercator projection. If the value is 0, the tile’s left edge corresponds
+ to the 180th meridian west. If the value is 2<sup><var>z</var></sup>−1,
+ the tile’s right edge corresponds to the 180th meridian east.</td>
+</tr>
+<tr>
+ <td><code>{y}</code></td>
+ <td>The index of the tile along the map’s y axis according to Spherical
+ Mercator projection. If the value is 0, the tile’s tile edge corresponds
+ to arctan(sinh(π)), or approximately 85.0511 degrees north. If the value
+ is 2<sup><var>z</var></sup>−1, the tile’s bottom edge corresponds to
+ −arctan(sinh(π)), or approximately 85.0511 degrees south. The y axis is
+ inverted if the <code>options</code> parameter contains
+ <code>MGLTileSourceOptionTileCoordinateSystem</code> with a value of
+ <code>MGLTileCoordinateSystemTMS</code>.</td>
+</tr>
+<tr>
+ <td><code>{z}</code></td>
+ <td>The tile’s zoom level. At zoom level 0, each tile covers the entire
+ world map; at zoom level 1, it covers ¼ of the world; at zoom level 2,
+ <sup>1</sup>⁄<sub>16</sub> of the world, and so on. For tiles loaded by
+ a <code>MGLRasterSource</code> object, whether the tile zoom level
+ matches the map’s current zoom level depends on the value of the
+ source’s tile size as specified in the
+ <code>MGLTileSourceOptionTileSize</code> key of the <code>options</code>
+ parameter.</td>
+</tr>
+<tr>
+ <td><code>{bbox-epsg-3857}</code></td>
+ <td>The tile’s bounding box, expressed as a comma-separated list of the
+ tile’s western, southern, eastern, and northern extents according to
+ Spherical Mercator (EPSG:3857) projection. The bounding box is typically
+ used with map services conforming to the
+ <a href="http://www.opengeospatial.org/standards/wms">Web Map Service</a>
+ protocol.</td>
+</tr>
+<tr>
+ <td><code>{quadkey}</code></td>
+ <td>A quadkey indicating both the tile’s location and its zoom level. The
+ quadkey is typically used with
+ <a href="https://msdn.microsoft.com/en-us/library/bb259689.aspx">Bing Maps</a>.
+ </td>
+</tr>
+<tr>
+ <td><code>{ratio}</code></td>
+ <td>A suffix indicating the resolution of the tile image. The suffix is the
+ empty string for standard resolution displays and <code>@2x</code> for
+<% if (iOS) { -%>
+ Retina displays, including displays for which <code>UIScreen.scale</code>
+ is 3.
+<% } else { -%>
+ Retina displays.
+<% } -%>
+ </td>
+</tr>
+<tr>
+ <td><code>{prefix}</code></td>
+ <td>Two hexadecimal digits chosen such that each visible tile has a
+ different prefix. The prefix is typically used for domain sharding.</td>
+</tr>
+</tbody>
+</table>
+
+For more information about the `{x}`, `{y}`, and `{z}` placeholder strings,
+consult the
+[OpenStreetMap Wiki](https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames).
diff --git a/platform/darwin/scripts/generate-style-code.js b/platform/darwin/scripts/generate-style-code.js
index 330a8f1d03..7efc8d441c 100644
--- a/platform/darwin/scripts/generate-style-code.js
+++ b/platform/darwin/scripts/generate-style-code.js
@@ -522,8 +522,9 @@ global.setSourceLayer = function() {
const layerH = ejs.compile(fs.readFileSync('platform/darwin/src/MGLStyleLayer.h.ejs', 'utf8'), { strict: true });
const layerM = ejs.compile(fs.readFileSync('platform/darwin/src/MGLStyleLayer.mm.ejs', 'utf8'), { strict: true});
const testLayers = ejs.compile(fs.readFileSync('platform/darwin/test/MGLStyleLayerTests.mm.ejs', 'utf8'), { strict: true});
-const guideMD = ejs.compile(fs.readFileSync('platform/darwin/docs/guides/For Style Authors.md.ejs', 'utf8'), { strict: true });
+const forStyleAuthorsMD = ejs.compile(fs.readFileSync('platform/darwin/docs/guides/For Style Authors.md.ejs', 'utf8'), { strict: true });
const ddsGuideMD = ejs.compile(fs.readFileSync('platform/darwin/docs/guides/Using Style Functions at Runtime.md.ejs', 'utf8'), { strict: true });
+const templatesMD = ejs.compile(fs.readFileSync('platform/darwin/docs/guides/Tile URL Templates.md.ejs', 'utf8'), { strict: true });
const layers = _(spec.layer.type.values).map((value, layerType) => {
const layoutProperties = Object.keys(spec[`layout_${layerType}`]).reduce((memo, name) => {
@@ -635,12 +636,12 @@ global.guideExample = function (guide, exampleId, os) {
return '```swift\n' + example + '\n```';
};
-fs.writeFileSync(`platform/ios/docs/guides/For Style Authors.md`, guideMD({
+fs.writeFileSync(`platform/ios/docs/guides/For Style Authors.md`, forStyleAuthorsMD({
os: 'iOS',
renamedProperties: renamedPropertiesByLayerType,
layers: layers,
}));
-fs.writeFileSync(`platform/macos/docs/guides/For Style Authors.md`, guideMD({
+fs.writeFileSync(`platform/macos/docs/guides/For Style Authors.md`, forStyleAuthorsMD({
os: 'macOS',
renamedProperties: renamedPropertiesByLayerType,
layers: layers,
@@ -651,3 +652,9 @@ fs.writeFileSync(`platform/ios/docs/guides/Using Style Functions at Runtime.md`,
fs.writeFileSync(`platform/macos/docs/guides/Using Style Functions at Runtime.md`, ddsGuideMD({
os: 'macOS',
}));
+fs.writeFileSync(`platform/ios/docs/guides/Tile URL Templates.md`, templatesMD({
+ os: 'iOS',
+}));
+fs.writeFileSync(`platform/macos/docs/guides/Tile URL Templates.md`, templatesMD({
+ os: 'macOS',
+}));
diff --git a/platform/darwin/src/MGLAttributionInfo.mm b/platform/darwin/src/MGLAttributionInfo.mm
index 7583244491..770aeb25e7 100644
--- a/platform/darwin/src/MGLAttributionInfo.mm
+++ b/platform/darwin/src/MGLAttributionInfo.mm
@@ -6,8 +6,10 @@
#import <Cocoa/Cocoa.h>
#endif
+#import "MGLAccountManager.h"
#import "MGLMapCamera.h"
#import "NSArray+MGLAdditions.h"
+#import "NSBundle+MGLAdditions.h"
#import "NSString+MGLAdditions.h"
#include <string>
@@ -126,13 +128,34 @@
}
- (nullable NSURL *)feedbackURLAtCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate zoomLevel:(double)zoomLevel {
+ return [self feedbackURLForStyleURL:nil atCenterCoordinate:centerCoordinate zoomLevel:zoomLevel direction:0 pitch:0];
+}
+
+- (nullable NSURL *)feedbackURLForStyleURL:(nullable NSURL *)styleURL atCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate zoomLevel:(double)zoomLevel direction:(CLLocationDirection)direction pitch:(CGFloat)pitch {
if (!self.feedbackLink) {
return nil;
}
-
- NSURLComponents *components = [NSURLComponents componentsWithURL:self.URL resolvingAgainstBaseURL:NO];
- components.fragment = [NSString stringWithFormat:@"/%.5f/%.5f/%i",
- centerCoordinate.longitude, centerCoordinate.latitude, (int)round(zoomLevel + 1)];
+
+ NSURLComponents *components = [NSURLComponents componentsWithString:@"https://www.mapbox.com/feedback/"];
+ components.fragment = [NSString stringWithFormat:@"/%.5f/%.5f/%.2f/%.1f/%i",
+ centerCoordinate.longitude, centerCoordinate.latitude, zoomLevel,
+ direction, (int)round(pitch)];
+
+ NSURLQueryItem *referrerQueryItem = [NSURLQueryItem queryItemWithName:@"referrer"
+ value:[NSBundle mgl_applicationBundleIdentifier]];
+ NSMutableArray<NSURLQueryItem *> *queryItems = [NSMutableArray arrayWithObject:referrerQueryItem];
+ if ([styleURL.scheme isEqualToString:@"mapbox"] && [styleURL.host isEqualToString:@"styles"]) {
+ NSArray<NSString *> *stylePathComponents = styleURL.pathComponents;
+ if (stylePathComponents.count >= 3) {
+ [queryItems addObjectsFromArray:@[
+ [NSURLQueryItem queryItemWithName:@"owner" value:stylePathComponents[1]],
+ [NSURLQueryItem queryItemWithName:@"id" value:stylePathComponents[2]],
+ [NSURLQueryItem queryItemWithName:@"access_token" value:[MGLAccountManager accessToken]],
+ ]];
+ }
+ }
+ components.queryItems = queryItems;
+
return components.URL;
}
diff --git a/platform/darwin/src/MGLAttributionInfo_Private.h b/platform/darwin/src/MGLAttributionInfo_Private.h
index 08bc6bfc4d..c639752ac3 100644
--- a/platform/darwin/src/MGLAttributionInfo_Private.h
+++ b/platform/darwin/src/MGLAttributionInfo_Private.h
@@ -20,6 +20,24 @@ NS_ASSUME_NONNULL_BEGIN
+ (NSAttributedString *)attributedStringForAttributionInfos:(NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfos;
+/**
+ Returns a copy of the `URL` property modified to account for the given style
+ URL, center coordinate, and zoom level.
+
+ @param styleURL The map’s style URL.
+ @param centerCoordinate The map’s center coordinate.
+ @param zoomLevel The map’s zoom level. See the `MGLMapView.zoomLevel` property
+ for more information.
+ @param direction The heading of the map, measured in degrees clockwise from
+ true north.
+ @param pitch Pitch toward the horizon measured in degrees, with 0 degrees
+ resulting in a two-dimensional map.
+ @return A modified URL containing a fragment that points to the specified
+ viewport. If the `feedbackLink` property is set to `NO`, this method returns
+ `nil`.
+ */
+- (nullable NSURL *)feedbackURLForStyleURL:(nullable NSURL *)styleURL atCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate zoomLevel:(double)zoomLevel direction:(CLLocationDirection)direction pitch:(CGFloat)pitch;
+
@end
@interface NSMutableArray (MGLAttributionInfoAdditions)
diff --git a/platform/darwin/src/MGLFillExtrusionStyleLayer.h b/platform/darwin/src/MGLFillExtrusionStyleLayer.h
index 84f6bedde4..c4fb9aa77e 100644
--- a/platform/darwin/src/MGLFillExtrusionStyleLayer.h
+++ b/platform/darwin/src/MGLFillExtrusionStyleLayer.h
@@ -46,7 +46,7 @@ typedef NS_ENUM(NSUInteger, MGLFillExtrusionTranslationAnchor) {
layer.sourceLayerIdentifier = "building"
layer.fillExtrusionHeight = MGLStyleValue(interpolationMode: .identity, sourceStops: nil, attributeName: "height", options: nil)
layer.fillExtrusionBase = MGLStyleValue(interpolationMode: .identity, sourceStops: nil, attributeName: "min_height", options: nil)
- layer.predicate = NSPredicate(format: "extrude == TRUE")
+ layer.predicate = NSPredicate(format: "extrude == 'true'")
mapView.style?.addLayer(layer)
```
*/
diff --git a/platform/darwin/src/MGLGeometry_Private.h b/platform/darwin/src/MGLGeometry_Private.h
index 3e029e8ee0..7ad8314a79 100644
--- a/platform/darwin/src/MGLGeometry_Private.h
+++ b/platform/darwin/src/MGLGeometry_Private.h
@@ -8,6 +8,26 @@
#import <mbgl/util/geo.hpp>
#import <mbgl/util/geometry.hpp>
+typedef double MGLLocationRadians;
+typedef double MGLRadianDistance;
+typedef double MGLRadianDirection;
+
+/** Defines the coordinate by a `MGLRadianCoordinate2D`. */
+typedef struct MGLRadianCoordinate2D {
+ MGLLocationRadians latitude;
+ MGLLocationRadians longitude;
+} MGLRadianCoordinate2D;
+
+/**
+ Creates a new `MGLRadianCoordinate2D` from the given latitudinal and longitudinal.
+ */
+NS_INLINE MGLRadianCoordinate2D MGLRadianCoordinate2DMake(MGLLocationRadians latitude, MGLLocationRadians longitude) {
+ MGLRadianCoordinate2D radianCoordinate;
+ radianCoordinate.latitude = latitude;
+ radianCoordinate.longitude = longitude;
+ return radianCoordinate;
+}
+
/// Returns the smallest rectangle that contains both the given rectangle and
/// the given point.
CGRect MGLExtendRect(CGRect rect, CGPoint point);
@@ -18,6 +38,10 @@ NS_INLINE mbgl::Point<double> MGLPointFromLocationCoordinate2D(CLLocationCoordin
return mbgl::Point<double>(coordinate.longitude, coordinate.latitude);
}
+NS_INLINE CLLocationCoordinate2D MGLLocationCoordinate2DFromPoint(mbgl::Point<double> point) {
+ return CLLocationCoordinate2DMake(point.y, point.x);
+}
+
NS_INLINE CLLocationCoordinate2D MGLLocationCoordinate2DFromLatLng(mbgl::LatLng latLng) {
return CLLocationCoordinate2DMake(latLng.latitude(), latLng.longitude());
}
@@ -59,3 +83,43 @@ CLLocationDistance MGLAltitudeForZoomLevel(double zoomLevel, CGFloat pitch, CLLo
@param size The size of the viewport.
@return A zero-based zoom level. */
double MGLZoomLevelForAltitude(CLLocationDistance altitude, CGFloat pitch, CLLocationDegrees latitude, CGSize size);
+
+/** Returns MGLRadianCoordinate2D, converted from CLLocationCoordinate2D. */
+NS_INLINE MGLRadianCoordinate2D MGLRadianCoordinateFromLocationCoordinate(CLLocationCoordinate2D locationCoordinate) {
+ return MGLRadianCoordinate2DMake(MGLRadiansFromDegrees(locationCoordinate.latitude),
+ MGLRadiansFromDegrees(locationCoordinate.longitude));
+}
+
+/*
+ Returns the distance in radians given two coordinates.
+ */
+NS_INLINE MGLRadianDistance MGLDistanceBetweenRadianCoordinates(MGLRadianCoordinate2D from, MGLRadianCoordinate2D to)
+{
+ double a = pow(sin((to.latitude - from.latitude) / 2), 2)
+ + pow(sin((to.longitude - from.longitude) / 2), 2) * cos(from.latitude) * cos(to.latitude);
+
+ return 2 * atan2(sqrt(a), sqrt(1 - a));
+}
+
+/*
+ Returns direction in radians given two coordinates.
+ */
+NS_INLINE MGLRadianDirection MGLRadianCoordinatesDirection(MGLRadianCoordinate2D from, MGLRadianCoordinate2D to) {
+ double a = sin(to.longitude - from.longitude) * cos(to.latitude);
+ double b = cos(from.latitude) * sin(to.latitude)
+ - sin(from.latitude) * cos(to.latitude) * cos(to.longitude - from.longitude);
+ return atan2(a, b);
+}
+
+/*
+ Returns coordinate at a given distance and direction away from coordinate.
+ */
+NS_INLINE MGLRadianCoordinate2D MGLRadianCoordinateAtDistanceFacingDirection(MGLRadianCoordinate2D coordinate,
+ MGLRadianDistance distance,
+ MGLRadianDirection direction) {
+ double otherLatitude = asin(sin(coordinate.latitude) * cos(distance)
+ + cos(coordinate.latitude) * sin(distance) * cos(direction));
+ double otherLongitude = coordinate.longitude + atan2(sin(direction) * sin(distance) * cos(coordinate.latitude),
+ cos(distance) - sin(coordinate.latitude) * sin(otherLatitude));
+ return MGLRadianCoordinate2DMake(otherLatitude, otherLongitude);
+}
diff --git a/platform/darwin/src/MGLLight.h b/platform/darwin/src/MGLLight.h
new file mode 100644
index 0000000000..ef9811bd33
--- /dev/null
+++ b/platform/darwin/src/MGLLight.h
@@ -0,0 +1,125 @@
+#import <CoreLocation/CoreLocation.h>
+
+#import "MGLFoundation.h"
+#import "MGLStyleValue.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+
+/** Options to specify extruded geometries are lit relative to the map or viewport. */
+typedef NS_ENUM(NSUInteger, MGLLightAnchor) {
+ /** The position of the light source is aligned to the rotation of the map. */
+ MGLLightAnchorMap,
+ /** The position of the light source is aligned to the rotation of the viewport. */
+ MGLLightAnchorViewport
+};
+
+/**
+ A structure containing information about the position of the light source
+ relative to lit geometries.
+ */
+typedef struct MGLSphericalPosition {
+ /** Distance from the center of the base of an object to its light. */
+ CLLocationDistance radial;
+ /** Position of the light relative to 0° (0° when `MGLLight.anchor` is set to viewport corresponds
+ to the top of the viewport, or 0° when `MGLLight.anchor` is set to map corresponds to due north,
+ and degrees proceed clockwise). */
+ CLLocationDirection azimuthal;
+ /** Indicates the height of the light (from 0°, directly above, to 180°, directly below). */
+ CLLocationDirection polar;
+} MGLSphericalPosition;
+
+/**
+ Creates a new `MGLSphericalPosition` from the given radial, azimuthal, polar.
+
+ @param radial The radial coordinate.
+ @param azimuthal The azimuthal angle.
+ @param polar The polar angle.
+
+ @return Returns a `MGLSphericalPosition` struct containing the position attributes.
+ */
+NS_INLINE MGLSphericalPosition MGLSphericalPositionMake(CLLocationDistance radial, CLLocationDirection azimuthal, CLLocationDirection polar) {
+ MGLSphericalPosition position;
+ position.radial = radial;
+ position.azimuthal = azimuthal;
+ position.polar = polar;
+
+ return position;
+}
+
+/**
+ An `MGLLight` object represents the light source for extruded geometries in `MGLStyle`.
+ */
+MGL_EXPORT
+@interface MGLLight : NSObject
+
+/**
+ `anchor` Whether extruded geometries are lit relative to the map or viewport.
+
+ This property corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-js/style-spec/#light-anchor"><code>anchor</code></a>
+ light property in the Mapbox Style Specification.
+ */
+@property (nonatomic) MGLStyleValue<NSValue *> *anchor;
+
+/**
+ Values describing animated transitions to `anchor` property.
+ */
+@property (nonatomic) MGLTransition anchorTransition;
+
+
+/**
+ Position of the light source relative to lit (extruded) geometries.
+
+ This property corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-js/style-spec/#light-position"><code>position</code></a>
+ light property in the Mapbox Style Specification.
+ */
+@property (nonatomic) MGLStyleValue<NSValue *> *position;
+
+/**
+ Values describing animated transitions to `position` property.
+ */
+@property (nonatomic) MGLTransition positionTransiton;
+
+
+#if TARGET_OS_IPHONE
+/**
+ Color tint for lighting extruded geometries.
+
+ This property corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-js/style-spec/#light-color"><code>color</code></a>
+ light property in the Mapbox Style Specification.
+ */
+@property (nonatomic) MGLStyleValue<UIColor *> *color;
+#else
+
+/**
+ Color tint for lighting extruded geometries.
+ */
+@property (nonatomic) MGLStyleValue<NSColor *> *color;
+#endif
+
+/**
+ Values describing animated transitions to `color` property.
+ */
+@property (nonatomic) MGLTransition colorTransiton;
+
+
+/**
+ Intensity of lighting (on a scale from 0 to 1). Higher numbers will present as more extreme contrast.
+
+ This property corresponds to the <a
+ href="https://www.mapbox.com/mapbox-gl-js/style-spec/#light-intensity"><code>intensity</code></a>
+ light property in the Mapbox Style Specification.
+ */
+@property(nonatomic) MGLStyleValue<NSNumber *> *intensity;
+
+/**
+ Values describing animated transitions to `intensity` property.
+ */
+@property (nonatomic) MGLTransition intensityTransition;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLLight.mm b/platform/darwin/src/MGLLight.mm
new file mode 100644
index 0000000000..262fad3b07
--- /dev/null
+++ b/platform/darwin/src/MGLLight.mm
@@ -0,0 +1,113 @@
+#import "MGLLight.h"
+
+#import "MGLTypes.h"
+#import "NSDate+MGLAdditions.h"
+#import "MGLStyleValue_Private.h"
+#import "NSValue+MGLAdditions.h"
+
+#import <mbgl/style/light.hpp>
+#import <mbgl/style/types.hpp>
+
+namespace mbgl {
+
+ MBGL_DEFINE_ENUM(MGLLightAnchor, {
+ { MGLLightAnchorMap, "map" },
+ { MGLLightAnchorViewport, "viewport" },
+ });
+
+}
+
+NS_INLINE MGLTransition MGLTransitionFromOptions(const mbgl::style::TransitionOptions& options) {
+ MGLTransition transition;
+ transition.duration = MGLTimeIntervalFromDuration(options.duration.value_or(mbgl::Duration::zero()));
+ transition.delay = MGLTimeIntervalFromDuration(options.delay.value_or(mbgl::Duration::zero()));
+
+ return transition;
+}
+
+NS_INLINE mbgl::style::TransitionOptions MGLOptionsFromTransition(MGLTransition transition) {
+ mbgl::style::TransitionOptions options { { MGLDurationFromTimeInterval(transition.duration) }, { MGLDurationFromTimeInterval(transition.delay) } };
+ return options;
+}
+
+@interface MGLLight()
+
+@end
+
+@implementation MGLLight
+
+- (instancetype)initWithMBGLLight:(const mbgl::style::Light *)mbglLight
+{
+ if (self = [super init]) {
+ auto anchor = mbglLight->getAnchor();
+ MGLStyleValue<NSValue *> *anchorStyleValue;
+ if (anchor.isUndefined()) {
+ mbgl::style::PropertyValue<mbgl::style::LightAnchorType> defaultAnchor = mbglLight->getDefaultAnchor();
+ anchorStyleValue = MGLStyleValueTransformer<mbgl::style::LightAnchorType, NSValue *, mbgl::style::LightAnchorType, MGLLightAnchor>().toEnumStyleValue(defaultAnchor);
+ } else {
+ anchorStyleValue = MGLStyleValueTransformer<mbgl::style::LightAnchorType, NSValue *, mbgl::style::LightAnchorType, MGLLightAnchor>().toEnumStyleValue(anchor);
+ }
+
+ _anchor = anchorStyleValue;
+
+ _anchorTransition = MGLTransitionFromOptions(mbglLight->getAnchorTransition());
+
+ auto positionValue = mbglLight->getPosition();
+ if (positionValue.isUndefined()) {
+ _position = MGLStyleValueTransformer<mbgl::style::Position, NSValue *>().toStyleValue(mbglLight->getDefaultPosition());
+ } else {
+ _position = MGLStyleValueTransformer<mbgl::style::Position, NSValue *>().toStyleValue(positionValue);
+ }
+
+ _positionTransiton = MGLTransitionFromOptions(mbglLight->getPositionTransition());
+
+ auto colorValue = mbglLight->getColor();
+ if (colorValue.isUndefined()) {
+ _color = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(mbglLight->getDefaultColor());
+ } else {
+ _color = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(colorValue);
+ }
+
+ _colorTransiton = MGLTransitionFromOptions(mbglLight->getColorTransition());
+
+ auto intensityValue = mbglLight->getIntensity();
+ if (intensityValue.isUndefined()) {
+ _intensity = MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(mbglLight->getDefaultIntensity());
+ } else {
+ _intensity = MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(intensityValue);
+ }
+
+ _intensityTransition = MGLTransitionFromOptions(mbglLight->getIntensityTransition());
+ }
+
+ return self;
+}
+
+- (mbgl::style::Light)mbglLight
+{
+ mbgl::style::Light mbglLight;
+
+ auto anchor = MGLStyleValueTransformer<mbgl::style::LightAnchorType, NSValue *, mbgl::style::LightAnchorType, MGLLightAnchor>().toEnumPropertyValue(self.anchor);
+ mbglLight.setAnchor(anchor);
+
+ mbglLight.setAnchorTransition(MGLOptionsFromTransition(self.anchorTransition));
+
+ auto position = MGLStyleValueTransformer<mbgl::style::Position, NSValue *>().toInterpolatablePropertyValue(self.position);
+ mbglLight.setPosition(position);
+
+ mbglLight.setPositionTransition(MGLOptionsFromTransition(self.positionTransiton));
+
+ auto color = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toInterpolatablePropertyValue(self.color);
+ mbglLight.setColor(color);
+
+ mbglLight.setColorTransition(MGLOptionsFromTransition(self.colorTransiton));
+
+ auto intensity = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(self.intensity);
+ mbglLight.setIntensity(intensity);
+
+ mbglLight.setIntensityTransition(MGLOptionsFromTransition(self.intensityTransition));
+
+ return mbglLight;
+}
+
+@end
diff --git a/platform/darwin/src/MGLLight_Private.h b/platform/darwin/src/MGLLight_Private.h
new file mode 100644
index 0000000000..dbc29c1eff
--- /dev/null
+++ b/platform/darwin/src/MGLLight_Private.h
@@ -0,0 +1,23 @@
+#import <Foundation/Foundation.h>
+
+#import "MGLLight.h"
+
+namespace mbgl {
+ namespace style {
+ class Light;
+ }
+}
+
+@interface MGLLight (Private)
+
+/**
+ Initializes and returns a `MGLLight` associated with a style's light.
+ */
+- (instancetype)initWithMBGLLight:(const mbgl::style::Light *)mbglLight;
+
+/**
+ Returns an `mbgl::style::Light` representation of the `MGLLight`.
+ */
+- (mbgl::style::Light)mbglLight;
+
+@end
diff --git a/platform/darwin/src/MGLOfflineStorage.mm b/platform/darwin/src/MGLOfflineStorage.mm
index 195ef3c36a..81774ad3cb 100644
--- a/platform/darwin/src/MGLOfflineStorage.mm
+++ b/platform/darwin/src/MGLOfflineStorage.mm
@@ -7,6 +7,7 @@
#import "MGLOfflinePack_Private.h"
#import "MGLOfflineRegion_Private.h"
#import "MGLTilePyramidOfflineRegion.h"
+#import "NSBundle+MGLAdditions.h"
#import "NSValue+MGLAdditions.h"
#include <mbgl/util/string.hpp>
@@ -132,7 +133,7 @@ NSString * const MGLOfflinePackMaximumCountUserInfoKey = MGLOfflinePackUserInfoK
appropriateForURL:nil
create:YES
error:nil];
- NSString *bundleIdentifier = [self bundleIdentifier];
+ NSString *bundleIdentifier = [NSBundle mgl_applicationBundleIdentifier];
if (!bundleIdentifier) {
// There’s no main bundle identifier when running in a unit test bundle.
bundleIdentifier = [NSBundle bundleForClass:self].bundleIdentifier;
@@ -166,7 +167,7 @@ NSString * const MGLOfflinePackMaximumCountUserInfoKey = MGLOfflinePackUserInfoK
NSString *legacyCachePath = [legacyPaths.firstObject stringByAppendingPathComponent:MGLOfflineStorageFileName3_2_0_beta_1];
#elif TARGET_OS_MAC
// ~/Library/Caches/tld.app.bundle.id/offline.db
- NSString *bundleIdentifier = [self bundleIdentifier];
+ NSString *bundleIdentifier = [NSBundle mgl_applicationBundleIdentifier];
NSURL *legacyCacheDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSCachesDirectory
inDomain:NSUserDomainMask
appropriateForURL:nil
@@ -219,15 +220,6 @@ NSString * const MGLOfflinePackMaximumCountUserInfoKey = MGLOfflinePackUserInfoK
return self;
}
-+ (NSString *)bundleIdentifier {
- NSString *bundleIdentifier = [NSBundle mainBundle].bundleIdentifier;
- if (!bundleIdentifier) {
- // There’s no main bundle identifier when running in a unit test bundle.
- bundleIdentifier = [NSBundle bundleForClass:self].bundleIdentifier;
- }
- return bundleIdentifier;
-}
-
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[[MGLNetworkConfiguration sharedManager] removeObserver:self forKeyPath:@"apiBaseURL"];
diff --git a/platform/darwin/src/MGLPolygon.mm b/platform/darwin/src/MGLPolygon.mm
index ceafe873bf..d966ff13ce 100644
--- a/platform/darwin/src/MGLPolygon.mm
+++ b/platform/darwin/src/MGLPolygon.mm
@@ -6,6 +6,7 @@
#import "MGLPolygon+MGLAdditions.h"
#import <mbgl/util/geojson.hpp>
+#import <mapbox/polylabel.hpp>
@implementation MGLPolygon
@@ -54,6 +55,13 @@
return [super hash] + [[self geoJSONDictionary] hash];
}
+- (CLLocationCoordinate2D)coordinate {
+ // pole of inaccessibility
+ auto poi = mapbox::polylabel([self polygon]);
+
+ return MGLLocationCoordinate2DFromPoint(poi);
+}
+
- (mbgl::LinearRing<double>)ring {
NSUInteger count = self.pointCount;
CLLocationCoordinate2D *coordinates = self.coordinates;
@@ -155,11 +163,17 @@
return hash;
}
+- (CLLocationCoordinate2D)coordinate {
+ MGLPolygon *firstPolygon = self.polygons.firstObject;
+
+ return firstPolygon.coordinate;
+}
+
- (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds {
return MGLCoordinateBoundsIntersectsCoordinateBounds(_overlayBounds, overlayBounds);
}
-- (mbgl::Geometry<double>)geometryObject {
+- (mbgl::MultiPolygon<double>)multiPolygon {
mbgl::MultiPolygon<double> multiPolygon;
multiPolygon.reserve(self.polygons.count);
for (MGLPolygon *polygon in self.polygons) {
@@ -173,6 +187,10 @@
return multiPolygon;
}
+- (mbgl::Geometry<double>)geometryObject {
+ return [self multiPolygon];
+}
+
- (NSDictionary *)geoJSONDictionary {
NSMutableArray *coordinates = [[NSMutableArray alloc] initWithCapacity:self.polygons.count];
for (MGLPolygonFeature *feature in self.polygons) {
diff --git a/platform/darwin/src/MGLPolyline.mm b/platform/darwin/src/MGLPolyline.mm
index ae4fbe61de..fd75dc2795 100644
--- a/platform/darwin/src/MGLPolyline.mm
+++ b/platform/darwin/src/MGLPolyline.mm
@@ -6,6 +6,7 @@
#import "MGLPolyline+MGLAdditions.h"
#import <mbgl/util/geojson.hpp>
+#import <mapbox/polylabel.hpp>
@implementation MGLPolyline
@@ -52,6 +53,61 @@
return self == other || ([other isKindOfClass:[MGLPolyline class]] && [super isEqual:other]);
}
+- (CLLocationCoordinate2D)coordinate {
+ NSUInteger count = self.pointCount;
+ NSAssert(count > 0, @"Polyline must have coordinates");
+
+ CLLocationCoordinate2D *coordinates = self.coordinates;
+ CLLocationDistance middle = [self length] / 2.0;
+ CLLocationDistance traveled = 0.0;
+
+ if (count > 1 || middle > traveled) {
+ for (NSUInteger i = 0; i < count; i++) {
+
+ MGLRadianCoordinate2D from = MGLRadianCoordinateFromLocationCoordinate(coordinates[i]);
+ MGLRadianCoordinate2D to = MGLRadianCoordinateFromLocationCoordinate(coordinates[i + 1]);
+
+ if (traveled >= middle) {
+ double overshoot = middle - traveled;
+ if (overshoot == 0) {
+ return coordinates[i];
+ }
+ to = MGLRadianCoordinateFromLocationCoordinate(coordinates[i - 1]);
+ CLLocationDirection direction = [self direction:from to:to] - 180;
+ MGLRadianCoordinate2D otherCoordinate = MGLRadianCoordinateAtDistanceFacingDirection(from,
+ overshoot/mbgl::util::EARTH_RADIUS_M,
+ MGLRadiansFromDegrees(direction));
+ return CLLocationCoordinate2DMake(MGLDegreesFromRadians(otherCoordinate.latitude),
+ MGLDegreesFromRadians(otherCoordinate.longitude));
+ }
+
+ traveled += (MGLDistanceBetweenRadianCoordinates(from, to) * mbgl::util::EARTH_RADIUS_M);
+
+ }
+ }
+
+ return coordinates[count - 1];
+}
+
+- (CLLocationDistance)length
+{
+ CLLocationDistance length = 0.0;
+
+ NSUInteger count = self.pointCount;
+ CLLocationCoordinate2D *coordinates = self.coordinates;
+
+ for (NSUInteger i = 0; i < count - 1; i++) {
+ length += (MGLDistanceBetweenRadianCoordinates(MGLRadianCoordinateFromLocationCoordinate(coordinates[i]), MGLRadianCoordinateFromLocationCoordinate(coordinates[i + 1])) * mbgl::util::EARTH_RADIUS_M);
+ }
+
+ return length;
+}
+
+- (CLLocationDirection)direction:(MGLRadianCoordinate2D)from to:(MGLRadianCoordinate2D)to
+{
+ return MGLDegreesFromRadians(MGLRadianCoordinatesDirection(from, to));
+}
+
@end
@interface MGLMultiPolyline ()
@@ -114,6 +170,15 @@
return hash;
}
+- (CLLocationCoordinate2D)coordinate {
+ MGLPolyline *polyline = self.polylines.firstObject;
+ CLLocationCoordinate2D *coordinates = polyline.coordinates;
+ NSAssert([polyline pointCount] > 0, @"Polyline must have coordinates");
+ CLLocationCoordinate2D firstCoordinate = coordinates[0];
+
+ return firstCoordinate;
+}
+
- (BOOL)intersectsOverlayBounds:(MGLCoordinateBounds)overlayBounds {
return MGLCoordinateBoundsIntersectsCoordinateBounds(_overlayBounds, overlayBounds);
}
diff --git a/platform/darwin/src/MGLRasterSource.h b/platform/darwin/src/MGLRasterSource.h
index 519784f4f1..4f4b7c96c3 100644
--- a/platform/darwin/src/MGLRasterSource.h
+++ b/platform/darwin/src/MGLRasterSource.h
@@ -108,96 +108,13 @@ MGL_EXPORT
Returns a raster source initialized an identifier, tile URL templates, and
options.
+ Tile URL templates are strings that specify the URLs of the raster tile images
+ to load. See the “<a href="../tile-url-templates.html">Tile URL Templates</a>”
+ guide for information about the format of a tile URL template.
+
After initializing and configuring the source, add it to a map view’s style
using the `-[MGLStyle addSource:]` method.
- #### Tile URL templates
-
- Tile URL templates are strings that specify the URLs of the tile images to
- load. Each template resembles an absolute URL, but with any number of
- placeholder strings that the source evaluates based on the tile it needs to
- load. For example:
-
- <ul>
- <li><code>http://www.example.com/tiles/{z}/{x}/{y}.pbf</code> could be
- evaluated as <code>http://www.example.com/tiles/14/6/9.pbf</code>.</li>
- <li><code>http://www.example.com/tiles/{z}/{x}/{y}{ratio}.png</code> could be
- evaluated as <code>http://www.example.com/tiles/14/6/9@2x.png</code>.</li>
- </ul>
-
- Tile sources support the following placeholder strings in tile URL templates,
- all of which are optional:
-
- <table>
- <thead>
- <tr><th>Placeholder string</th><th>Description</th></tr>
- </thead>
- <tbody>
- <tr>
- <td><code>{x}</code></td>
- <td>The index of the tile along the map’s x axis according to Spherical
- Mercator projection. If the value is 0, the tile’s left edge corresponds
- to the 180th meridian west. If the value is 2<sup><var>z</var></sup>−1,
- the tile’s right edge corresponds to the 180th meridian east.</td>
- </tr>
- <tr>
- <td><code>{y}</code></td>
- <td>The index of the tile along the map’s y axis according to Spherical
- Mercator projection. If the value is 0, the tile’s tile edge corresponds
- to arctan(sinh(π)), or approximately 85.0511 degrees north. If the value
- is 2<sup><var>z</var></sup>−1, the tile’s bottom edge corresponds to
- −arctan(sinh(π)), or approximately 85.0511 degrees south. The y axis is
- inverted if the <code>options</code> parameter contains
- <code>MGLTileSourceOptionTileCoordinateSystem</code> with a value of
- <code>MGLTileCoordinateSystemTMS</code>.</td>
- </tr>
- <tr>
- <td><code>{z}</code></td>
- <td>The tile’s zoom level. At zoom level 0, each tile covers the entire
- world map; at zoom level 1, it covers ¼ of the world; at zoom level 2,
- <sup>1</sup>⁄<sub>16</sub> of the world, and so on. For tiles loaded by
- a <code>MGLRasterSource</code> object, whether the tile zoom level
- matches the map’s current zoom level depends on the value of the
- source’s tile size as specified in the
- <code>MGLTileSourceOptionTileSize</code> key of the
- <code>options</code> parameter.</td>
- </tr>
- <tr>
- <td><code>{bbox-epsg-3857}</code></td>
- <td>The tile’s bounding box, expressed as a comma-separated list of the
- tile’s western, southern, eastern, and northern extents according to
- Spherical Mercator (EPSG:3857) projection. The bounding box is typically
- used with map services conforming to the
- <a href="http://www.opengeospatial.org/standards/wms">Web Map Service</a>
- protocol.</td>
- </tr>
- <tr>
- <td><code>{quadkey}</code></td>
- <td>A quadkey indicating both the tile’s location and its zoom level. The
- quadkey is typically used with
- <a href="https://msdn.microsoft.com/en-us/library/bb259689.aspx">Bing Maps</a>.
- </td>
- </tr>
- <tr>
- <td><code>{ratio}</code></td>
- <td>A suffix indicating the resolution of the tile image. The suffix is the
- empty string for standard resolution displays and <code>@2x</code> for
- Retina displays, including displays for which
- <code>NSScreen.backingScaleFactor</code> or <code>UIScreen.scale</code>
- is 3.</td>
- </tr>
- <tr>
- <td><code>{prefix}</code></td>
- <td>Two hexadecimal digits chosen such that each visible tile has a
- different prefix. The prefix is typically used for domain sharding.</td>
- </tr>
- </tbody>
- </table>
-
- For more information about the `{x}`, `{y}`, and `{z}` placeholder strings,
- consult the
- <a href="https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames">OpenStreetMap Wiki</a>.
-
@param identifier A string that uniquely identifies the source in the style to
which it is added.
@param tileURLTemplates An array of tile URL template strings. Only the first
diff --git a/platform/darwin/src/MGLStyle.h b/platform/darwin/src/MGLStyle.h
index ccec863236..6fb4a6cc6b 100644
--- a/platform/darwin/src/MGLStyle.h
+++ b/platform/darwin/src/MGLStyle.h
@@ -6,6 +6,7 @@
#import "MGLTypes.h"
@class MGLSource;
+@class MGLLight;
NS_ASSUME_NONNULL_BEGIN
@@ -548,6 +549,14 @@ MGL_EXPORT
*/
- (void)removeImageForName:(NSString *)name;
+
+#pragma mark Managing the Style's Light
+
+/**
+ Provides global light source for the style.
+ */
+@property (nonatomic, strong) MGLLight *light;
+
@end
NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLStyle.mm b/platform/darwin/src/MGLStyle.mm
index 5f26b4fed2..2e6f2bc29a 100644
--- a/platform/darwin/src/MGLStyle.mm
+++ b/platform/darwin/src/MGLStyle.mm
@@ -14,6 +14,7 @@
#import "MGLStyle_Private.h"
#import "MGLStyleLayer_Private.h"
#import "MGLSource_Private.h"
+#import "MGLLight_Private.h"
#import "NSDate+MGLAdditions.h"
@@ -28,6 +29,7 @@
#include <mbgl/map/map.hpp>
#include <mbgl/util/default_styles.hpp>
#include <mbgl/style/image.hpp>
+#include <mbgl/style/light.hpp>
#include <mbgl/style/layers/fill_layer.hpp>
#include <mbgl/style/layers/fill_extrusion_layer.hpp>
#include <mbgl/style/layers/line_layer.hpp>
@@ -556,6 +558,21 @@ static NSURL *MGLStyleURL_emerald;
return transition;
}
+#pragma mark Style light
+
+- (void)setLight:(MGLLight *)light
+{
+ std::unique_ptr<mbgl::style::Light> mbglLight = std::make_unique<mbgl::style::Light>([light mbglLight]);
+ self.mapView.mbglMap->setLight(std::move(mbglLight));
+}
+
+- (MGLLight *)light
+{
+ auto mbglLight = self.mapView.mbglMap->getLight();
+ MGLLight *light = [[MGLLight alloc] initWithMBGLLight:mbglLight];
+ return light;
+}
+
- (NSString *)description
{
return [NSString stringWithFormat:@"<%@: %p; name = %@, URL = %@>",
diff --git a/platform/darwin/src/MGLStyleValue.h b/platform/darwin/src/MGLStyleValue.h
index 70074c8a13..2bb3aca4f4 100644
--- a/platform/darwin/src/MGLStyleValue.h
+++ b/platform/darwin/src/MGLStyleValue.h
@@ -75,9 +75,9 @@ typedef NS_ENUM(NSUInteger, MGLInterpolationMode) {
*/
MGLInterpolationModeCategorical,
/**
- Values between two stops are not interpolated. Instead, values are set to their
- input value. Use identity interpolation mode to show attribute values that can be
- used as style values.
+ Values between two stops are not interpolated. Instead, for any given feature, the
+ style value matches a value in that feature’s attributes dictionary. Use identity
+ interpolation mode to show attribute values that can be used as style values.
*/
MGLInterpolationModeIdentity
};
diff --git a/platform/darwin/src/MGLStyleValue.mm b/platform/darwin/src/MGLStyleValue.mm
index 33b6babadf..4dd6b550d8 100644
--- a/platform/darwin/src/MGLStyleValue.mm
+++ b/platform/darwin/src/MGLStyleValue.mm
@@ -128,7 +128,7 @@ const MGLStyleFunctionOption MGLStyleFunctionOptionDefaultValue = @"MGLStyleFunc
return {};
}
- if (self == [super init]) {
+ if (self = [super init]) {
self.interpolationMode = interpolationMode;
self.stops = stops;
@@ -181,7 +181,7 @@ const MGLStyleFunctionOption MGLStyleFunctionOptionDefaultValue = @"MGLStyleFunc
}
- (instancetype)initWithInterpolationMode:(MGLInterpolationMode)interpolationMode stops:(NSDictionary *)stops attributeName:(NSString *)attributeName options:(NSDictionary *)options {
- if (self == [super init]) {
+ if (self = [super init]) {
self.interpolationMode = interpolationMode;
self.stops = stops;
_attributeName = attributeName;
@@ -251,7 +251,7 @@ const MGLStyleFunctionOption MGLStyleFunctionOptionDefaultValue = @"MGLStyleFunc
}
- (instancetype)initWithInterpolationMode:(MGLInterpolationMode)interpolationMode stops:(NSDictionary *)stops attributeName:(NSString *)attributeName options:(NSDictionary *)options {
- if (self == [super init]) {
+ if (self = [super init]) {
self.interpolationMode = interpolationMode;
self.stops = stops;
_attributeName = attributeName;
diff --git a/platform/darwin/src/MGLStyleValue_Private.h b/platform/darwin/src/MGLStyleValue_Private.h
index 263b54d7e5..2155c657bd 100644
--- a/platform/darwin/src/MGLStyleValue_Private.h
+++ b/platform/darwin/src/MGLStyleValue_Private.h
@@ -3,11 +3,13 @@
#import "MGLStyleValue.h"
#import "NSValue+MGLStyleAttributeAdditions.h"
+#import "NSValue+MGLAdditions.h"
#import "MGLTypes.h"
#import "MGLConversion.h"
#include <mbgl/style/conversion/data_driven_property_value.hpp>
#include <mbgl/style/conversion.hpp>
+#import <mbgl/style/types.hpp>
#import <mbgl/util/enum.hpp>
@@ -415,6 +417,12 @@ private: // Private utilities for converting from mgl to mbgl values
mbglValue.push_back(mbglElement);
}
}
+
+ void getMBGLValue(NSValue *rawValue, mbgl::style::Position &mbglValue) {
+ auto spherical = rawValue.mgl_lightPositionArrayValue;
+ mbgl::style::Position position(spherical);
+ mbglValue = position;
+ }
// Enumerations
template <typename MBGLEnum = MBGLType,
@@ -473,6 +481,12 @@ private: // Private utilities for converting from mbgl to mgl values
}
return array;
}
+
+ static NSValue *toMGLRawStyleValue(const mbgl::style::Position &mbglStopValue) {
+ std::array<float, 3> spherical = mbglStopValue.getSpherical();
+ MGLSphericalPosition position = MGLSphericalPositionMake(spherical[0], spherical[1], spherical[2]);
+ return [NSValue valueWithMGLSphericalPosition:position];
+ }
// Enumerations
template <typename MBGLEnum = MBGLType, typename MGLEnum = ObjCEnum>
diff --git a/platform/darwin/src/MGLTypes.h b/platform/darwin/src/MGLTypes.h
index c06fd8b0e7..16f510b5a6 100644
--- a/platform/darwin/src/MGLTypes.h
+++ b/platform/darwin/src/MGLTypes.h
@@ -1,4 +1,5 @@
#import <Foundation/Foundation.h>
+#import <CoreGraphics/CoreGraphics.h>
#import "MGLFoundation.h"
diff --git a/platform/darwin/src/MGLVectorSource.h b/platform/darwin/src/MGLVectorSource.h
index a48434f7a3..968be3c0e0 100644
--- a/platform/darwin/src/MGLVectorSource.h
+++ b/platform/darwin/src/MGLVectorSource.h
@@ -74,96 +74,13 @@ MGL_EXPORT
Returns a vector source initialized an identifier, tile URL templates, and
options.
+ Tile URL templates are strings that specify the URLs of the vector tiles to
+ load. See the “<a href="../tile-url-templates.html">Tile URL Templates</a>”
+ guide for information about the format of a tile URL template.
+
After initializing and configuring the source, add it to a map view’s style
using the `-[MGLStyle addSource:]` method.
- #### Tile URL templates
-
- Tile URL templates are strings that specify the URLs of the tile images to
- load. Each template resembles an absolute URL, but with any number of
- placeholder strings that the source evaluates based on the tile it needs to
- load. For example:
-
- <ul>
- <li><code>http://www.example.com/tiles/{z}/{x}/{y}.pbf</code> could be
- evaluated as <code>http://www.example.com/tiles/14/6/9.pbf</code>.</li>
- <li><code>http://www.example.com/tiles/{z}/{x}/{y}{ratio}.png</code> could be
- evaluated as <code>http://www.example.com/tiles/14/6/9@2x.png</code>.</li>
- </ul>
-
- Tile sources support the following placeholder strings in tile URL templates,
- all of which are optional:
-
- <table>
- <thead>
- <tr><th>Placeholder string</th><th>Description</th></tr>
- </thead>
- <tbody>
- <tr>
- <td><code>{x}</code></td>
- <td>The index of the tile along the map’s x axis according to Spherical
- Mercator projection. If the value is 0, the tile’s left edge corresponds
- to the 180th meridian west. If the value is 2<sup><var>z</var></sup>−1,
- the tile’s right edge corresponds to the 180th meridian east.</td>
- </tr>
- <tr>
- <td><code>{y}</code></td>
- <td>The index of the tile along the map’s y axis according to Spherical
- Mercator projection. If the value is 0, the tile’s tile edge corresponds
- to arctan(sinh(π)), or approximately 85.0511 degrees north. If the value
- is 2<sup><var>z</var></sup>−1, the tile’s bottom edge corresponds to
- −arctan(sinh(π)), or approximately 85.0511 degrees south. The y axis is
- inverted if the <code>options</code> parameter contains
- <code>MGLTileSourceOptionTileCoordinateSystem</code> with a value of
- <code>MGLTileCoordinateSystemTMS</code>.</td>
- </tr>
- <tr>
- <td><code>{z}</code></td>
- <td>The tile’s zoom level. At zoom level 0, each tile covers the entire
- world map; at zoom level 1, it covers ¼ of the world; at zoom level 2,
- <sup>1</sup>⁄<sub>16</sub> of the world, and so on. For tiles loaded by
- a <code>MGLRasterSource</code> object, whether the tile zoom level
- matches the map’s current zoom level depends on the value of the
- source’s tile size as specified in the
- <code>MGLTileSourceOptionTileSize</code> key of the
- <code>options</code> parameter.</td>
- </tr>
- <tr>
- <td><code>{bbox-epsg-3857}</code></td>
- <td>The tile’s bounding box, expressed as a comma-separated list of the
- tile’s western, southern, eastern, and northern extents according to
- Spherical Mercator (EPSG:3857) projection. The bounding box is typically
- used with map services conforming to the
- <a href="http://www.opengeospatial.org/standards/wms">Web Map Service</a>
- protocol.</td>
- </tr>
- <tr>
- <td><code>{quadkey}</code></td>
- <td>A quadkey indicating both the tile’s location and its zoom level. The
- quadkey is typically used with
- <a href="https://msdn.microsoft.com/en-us/library/bb259689.aspx">Bing Maps</a>.
- </td>
- </tr>
- <tr>
- <td><code>{ratio}</code></td>
- <td>A suffix indicating the resolution of the tile image. The suffix is the
- empty string for standard resolution displays and <code>@2x</code> for
- Retina displays, including displays for which
- <code>NSScreen.backingScaleFactor</code> or <code>UIScreen.scale</code>
- is 3.</td>
- </tr>
- <tr>
- <td><code>{prefix}</code></td>
- <td>Two hexadecimal digits chosen such that each visible tile has a
- different prefix. The prefix is typically used for domain sharding.</td>
- </tr>
- </tbody>
- </table>
-
- For more information about the `{x}`, `{y}`, and `{z}` placeholder strings,
- consult the
- <a href="https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames">OpenStreetMap Wiki</a>.
-
@param identifier A string that uniquely identifies the source in the style to
which it is added.
@param tileURLTemplates An array of tile URL template strings. Only the first
diff --git a/platform/darwin/src/NSBundle+MGLAdditions.h b/platform/darwin/src/NSBundle+MGLAdditions.h
index 1fc9e8b896..ad5e9d5369 100644
--- a/platform/darwin/src/NSBundle+MGLAdditions.h
+++ b/platform/darwin/src/NSBundle+MGLAdditions.h
@@ -36,9 +36,7 @@ NS_ASSUME_NONNULL_BEGIN
+ (nullable NS_DICTIONARY_OF(NSString *, id) *)mgl_frameworkInfoDictionary;
-/// The relative path to the directory containing the SDK’s resource files, or
-/// `nil` if the files are located directly within the bundle’s root directory.
-@property (readonly, copy, nullable) NSString *mgl_resourcesDirectory;
++ (nullable NSString *)mgl_applicationBundleIdentifier;
@end
diff --git a/platform/darwin/src/NSBundle+MGLAdditions.m b/platform/darwin/src/NSBundle+MGLAdditions.m
index 76d9cc0db7..f383a50300 100644
--- a/platform/darwin/src/NSBundle+MGLAdditions.m
+++ b/platform/darwin/src/NSBundle+MGLAdditions.m
@@ -6,12 +6,19 @@
+ (instancetype)mgl_frameworkBundle {
NSBundle *bundle = [self bundleForClass:[MGLAccountManager class]];
- if (![bundle.infoDictionary[@"CFBundlePackageType"] isEqualToString:@"FMWK"] && !bundle.mgl_resourcesDirectory) {
+
+ if (![bundle.infoDictionary[@"CFBundlePackageType"] isEqualToString:@"FMWK"]) {
// For static frameworks, the bundle is the containing application
- // bundle but the resources are still in the framework bundle.
- bundle = [NSBundle bundleWithPath:[bundle.privateFrameworksPath
- stringByAppendingPathComponent:@"Mapbox.framework"]];
+ // bundle but the resources are in Mapbox.bundle.
+ NSString *bundlePath = [bundle pathForResource:@"Mapbox" ofType:@"bundle"];
+ if (bundlePath) {
+ bundle = [self bundleWithPath:bundlePath];
+ } else {
+ [NSException raise:@"MGLBundleNotFoundException" format:
+ @"The Mapbox framework bundle could not be found. If using the Mapbox iOS SDK as a static framework, make sure that Mapbox.bundle is copied into the root of the app bundle."];
+ }
}
+
return bundle;
}
@@ -21,18 +28,16 @@
+ (nullable NS_DICTIONARY_OF(NSString *, id) *)mgl_frameworkInfoDictionary {
NSBundle *bundle = self.mgl_frameworkBundle;
- if (bundle.mgl_resourcesDirectory) {
- NSString *infoPlistPath = [bundle pathForResource:@"Info"
- ofType:@"plist"
- inDirectory:bundle.mgl_resourcesDirectory];
- return [NSDictionary dictionaryWithContentsOfFile:infoPlistPath];
- } else {
- return bundle.infoDictionary;
- }
+ return bundle.infoDictionary;
}
-- (NSString *)mgl_resourcesDirectory {
- return [self pathForResource:@"Mapbox" ofType:@"bundle"] ? @"Mapbox.bundle" : nil;
++ (nullable NSString *)mgl_applicationBundleIdentifier {
+ NSString *bundleIdentifier = [NSBundle mainBundle].bundleIdentifier;
+ if (!bundleIdentifier) {
+ // There’s no main bundle identifier when running in a unit test bundle.
+ bundleIdentifier = [NSBundle bundleForClass:[MGLAccountManager class]].bundleIdentifier;
+ }
+ return bundleIdentifier;
}
@end
diff --git a/platform/darwin/src/NSValue+MGLAdditions.h b/platform/darwin/src/NSValue+MGLAdditions.h
index e6755021d0..0aaa2a337a 100644
--- a/platform/darwin/src/NSValue+MGLAdditions.h
+++ b/platform/darwin/src/NSValue+MGLAdditions.h
@@ -1,6 +1,7 @@
#import <Foundation/Foundation.h>
#import "MGLGeometry.h"
+#import "MGLLight.h"
#import "MGLOfflinePack.h"
#import "MGLTypes.h"
@@ -87,6 +88,34 @@ NS_ASSUME_NONNULL_BEGIN
*/
@property (readonly) MGLTransition MGLTransitionValue;
+/**
+ Creates a new value object containing the given `MGLSphericalPosition`
+ structure.
+
+ @param lightPosition The value for the new object.
+ @return A new value object that contains the light position information.
+ */
++ (instancetype)valueWithMGLSphericalPosition:(MGLSphericalPosition)lightPosition;
+
+/**
+ The `MGLSphericalPosition` structure representation of the value.
+ */
+@property (readonly) MGLSphericalPosition MGLSphericalPositionValue;
+
+/**
+ Creates a new value object containing the given `MGLLightAnchor`
+ enum.
+
+ @param lightAnchor The value for the new object.
+ @return A new value object that contains the light anchor information.
+ */
++ (NSValue *)valueWithMGLLightAnchor:(MGLLightAnchor)lightAnchor;
+
+/**
+ The `MGLLightAnchor` enum representation of the value.
+ */
+@property (readonly) MGLLightAnchor MGLLightAnchorValue;
+
@end
NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/NSValue+MGLAdditions.m b/platform/darwin/src/NSValue+MGLAdditions.m
index a95ef23941..ef894f0eb4 100644
--- a/platform/darwin/src/NSValue+MGLAdditions.m
+++ b/platform/darwin/src/NSValue+MGLAdditions.m
@@ -58,4 +58,27 @@
return transition;
}
++ (NSValue *)valueWithMGLSphericalPosition:(MGLSphericalPosition)lightPosition
+{
+ return [NSValue value:&lightPosition withObjCType:@encode(MGLSphericalPosition)];
+}
+
+- (MGLSphericalPosition)MGLSphericalPositionValue
+{
+ MGLSphericalPosition lightPosition;
+ [self getValue:&lightPosition];
+ return lightPosition;
+}
+
++ (NSValue *)valueWithMGLLightAnchor:(MGLLightAnchor)lightAnchor {
+ return [NSValue value:&lightAnchor withObjCType:@encode(MGLLightAnchor)];
+}
+
+- (MGLLightAnchor)MGLLightAnchorValue
+{
+ MGLLightAnchor achorType;
+ [self getValue:&achorType];
+ return achorType;
+}
+
@end
diff --git a/platform/darwin/src/NSValue+MGLStyleAttributeAdditions.h b/platform/darwin/src/NSValue+MGLStyleAttributeAdditions.h
index 60c1ee4075..0f1e511694 100644
--- a/platform/darwin/src/NSValue+MGLStyleAttributeAdditions.h
+++ b/platform/darwin/src/NSValue+MGLStyleAttributeAdditions.h
@@ -9,5 +9,6 @@
- (std::array<float, 2>)mgl_offsetArrayValue;
- (std::array<float, 4>)mgl_paddingArrayValue;
+- (std::array<float, 3>)mgl_lightPositionArrayValue;
@end
diff --git a/platform/darwin/src/NSValue+MGLStyleAttributeAdditions.mm b/platform/darwin/src/NSValue+MGLStyleAttributeAdditions.mm
index e66145aec1..a41950b6b3 100644
--- a/platform/darwin/src/NSValue+MGLStyleAttributeAdditions.mm
+++ b/platform/darwin/src/NSValue+MGLStyleAttributeAdditions.mm
@@ -1,5 +1,5 @@
#import "NSValue+MGLStyleAttributeAdditions.h"
-
+#import "MGLLight.h"
#if TARGET_OS_IPHONE
#import <UIKit/UIKit.h>
#define MGLEdgeInsets UIEdgeInsets
@@ -61,4 +61,17 @@
};
}
+- (std::array<float, 3>)mgl_lightPositionArrayValue
+{
+ NSAssert(strcmp(self.objCType, @encode(MGLSphericalPosition)) == 0, @"Value does not represent an MGLSphericalPosition");
+ MGLSphericalPosition lightPosition;
+ [self getValue:&lightPosition];
+ // Style specification defines padding in clockwise order: top, right, bottom, left.
+ return {
+ static_cast<float>(lightPosition.radial),
+ static_cast<float>(lightPosition.azimuthal),
+ static_cast<float>(lightPosition.polar),
+ };
+}
+
@end
diff --git a/platform/darwin/test/MGLAttributionInfoTests.m b/platform/darwin/test/MGLAttributionInfoTests.m
index e258671c09..ed4927d44b 100644
--- a/platform/darwin/test/MGLAttributionInfoTests.m
+++ b/platform/darwin/test/MGLAttributionInfoTests.m
@@ -46,8 +46,18 @@
XCTAssertEqualObjects(infos[3].title.string, @"Improve this map");
XCTAssertEqualObjects(infos[3].URL, [NSURL URLWithString:@"https://www.mapbox.com/map-feedback/"]);
XCTAssertTrue(infos[3].feedbackLink);
+ NSURL *styleURL = [MGLStyle satelliteStreetsStyleURLWithVersion:99];
+#if TARGET_OS_IPHONE
+ XCTAssertEqualObjects([infos[3] feedbackURLAtCenterCoordinate:mapbox zoomLevel:14],
+ [NSURL URLWithString:@"https://www.mapbox.com/feedback/?referrer=com.mapbox.sdk.ios#/77.63680/12.98108/14.00/0.0/0"]);
+ XCTAssertEqualObjects([infos[3] feedbackURLForStyleURL:styleURL atCenterCoordinate:mapbox zoomLevel:3.14159 direction:90.9 pitch:12.5],
+ [NSURL URLWithString:@"https://www.mapbox.com/feedback/?referrer=com.mapbox.sdk.ios&owner=mapbox&id=satellite-streets-v99&access_token#/77.63680/12.98108/3.14/90.9/13"]);
+#else
XCTAssertEqualObjects([infos[3] feedbackURLAtCenterCoordinate:mapbox zoomLevel:14],
- [NSURL URLWithString:@"https://www.mapbox.com/map-feedback/#/77.63680/12.98108/15"]);
+ [NSURL URLWithString:@"https://www.mapbox.com/feedback/?referrer=com.mapbox.MapboxGL#/77.63680/12.98108/14.00/0.0/0"]);
+ XCTAssertEqualObjects([infos[3] feedbackURLForStyleURL:styleURL atCenterCoordinate:mapbox zoomLevel:3.14159 direction:90.9 pitch:12.5],
+ [NSURL URLWithString:@"https://www.mapbox.com/feedback/?referrer=com.mapbox.MapboxGL&owner=mapbox&id=satellite-streets-v99&access_token#/77.63680/12.98108/3.14/90.9/13"]);
+#endif
}
- (void)testStyle {
diff --git a/platform/darwin/test/MGLCodingTests.m b/platform/darwin/test/MGLCodingTests.m
index ff0d674ad1..ac61672b76 100644
--- a/platform/darwin/test/MGLCodingTests.m
+++ b/platform/darwin/test/MGLCodingTests.m
@@ -66,12 +66,54 @@
[unarchivedPolyline replaceCoordinatesInRange:NSMakeRange(0, 1) withCoordinates:otherCoordinates];
XCTAssertNotEqualObjects(polyline, unarchivedPolyline);
+
+ CLLocationCoordinate2D multiLineCoordinates[] = {
+ CLLocationCoordinate2DMake(51.000000, 0.000000),
+ CLLocationCoordinate2DMake(51.000000, 1.000000),
+ CLLocationCoordinate2DMake(51.000000, 2.000000),
+ };
+
+ NSUInteger multiLineCoordinatesCount = sizeof(multiLineCoordinates) / sizeof(CLLocationCoordinate2D);
+ MGLPolyline *multiLine = [MGLPolyline polylineWithCoordinates:multiLineCoordinates count:multiLineCoordinatesCount];
+ CLLocationCoordinate2D multiLineCenter = CLLocationCoordinate2DMake(51.000000, 1.000000);
+
+ XCTAssertEqual([multiLine coordinate].latitude, multiLineCenter.latitude);
+ XCTAssertEqual([multiLine coordinate].longitude, multiLineCenter.longitude);
+
+ CLLocationCoordinate2D segmentCoordinates[] = {
+ CLLocationCoordinate2DMake(35.040390, -85.311477),
+ CLLocationCoordinate2DMake(35.040390, -85.209510),
+ };
+
+ NSUInteger segmentCoordinatesCount = sizeof(segmentCoordinates) / sizeof(CLLocationCoordinate2D);
+ MGLPolyline *segmentLine = [MGLPolyline polylineWithCoordinates:segmentCoordinates count:segmentCoordinatesCount];
+ CLLocationCoordinate2D segmentCenter = CLLocationCoordinate2DMake(35.0404006631, -85.2604935);
+
+ XCTAssertEqualWithAccuracy([segmentLine coordinate].latitude, segmentCenter.latitude, 0.0001);
+ XCTAssertEqualWithAccuracy([segmentLine coordinate].longitude, segmentCenter.longitude, 0.0001);
+
+ CLLocationCoordinate2D sfToBerkeleyCoordinates[] = {
+ CLLocationCoordinate2DMake(37.782440, -122.397111),
+ CLLocationCoordinate2DMake(37.818384, -122.352994),
+ CLLocationCoordinate2DMake(37.831401, -122.274545),
+ CLLocationCoordinate2DMake(37.862172, -122.262700),
+ };
+
+ NSUInteger sfToBerkeleyCoordinatesCount = sizeof(sfToBerkeleyCoordinates) / sizeof(CLLocationCoordinate2D);
+ MGLPolyline *sfToBerkeleyLine = [MGLPolyline polylineWithCoordinates:sfToBerkeleyCoordinates count:sfToBerkeleyCoordinatesCount];
+ CLLocationCoordinate2D sfToBerkeleyCenter = CLLocationCoordinate2DMake(37.8230575118,-122.324867587);
+
+ XCTAssertEqualWithAccuracy([sfToBerkeleyLine coordinate].latitude, sfToBerkeleyCenter.latitude, 0.0001);
+ XCTAssertEqualWithAccuracy([sfToBerkeleyLine coordinate].longitude, sfToBerkeleyCenter.longitude, 0.0001);
+
}
- (void)testPolygon {
CLLocationCoordinate2D coordinates[] = {
- CLLocationCoordinate2DMake(0.664482398, 1.8865675),
- CLLocationCoordinate2DMake(2.13224687, 3.9984632)
+ CLLocationCoordinate2DMake(35.090745, -85.300259),
+ CLLocationCoordinate2DMake(35.092035, -85.298885),
+ CLLocationCoordinate2DMake(35.090639, -85.297416),
+ CLLocationCoordinate2DMake(35.089112, -85.298928)
};
NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
@@ -84,8 +126,24 @@
[NSKeyedArchiver archiveRootObject:polygon toFile:filePath];
MGLPolygon *unarchivedPolygon = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
+ [unarchivedPolygon coordinate];
XCTAssertEqualObjects(polygon, unarchivedPolygon);
+
+ CLLocationCoordinate2D squareCoordinates[] = {
+ CLLocationCoordinate2DMake(100.0, 0.0),
+ CLLocationCoordinate2DMake(101.0, 0.0),
+ CLLocationCoordinate2DMake(101.0, 1.0),
+ CLLocationCoordinate2DMake(100.0, 1.0),
+ };
+
+ NSUInteger squareCoordinatesCount = sizeof(squareCoordinates) / sizeof(CLLocationCoordinate2D);
+ MGLPolygon *squarePolygon = [MGLPolygon polygonWithCoordinates:squareCoordinates count:squareCoordinatesCount];
+ CLLocationCoordinate2D squareCenter = CLLocationCoordinate2DMake(100.5, 0.5);
+
+ XCTAssertEqual([squarePolygon coordinate].latitude, squareCenter.latitude);
+ XCTAssertEqual([squarePolygon coordinate].longitude, squareCenter.longitude);
+
}
- (void)testPolygonWithInteriorPolygons {
@@ -169,6 +227,11 @@
NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
MGLPointCollection *pointCollection = [MGLPointCollection pointCollectionWithCoordinates:coordinates count:numberOfCoordinates];
+ CLLocationCoordinate2D pointsCenter = CLLocationCoordinate2DMake(0, 1);
+
+ XCTAssertEqual([pointCollection coordinate].latitude, pointsCenter.latitude);
+ XCTAssertEqual([pointCollection coordinate].longitude, pointsCenter.longitude);
+
NSString *filePath = [self temporaryFilePathForClass:[MGLPointCollection class]];
[NSKeyedArchiver archiveRootObject:pointCollection toFile:filePath];
@@ -218,6 +281,30 @@
CLLocationCoordinate2DMake(20, 21),
CLLocationCoordinate2DMake(30, 31),
};
+
+ CLLocationCoordinate2D line1[] = {
+ CLLocationCoordinate2DMake(100, 40),
+ CLLocationCoordinate2DMake(105, 45),
+ CLLocationCoordinate2DMake(110, 55)
+ };
+
+ CLLocationCoordinate2D line2[] = {
+ CLLocationCoordinate2DMake(105, 40),
+ CLLocationCoordinate2DMake(110, 45),
+ CLLocationCoordinate2DMake(115, 55)
+ };
+
+ NSUInteger road1CoordinatesCount = sizeof(line1) / sizeof(CLLocationCoordinate2D);
+ NSUInteger road2CoordinatesCount = sizeof(line2) / sizeof(CLLocationCoordinate2D);
+
+ MGLPolyline *road1Polyline = [MGLPolyline polylineWithCoordinates:line1 count:road1CoordinatesCount];
+ MGLPolyline *road2Polyline = [MGLPolyline polylineWithCoordinates:line1 count:road2CoordinatesCount];
+
+ MGLMultiPolyline *roads = [MGLMultiPolyline multiPolylineWithPolylines:@[road1Polyline, road2Polyline]];
+ CLLocationCoordinate2D roadCenter = CLLocationCoordinate2DMake(100, 40);
+
+ XCTAssertEqual([roads coordinate].latitude, roadCenter.latitude);
+ XCTAssertEqual([roads coordinate].longitude, roadCenter.longitude);
NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
@@ -248,6 +335,31 @@
CLLocationCoordinate2DMake(20, 21),
CLLocationCoordinate2DMake(30, 31),
};
+
+ CLLocationCoordinate2D outerSquare[] = {
+ CLLocationCoordinate2DMake(100.0, 0.0),
+ CLLocationCoordinate2DMake(101.0, 0.0),
+ CLLocationCoordinate2DMake(101.0, 1.0),
+ CLLocationCoordinate2DMake(100.0, 1.0),
+ };
+
+ CLLocationCoordinate2D innerSquare[] = {
+ CLLocationCoordinate2DMake(100.35, 0.35),
+ CLLocationCoordinate2DMake(100.65, 0.35),
+ CLLocationCoordinate2DMake(100.65, 0.65),
+ CLLocationCoordinate2DMake(100.35, 0.65),
+ };
+
+ NSUInteger outerCoordinatesCount = sizeof(outerSquare) / sizeof(CLLocationCoordinate2D);
+ NSUInteger innerCoordinatesCount = sizeof(innerSquare) / sizeof(CLLocationCoordinate2D);
+
+ MGLPolygon *innerPolygonSquare = [MGLPolygon polygonWithCoordinates:innerSquare count:innerCoordinatesCount];
+ MGLPolygon *outerPolygonSquare = [MGLPolygon polygonWithCoordinates:outerSquare count:outerCoordinatesCount interiorPolygons:@[innerPolygonSquare]];
+ MGLMultiPolygon *squares = [MGLMultiPolygon multiPolygonWithPolygons:@[outerPolygonSquare, innerPolygonSquare]];
+ CLLocationCoordinate2D squareCenter = CLLocationCoordinate2DMake(100.5, 0.5);
+
+ XCTAssertEqual([squares coordinate].latitude, squareCenter.latitude);
+ XCTAssertEqual([squares coordinate].longitude, squareCenter.longitude);
NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
@@ -265,9 +377,10 @@
MGLMultiPolygon *unarchivedMultiPolygon = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
MGLMultiPolygon *anotherMultiPolygon = [MGLMultiPolygon multiPolygonWithPolygons:[polygons subarrayWithRange:NSMakeRange(0, polygons.count/2)]];
-
+
XCTAssertEqualObjects(multiPolygon, unarchivedMultiPolygon);
XCTAssertNotEqualObjects(anotherMultiPolygon, unarchivedMultiPolygon);
+
}
- (void)testShapeCollection {
diff --git a/platform/darwin/test/MGLDocumentationExampleTests.swift b/platform/darwin/test/MGLDocumentationExampleTests.swift
index 6d2dc597a9..48e6b17f44 100644
--- a/platform/darwin/test/MGLDocumentationExampleTests.swift
+++ b/platform/darwin/test/MGLDocumentationExampleTests.swift
@@ -168,7 +168,7 @@ class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate {
layer.sourceLayerIdentifier = "building"
layer.fillExtrusionHeight = MGLStyleValue(interpolationMode: .identity, sourceStops: nil, attributeName: "height", options: nil)
layer.fillExtrusionBase = MGLStyleValue(interpolationMode: .identity, sourceStops: nil, attributeName: "min_height", options: nil)
- layer.predicate = NSPredicate(format: "extrude == TRUE")
+ layer.predicate = NSPredicate(format: "extrude == 'true'")
mapView.style?.addLayer(layer)
//#-end-example-code
diff --git a/platform/darwin/test/MGLLightTest.mm b/platform/darwin/test/MGLLightTest.mm
new file mode 100644
index 0000000000..2c3d1c7bd1
--- /dev/null
+++ b/platform/darwin/test/MGLLightTest.mm
@@ -0,0 +1,217 @@
+#import <XCTest/XCTest.h>
+#import <Mapbox/Mapbox.h>
+
+#import "MGLLight_Private.h"
+
+#import "../../darwin/src/NSDate+MGLAdditions.h"
+
+#import <mbgl/style/light.hpp>
+#import <mbgl/style/types.hpp>
+#include <mbgl/style/transition_options.hpp>
+
+@interface MGLLightTest : XCTestCase
+
+@end
+
+@implementation MGLLightTest
+
+- (void)testProperties {
+
+ MGLTransition defaultTransition = MGLTransitionMake(0, 0);
+ MGLTransition transition = MGLTransitionMake(6, 3);
+ mbgl::style::TransitionOptions transitionOptions { { MGLDurationFromTimeInterval(6) }, { MGLDurationFromTimeInterval(3) } };
+
+ // anchor
+ {
+ mbgl::style::Light light;
+ MGLLight *mglLight = [[MGLLight alloc] initWithMBGLLight:&light];
+
+ NSAssert([mglLight.anchor isKindOfClass:[MGLConstantStyleValue class]], @"mglLight.anchor isn’t a MGLConstantStyleValue.");
+ NSValue *anchorValue = ((MGLConstantStyleValue *)mglLight.anchor).rawValue;
+ XCTAssertEqual(anchorValue.MGLLightAnchorValue, MGLLightAnchorViewport);
+ XCTAssertEqual(mglLight.anchorTransition.delay, defaultTransition.delay);
+ XCTAssertEqual(mglLight.anchorTransition.duration, defaultTransition.duration);
+
+ auto lightFromMGLlight = [mglLight mbglLight];
+
+ XCTAssertEqual(light.getDefaultAnchor(), lightFromMGLlight.getAnchor().asConstant());
+ auto anchorTransition = lightFromMGLlight.getAnchorTransition();
+ XCTAssert(anchorTransition.delay && MGLTimeIntervalFromDuration(*anchorTransition.delay) == defaultTransition.delay);
+ XCTAssert(anchorTransition.duration && MGLTimeIntervalFromDuration(*anchorTransition.duration) == defaultTransition.duration);
+
+ MGLStyleValue<NSValue *> *anchorStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLLightAnchor:MGLLightAnchorMap]];
+ mglLight.anchor = anchorStyleValue;
+ mglLight.anchorTransition = transition;
+ NSAssert([mglLight.anchor isKindOfClass:[MGLConstantStyleValue class]], @"mglLight.anchor isn’t a MGLConstantStyleValue.");
+ anchorValue = ((MGLConstantStyleValue *)mglLight.anchor).rawValue;
+
+ XCTAssertEqual(anchorValue.MGLLightAnchorValue, MGLLightAnchorMap);
+ XCTAssertEqual(mglLight.anchorTransition.delay, transition.delay);
+ XCTAssertEqual(mglLight.anchorTransition.duration, transition.duration);
+
+ mbgl::style::PropertyValue<mbgl::style::LightAnchorType> anchorProperty = { mbgl::style::LightAnchorType::Map };
+ light.setAnchor(anchorProperty);
+ light.setAnchorTransition(transitionOptions);
+
+ lightFromMGLlight = [mglLight mbglLight];
+
+ XCTAssertEqual(light.getAnchor().asConstant(), lightFromMGLlight.getAnchor().asConstant());
+ anchorTransition = lightFromMGLlight.getAnchorTransition();
+ XCTAssert(anchorTransition.delay && MGLTimeIntervalFromDuration(*anchorTransition.delay) == transition.delay);
+ XCTAssert(anchorTransition.duration && MGLTimeIntervalFromDuration(*anchorTransition.duration) == transition.duration);
+
+ }
+
+ // position
+ {
+ mbgl::style::Light light;
+ MGLLight *mglLight = [[MGLLight alloc] initWithMBGLLight:&light];
+ NSAssert([mglLight.position isKindOfClass:[MGLConstantStyleValue class]], @"mglLight.position isn’t a MGLConstantStyleValue.");
+ NSValue *positionValue = ((MGLConstantStyleValue *)mglLight.position).rawValue;
+ auto positionArray = light.getDefaultPosition().getSpherical();
+ MGLSphericalPosition defaultPosition = MGLSphericalPositionMake(positionArray[0], positionArray[1], positionArray[2]);
+
+ XCTAssert(defaultPosition.radial == positionValue.MGLSphericalPositionValue.radial);
+ XCTAssert(defaultPosition.azimuthal == positionValue.MGLSphericalPositionValue.azimuthal);
+ XCTAssert(defaultPosition.polar == positionValue.MGLSphericalPositionValue.polar);
+ XCTAssertEqual(mglLight.positionTransiton.delay, defaultTransition.delay);
+ XCTAssertEqual(mglLight.positionTransiton.duration, defaultTransition.duration);
+
+ auto lightFromMGLlight = [mglLight mbglLight];
+
+ XCTAssertEqual(positionArray, lightFromMGLlight.getPosition().asConstant().getSpherical());
+ auto positionTransition = lightFromMGLlight.getPositionTransition();
+ XCTAssert(positionTransition.delay && MGLTimeIntervalFromDuration(*positionTransition.delay) == defaultTransition.delay);
+ XCTAssert(positionTransition.duration && MGLTimeIntervalFromDuration(*positionTransition.duration) == defaultTransition.duration);
+
+ defaultPosition = MGLSphericalPositionMake(6, 180, 90);
+ MGLStyleValue<NSValue *> *positionStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLSphericalPosition:defaultPosition]];
+ mglLight.position = positionStyleValue;
+ mglLight.positionTransiton = transition;
+
+ NSAssert([mglLight.position isKindOfClass:[MGLConstantStyleValue class]], @"mglLight.position isn’t a MGLConstantStyleValue.");
+ positionValue = ((MGLConstantStyleValue *)mglLight.position).rawValue;
+
+ XCTAssert(defaultPosition.radial == positionValue.MGLSphericalPositionValue.radial);
+ XCTAssert(defaultPosition.azimuthal == positionValue.MGLSphericalPositionValue.azimuthal);
+ XCTAssert(defaultPosition.polar == positionValue.MGLSphericalPositionValue.polar);
+ XCTAssertEqual(mglLight.positionTransiton.delay, transition.delay);
+ XCTAssertEqual(mglLight.positionTransiton.duration, transition.duration);
+
+ lightFromMGLlight = [mglLight mbglLight];
+
+ positionArray = { { 6, 180, 90 } };
+ mbgl::style::Position position = { positionArray };
+ mbgl::style::PropertyValue<mbgl::style::Position> positionProperty = { position };
+ light.setPosition(positionProperty);
+ light.setPositionTransition(transitionOptions);
+
+ XCTAssertEqual(positionArray, lightFromMGLlight.getPosition().asConstant().getSpherical());
+ positionTransition = lightFromMGLlight.getPositionTransition();
+ XCTAssert(positionTransition.delay && MGLTimeIntervalFromDuration(*positionTransition.delay) == transition.delay);
+ XCTAssert(positionTransition.duration && MGLTimeIntervalFromDuration(*positionTransition.duration) == transition.duration);
+
+ }
+
+ // color
+ {
+ mbgl::style::Light light;
+ MGLLight *mglLight = [[MGLLight alloc] initWithMBGLLight:&light];
+ NSAssert([mglLight.color isKindOfClass:[MGLConstantStyleValue class]], @"mglLight.color isn’t a MGLConstantStyleValue.");
+ MGLColor *colorValue = ((MGLConstantStyleValue *)mglLight.color).rawValue;
+ auto color = light.getDefaultColor();
+ const CGFloat *colorComponents = CGColorGetComponents(colorValue.CGColor);
+
+ XCTAssert(color.r == colorComponents[0] && color.g == colorComponents[1] && color.b == colorComponents[2] &&
+ color.a == colorComponents[3]);
+ XCTAssertEqual(mglLight.colorTransiton.delay, defaultTransition.delay);
+ XCTAssertEqual(mglLight.colorTransiton.duration, defaultTransition.duration);
+
+ auto lightFromMGLlight = [mglLight mbglLight];
+
+ XCTAssertEqual(color, lightFromMGLlight.getColor().asConstant());
+ auto colorTransition = lightFromMGLlight.getColorTransition();
+ XCTAssert(colorTransition.delay && MGLTimeIntervalFromDuration(*colorTransition.delay) == defaultTransition.delay);
+ XCTAssert(colorTransition.duration && MGLTimeIntervalFromDuration(*colorTransition.duration) == defaultTransition.duration);
+
+ MGLStyleValue<MGLColor *> *colorStyleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor blackColor]];
+ mglLight.color = colorStyleValue;
+ mglLight.colorTransiton = transition;
+
+ NSAssert([mglLight.color isKindOfClass:[MGLConstantStyleValue class]], @"mglLight.color isn’t a MGLConstantStyleValue.");
+ colorValue = ((MGLConstantStyleValue *)mglLight.color).rawValue;
+
+ XCTAssertEqual([MGLColor blackColor], colorValue);
+ XCTAssertEqual(mglLight.colorTransiton.delay, transition.delay);
+ XCTAssertEqual(mglLight.colorTransiton.duration, transition.duration);
+
+ mbgl::style::PropertyValue<mbgl::Color> colorProperty = { { 0, 0, 0, 1 } };
+ light.setColor(colorProperty);
+ light.setColorTransition(transitionOptions);
+
+ lightFromMGLlight = [mglLight mbglLight];
+
+ colorComponents = CGColorGetComponents(colorValue.CGColor);
+ color = lightFromMGLlight.getColor().asConstant();
+ XCTAssertEqual(light.getColor().asConstant(),lightFromMGLlight.getColor().asConstant());
+ colorTransition = lightFromMGLlight.getColorTransition();
+ XCTAssert(colorTransition.delay && MGLTimeIntervalFromDuration(*colorTransition.delay) == transition.delay);
+ XCTAssert(colorTransition.duration && MGLTimeIntervalFromDuration(*colorTransition.duration) == transition.duration);
+ }
+
+ // intensity
+ {
+ mbgl::style::Light light;
+ MGLLight *mglLight = [[MGLLight alloc] initWithMBGLLight:&light];
+ NSAssert([mglLight.intensity isKindOfClass:[MGLConstantStyleValue class]], @"mglLight.intensity isn’t a MGLConstantStyleValue.");
+ NSNumber *intensityNumber = ((MGLConstantStyleValue *)mglLight.intensity).rawValue;
+ auto intensity = light.getDefaultIntensity();
+
+ XCTAssert(intensityNumber.floatValue == intensity);
+ XCTAssertEqual(mglLight.intensityTransition.delay, defaultTransition.delay);
+ XCTAssertEqual(mglLight.intensityTransition.duration, defaultTransition.duration);
+
+ auto lightFromMGLlight = [mglLight mbglLight];
+
+ XCTAssertEqual(intensity, lightFromMGLlight.getIntensity().asConstant());
+ auto intensityTransition = lightFromMGLlight.getIntensityTransition();
+ XCTAssert(intensityTransition.delay && MGLTimeIntervalFromDuration(*intensityTransition.delay) == defaultTransition.delay);
+ XCTAssert(intensityTransition.duration && MGLTimeIntervalFromDuration(*intensityTransition.duration) == defaultTransition.duration);
+
+ NSNumber *intensityValue = @0.4;
+ MGLStyleValue<NSNumber *> *intensityStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:intensityValue];
+ mglLight.intensity = intensityStyleValue;
+ mglLight.intensityTransition = transition;
+
+ NSAssert([mglLight.intensity isKindOfClass:[MGLConstantStyleValue class]], @"mglLight.intensity isn’t a MGLConstantStyleValue.");
+ intensityNumber = ((MGLConstantStyleValue *)mglLight.intensity).rawValue;
+ XCTAssert(intensityNumber.floatValue == intensityValue.floatValue);
+ XCTAssertEqual(mglLight.intensityTransition.delay, transition.delay);
+ XCTAssertEqual(mglLight.intensityTransition.duration, transition.duration);
+
+ mbgl::style::PropertyValue<float> intensityProperty = { 0.4 };
+ light.setIntensity(intensityProperty);
+ light.setIntensityTransition(transitionOptions);
+
+ lightFromMGLlight = [mglLight mbglLight];
+
+ XCTAssertEqual(light.getIntensity().asConstant(), lightFromMGLlight.getIntensity().asConstant());
+ intensityTransition = lightFromMGLlight.getIntensityTransition();
+ XCTAssert(intensityTransition.delay && MGLTimeIntervalFromDuration(*intensityTransition.delay) == transition.delay);
+ XCTAssert(intensityTransition.duration && MGLTimeIntervalFromDuration(*intensityTransition.duration) == transition.duration);
+
+ }
+
+}
+
+- (void)testValueAdditions {
+ MGLSphericalPosition position = MGLSphericalPositionMake(1.15, 210, 30);
+
+ XCTAssertEqual([NSValue valueWithMGLSphericalPosition:position].MGLSphericalPositionValue.radial, position.radial);
+ XCTAssertEqual([NSValue valueWithMGLSphericalPosition:position].MGLSphericalPositionValue.azimuthal, position.azimuthal);
+ XCTAssertEqual([NSValue valueWithMGLSphericalPosition:position].MGLSphericalPositionValue.polar, position.polar);
+ XCTAssertEqual([NSValue valueWithMGLLightAnchor:MGLLightAnchorMap].MGLLightAnchorValue, MGLLightAnchorMap);
+ XCTAssertEqual([NSValue valueWithMGLLightAnchor:MGLLightAnchorViewport].MGLLightAnchorValue, MGLLightAnchorViewport);
+}
+
+@end
diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md
index ceb371118d..977dd1b418 100644
--- a/platform/ios/CHANGELOG.md
+++ b/platform/ios/CHANGELOG.md
@@ -2,7 +2,13 @@
Mapbox welcomes participation and contributions from everyone. Please read [CONTRIBUTING.md](../../CONTRIBUTING.md) to get started.
-## master
+## 3.6.0
+
+### Packaging
+
+* Xcode 8.0 or higher is now recommended for using this SDK. ([#8775](https://github.com/mapbox/mapbox-gl-native/pull/8775))
+* Fixed an issue in the static framework where localizations would never load. ([#9074](https://github.com/mapbox/mapbox-gl-native/pull/9074))
+* Updated MGLMapView’s logo view to display [the new Mapbox logo](https://www.mapbox.com/blog/new-mapbox-logo/). ([#8771](https://github.com/mapbox/mapbox-gl-native/pull/8771), [#8773](https://github.com/mapbox/mapbox-gl-native/pull/8773))
* The previously-deprecated support for style classes has been removed. For interface compatibility, the API methods remain, but they are now non-functional.
* Added an `overlays` property to `MGLMapView`. ([#8617](https://github.com/mapbox/mapbox-gl-native/pull/8617))
@@ -16,26 +22,36 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT
* Added class methods to MGLStyle that correspond to the new [Traffic Day and Traffic Night](https://www.mapbox.com/blog/live-traffic-maps/) styles. ([#6301](https://github.com/mapbox/mapbox-gl-native/pull/6301))
* MGLSymbolStyleLayer’s `iconImageName`, `iconScale`, `textFontSize`, `textOffset`, and `textRotation` properties can now be set to a source or composite function. ([#8544](https://github.com/mapbox/mapbox-gl-native/pull/8544), [#8590](https://github.com/mapbox/mapbox-gl-native/pull/8590), [#8592](https://github.com/mapbox/mapbox-gl-native/pull/8592), [#8593](https://github.com/mapbox/mapbox-gl-native/pull/8593))
* Fixed an issue where setting the `MGLVectorStyleLayer.predicate` property failed to take effect if the relevant source was not in use by a visible layer at the time. ([#8653](https://github.com/mapbox/mapbox-gl-native/pull/8653))
+* Fixed an issue preventing programmatically added style layers from appearing in already cached tiles. ([#8954](https://github.com/mapbox/mapbox-gl-native/pull/8954))
* Fixed an issue causing a composite function’s highest zoom level stop to be misinterpreted. ([#8613](https://github.com/mapbox/mapbox-gl-native/pull/8613), [#8790](https://github.com/mapbox/mapbox-gl-native/pull/8790))
* Fixed an issue where re-adding a layer that had been previously removed from a style would reset its paint properties. Moved initializers for `MGLTileSource`, `MGLStyleLayer`, and `MGLForegroundStyleLayer` to their concrete subclasses; because these classes were already intended for initialization only via concrete subclasses, this should have no developer impact. ([#8626](https://github.com/mapbox/mapbox-gl-native/pull/8626))
* Feature querying results now account for any changes to a feature’s size caused by a source or composite style function. ([#8665](https://github.com/mapbox/mapbox-gl-native/pull/8665))
+* Letter spacing is now disabled in Arabic text so that ligatures are drawn correctly. ([#9062](https://github.com/mapbox/mapbox-gl-native/pull/9062))
### Annotations
+* Added a new initializer to `MGLAnnotationView` so that it is possible to create a new instance with an associated annotation object. ([#9029](https://github.com/mapbox/mapbox-gl-native/pull/9029))
+* Added a new `rotatesToMatchCamera` property to `MGLAnnotationView` that, when set to true, causes the annotation view to rotate along with the map's rotation angle giving the appearance that the annoation view is pinned to the map. ([#9147](https://github.com/mapbox/mapbox-gl-native/pull/9147))
* Fixed an issue causing a view-backed annotation to disappear immediately instead of animating when the annotation’s `coordinate` property is set to a value outside the current viewport. ([#8565](https://github.com/mapbox/mapbox-gl-native/pull/8565))
* Fixed an issue in which `MGLMapView` overrode the tint colors of its annotation views. ([#8789](https://github.com/mapbox/mapbox-gl-native/pull/8789))
+* Fixed an issue causing annotation views to persist in the map’s annotation container view even after their associated annotations were removed. ([#9025](https://github.com/mapbox/mapbox-gl-native/pull/9025))
+* The `MGLPolyline.coordinate` and `MGLPolygon.coordinate` properties now return the midpoint and centroid, respectively, instead of the first coordinate. ([#8713](https://github.com/mapbox/mapbox-gl-native/pull/8713))
### User interaction
* Added a scale bar to `MGLMapView` that indicates the scale of the map. ([#7631](https://github.com/mapbox/mapbox-gl-native/pull/7631))
* Fixed an issue where gesture recognizers associated with map view interactivity were not disabled when their related interactions were disabled. ([#8304](https://github.com/mapbox/mapbox-gl-native/pull/8304))
+* Fixed an issue preventing the Mapbox Telemetry confirmation dialog from appearing when opened from within a map view in a modal view controller. ([#9027](https://github.com/mapbox/mapbox-gl-native/pull/9027))
+* Corrected the size of MGLMapView’s compass. ([#9060](https://github.com/mapbox/mapbox-gl-native/pull/9060))
+* The Improve This Map button in the attribution action sheet now leads to a feedback tool that matches MGLMapView’s rotation and pitch. `-[MGLAttributionInfo feedbackURLAtCenterCoordinate:zoomLevel:]` no longer respects the feedback URL specified in TileJSON. ([#9078](https://github.com/mapbox/mapbox-gl-native/pull/9078))
### Other changes
-* Xcode 8.0 or higher is now recommended for using this SDK. ([#8775](https://github.com/mapbox/mapbox-gl-native/pull/8775))
-* Updated MGLMapView’s logo view to display [the new Mapbox logo](https://www.mapbox.com/blog/new-mapbox-logo/). ([#8771](https://github.com/mapbox/mapbox-gl-native/pull/8771), [#8773](https://github.com/mapbox/mapbox-gl-native/pull/8773))
+* Fixed a crash that occurred when accessing the `MGLMultiPolygon.coordinate` property. ([#8713](https://github.com/mapbox/mapbox-gl-native/pull/8713))
* Fixed a crash or console spew when MGLMapView is initialized with a frame smaller than 64 points wide by 64 points tall. ([#8562](https://github.com/mapbox/mapbox-gl-native/pull/8562))
+* Fixed an issue that caused the compass and scale bar to underlap navigation and tab bars. ([#7716](https://github.com/mapbox/mapbox-gl-native/pull/7716))
* The error passed into `-[MGLMapViewDelegate mapViewDidFailLoadingMap:withError:]` now includes a more specific description and failure reason. ([#8418](https://github.com/mapbox/mapbox-gl-native/pull/8418))
+* Improved CPU and battery performance while animating a tilted map’s camera in an area with many labels. ([#9031](https://github.com/mapbox/mapbox-gl-native/pull/9031))
* Fixed an issue rendering polylines that contain duplicate vertices. ([#8808](https://github.com/mapbox/mapbox-gl-native/pull/8808))
## 3.5.4 - May 9, 2017
diff --git a/platform/ios/Mapbox-iOS-SDK-symbols.podspec b/platform/ios/Mapbox-iOS-SDK-symbols.podspec
index f8b20777fa..3116ede9f5 100644
--- a/platform/ios/Mapbox-iOS-SDK-symbols.podspec
+++ b/platform/ios/Mapbox-iOS-SDK-symbols.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |m|
- version = '3.6.0-alpha.1'
+ version = '3.6.0-beta.2'
m.name = 'Mapbox-iOS-SDK-symbols'
m.version = "#{version}-symbols"
diff --git a/platform/ios/Mapbox-iOS-SDK.podspec b/platform/ios/Mapbox-iOS-SDK.podspec
index 15658e6241..f6bc3030ab 100644
--- a/platform/ios/Mapbox-iOS-SDK.podspec
+++ b/platform/ios/Mapbox-iOS-SDK.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |m|
- version = '3.6.0-alpha.1'
+ version = '3.6.0-beta.2'
m.name = 'Mapbox-iOS-SDK'
m.version = version
diff --git a/platform/ios/app/MBXViewController.m b/platform/ios/app/MBXViewController.m
index 7cbe9d594f..7f3adfb78b 100644
--- a/platform/ios/app/MBXViewController.m
+++ b/platform/ios/app/MBXViewController.m
@@ -1396,19 +1396,20 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
- (NSString *)bestLanguageForUser
{
- NSArray *supportedLanguages = @[ @"en", @"es", @"fr", @"de", @"ru", @"zh" ];
- NSArray<NSString *> *preferredLanguages = [NSLocale preferredLanguages];
- NSString *bestLanguage;
-
- for (NSString *language in preferredLanguages) {
- NSString *thisLanguage = [[NSLocale localeWithLocaleIdentifier:language] objectForKey:NSLocaleLanguageCode];
- if ([supportedLanguages containsObject:thisLanguage]) {
- bestLanguage = thisLanguage;
- break;
+ // https://www.mapbox.com/vector-tiles/mapbox-streets-v7/#overview
+ NSArray *supportedLanguages = @[ @"ar", @"en", @"es", @"fr", @"de", @"pt", @"ru", @"zh", @"zh-Hans" ];
+ NSArray<NSString *> *preferredLanguages = [NSBundle preferredLocalizationsFromArray:supportedLanguages forPreferences:[NSLocale preferredLanguages]];
+ NSString *mostSpecificLanguage;
+
+ for (NSString *language in preferredLanguages)
+ {
+ if (language.length > mostSpecificLanguage.length)
+ {
+ mostSpecificLanguage = language;
}
}
- return bestLanguage ?: @"en";
+ return mostSpecificLanguage ?: @"en";
}
- (IBAction)startWorldTour
diff --git a/platform/ios/docs/guides/Tile URL Templates.md b/platform/ios/docs/guides/Tile URL Templates.md
new file mode 100644
index 0000000000..f61d2ea33a
--- /dev/null
+++ b/platform/ios/docs/guides/Tile URL Templates.md
@@ -0,0 +1,99 @@
+<!--
+ This file is generated.
+ Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
+-->
+# Tile URL Templates
+
+`MGLTileSource` objects, specifically `MGLRasterSource` and `MGLVectorSource`
+objects, can be created using an initializer that accepts an array of tile URL
+templates. Tile URL templates are strings that specify the URLs of the vector
+tiles or raster tile images to load. A template resembles an absolute URL, but
+with any number of placeholder strings that the source evaluates based on the
+tile it needs to load. For example:
+
+* `http://www.example.com/tiles/{z}/{x}/{y}.pbf` could be
+ evaluated as `http://www.example.com/tiles/14/6/9.pbf`.
+* `http://www.example.com/tiles/{z}/{x}/{y}{ratio}.png` could be
+ evaluated as `http://www.example.com/tiles/14/6/9@2x.png`.
+
+Tile URL templates are also used to define tilesets in TileJSON manifests or
+[`raster`](https://www.mapbox.com/mapbox-gl-js/style-spec/#sources-raster-tiles)
+and
+[`vector`](https://www.mapbox.com/mapbox-gl-js/style-spec/#sources-vector-tiles)
+sources in style JSON files. See the
+[TileJSON specification](https://github.com/mapbox/tilejson-spec/tree/master/2.2.0)
+for information about tile URL templates in the context of a TileJSON or style
+JSON file.
+
+Tile sources support the following placeholder strings in tile URL templates,
+all of which are optional:
+
+<table>
+<thead>
+<tr><th>Placeholder string</th><th>Description</th></tr>
+</thead>
+<tbody>
+<tr>
+ <td><code>{x}</code></td>
+ <td>The index of the tile along the map’s x axis according to Spherical
+ Mercator projection. If the value is 0, the tile’s left edge corresponds
+ to the 180th meridian west. If the value is 2<sup><var>z</var></sup>−1,
+ the tile’s right edge corresponds to the 180th meridian east.</td>
+</tr>
+<tr>
+ <td><code>{y}</code></td>
+ <td>The index of the tile along the map’s y axis according to Spherical
+ Mercator projection. If the value is 0, the tile’s tile edge corresponds
+ to arctan(sinh(π)), or approximately 85.0511 degrees north. If the value
+ is 2<sup><var>z</var></sup>−1, the tile’s bottom edge corresponds to
+ −arctan(sinh(π)), or approximately 85.0511 degrees south. The y axis is
+ inverted if the <code>options</code> parameter contains
+ <code>MGLTileSourceOptionTileCoordinateSystem</code> with a value of
+ <code>MGLTileCoordinateSystemTMS</code>.</td>
+</tr>
+<tr>
+ <td><code>{z}</code></td>
+ <td>The tile’s zoom level. At zoom level 0, each tile covers the entire
+ world map; at zoom level 1, it covers ¼ of the world; at zoom level 2,
+ <sup>1</sup>⁄<sub>16</sub> of the world, and so on. For tiles loaded by
+ a <code>MGLRasterSource</code> object, whether the tile zoom level
+ matches the map’s current zoom level depends on the value of the
+ source’s tile size as specified in the
+ <code>MGLTileSourceOptionTileSize</code> key of the <code>options</code>
+ parameter.</td>
+</tr>
+<tr>
+ <td><code>{bbox-epsg-3857}</code></td>
+ <td>The tile’s bounding box, expressed as a comma-separated list of the
+ tile’s western, southern, eastern, and northern extents according to
+ Spherical Mercator (EPSG:3857) projection. The bounding box is typically
+ used with map services conforming to the
+ <a href="http://www.opengeospatial.org/standards/wms">Web Map Service</a>
+ protocol.</td>
+</tr>
+<tr>
+ <td><code>{quadkey}</code></td>
+ <td>A quadkey indicating both the tile’s location and its zoom level. The
+ quadkey is typically used with
+ <a href="https://msdn.microsoft.com/en-us/library/bb259689.aspx">Bing Maps</a>.
+ </td>
+</tr>
+<tr>
+ <td><code>{ratio}</code></td>
+ <td>A suffix indicating the resolution of the tile image. The suffix is the
+ empty string for standard resolution displays and <code>@2x</code> for
+ Retina displays, including displays for which <code>UIScreen.scale</code>
+ is 3.
+ </td>
+</tr>
+<tr>
+ <td><code>{prefix}</code></td>
+ <td>Two hexadecimal digits chosen such that each visible tile has a
+ different prefix. The prefix is typically used for domain sharding.</td>
+</tr>
+</tbody>
+</table>
+
+For more information about the `{x}`, `{y}`, and `{z}` placeholder strings,
+consult the
+[OpenStreetMap Wiki](https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames).
diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj
index 215d31810d..b6d422d0fc 100644
--- a/platform/ios/ios.xcodeproj/project.pbxproj
+++ b/platform/ios/ios.xcodeproj/project.pbxproj
@@ -9,6 +9,13 @@
/* Begin PBXBuildFile section */
1753ED421E53CE6F00A9FD90 /* MGLConversion.h in Headers */ = {isa = PBXBuildFile; fileRef = 1753ED411E53CE6F00A9FD90 /* MGLConversion.h */; };
1753ED431E53CE6F00A9FD90 /* MGLConversion.h in Headers */ = {isa = PBXBuildFile; fileRef = 1753ED411E53CE6F00A9FD90 /* MGLConversion.h */; };
+ 1F06668A1EC64F8E001C16D7 /* MGLLight.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F0666881EC64F8E001C16D7 /* MGLLight.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 1F06668D1EC64F8E001C16D7 /* MGLLight.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1F0666891EC64F8E001C16D7 /* MGLLight.mm */; };
+ 1F7454921ECBB42C00021D39 /* MGLLight.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1F0666891EC64F8E001C16D7 /* MGLLight.mm */; };
+ 1F7454931ECBB43F00021D39 /* MGLLight.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F0666881EC64F8E001C16D7 /* MGLLight.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 1F7454961ECD450D00021D39 /* MGLLight_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F7454941ECD450D00021D39 /* MGLLight_Private.h */; };
+ 1F7454971ECD450D00021D39 /* MGLLight_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F7454941ECD450D00021D39 /* MGLLight_Private.h */; };
+ 1F7454A91ED08AB400021D39 /* MGLLightTest.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1F7454A61ED08AB400021D39 /* MGLLightTest.mm */; };
1F95931D1E6DE2E900D5B294 /* MGLNSDateAdditionsTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1F95931C1E6DE2E900D5B294 /* MGLNSDateAdditionsTests.mm */; };
30E578171DAA85520050F07E /* UIImage+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 30E578111DAA7D690050F07E /* UIImage+MGLAdditions.h */; };
30E578181DAA85520050F07E /* UIImage+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 30E578111DAA7D690050F07E /* UIImage+MGLAdditions.h */; };
@@ -165,6 +172,7 @@
408AA8571DAEDA1700022900 /* NSDictionary+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 408AA8551DAEDA0800022900 /* NSDictionary+MGLAdditions.h */; };
408AA8581DAEDA1E00022900 /* NSDictionary+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 408AA8561DAEDA0800022900 /* NSDictionary+MGLAdditions.mm */; };
408AA8591DAEDA1E00022900 /* NSDictionary+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 408AA8561DAEDA0800022900 /* NSDictionary+MGLAdditions.mm */; };
+ 409D0A0D1ED614CE00C95D0C /* MGLAnnotationViewIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 409D0A0C1ED614CE00C95D0C /* MGLAnnotationViewIntegrationTests.swift */; };
409F43FD1E9E781C0048729D /* MGLMapViewDelegateIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 409F43FC1E9E781C0048729D /* MGLMapViewDelegateIntegrationTests.swift */; };
40CF6DBB1DAC3C6600A4D18B /* MGLShape_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 40CF6DBA1DAC3C1800A4D18B /* MGLShape_Private.h */; };
40CFA6511D7875BB008103BD /* MGLShapeSourceTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 40CFA6501D787579008103BD /* MGLShapeSourceTests.mm */; };
@@ -193,6 +201,8 @@
7E016D861D9E890300A29A21 /* MGLPolygon+MGLAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 7E016D831D9E890300A29A21 /* MGLPolygon+MGLAdditions.m */; };
7E016D871D9E890300A29A21 /* MGLPolygon+MGLAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 7E016D831D9E890300A29A21 /* MGLPolygon+MGLAdditions.m */; };
920A3E5D1E6F995200C16EFC /* MGLSourceQueryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 920A3E5C1E6F995200C16EFC /* MGLSourceQueryTests.m */; };
+ 960D0C361ECF5AAF008E151F /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 960D0C351ECF5AAF008E151F /* Images.xcassets */; };
+ 960D0C371ECF5AAF008E151F /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 960D0C351ECF5AAF008E151F /* Images.xcassets */; };
9620BB381E69FE1700705A1D /* MGLSDKUpdateChecker.h in Headers */ = {isa = PBXBuildFile; fileRef = 9620BB361E69FE1700705A1D /* MGLSDKUpdateChecker.h */; };
9620BB391E69FE1700705A1D /* MGLSDKUpdateChecker.h in Headers */ = {isa = PBXBuildFile; fileRef = 9620BB361E69FE1700705A1D /* MGLSDKUpdateChecker.h */; };
9620BB3A1E69FE1700705A1D /* MGLSDKUpdateChecker.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9620BB371E69FE1700705A1D /* MGLSDKUpdateChecker.mm */; };
@@ -326,15 +336,6 @@
DA88485C1CBAFB9800AB86E3 /* MGLFaux3DUserLocationAnnotationView.h in Headers */ = {isa = PBXBuildFile; fileRef = DA88484D1CBAFB9800AB86E3 /* MGLFaux3DUserLocationAnnotationView.h */; };
DA88485D1CBAFB9800AB86E3 /* MGLFaux3DUserLocationAnnotationView.m in Sources */ = {isa = PBXBuildFile; fileRef = DA88484E1CBAFB9800AB86E3 /* MGLFaux3DUserLocationAnnotationView.m */; };
DA8848601CBAFC2E00AB86E3 /* Mapbox.h in Headers */ = {isa = PBXBuildFile; fileRef = DA88485E1CBAFC2E00AB86E3 /* Mapbox.h */; settings = {ATTRIBUTES = (Public, ); }; };
- DA88486D1CBAFCC100AB86E3 /* Compass.png in Resources */ = {isa = PBXBuildFile; fileRef = DA8848631CBAFCC100AB86E3 /* Compass.png */; };
- DA88486E1CBAFCC100AB86E3 /* Compass@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA8848641CBAFCC100AB86E3 /* Compass@2x.png */; };
- DA88486F1CBAFCC100AB86E3 /* Compass@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA8848651CBAFCC100AB86E3 /* Compass@3x.png */; };
- DA8848701CBAFCC100AB86E3 /* default_marker.png in Resources */ = {isa = PBXBuildFile; fileRef = DA8848661CBAFCC100AB86E3 /* default_marker.png */; };
- DA8848711CBAFCC100AB86E3 /* default_marker@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA8848671CBAFCC100AB86E3 /* default_marker@2x.png */; };
- DA8848721CBAFCC100AB86E3 /* default_marker@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA8848681CBAFCC100AB86E3 /* default_marker@3x.png */; };
- DA8848731CBAFCC100AB86E3 /* mapbox.png in Resources */ = {isa = PBXBuildFile; fileRef = DA8848691CBAFCC100AB86E3 /* mapbox.png */; };
- DA8848741CBAFCC100AB86E3 /* mapbox@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA88486A1CBAFCC100AB86E3 /* mapbox@2x.png */; };
- DA8848751CBAFCC100AB86E3 /* mapbox@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA88486B1CBAFCC100AB86E3 /* mapbox@3x.png */; };
DA8848841CBB033F00AB86E3 /* FABAttributes.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8848801CBB033F00AB86E3 /* FABAttributes.h */; };
DA8848851CBB033F00AB86E3 /* FABKitProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8848811CBB033F00AB86E3 /* FABKitProtocol.h */; };
DA8848861CBB033F00AB86E3 /* Fabric+FABKits.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8848821CBB033F00AB86E3 /* Fabric+FABKits.h */; };
@@ -348,15 +349,6 @@
DA8933DB1CCD31D400E68420 /* Foundation.strings in Resources */ = {isa = PBXBuildFile; fileRef = DA8933BA1CCD2CA100E68420 /* Foundation.strings */; };
DA8933DC1CCD31D400E68420 /* Foundation.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = DA8933BD1CCD2CAD00E68420 /* Foundation.stringsdict */; };
DA8933E01CCD31DF00E68420 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = DA89339F1CCC951200E68420 /* Localizable.strings */; };
- DA8933E11CCD31DF00E68420 /* Compass.png in Resources */ = {isa = PBXBuildFile; fileRef = DA8848631CBAFCC100AB86E3 /* Compass.png */; };
- DA8933E21CCD31DF00E68420 /* Compass@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA8848641CBAFCC100AB86E3 /* Compass@2x.png */; };
- DA8933E31CCD31DF00E68420 /* Compass@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA8848651CBAFCC100AB86E3 /* Compass@3x.png */; };
- DA8933E41CCD31DF00E68420 /* default_marker.png in Resources */ = {isa = PBXBuildFile; fileRef = DA8848661CBAFCC100AB86E3 /* default_marker.png */; };
- DA8933E51CCD31DF00E68420 /* default_marker@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA8848671CBAFCC100AB86E3 /* default_marker@2x.png */; };
- DA8933E61CCD31DF00E68420 /* default_marker@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA8848681CBAFCC100AB86E3 /* default_marker@3x.png */; };
- DA8933E71CCD31DF00E68420 /* mapbox.png in Resources */ = {isa = PBXBuildFile; fileRef = DA8848691CBAFCC100AB86E3 /* mapbox.png */; };
- DA8933E81CCD31DF00E68420 /* mapbox@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA88486A1CBAFCC100AB86E3 /* mapbox@2x.png */; };
- DA8933E91CCD31DF00E68420 /* mapbox@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA88486B1CBAFCC100AB86E3 /* mapbox@3x.png */; };
DA8933F01CCD387900E68420 /* strip-frameworks.sh in Resources */ = {isa = PBXBuildFile; fileRef = DA8933EF1CCD387900E68420 /* strip-frameworks.sh */; };
DA8963371CC549A100684375 /* glyphs in Resources */ = {isa = PBXBuildFile; fileRef = DA8963331CC549A100684375 /* glyphs */; };
DA8963381CC549A100684375 /* sprites in Resources */ = {isa = PBXBuildFile; fileRef = DA8963341CC549A100684375 /* sprites */; };
@@ -545,6 +537,10 @@
/* Begin PBXFileReference section */
1753ED411E53CE6F00A9FD90 /* MGLConversion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLConversion.h; sourceTree = "<group>"; };
+ 1F0666881EC64F8E001C16D7 /* MGLLight.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLLight.h; sourceTree = "<group>"; };
+ 1F0666891EC64F8E001C16D7 /* MGLLight.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLLight.mm; sourceTree = "<group>"; };
+ 1F7454941ECD450D00021D39 /* MGLLight_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLLight_Private.h; sourceTree = "<group>"; };
+ 1F7454A61ED08AB400021D39 /* MGLLightTest.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLLightTest.mm; path = ../../darwin/test/MGLLightTest.mm; sourceTree = "<group>"; };
1F95931C1E6DE2E900D5B294 /* MGLNSDateAdditionsTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLNSDateAdditionsTests.mm; path = ../../darwin/test/MGLNSDateAdditionsTests.mm; sourceTree = "<group>"; };
20DABE861DF78148007AC5FF /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Foundation.strings"; sourceTree = "<group>"; };
20DABE881DF78148007AC5FF /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = "<group>"; };
@@ -644,6 +640,7 @@
4085AF081D933DEA00F11B22 /* MGLTileSetTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLTileSetTests.mm; path = ../../darwin/test/MGLTileSetTests.mm; sourceTree = "<group>"; };
408AA8551DAEDA0800022900 /* NSDictionary+MGLAdditions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+MGLAdditions.h"; sourceTree = "<group>"; };
408AA8561DAEDA0800022900 /* NSDictionary+MGLAdditions.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSDictionary+MGLAdditions.mm"; sourceTree = "<group>"; };
+ 409D0A0C1ED614CE00C95D0C /* MGLAnnotationViewIntegrationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MGLAnnotationViewIntegrationTests.swift; sourceTree = "<group>"; };
409F43FC1E9E781C0048729D /* MGLMapViewDelegateIntegrationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MGLMapViewDelegateIntegrationTests.swift; sourceTree = "<group>"; };
40CF6DBA1DAC3C1800A4D18B /* MGLShape_Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLShape_Private.h; sourceTree = "<group>"; };
40CFA6501D787579008103BD /* MGLShapeSourceTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLShapeSourceTests.mm; path = ../../darwin/test/MGLShapeSourceTests.mm; sourceTree = "<group>"; };
@@ -668,6 +665,7 @@
7E016D821D9E890300A29A21 /* MGLPolygon+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MGLPolygon+MGLAdditions.h"; sourceTree = "<group>"; };
7E016D831D9E890300A29A21 /* MGLPolygon+MGLAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MGLPolygon+MGLAdditions.m"; sourceTree = "<group>"; };
920A3E5C1E6F995200C16EFC /* MGLSourceQueryTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLSourceQueryTests.m; path = ../../darwin/test/MGLSourceQueryTests.m; sourceTree = "<group>"; };
+ 960D0C351ECF5AAF008E151F /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
9620BB361E69FE1700705A1D /* MGLSDKUpdateChecker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLSDKUpdateChecker.h; sourceTree = "<group>"; };
9620BB371E69FE1700705A1D /* MGLSDKUpdateChecker.mm */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = MGLSDKUpdateChecker.mm; sourceTree = "<group>"; };
9660916B1E5BBFD700A9A03B /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = "<group>"; };
@@ -836,15 +834,6 @@
DA88484D1CBAFB9800AB86E3 /* MGLFaux3DUserLocationAnnotationView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLFaux3DUserLocationAnnotationView.h; sourceTree = "<group>"; };
DA88484E1CBAFB9800AB86E3 /* MGLFaux3DUserLocationAnnotationView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLFaux3DUserLocationAnnotationView.m; sourceTree = "<group>"; };
DA88485E1CBAFC2E00AB86E3 /* Mapbox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Mapbox.h; path = src/Mapbox.h; sourceTree = SOURCE_ROOT; };
- DA8848631CBAFCC100AB86E3 /* Compass.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Compass.png; sourceTree = "<group>"; };
- DA8848641CBAFCC100AB86E3 /* Compass@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Compass@2x.png"; sourceTree = "<group>"; };
- DA8848651CBAFCC100AB86E3 /* Compass@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Compass@3x.png"; sourceTree = "<group>"; };
- DA8848661CBAFCC100AB86E3 /* default_marker.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = default_marker.png; sourceTree = "<group>"; };
- DA8848671CBAFCC100AB86E3 /* default_marker@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "default_marker@2x.png"; sourceTree = "<group>"; };
- DA8848681CBAFCC100AB86E3 /* default_marker@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "default_marker@3x.png"; sourceTree = "<group>"; };
- DA8848691CBAFCC100AB86E3 /* mapbox.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = mapbox.png; sourceTree = "<group>"; };
- DA88486A1CBAFCC100AB86E3 /* mapbox@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "mapbox@2x.png"; sourceTree = "<group>"; };
- DA88486B1CBAFCC100AB86E3 /* mapbox@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "mapbox@3x.png"; sourceTree = "<group>"; };
DA8848801CBB033F00AB86E3 /* FABAttributes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FABAttributes.h; sourceTree = "<group>"; };
DA8848811CBB033F00AB86E3 /* FABKitProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FABKitProtocol.h; sourceTree = "<group>"; };
DA8848821CBB033F00AB86E3 /* Fabric+FABKits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Fabric+FABKits.h"; sourceTree = "<group>"; };
@@ -1039,6 +1028,9 @@
35599DB81D46AD7F0048254D /* Categories */,
353933F01D3FB6BA003F57D7 /* Layers */,
35136D491D4277EA00C20EFD /* Sources */,
+ 1F0666881EC64F8E001C16D7 /* MGLLight.h */,
+ 1F0666891EC64F8E001C16D7 /* MGLLight.mm */,
+ 1F7454941ECD450D00021D39 /* MGLLight_Private.h */,
DAAF72291DA903C700312FA4 /* MGLStyleValue.h */,
DAAF722A1DA903C700312FA4 /* MGLStyleValue_Private.h */,
35599DEA1D46F14E0048254D /* MGLStyleValue.mm */,
@@ -1069,6 +1061,7 @@
children = (
3575798F1D513EF1000B822E /* Layers */,
40CFA64E1D78754A008103BD /* Sources */,
+ 1F7454A61ED08AB400021D39 /* MGLLightTest.mm */,
357F09091DF84F3800941873 /* MGLStyleValueTests.h */,
3599A3E51DF708BC00E77FB2 /* MGLStyleValueTests.m */,
DA2207BE1DC0805F0002F84D /* MGLStyleValueTests.swift */,
@@ -1128,6 +1121,7 @@
isa = PBXGroup;
children = (
409F43FC1E9E781C0048729D /* MGLMapViewDelegateIntegrationTests.swift */,
+ 409D0A0C1ED614CE00C95D0C /* MGLAnnotationViewIntegrationTests.swift */,
);
name = "Swift Integration";
sourceTree = "<group>";
@@ -1348,17 +1342,9 @@
DA8848621CBAFCC100AB86E3 /* Kit Resources */ = {
isa = PBXGroup;
children = (
+ 960D0C351ECF5AAF008E151F /* Images.xcassets */,
DA89339F1CCC951200E68420 /* Localizable.strings */,
DAC49C5F1CD02BC9009E1AA3 /* Localizable.stringsdict */,
- DA8848631CBAFCC100AB86E3 /* Compass.png */,
- DA8848641CBAFCC100AB86E3 /* Compass@2x.png */,
- DA8848651CBAFCC100AB86E3 /* Compass@3x.png */,
- DA8848661CBAFCC100AB86E3 /* default_marker.png */,
- DA8848671CBAFCC100AB86E3 /* default_marker@2x.png */,
- DA8848681CBAFCC100AB86E3 /* default_marker@3x.png */,
- DA8848691CBAFCC100AB86E3 /* mapbox.png */,
- DA88486A1CBAFCC100AB86E3 /* mapbox@2x.png */,
- DA88486B1CBAFCC100AB86E3 /* mapbox@3x.png */,
DA8933EF1CCD387900E68420 /* strip-frameworks.sh */,
40599F001DEE1B2400182B5D /* api_mapbox_staging.der */,
40599F011DEE1B2400182B5D /* api_mapbox_com-digicert.der */,
@@ -1657,6 +1643,7 @@
DA8847F01CBAFA5100AB86E3 /* MGLAnnotation.h in Headers */,
7E016D841D9E890300A29A21 /* MGLPolygon+MGLAdditions.h in Headers */,
400533011DB0862B0069F638 /* NSArray+MGLAdditions.h in Headers */,
+ 1F06668A1EC64F8E001C16D7 /* MGLLight.h in Headers */,
4049C29D1DB6CD6C00B3F799 /* MGLPointCollection.h in Headers */,
40CF6DBB1DAC3C6600A4D18B /* MGLShape_Private.h in Headers */,
4018B1CA1CDC288E00F666AF /* MGLAnnotationView.h in Headers */,
@@ -1705,6 +1692,7 @@
353933F21D3FB753003F57D7 /* MGLCircleStyleLayer.h in Headers */,
DA8847F31CBAFA5100AB86E3 /* MGLMultiPoint.h in Headers */,
30E578171DAA85520050F07E /* UIImage+MGLAdditions.h in Headers */,
+ 1F7454961ECD450D00021D39 /* MGLLight_Private.h in Headers */,
DAD1656C1CF41981001FF4B9 /* MGLFeature.h in Headers */,
40EDA1C01CFE0E0200D9EA68 /* MGLAnnotationContainerView.h in Headers */,
9620BB381E69FE1700705A1D /* MGLSDKUpdateChecker.h in Headers */,
@@ -1783,6 +1771,7 @@
35CE61831D4165D9004F2359 /* UIColor+MGLAdditions.h in Headers */,
DABFB8671CBE99E500D62B32 /* MGLPolygon.h in Headers */,
404C26E81D89C55D000AA13D /* MGLTileSource_Private.h in Headers */,
+ 1F7454931ECBB43F00021D39 /* MGLLight.h in Headers */,
DAAF722C1DA903C700312FA4 /* MGLStyleValue.h in Headers */,
DABFB8651CBE99E500D62B32 /* MGLOverlay.h in Headers */,
35E79F211D41266300957B9E /* MGLStyleLayer_Private.h in Headers */,
@@ -1816,6 +1805,7 @@
DA35A2BC1CCA9A6900E826B2 /* MGLClockDirectionFormatter.h in Headers */,
35D13AC41D3D19DD00AFB4E0 /* MGLFillStyleLayer.h in Headers */,
DABFB86E1CBE9A0F00D62B32 /* MGLCalloutView.h in Headers */,
+ 1F7454971ECD450D00021D39 /* MGLLight_Private.h in Headers */,
DABFB8601CBE99E500D62B32 /* MGLMapCamera.h in Headers */,
DA737EE21D056A4E005BDA16 /* MGLMapViewDelegate.h in Headers */,
DAF0D8191DFE6B2800B28378 /* MGLAttributionInfo_Private.h in Headers */,
@@ -2073,18 +2063,10 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- DA8848731CBAFCC100AB86E3 /* mapbox.png in Resources */,
DA8933BC1CCD2CA100E68420 /* Foundation.strings in Resources */,
- DA8848741CBAFCC100AB86E3 /* mapbox@2x.png in Resources */,
DA8933A31CCC95B000E68420 /* Localizable.strings in Resources */,
- DA88486D1CBAFCC100AB86E3 /* Compass.png in Resources */,
- DA8848721CBAFCC100AB86E3 /* default_marker@3x.png in Resources */,
- DA88486F1CBAFCC100AB86E3 /* Compass@3x.png in Resources */,
- DA88486E1CBAFCC100AB86E3 /* Compass@2x.png in Resources */,
- DA8848701CBAFCC100AB86E3 /* default_marker.png in Resources */,
- DA8848711CBAFCC100AB86E3 /* default_marker@2x.png in Resources */,
+ 960D0C361ECF5AAF008E151F /* Images.xcassets in Resources */,
DA8933F01CCD387900E68420 /* strip-frameworks.sh in Resources */,
- DA8848751CBAFCC100AB86E3 /* mapbox@3x.png in Resources */,
DAC49C5C1CD02BC9009E1AA3 /* Localizable.stringsdict in Resources */,
DA8933BF1CCD2CAD00E68420 /* Foundation.stringsdict in Resources */,
408982E91DEE208200754016 /* api_mapbox_staging.der in Resources */,
@@ -2098,16 +2080,8 @@
buildActionMask = 2147483647;
files = (
DA8933E01CCD31DF00E68420 /* Localizable.strings in Resources */,
- DA8933E11CCD31DF00E68420 /* Compass.png in Resources */,
- DA8933E21CCD31DF00E68420 /* Compass@2x.png in Resources */,
- DA8933E31CCD31DF00E68420 /* Compass@3x.png in Resources */,
- DA8933E41CCD31DF00E68420 /* default_marker.png in Resources */,
- DA8933E51CCD31DF00E68420 /* default_marker@2x.png in Resources */,
- DA8933E61CCD31DF00E68420 /* default_marker@3x.png in Resources */,
- DA8933E71CCD31DF00E68420 /* mapbox.png in Resources */,
- DA8933E81CCD31DF00E68420 /* mapbox@2x.png in Resources */,
- DA8933E91CCD31DF00E68420 /* mapbox@3x.png in Resources */,
DA8933DB1CCD31D400E68420 /* Foundation.strings in Resources */,
+ 960D0C371ECF5AAF008E151F /* Images.xcassets in Resources */,
DA8933DC1CCD31D400E68420 /* Foundation.stringsdict in Resources */,
DAC49C5D1CD02BC9009E1AA3 /* Localizable.stringsdict in Resources */,
40599F0C1DEE1B7600182B5D /* api_mapbox_staging.der in Resources */,
@@ -2166,6 +2140,7 @@
DAE7DEC21E245455007505A6 /* MGLNSStringAdditionsTests.m in Sources */,
4085AF091D933DEA00F11B22 /* MGLTileSetTests.mm in Sources */,
DAEDC4341D603417000224FF /* MGLAttributionInfoTests.m in Sources */,
+ 1F7454A91ED08AB400021D39 /* MGLLightTest.mm in Sources */,
357579851D502AF5000B822E /* MGLSymbolStyleLayerTests.mm in Sources */,
357579871D502AFE000B822E /* MGLLineStyleLayerTests.mm in Sources */,
357579891D502B06000B822E /* MGLCircleStyleLayerTests.mm in Sources */,
@@ -2176,6 +2151,7 @@
1F95931D1E6DE2E900D5B294 /* MGLNSDateAdditionsTests.mm in Sources */,
DD58A4C61D822BD000E1F038 /* MGLExpressionTests.mm in Sources */,
3575798B1D502B0C000B822E /* MGLBackgroundStyleLayerTests.mm in Sources */,
+ 409D0A0D1ED614CE00C95D0C /* MGLAnnotationViewIntegrationTests.swift in Sources */,
DA2E88621CC0382C00F24E7B /* MGLOfflinePackTests.m in Sources */,
55E2AD131E5B125400E8C587 /* MGLOfflineStorageTests.mm in Sources */,
920A3E5D1E6F995200C16EFC /* MGLSourceQueryTests.m in Sources */,
@@ -2221,6 +2197,7 @@
3566C76E1D4A8DFA008152BC /* MGLRasterSource.mm in Sources */,
DA88488C1CBB037E00AB86E3 /* SMCalloutView.m in Sources */,
35136D4E1D4277FC00C20EFD /* MGLSource.mm in Sources */,
+ 1F06668D1EC64F8E001C16D7 /* MGLLight.mm in Sources */,
DA35A2B81CCA9A5D00E826B2 /* MGLClockDirectionFormatter.m in Sources */,
DAD1657A1CF4CDFF001FF4B9 /* MGLShapeCollection.mm in Sources */,
35136D451D42275100C20EFD /* MGLSymbolStyleLayer.mm in Sources */,
@@ -2328,6 +2305,7 @@
DAA4E4321CBB730400178DFB /* MGLMapView.mm in Sources */,
DAA4E41E1CBB730400178DFB /* MGLMapCamera.mm in Sources */,
FA68F14E1E9D656600F9F6C2 /* MGLFillExtrusionStyleLayer.mm in Sources */,
+ 1F7454921ECBB42C00021D39 /* MGLLight.mm in Sources */,
404C26E51D89B877000AA13D /* MGLTileSource.mm in Sources */,
355AE0021E9281DA00F3939D /* MGLScaleBar.mm in Sources */,
4018B1C81CDC287F00F666AF /* MGLAnnotationView.mm in Sources */,
@@ -2681,7 +2659,10 @@
baseConfigurationReference = 55D8C9941D0F133500F42F10 /* config.xcconfig */;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
- HEADER_SEARCH_PATHS = "$(mbgl_core_INCLUDE_DIRECTORIES)";
+ HEADER_SEARCH_PATHS = (
+ "$(mbgl_core_INCLUDE_DIRECTORIES)",
+ "$(polylabel_INCLUDE_DIRECTORIES)",
+ );
INFOPLIST_FILE = test/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
@@ -2705,7 +2686,10 @@
baseConfigurationReference = 55D8C9941D0F133500F42F10 /* config.xcconfig */;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
- HEADER_SEARCH_PATHS = "$(mbgl_core_INCLUDE_DIRECTORIES)";
+ HEADER_SEARCH_PATHS = (
+ "$(mbgl_core_INCLUDE_DIRECTORIES)",
+ "$(polylabel_INCLUDE_DIRECTORIES)",
+ );
INFOPLIST_FILE = test/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
@@ -2733,7 +2717,10 @@
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
- HEADER_SEARCH_PATHS = "$(mbgl_core_INCLUDE_DIRECTORIES)";
+ HEADER_SEARCH_PATHS = (
+ "$(mbgl_core_INCLUDE_DIRECTORIES)",
+ "$(polylabel_INCLUDE_DIRECTORIES)",
+ );
INFOPLIST_FILE = framework/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
@@ -2767,7 +2754,10 @@
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
- HEADER_SEARCH_PATHS = "$(mbgl_core_INCLUDE_DIRECTORIES)";
+ HEADER_SEARCH_PATHS = (
+ "$(mbgl_core_INCLUDE_DIRECTORIES)",
+ "$(polylabel_INCLUDE_DIRECTORIES)",
+ );
INFOPLIST_FILE = framework/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
@@ -2818,7 +2808,10 @@
baseConfigurationReference = 55D8C9941D0F133500F42F10 /* config.xcconfig */;
buildSettings = {
BITCODE_GENERATION_MODE = bitcode;
- HEADER_SEARCH_PATHS = "$(mbgl_core_INCLUDE_DIRECTORIES)";
+ HEADER_SEARCH_PATHS = (
+ "$(mbgl_core_INCLUDE_DIRECTORIES)",
+ "$(polylabel_INCLUDE_DIRECTORIES)",
+ );
OTHER_CPLUSPLUSFLAGS = (
"$(OTHER_CFLAGS)",
"$(sqlite_cflags)",
@@ -2844,7 +2837,10 @@
baseConfigurationReference = 55D8C9941D0F133500F42F10 /* config.xcconfig */;
buildSettings = {
BITCODE_GENERATION_MODE = bitcode;
- HEADER_SEARCH_PATHS = "$(mbgl_core_INCLUDE_DIRECTORIES)";
+ HEADER_SEARCH_PATHS = (
+ "$(mbgl_core_INCLUDE_DIRECTORIES)",
+ "$(polylabel_INCLUDE_DIRECTORIES)",
+ );
OTHER_CPLUSPLUSFLAGS = (
"$(OTHER_CFLAGS)",
"$(sqlite_cflags)",
diff --git a/platform/ios/jazzy.yml b/platform/ios/jazzy.yml
index e0ce29beba..31380faa2c 100644
--- a/platform/ios/jazzy.yml
+++ b/platform/ios/jazzy.yml
@@ -23,6 +23,7 @@ custom_categories:
- Working with Mapbox Studio
- Working with GeoJSON Data
- For Style Authors
+ - Tile URL Templates
- Info.plist Keys
- Gesture Recognizers
- name: Maps
@@ -59,6 +60,7 @@ custom_categories:
children:
- MGLStyle
- MGLStyleValue
+ - MGLLight
- name: Style Primitives
children:
- MGLFeature
diff --git a/platform/ios/originals/compass.sketch b/platform/ios/originals/compass.sketch
new file mode 100644
index 0000000000..f5b848cd96
--- /dev/null
+++ b/platform/ios/originals/compass.sketch
Binary files differ
diff --git a/platform/ios/resources/Compass.png b/platform/ios/resources/Compass.png
deleted file mode 100644
index 08bed0591b..0000000000
--- a/platform/ios/resources/Compass.png
+++ /dev/null
Binary files differ
diff --git a/platform/ios/resources/Compass@2x.png b/platform/ios/resources/Compass@2x.png
deleted file mode 100644
index 8473a2d1ec..0000000000
--- a/platform/ios/resources/Compass@2x.png
+++ /dev/null
Binary files differ
diff --git a/platform/ios/resources/Compass@3x.png b/platform/ios/resources/Compass@3x.png
deleted file mode 100644
index 9cf66ca483..0000000000
--- a/platform/ios/resources/Compass@3x.png
+++ /dev/null
Binary files differ
diff --git a/platform/ios/resources/Images.xcassets/Compass.imageset/Contents.json b/platform/ios/resources/Images.xcassets/Compass.imageset/Contents.json
new file mode 100644
index 0000000000..6065a93b4e
--- /dev/null
+++ b/platform/ios/resources/Images.xcassets/Compass.imageset/Contents.json
@@ -0,0 +1,12 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "compass.pdf"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/platform/ios/resources/Images.xcassets/Compass.imageset/compass.pdf b/platform/ios/resources/Images.xcassets/Compass.imageset/compass.pdf
new file mode 100644
index 0000000000..2048f96089
--- /dev/null
+++ b/platform/ios/resources/Images.xcassets/Compass.imageset/compass.pdf
Binary files differ
diff --git a/platform/ios/resources/Images.xcassets/Contents.json b/platform/ios/resources/Images.xcassets/Contents.json
new file mode 100644
index 0000000000..da4a164c91
--- /dev/null
+++ b/platform/ios/resources/Images.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/platform/ios/resources/Images.xcassets/default_marker.imageset/Contents.json b/platform/ios/resources/Images.xcassets/default_marker.imageset/Contents.json
new file mode 100644
index 0000000000..9bef658a11
--- /dev/null
+++ b/platform/ios/resources/Images.xcassets/default_marker.imageset/Contents.json
@@ -0,0 +1,12 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "default_marker.pdf"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/platform/ios/resources/Images.xcassets/default_marker.imageset/default_marker.pdf b/platform/ios/resources/Images.xcassets/default_marker.imageset/default_marker.pdf
new file mode 100644
index 0000000000..4e2e332301
--- /dev/null
+++ b/platform/ios/resources/Images.xcassets/default_marker.imageset/default_marker.pdf
Binary files differ
diff --git a/platform/ios/resources/Images.xcassets/mapbox.imageset/Contents.json b/platform/ios/resources/Images.xcassets/mapbox.imageset/Contents.json
new file mode 100644
index 0000000000..b49c53da84
--- /dev/null
+++ b/platform/ios/resources/Images.xcassets/mapbox.imageset/Contents.json
@@ -0,0 +1,12 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "mapbox.pdf"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/platform/ios/resources/Images.xcassets/mapbox.imageset/mapbox.pdf b/platform/ios/resources/Images.xcassets/mapbox.imageset/mapbox.pdf
new file mode 100644
index 0000000000..45111c31a6
--- /dev/null
+++ b/platform/ios/resources/Images.xcassets/mapbox.imageset/mapbox.pdf
Binary files differ
diff --git a/platform/ios/resources/default_marker.png b/platform/ios/resources/default_marker.png
deleted file mode 100644
index b112096c18..0000000000
--- a/platform/ios/resources/default_marker.png
+++ /dev/null
Binary files differ
diff --git a/platform/ios/resources/default_marker@2x.png b/platform/ios/resources/default_marker@2x.png
deleted file mode 100644
index d05c82bfe2..0000000000
--- a/platform/ios/resources/default_marker@2x.png
+++ /dev/null
Binary files differ
diff --git a/platform/ios/resources/default_marker@3x.png b/platform/ios/resources/default_marker@3x.png
deleted file mode 100644
index 703b172c15..0000000000
--- a/platform/ios/resources/default_marker@3x.png
+++ /dev/null
Binary files differ
diff --git a/platform/ios/resources/mapbox.png b/platform/ios/resources/mapbox.png
deleted file mode 100644
index 00bc897a58..0000000000
--- a/platform/ios/resources/mapbox.png
+++ /dev/null
Binary files differ
diff --git a/platform/ios/resources/mapbox@2x.png b/platform/ios/resources/mapbox@2x.png
deleted file mode 100644
index 206ed5883e..0000000000
--- a/platform/ios/resources/mapbox@2x.png
+++ /dev/null
Binary files differ
diff --git a/platform/ios/resources/mapbox@3x.png b/platform/ios/resources/mapbox@3x.png
deleted file mode 100644
index efd631b587..0000000000
--- a/platform/ios/resources/mapbox@3x.png
+++ /dev/null
Binary files differ
diff --git a/platform/ios/src/MGLAPIClient.m b/platform/ios/src/MGLAPIClient.m
index 22ee5c55f5..124d436197 100644
--- a/platform/ios/src/MGLAPIClient.m
+++ b/platform/ios/src/MGLAPIClient.m
@@ -117,7 +117,7 @@ static NSString * const MGLAPIClientHTTPMethodPost = @"POST";
- (void)loadCertificate:(NSData **)certificate withResource:(NSString *)resource {
NSBundle *frameworkBundle = [NSBundle mgl_frameworkBundle];
- NSString *cerPath = [frameworkBundle pathForResource:resource ofType:@"der" inDirectory:frameworkBundle.mgl_resourcesDirectory];
+ NSString *cerPath = [frameworkBundle pathForResource:resource ofType:@"der"];
if (cerPath != nil) {
*certificate = [NSData dataWithContentsOfFile:cerPath];
}
diff --git a/platform/ios/src/MGLAnnotationView.h b/platform/ios/src/MGLAnnotationView.h
index 184efdb324..2802d31b05 100644
--- a/platform/ios/src/MGLAnnotationView.h
+++ b/platform/ios/src/MGLAnnotationView.h
@@ -74,6 +74,36 @@ typedef NS_ENUM(NSUInteger, MGLAnnotationViewDragState) {
- (instancetype)initWithReuseIdentifier:(nullable NSString *)reuseIdentifier;
/**
+ Initializes and returns a new annotation view object.
+
+ Providing an annotation allows you to explicitly associate the annotation instance
+ with the new view and, in custom subclasses of `MGLAnnotationView`, customize the view
+ based on properties of the annotation instance in an overridden initializer. However,
+ annotation views that are reused will not necessarily be associated with the
+ same annotation they were initialized with. Also, annotation views that are in
+ the reuse queue will have a nil value for the annotation property. Passing an annotation
+ instance to the view is optional and the map view will automatically associate annotations
+ with views when views are provided to the map via the `-[MGLMapViewDelegate mapView:viewForAnnotation:]`
+ method.
+
+ The reuse identifier provides a way for you to improve performance by recycling
+ annotation views as they enter and leave the map’s viewport. As an annotation
+ leaves the viewport, the map view moves its associated view to a reuse queue.
+ When a new annotation becomes visible, you can request a view for that
+ annotation by passing the appropriate reuse identifier string to the
+ `-[MGLMapView dequeueReusableAnnotationViewWithIdentifier:]` method.
+
+ @param annotation The annotation object to associate with the new view.
+ @param reuseIdentifier A unique string identifier for this view that allows you
+ to reuse this view with multiple similar annotations. You can set this
+ parameter to `nil` if you don’t intend to reuse the view, but it is a good
+ idea in general to specify a reuse identifier to avoid creating redundant
+ views.
+ @return The initialized annotation view object.
+ */
+- (instancetype)initWithAnnotation:(nullable id<MGLAnnotation>)annotation reuseIdentifier:(nullable NSString *)reuseIdentifier;
+
+/**
Called when the view is removed from the reuse queue.
The default implementation of this method does nothing. You can override it in
@@ -141,6 +171,19 @@ typedef NS_ENUM(NSUInteger, MGLAnnotationViewDragState) {
*/
@property (nonatomic, assign) BOOL scalesWithViewingDistance;
+/**
+ A Boolean value that determines whether the annotation view rotates together
+ with the map.
+
+ When the value of this property is `YES` and the map is rotated, the annotation
+ view rotates. This is also the behavior of `MGLAnnotationImage` objects. When the
+ value of this property is `NO` the annotation has its rotation angle fixed.
+
+ The default value of this property is `NO`. Set this property to `YES` if the
+ view’s rotation is important.
+ */
+@property (nonatomic, assign) BOOL rotatesToMatchCamera;
+
#pragma mark Managing the Selection State
/**
diff --git a/platform/ios/src/MGLAnnotationView.mm b/platform/ios/src/MGLAnnotationView.mm
index 5e0ae3b848..94d0649413 100644
--- a/platform/ios/src/MGLAnnotationView.mm
+++ b/platform/ios/src/MGLAnnotationView.mm
@@ -11,6 +11,7 @@
@property (nonatomic, readwrite, nullable) NSString *reuseIdentifier;
@property (nonatomic, readwrite) CATransform3D lastAppliedScaleTransform;
+@property (nonatomic, readwrite) CATransform3D lastAppliedRotateTransform;
@property (nonatomic, weak) UIPanGestureRecognizer *panGestureRecognizer;
@property (nonatomic, weak) UILongPressGestureRecognizer *longPressRecognizer;
@property (nonatomic, weak) MGLMapView *mapView;
@@ -19,21 +20,32 @@
@implementation MGLAnnotationView
-- (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier
-{
- self = [self initWithFrame:CGRectZero];
- if (self)
- {
- _lastAppliedScaleTransform = CATransform3DIdentity;
- _reuseIdentifier = [reuseIdentifier copy];
- _scalesWithViewingDistance = YES;
- _enabled = YES;
++ (BOOL)supportsSecureCoding {
+ return YES;
+}
+
+- (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier {
+ self = [super initWithFrame:CGRectZero];
+ if (self) {
+ [self commonInitWithAnnotation:nil reuseIdentifier:reuseIdentifier];
}
return self;
}
-+ (BOOL)supportsSecureCoding {
- return YES;
+- (instancetype)initWithAnnotation:(nullable id<MGLAnnotation>)annotation reuseIdentifier:(nullable NSString *)reuseIdentifier {
+ self = [super initWithFrame:CGRectZero];
+ if (self) {
+ [self commonInitWithAnnotation:annotation reuseIdentifier:reuseIdentifier];
+ }
+ return self;
+}
+
+- (void)commonInitWithAnnotation:(nullable id<MGLAnnotation>)annotation reuseIdentifier:(nullable NSString *)reuseIdentifier {
+ _lastAppliedScaleTransform = CATransform3DIdentity;
+ _annotation = annotation;
+ _reuseIdentifier = [reuseIdentifier copy];
+ _scalesWithViewingDistance = YES;
+ _enabled = YES;
}
- (instancetype)initWithCoder:(NSCoder *)decoder {
@@ -42,6 +54,7 @@
_annotation = [decoder decodeObjectOfClass:[NSObject class] forKey:@"annotation"];
_centerOffset = [decoder decodeCGVectorForKey:@"centerOffset"];
_scalesWithViewingDistance = [decoder decodeBoolForKey:@"scalesWithViewingDistance"];
+ _rotatesToMatchCamera = [decoder decodeBoolForKey:@"rotatesToMatchCamera"];
_selected = [decoder decodeBoolForKey:@"selected"];
_enabled = [decoder decodeBoolForKey:@"enabled"];
self.draggable = [decoder decodeBoolForKey:@"draggable"];
@@ -55,6 +68,7 @@
[coder encodeObject:_annotation forKey:@"annotation"];
[coder encodeCGVector:_centerOffset forKey:@"centerOffset"];
[coder encodeBool:_scalesWithViewingDistance forKey:@"scalesWithViewingDistance"];
+ [coder encodeBool:_rotatesToMatchCamera forKey:@"rotatesToMatchCamera"];
[coder encodeBool:_selected forKey:@"selected"];
[coder encodeBool:_enabled forKey:@"enabled"];
[coder encodeBool:_draggable forKey:@"draggable"];
@@ -98,6 +112,7 @@
super.center = center;
[self updateScaleTransformForViewingDistance];
+ [self updateRotateTransform];
}
- (void)setScalesWithViewingDistance:(BOOL)scalesWithViewingDistance
@@ -146,6 +161,26 @@
}
}
+- (void)setRotatesToMatchCamera:(BOOL)rotatesToMatchCamera
+{
+ if (_rotatesToMatchCamera != rotatesToMatchCamera)
+ {
+ _rotatesToMatchCamera = rotatesToMatchCamera;
+ [self updateRotateTransform];
+ }
+}
+
+- (void)updateRotateTransform
+{
+ if (self.rotatesToMatchCamera == NO) return;
+
+ CGFloat directionRad = self.mapView.direction * M_PI / 180.0;
+ CATransform3D newRotateTransform = CATransform3DMakeRotation(-directionRad, 0, 0, 1);
+ self.layer.transform = CATransform3DConcat(CATransform3DIdentity, newRotateTransform);
+
+ _lastAppliedRotateTransform = newRotateTransform;
+}
+
#pragma mark - Draggable
- (void)setDraggable:(BOOL)draggable
diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm
index d97c0b6602..9a9f71d5c3 100644
--- a/platform/ios/src/MGLMapView.mm
+++ b/platform/ios/src/MGLMapView.mm
@@ -64,7 +64,7 @@
#import "MGLCompactCalloutView.h"
#import "MGLAnnotationContainerView.h"
#import "MGLAnnotationContainerView_Private.h"
-#import "MGLAttributionInfo.h"
+#import "MGLAttributionInfo_Private.h"
#include <algorithm>
#include <cstdlib>
@@ -131,6 +131,9 @@ const CGFloat MGLAnnotationImagePaddingForCallout = 1;
const CGSize MGLAnnotationAccessibilityElementMinimumSize = CGSizeMake(10, 10);
+// Context for KVO observing UILayoutGuides.
+static void * MGLLayoutGuidesUpdatedContext = &MGLLayoutGuidesUpdatedContext;
+
/// Unique identifier representing a single annotation in mbgl.
typedef uint32_t MGLAnnotationTag;
@@ -233,13 +236,9 @@ public:
@property (nonatomic) GLKView *glView;
@property (nonatomic) UIImageView *glSnapshotView;
@property (nonatomic, readwrite) MGLScaleBar *scaleBar;
-@property (nonatomic) NS_MUTABLE_ARRAY_OF(NSLayoutConstraint *) *scaleBarConstraints;
@property (nonatomic, readwrite) UIImageView *compassView;
-@property (nonatomic) NS_MUTABLE_ARRAY_OF(NSLayoutConstraint *) *compassViewConstraints;
@property (nonatomic, readwrite) UIImageView *logoView;
-@property (nonatomic) NS_MUTABLE_ARRAY_OF(NSLayoutConstraint *) *logoViewConstraints;
@property (nonatomic, readwrite) UIButton *attributionButton;
-@property (nonatomic) NS_MUTABLE_ARRAY_OF(NSLayoutConstraint *) *attributionButtonConstraints;
@property (nonatomic, readwrite) MGLStyle *style;
@property (nonatomic) UITapGestureRecognizer *singleTapGestureRecognizer;
@property (nonatomic) UITapGestureRecognizer *doubleTap;
@@ -294,7 +293,8 @@ public:
NSDate *_userLocationAnimationCompletionDate;
/// True if a willChange notification has been issued for shape annotation layers and a didChange notification is pending.
BOOL _isChangingAnnotationLayers;
-
+ BOOL _isObservingTopLayoutGuide;
+ BOOL _isObservingBottomLayoutGuide;
BOOL _isWaitingForRedundantReachableNotification;
BOOL _isTargetingInterfaceBuilder;
@@ -467,13 +467,11 @@ public:
// setup logo bug
//
- UIImage *logo = [MGLMapView resourceImageNamed:@"mapbox.png"];
+ UIImage *logo = [MGLMapView resourceImageNamed:@"mapbox"];
_logoView = [[UIImageView alloc] initWithImage:logo];
_logoView.accessibilityTraits = UIAccessibilityTraitStaticText;
_logoView.accessibilityLabel = NSLocalizedStringWithDefaultValue(@"LOGO_A11Y_LABEL", nil, nil, @"Mapbox", @"Accessibility label");
- _logoView.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:_logoView];
- _logoViewConstraints = [NSMutableArray array];
// setup attribution
//
@@ -481,9 +479,7 @@ public:
_attributionButton.accessibilityLabel = NSLocalizedStringWithDefaultValue(@"INFO_A11Y_LABEL", nil, nil, @"About this map", @"Accessibility label");
_attributionButton.accessibilityHint = NSLocalizedStringWithDefaultValue(@"INFO_A11Y_HINT", nil, nil, @"Shows credits, a feedback form, and more", @"Accessibility hint");
[_attributionButton addTarget:self action:@selector(showAttribution) forControlEvents:UIControlEventTouchUpInside];
- _attributionButton.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:_attributionButton];
- _attributionButtonConstraints = [NSMutableArray array];
[_attributionButton addObserver:self forKeyPath:@"hidden" options:NSKeyValueObservingOptionNew context:NULL];
// setup compass
@@ -495,16 +491,12 @@ public:
_compassView.accessibilityTraits = UIAccessibilityTraitButton;
_compassView.accessibilityLabel = NSLocalizedStringWithDefaultValue(@"COMPASS_A11Y_LABEL", nil, nil, @"Compass", @"Accessibility label");
_compassView.accessibilityHint = NSLocalizedStringWithDefaultValue(@"COMPASS_A11Y_HINT", nil, nil, @"Rotates the map to face due north", @"Accessibility hint");
- _compassView.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:_compassView];
- _compassViewConstraints = [NSMutableArray array];
// setup scale control
//
_scaleBar = [[MGLScaleBar alloc] init];
- _scaleBar.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:_scaleBar];
- _scaleBarConstraints = [NSMutableArray array];
// setup interaction
//
@@ -624,11 +616,11 @@ public:
- (UIImage *)compassImage
{
- UIImage *scaleImage = [MGLMapView resourceImageNamed:@"Compass.png"];
+ UIImage *scaleImage = [MGLMapView resourceImageNamed:@"Compass"];
UIGraphicsBeginImageContextWithOptions(scaleImage.size, NO, [UIScreen mainScreen].scale);
[scaleImage drawInRect:{ CGPointZero, scaleImage.size }];
- CGFloat northSize = 9;
+ CGFloat northSize = 11;
UIFont *northFont;
if ([UIFont respondsToSelector:@selector(systemFontOfSize:weight:)])
{
@@ -643,7 +635,7 @@ public:
NSForegroundColorAttributeName: [UIColor whiteColor],
}];
CGRect stringRect = CGRectMake((scaleImage.size.width - north.size.width) / 2,
- scaleImage.size.height * 0.45,
+ scaleImage.size.height * 0.435,
north.size.width, north.size.height);
[north drawInRect:stringRect];
@@ -664,6 +656,48 @@ public:
_isWaitingForRedundantReachableNotification = NO;
}
+- (void)willMoveToWindow:(UIWindow *)newWindow
+{
+ [super willMoveToWindow:newWindow];
+
+ if (newWindow) {
+ [self addLayoutGuideObserversIfNeeded];
+ } else {
+ [self removeLayoutGuideObserversIfNeeded];
+ }
+}
+
+- (void)addLayoutGuideObserversIfNeeded
+{
+ UIViewController *viewController = self.viewControllerForLayoutGuides;
+ BOOL useLayoutGuides = viewController.view && viewController.automaticallyAdjustsScrollViewInsets;
+
+ if (useLayoutGuides && viewController.topLayoutGuide && !_isObservingTopLayoutGuide) {
+ [(NSObject *)viewController.topLayoutGuide addObserver:self forKeyPath:@"bounds" options:0 context:(void *)&MGLLayoutGuidesUpdatedContext];
+ _isObservingTopLayoutGuide = YES;
+ }
+
+ if (useLayoutGuides && viewController.bottomLayoutGuide && !_isObservingBottomLayoutGuide) {
+ [(NSObject *)viewController.bottomLayoutGuide addObserver:self forKeyPath:@"bounds" options:0 context:(void *)&MGLLayoutGuidesUpdatedContext];
+ _isObservingBottomLayoutGuide = YES;
+ }
+}
+
+- (void)removeLayoutGuideObserversIfNeeded
+{
+ UIViewController *viewController = self.viewControllerForLayoutGuides;
+
+ if (_isObservingTopLayoutGuide) {
+ [(NSObject *)viewController.topLayoutGuide removeObserver:self forKeyPath:@"bounds" context:(void *)&MGLLayoutGuidesUpdatedContext];
+ _isObservingTopLayoutGuide = NO;
+ }
+
+ if (_isObservingBottomLayoutGuide) {
+ [(NSObject *)viewController.bottomLayoutGuide removeObserver:self forKeyPath:@"bounds" context:(void *)&MGLLayoutGuidesUpdatedContext];
+ _isObservingBottomLayoutGuide = NO;
+ }
+}
+
- (void)dealloc
{
[_reachability stopNotifier];
@@ -672,6 +706,8 @@ public:
[[NSNotificationCenter defaultCenter] removeObserver:self];
[_attributionButton removeObserver:self forKeyPath:@"hidden"];
+ [self removeLayoutGuideObserversIfNeeded];
+
// Removing the annotations unregisters any outstanding KVO observers.
NSArray *annotations = self.annotations;
if (annotations)
@@ -697,11 +733,6 @@ public:
{
[EAGLContext setCurrentContext:nil];
}
-
- [self.logoViewConstraints removeAllObjects];
- self.logoViewConstraints = nil;
- [self.attributionButtonConstraints removeAllObjects];
- self.attributionButtonConstraints = nil;
}
- (void)setDelegate:(nullable id<MGLMapViewDelegate>)delegate
@@ -786,105 +817,13 @@ public:
- (void)updateConstraints
{
- // scale control
- //
- [self removeConstraints:self.scaleBarConstraints];
- [self.scaleBarConstraints removeAllObjects];
-
- [self.scaleBarConstraints addObject:
- [NSLayoutConstraint constraintWithItem:self.scaleBar
- attribute:NSLayoutAttributeTop
- relatedBy:NSLayoutRelationEqual
- toItem:self
- attribute:NSLayoutAttributeTop
- multiplier:1
- constant:5+self.contentInset.top]];
-
- [self.scaleBarConstraints addObject:
- [NSLayoutConstraint constraintWithItem:self.scaleBar
- attribute:NSLayoutAttributeLeading
- relatedBy:NSLayoutRelationEqual
- toItem:self
- attribute:NSLayoutAttributeLeading
- multiplier:1
- constant:8 + self.contentInset.left]];
-
- [self addConstraints:self.scaleBarConstraints];
-
- // compass
- //
- [self removeConstraints:self.compassViewConstraints];
- [self.compassViewConstraints removeAllObjects];
-
- [self.compassViewConstraints addObject:
- [NSLayoutConstraint constraintWithItem:self.compassView
- attribute:NSLayoutAttributeTop
- relatedBy:NSLayoutRelationEqual
- toItem:self
- attribute:NSLayoutAttributeTop
- multiplier:1
- constant:5 + self.contentInset.top]];
-
- [self.compassViewConstraints addObject:
- [NSLayoutConstraint constraintWithItem:self
- attribute:NSLayoutAttributeTrailing
- relatedBy:NSLayoutRelationEqual
- toItem:self.compassView
- attribute:NSLayoutAttributeTrailing
- multiplier:1
- constant:5 + self.contentInset.right]];
-
- [self addConstraints:self.compassViewConstraints];
-
- // logo bug
- //
- [self removeConstraints:self.logoViewConstraints];
- [self.logoViewConstraints removeAllObjects];
-
- [self.logoViewConstraints addObject:
- [NSLayoutConstraint constraintWithItem:self
- attribute:NSLayoutAttributeBottom
- relatedBy:NSLayoutRelationEqual
- toItem:self.logoView
- attribute:NSLayoutAttributeBaseline
- multiplier:1
- constant:8 + self.contentInset.bottom]];
-
- [self.logoViewConstraints addObject:
- [NSLayoutConstraint constraintWithItem:self.logoView
- attribute:NSLayoutAttributeLeading
- relatedBy:NSLayoutRelationEqual
- toItem:self
- attribute:NSLayoutAttributeLeading
- multiplier:1
- constant:8 + self.contentInset.left]];
- [self addConstraints:self.logoViewConstraints];
-
- // attribution button
- //
- [self removeConstraints:self.attributionButtonConstraints];
- [self.attributionButtonConstraints removeAllObjects];
-
- [self.attributionButtonConstraints addObject:
- [NSLayoutConstraint constraintWithItem:self
- attribute:NSLayoutAttributeBottom
- relatedBy:NSLayoutRelationEqual
- toItem:self.attributionButton
- attribute:NSLayoutAttributeBaseline
- multiplier:1
- constant:8 + self.contentInset.bottom]];
-
- [self.attributionButtonConstraints addObject:
- [NSLayoutConstraint constraintWithItem:self
- attribute:NSLayoutAttributeTrailing
- relatedBy:NSLayoutRelationEqual
- toItem:self.attributionButton
- attribute:NSLayoutAttributeTrailing
- multiplier:1
- constant:8 + self.contentInset.right]];
- [self addConstraints:self.attributionButtonConstraints];
-
[super updateConstraints];
+
+ // If we have a view controller reference and its automaticallyAdjustsScrollViewInsets
+ // is set to YES, -[MGLMapView adjustContentInset] takes top and bottom layout
+ // guides into account. To get notified about changes to the layout guides,
+ // we need to observe their bounds and re-layout accordingly.
+ [self addLayoutGuideObserversIfNeeded];
}
- (BOOL)isOpaque
@@ -917,6 +856,8 @@ public:
[super layoutSubviews];
[self adjustContentInset];
+
+ [self layoutOrnaments];
if (!_isTargetingInterfaceBuilder) {
_mbglMap->setSize([self size]);
@@ -931,6 +872,39 @@ public:
[self updateUserLocationAnnotationView];
}
+- (void)layoutOrnaments
+{
+ // scale bar
+ self.scaleBar.frame = {
+ self.contentInset.left+8,
+ self.contentInset.top+5,
+ CGRectGetWidth(self.scaleBar.frame),
+ CGRectGetHeight(self.scaleBar.frame)
+ };
+
+ // compass
+ self.compassView.center = {
+ .x = CGRectGetWidth(self.bounds)-CGRectGetMidX(self.compassView.bounds)-self.contentInset.right-5,
+ .y = CGRectGetMidY(self.compassView.bounds)+self.contentInset.top+5
+ };
+
+ // logo bug
+ self.logoView.frame = {
+ self.contentInset.left+8,
+ CGRectGetHeight(self.bounds)-8-self.contentInset.bottom-CGRectGetHeight(self.logoView.bounds),
+ CGRectGetWidth(self.logoView.bounds),
+ CGRectGetHeight(self.logoView.bounds)
+ };
+
+ // attribution
+ self.attributionButton.frame = {
+ CGRectGetWidth(self.bounds)-CGRectGetWidth(self.attributionButton.bounds)-self.contentInset.right-8,
+ CGRectGetHeight(self.bounds)-CGRectGetHeight(self.attributionButton.bounds)-self.contentInset.bottom-8,
+ CGRectGetWidth(self.attributionButton.bounds),
+ CGRectGetHeight(self.attributionButton.bounds)
+ };
+}
+
/// Updates `contentInset` to reflect the current window geometry.
- (void)adjustContentInset
{
@@ -1000,7 +974,7 @@ public:
}
// Compass, logo and attribution button constraints needs to be updated.
- [self setNeedsUpdateConstraints];
+ [self setNeedsLayout];
}
/// Returns the frame of inset content within the map view.
@@ -1921,8 +1895,12 @@ public:
{
if (info.feedbackLink)
{
- url = [info feedbackURLAtCenterCoordinate:self.centerCoordinate
- zoomLevel:self.zoomLevel];
+ MGLMapCamera *camera = self.camera;
+ url = [info feedbackURLForStyleURL:self.styleURL
+ atCenterCoordinate:camera.centerCoordinate
+ zoomLevel:self.zoomLevel
+ direction:camera.heading
+ pitch:camera.pitch];
}
[[UIApplication sharedApplication] openURL:url];
}
@@ -1999,9 +1977,10 @@ public:
}];
[alertController addAction:participateAction];
- [self.window.rootViewController presentViewController:alertController
- animated:YES
- completion:NULL];
+ UIViewController *viewController = [self.window.rootViewController mgl_topMostViewController];
+ [viewController presentViewController:alertController
+ animated:YES
+ completion:NULL];
}
#pragma mark - Properties -
@@ -2065,6 +2044,10 @@ public:
[self updateCalloutView];
}
}
+ else if (context == MGLLayoutGuidesUpdatedContext && [keyPath isEqualToString:@"bounds"])
+ {
+ [self setNeedsLayout];
+ }
}
+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingZoomEnabled
@@ -3501,6 +3484,7 @@ public:
annotationView.annotation = nil;
[annotationView removeFromSuperview];
+ [self.annotationContainerView.annotationViews removeObject:annotationView];
if (annotationTag == _selectedAnnotationTag)
{
@@ -5314,18 +5298,17 @@ public:
+ (UIImage *)resourceImageNamed:(NSString *)imageName
{
- NSString *extension = imageName.pathExtension.length ? imageName.pathExtension : @"png";
- NSBundle *bundle = [NSBundle mgl_frameworkBundle];
- NSString *path = [bundle pathForResource:imageName.stringByDeletingPathExtension
- ofType:extension
- inDirectory:bundle.mgl_resourcesDirectory];
- if ( ! path)
+ UIImage *image = [UIImage imageNamed:imageName
+ inBundle:[NSBundle mgl_frameworkBundle]
+ compatibleWithTraitCollection:nil];
+
+ if ( ! image)
{
- [NSException raise:@"Resource not found" format:
+ [NSException raise:@"MGLResourceNotFoundException" format:
@"The resource named “%@” could not be found in the Mapbox framework bundle.", imageName];
}
- return [UIImage imageWithContentsOfFile:path];
+ return image;
}
- (BOOL)isFullyLoaded
diff --git a/platform/ios/src/MGLMapboxEvents.m b/platform/ios/src/MGLMapboxEvents.m
index 7b28ccf1a8..4f1413d300 100644
--- a/platform/ios/src/MGLMapboxEvents.m
+++ b/platform/ios/src/MGLMapboxEvents.m
@@ -317,13 +317,6 @@ const NSTimeInterval MGLFlushInterval = 180;
return;
}
- if ([self.eventQueue count] <= 1) {
- [self.eventQueue removeAllObjects];
- [[UIApplication sharedApplication] endBackgroundTask:_backgroundTaskIdentifier];
- _backgroundTaskIdentifier = UIBackgroundTaskInvalid;
- return;
- }
-
NSArray *events = [NSArray arrayWithArray:self.eventQueue];
[self.eventQueue removeAllObjects];
diff --git a/platform/ios/src/MGLScaleBar.mm b/platform/ios/src/MGLScaleBar.mm
index 1216e400b3..cd88c1e08e 100644
--- a/platform/ios/src/MGLScaleBar.mm
+++ b/platform/ios/src/MGLScaleBar.mm
@@ -220,6 +220,12 @@ static const CGFloat MGLFeetPerMeter = 3.28084;
self.row = [self preferredRow];
+ CGSize size = self.intrinsicContentSize;
+ self.frame = CGRectMake(CGRectGetMinX(self.frame),
+ CGRectGetMinY(self.frame),
+ size.width,
+ size.height);
+
[self invalidateIntrinsicContentSize];
[self setNeedsLayout];
}
diff --git a/platform/ios/src/Mapbox.h b/platform/ios/src/Mapbox.h
index 9a9dc702ca..67a26e8ed4 100644
--- a/platform/ios/src/Mapbox.h
+++ b/platform/ios/src/Mapbox.h
@@ -19,6 +19,7 @@ FOUNDATION_EXPORT MGL_EXPORT const unsigned char MapboxVersionString[];
#import "MGLDistanceFormatter.h"
#import "MGLFeature.h"
#import "MGLGeometry.h"
+#import "MGLLight.h"
#import "MGLMapCamera.h"
#import "MGLMapView.h"
#import "MGLMapView+IBAdditions.h"
diff --git a/platform/ios/test/MGLAnnotationViewIntegrationTests.swift b/platform/ios/test/MGLAnnotationViewIntegrationTests.swift
new file mode 100644
index 0000000000..82a57a4009
--- /dev/null
+++ b/platform/ios/test/MGLAnnotationViewIntegrationTests.swift
@@ -0,0 +1,23 @@
+import XCTest
+import Mapbox
+
+class CustomAnnotationView: MGLAnnotationView {
+
+ override init(reuseIdentifier: String?) {
+ super.init(reuseIdentifier: reuseIdentifier)
+ }
+
+ required init?(coder aDecoder: NSCoder) {
+ super.init(coder: aDecoder)
+ }
+
+}
+
+class MGLAnnotationViewIntegrationTests: XCTestCase {
+
+ func testCreatingCustomAnnotationView() {
+ let customAnnotationView = CustomAnnotationView(reuseIdentifier: "resuse-id")
+ XCTAssertNotNil(customAnnotationView)
+ }
+
+}
diff --git a/platform/ios/test/MGLAnnotationViewTests.m b/platform/ios/test/MGLAnnotationViewTests.m
index c0978eaf65..fc4f35a9e1 100644
--- a/platform/ios/test/MGLAnnotationViewTests.m
+++ b/platform/ios/test/MGLAnnotationViewTests.m
@@ -3,11 +3,24 @@
static NSString * const MGLTestAnnotationReuseIdentifer = @"MGLTestAnnotationReuseIdentifer";
+@interface MGLCustomAnnotationView : MGLAnnotationView
+
+@end
+
+@implementation MGLCustomAnnotationView
+
+- (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier {
+ return [super initWithReuseIdentifier:@"reuse-id"];
+}
+
+@end
+
@interface MGLAnnotationView (Test)
+
@property (nonatomic) MGLMapView *mapView;
@property (nonatomic, readwrite) MGLAnnotationViewDragState dragState;
-
- (void)setDragState:(MGLAnnotationViewDragState)dragState;
+
@end
@interface MGLMapView (Test)
@@ -79,13 +92,19 @@ static NSString * const MGLTestAnnotationReuseIdentifer = @"MGLTestAnnotationReu
XCTAssertNil(_annotationView.annotation, @"annotation property should be nil");
}
+- (void)testCustomAnnotationView
+{
+ MGLCustomAnnotationView *customAnnotationView = [[MGLCustomAnnotationView alloc] initWithReuseIdentifier:@"reuse-id"];
+ XCTAssertNotNil(customAnnotationView);
+}
+
- (MGLAnnotationView *)mapView:(MGLMapView *)mapView viewForAnnotation:(id<MGLAnnotation>)annotation
{
MGLAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:MGLTestAnnotationReuseIdentifer];
if (!annotationView)
{
- annotationView = [[MGLAnnotationView alloc] initWithReuseIdentifier:MGLTestAnnotationReuseIdentifer];
+ annotationView = [[MGLAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:MGLTestAnnotationReuseIdentifer];
}
_annotationView = annotationView;
diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md
index 579624f0e6..4301566258 100644
--- a/platform/macos/CHANGELOG.md
+++ b/platform/macos/CHANGELOG.md
@@ -1,6 +1,11 @@
# Changelog for Mapbox macOS SDK
-## master
+## 3.6.0
+
+### Packaging
+
+* Xcode 8.0 or higher is now recommended for using this SDK. ([#8775](https://github.com/mapbox/mapbox-gl-native/pull/8775))
+* Updated MGLMapView’s logo view to display [the new Mapbox logo](https://www.mapbox.com/blog/new-mapbox-logo/). ([#8771](https://github.com/mapbox/mapbox-gl-native/pull/8771), [#8773](https://github.com/mapbox/mapbox-gl-native/pull/8773))
* The previously-deprecated support for style classes has been removed. For interface compatibility, the API methods remain, but they are now non-functional.
* Added an `overlays` property to `MGLMapView`. ([#8617](https://github.com/mapbox/mapbox-gl-native/pull/8617))
@@ -14,17 +19,21 @@
* Added class methods to MGLStyle that correspond to the new [Traffic Day and Traffic Night](https://www.mapbox.com/blog/live-traffic-maps/) styles. ([#6301](https://github.com/mapbox/mapbox-gl-native/pull/6301))
* MGLSymbolStyleLayer’s `iconImageName`, `iconScale`, `textFontSize`, `textOffset`, and `textRotation` properties can now be set to a source or composite function. ([#8544](https://github.com/mapbox/mapbox-gl-native/pull/8544), [#8590](https://github.com/mapbox/mapbox-gl-native/pull/8590), [#8592](https://github.com/mapbox/mapbox-gl-native/pull/8592), [#8593](https://github.com/mapbox/mapbox-gl-native/pull/8593))
* Fixed an issue where setting the `MGLVectorStyleLayer.predicate` property failed to take effect if the relevant source was not in use by a visible layer at the time. ([#8653](https://github.com/mapbox/mapbox-gl-native/pull/8653))
+* Fixed an issue preventing programmatically added style layers from appearing in already cached tiles. ([#8954](https://github.com/mapbox/mapbox-gl-native/pull/8954))
* Fixed an issue causing a composite function’s highest zoom level stop to be misinterpreted. ([#8613](https://github.com/mapbox/mapbox-gl-native/pull/8613), [#8790](https://github.com/mapbox/mapbox-gl-native/pull/8790))
* Fixed an issue where re-adding a layer that had been previously removed from a style would reset its paint properties. Moved initializers for `MGLTileSource`, `MGLStyleLayer`, and `MGLForegroundStyleLayer` to their concrete subclasses; because these classes were already intended for initialization only via concrete subclasses, this should have no developer impact. ([#8626](https://github.com/mapbox/mapbox-gl-native/pull/8626))
* Feature querying results now account for any changes to a feature’s size caused by a source or composite style function. ([#8665](https://github.com/mapbox/mapbox-gl-native/pull/8665))
+* Letter spacing is now disabled in Arabic text so that ligatures are drawn correctly. ([#9062](https://github.com/mapbox/mapbox-gl-native/pull/9062))
### Other changes
-* Xcode 8.0 or higher is now recommended for using this SDK. ([#8775](https://github.com/mapbox/mapbox-gl-native/pull/8775))
-* Updated MGLMapView’s logo view to display [the new Mapbox logo](https://www.mapbox.com/blog/new-mapbox-logo/). ([#8771](https://github.com/mapbox/mapbox-gl-native/pull/8771), [#8773](https://github.com/mapbox/mapbox-gl-native/pull/8773))
+* Fixed a crash when calling `MGLMultiPolygon.coordinate` [#8713](https://github.com/mapbox/mapbox-gl-native/pull/8713)
* Fixed an issue causing attribution button text to appear blue instead of black. ([#8701](https://github.com/mapbox/mapbox-gl-native/pull/8701))
* Fixed a crash or console spew when MGLMapView is initialized with a frame smaller than 64 points wide by 64 points tall. ([#8562](https://github.com/mapbox/mapbox-gl-native/pull/8562))
+* The Improve This Map button in the attribution action sheet now leads to a feedback tool that matches MGLMapView’s rotation and pitch. `-[MGLAttributionInfo feedbackURLAtCenterCoordinate:zoomLevel:]` no longer respects the feedback URL specified in TileJSON. ([#9078](https://github.com/mapbox/mapbox-gl-native/pull/9078))
* The error passed into `-[MGLMapViewDelegate mapViewDidFailLoadingMap:withError:]` now includes a more specific description and failure reason. ([#8418](https://github.com/mapbox/mapbox-gl-native/pull/8418))
+* The `MGLPolyline.coordinate` and `MGLPolygon.coordinate` properties now return the midpoint and centroid, respectively, instead of the first coordinate. ([#8713](https://github.com/mapbox/mapbox-gl-native/pull/8713))
+* Improved CPU and battery performance while animating a tilted map’s camera in an area with many labels. ([#9031](https://github.com/mapbox/mapbox-gl-native/pull/9031))
* Fixed an issue rendering polylines that contain duplicate vertices. ([#8808](https://github.com/mapbox/mapbox-gl-native/pull/8808))
## 0.4.1 - April 8, 2017
diff --git a/platform/macos/app/MGLVectorSource+MBXAdditions.h b/platform/macos/app/MGLVectorSource+MBXAdditions.h
index 312081ec51..1e25ee5a60 100644
--- a/platform/macos/app/MGLVectorSource+MBXAdditions.h
+++ b/platform/macos/app/MGLVectorSource+MBXAdditions.h
@@ -4,7 +4,7 @@ NS_ASSUME_NONNULL_BEGIN
@interface MGLVectorSource (MBXAdditions)
-+ (nullable NSString *)preferredMapboxStreetsLanguage;
++ (NSString *)preferredMapboxStreetsLanguage;
- (NS_DICTIONARY_OF(NSString *, NSString *) *)localizedKeysByKeyForPreferredLanguage:(nullable NSString *)preferredLanguage;
diff --git a/platform/macos/app/MGLVectorSource+MBXAdditions.m b/platform/macos/app/MGLVectorSource+MBXAdditions.m
index 644b43a651..323bc74366 100644
--- a/platform/macos/app/MGLVectorSource+MBXAdditions.m
+++ b/platform/macos/app/MGLVectorSource+MBXAdditions.m
@@ -7,19 +7,23 @@
static dispatch_once_t onceToken;
static NS_SET_OF(NSString *) *mapboxStreetsLanguages;
dispatch_once(&onceToken, ^{
- mapboxStreetsLanguages = [NSSet setWithObjects:@"en", @"es", @"fr", @"de", @"ru", @"zh", nil];
+ // https://www.mapbox.com/vector-tiles/mapbox-streets-v7/#overview
+ mapboxStreetsLanguages = [NSSet setWithObjects:@"ar", @"de", @"en", @"es", @"fr", @"pt", @"ru", @"zh", @"zh-Hans", nil];
});
return mapboxStreetsLanguages;
}
-+ (nullable NSString *)preferredMapboxStreetsLanguage {
- for (NSString *language in [NSLocale preferredLanguages]) {
- NSString *languageCode = [[NSLocale localeWithLocaleIdentifier:language] objectForKey:NSLocaleLanguageCode];
- if ([[MGLVectorSource mapboxStreetsLanguages] containsObject:languageCode]) {
- return languageCode;
++ (NSString *)preferredMapboxStreetsLanguage {
+ NSArray<NSString *> *supportedLanguages = [MGLVectorSource mapboxStreetsLanguages].allObjects;
+ NSArray<NSString *> *preferredLanguages = [NSBundle preferredLocalizationsFromArray:supportedLanguages
+ forPreferences:[NSLocale preferredLanguages]];
+ NSString *mostSpecificLanguage;
+ for (NSString *language in preferredLanguages) {
+ if (language.length > mostSpecificLanguage.length) {
+ mostSpecificLanguage = language;
}
}
- return nil;
+ return mostSpecificLanguage ?: @"en";
}
- (BOOL)isMapboxStreets {
diff --git a/platform/macos/app/MapDocument.m b/platform/macos/app/MapDocument.m
index 59c1817f63..59844d363e 100644
--- a/platform/macos/app/MapDocument.m
+++ b/platform/macos/app/MapDocument.m
@@ -345,7 +345,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
- (void)updateLabels {
MGLStyle *style = self.mapView.style;
- NSString *preferredLanguage = _isLocalizingLabels ? ([MGLVectorSource preferredMapboxStreetsLanguage] ?: @"en") : nil;
+ NSString *preferredLanguage = _isLocalizingLabels ? [MGLVectorSource preferredMapboxStreetsLanguage] : nil;
NSMutableDictionary *localizedKeysByKeyBySourceIdentifier = [NSMutableDictionary dictionary];
for (MGLSymbolStyleLayer *layer in style.layers) {
if (![layer isKindOfClass:[MGLSymbolStyleLayer class]]) {
@@ -807,6 +807,9 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
case 7:
state = [styleURL isEqual:[MGLStyle trafficDayStyleURL]];
break;
+ case 8:
+ state = [styleURL isEqual:[MGLStyle trafficNightStyleURL]];
+ break;
default:
return NO;
}
@@ -855,8 +858,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
if (menuItem.tag) {
NSLocale *locale = [NSLocale localeWithLocaleIdentifier:[NSBundle mainBundle].developmentLocalization];
NSString *preferredLanguage = [MGLVectorSource preferredMapboxStreetsLanguage];
- menuItem.enabled = !!preferredLanguage;
- menuItem.title = [locale displayNameForKey:NSLocaleIdentifier value:preferredLanguage ?: @"Preferred Language"];
+ menuItem.title = [locale displayNameForKey:NSLocaleIdentifier value:preferredLanguage];
}
return YES;
}
diff --git a/platform/macos/docs/guides/Tile URL Templates.md b/platform/macos/docs/guides/Tile URL Templates.md
new file mode 100644
index 0000000000..01672c6686
--- /dev/null
+++ b/platform/macos/docs/guides/Tile URL Templates.md
@@ -0,0 +1,98 @@
+<!--
+ This file is generated.
+ Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
+-->
+# Tile URL Templates
+
+`MGLTileSource` objects, specifically `MGLRasterSource` and `MGLVectorSource`
+objects, can be created using an initializer that accepts an array of tile URL
+templates. Tile URL templates are strings that specify the URLs of the vector
+tiles or raster tile images to load. A template resembles an absolute URL, but
+with any number of placeholder strings that the source evaluates based on the
+tile it needs to load. For example:
+
+* `http://www.example.com/tiles/{z}/{x}/{y}.pbf` could be
+ evaluated as `http://www.example.com/tiles/14/6/9.pbf`.
+* `http://www.example.com/tiles/{z}/{x}/{y}{ratio}.png` could be
+ evaluated as `http://www.example.com/tiles/14/6/9@2x.png`.
+
+Tile URL templates are also used to define tilesets in TileJSON manifests or
+[`raster`](https://www.mapbox.com/mapbox-gl-js/style-spec/#sources-raster-tiles)
+and
+[`vector`](https://www.mapbox.com/mapbox-gl-js/style-spec/#sources-vector-tiles)
+sources in style JSON files. See the
+[TileJSON specification](https://github.com/mapbox/tilejson-spec/tree/master/2.2.0)
+for information about tile URL templates in the context of a TileJSON or style
+JSON file.
+
+Tile sources support the following placeholder strings in tile URL templates,
+all of which are optional:
+
+<table>
+<thead>
+<tr><th>Placeholder string</th><th>Description</th></tr>
+</thead>
+<tbody>
+<tr>
+ <td><code>{x}</code></td>
+ <td>The index of the tile along the map’s x axis according to Spherical
+ Mercator projection. If the value is 0, the tile’s left edge corresponds
+ to the 180th meridian west. If the value is 2<sup><var>z</var></sup>−1,
+ the tile’s right edge corresponds to the 180th meridian east.</td>
+</tr>
+<tr>
+ <td><code>{y}</code></td>
+ <td>The index of the tile along the map’s y axis according to Spherical
+ Mercator projection. If the value is 0, the tile’s tile edge corresponds
+ to arctan(sinh(π)), or approximately 85.0511 degrees north. If the value
+ is 2<sup><var>z</var></sup>−1, the tile’s bottom edge corresponds to
+ −arctan(sinh(π)), or approximately 85.0511 degrees south. The y axis is
+ inverted if the <code>options</code> parameter contains
+ <code>MGLTileSourceOptionTileCoordinateSystem</code> with a value of
+ <code>MGLTileCoordinateSystemTMS</code>.</td>
+</tr>
+<tr>
+ <td><code>{z}</code></td>
+ <td>The tile’s zoom level. At zoom level 0, each tile covers the entire
+ world map; at zoom level 1, it covers ¼ of the world; at zoom level 2,
+ <sup>1</sup>⁄<sub>16</sub> of the world, and so on. For tiles loaded by
+ a <code>MGLRasterSource</code> object, whether the tile zoom level
+ matches the map’s current zoom level depends on the value of the
+ source’s tile size as specified in the
+ <code>MGLTileSourceOptionTileSize</code> key of the <code>options</code>
+ parameter.</td>
+</tr>
+<tr>
+ <td><code>{bbox-epsg-3857}</code></td>
+ <td>The tile’s bounding box, expressed as a comma-separated list of the
+ tile’s western, southern, eastern, and northern extents according to
+ Spherical Mercator (EPSG:3857) projection. The bounding box is typically
+ used with map services conforming to the
+ <a href="http://www.opengeospatial.org/standards/wms">Web Map Service</a>
+ protocol.</td>
+</tr>
+<tr>
+ <td><code>{quadkey}</code></td>
+ <td>A quadkey indicating both the tile’s location and its zoom level. The
+ quadkey is typically used with
+ <a href="https://msdn.microsoft.com/en-us/library/bb259689.aspx">Bing Maps</a>.
+ </td>
+</tr>
+<tr>
+ <td><code>{ratio}</code></td>
+ <td>A suffix indicating the resolution of the tile image. The suffix is the
+ empty string for standard resolution displays and <code>@2x</code> for
+ Retina displays.
+ </td>
+</tr>
+<tr>
+ <td><code>{prefix}</code></td>
+ <td>Two hexadecimal digits chosen such that each visible tile has a
+ different prefix. The prefix is typically used for domain sharding.</td>
+</tr>
+</tbody>
+</table>
+
+For more information about the `{x}`, `{y}`, and `{z}` placeholder strings,
+consult the
+[OpenStreetMap Wiki](https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames).
diff --git a/platform/macos/jazzy.yml b/platform/macos/jazzy.yml
index 3c24b351cc..fcd4bfd301 100644
--- a/platform/macos/jazzy.yml
+++ b/platform/macos/jazzy.yml
@@ -20,6 +20,7 @@ custom_categories:
- Working with GeoJSON Data
- For Style Authors
- Using Style Functions at Runtime
+ - Tile URL Templates
- Info.plist Keys
- name: Maps
children:
@@ -45,6 +46,7 @@ custom_categories:
children:
- MGLStyle
- MGLStyleValue
+ - MGLLight
- name: Content Primitives
children:
- MGLFeature
diff --git a/platform/macos/macos.xcodeproj/project.pbxproj b/platform/macos/macos.xcodeproj/project.pbxproj
index 9a18ce4a0e..564d81afb2 100644
--- a/platform/macos/macos.xcodeproj/project.pbxproj
+++ b/platform/macos/macos.xcodeproj/project.pbxproj
@@ -8,6 +8,10 @@
/* Begin PBXBuildFile section */
1753ED401E53CE6100A9FD90 /* MGLConversion.h in Headers */ = {isa = PBXBuildFile; fileRef = 1753ED3F1E53CE5200A9FD90 /* MGLConversion.h */; };
+ 1F7454A31ECFB00300021D39 /* MGLLight_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F7454A01ECFB00300021D39 /* MGLLight_Private.h */; };
+ 1F7454A41ECFB00300021D39 /* MGLLight.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F7454A11ECFB00300021D39 /* MGLLight.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 1F7454A51ECFB00300021D39 /* MGLLight.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1F7454A21ECFB00300021D39 /* MGLLight.mm */; };
+ 1F7454AB1ED1DDBD00021D39 /* MGLLightTest.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1F7454AA1ED1DDBD00021D39 /* MGLLightTest.mm */; };
1F95931B1E6DE2B600D5B294 /* MGLNSDateAdditionsTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1F95931A1E6DE2B600D5B294 /* MGLNSDateAdditionsTests.mm */; };
30E5781B1DAA857E0050F07E /* NSImage+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 30E578141DAA7D920050F07E /* NSImage+MGLAdditions.h */; };
3508EC641D749D39009B0EE4 /* NSExpression+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 3508EC621D749D39009B0EE4 /* NSExpression+MGLAdditions.h */; };
@@ -268,6 +272,10 @@
/* Begin PBXFileReference section */
1753ED3F1E53CE5200A9FD90 /* MGLConversion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLConversion.h; sourceTree = "<group>"; };
+ 1F7454A01ECFB00300021D39 /* MGLLight_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLLight_Private.h; sourceTree = "<group>"; };
+ 1F7454A11ECFB00300021D39 /* MGLLight.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLLight.h; sourceTree = "<group>"; };
+ 1F7454A21ECFB00300021D39 /* MGLLight.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLLight.mm; sourceTree = "<group>"; };
+ 1F7454AA1ED1DDBD00021D39 /* MGLLightTest.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLLightTest.mm; sourceTree = "<group>"; };
1F95931A1E6DE2B600D5B294 /* MGLNSDateAdditionsTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLNSDateAdditionsTests.mm; path = ../../darwin/test/MGLNSDateAdditionsTests.mm; sourceTree = "<group>"; };
30E578141DAA7D920050F07E /* NSImage+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSImage+MGLAdditions.h"; path = "src/NSImage+MGLAdditions.h"; sourceTree = SOURCE_ROOT; };
3508EC621D749D39009B0EE4 /* NSExpression+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSExpression+MGLAdditions.h"; sourceTree = "<group>"; };
@@ -670,6 +678,9 @@
352742771D4C220900A1ECE6 /* MGLStyleValue.h */,
DA8F259B1D51CB000010E6B5 /* MGLStyleValue_Private.h */,
3527429E1D4C25BD00A1ECE6 /* MGLStyleValue.mm */,
+ 1F7454A11ECFB00300021D39 /* MGLLight.h */,
+ 1F7454A21ECFB00300021D39 /* MGLLight.mm */,
+ 1F7454A01ECFB00300021D39 /* MGLLight_Private.h */,
);
name = Styling;
sourceTree = "<group>";
@@ -810,6 +821,7 @@
children = (
DA8F257C1D51C5F40010E6B5 /* Layers */,
DA87A99A1DC9D88800810D09 /* Sources */,
+ 1F7454AA1ED1DDBD00021D39 /* MGLLightTest.mm */,
353722EB1DF850ED004D2F3F /* MGLStyleValueTests.h */,
3599A3E71DF70E2000E77FB2 /* MGLStyleValueTests.m */,
DA2207BB1DC076940002F84D /* MGLStyleValueTests.swift */,
@@ -1133,6 +1145,7 @@
DA8F258B1D51CA540010E6B5 /* MGLLineStyleLayer.h in Headers */,
35C6DF841E214C0400ACA483 /* MGLDistanceFormatter.h in Headers */,
DA8F25B21D51CB270010E6B5 /* NSValue+MGLStyleAttributeAdditions.h in Headers */,
+ 1F7454A31ECFB00300021D39 /* MGLLight_Private.h in Headers */,
359819591E02F611008FC139 /* NSCoder+MGLAdditions.h in Headers */,
DAE6C38E1CC31E2A00DB3429 /* MGLOfflineStorage_Private.h in Headers */,
408AA8661DAEEE3600022900 /* MGLPolyline+MGLAdditions.h in Headers */,
@@ -1166,6 +1179,7 @@
DACC22181CF3D4F700D220D9 /* MGLFeature_Private.h in Headers */,
DA6408D71DA4E5DA00908C90 /* MGLVectorStyleLayer.h in Headers */,
352742891D4C245800A1ECE6 /* MGLShapeSource.h in Headers */,
+ 1F7454A41ECFB00300021D39 /* MGLLight.h in Headers */,
408AA8671DAEEE3900022900 /* NSDictionary+MGLAdditions.h in Headers */,
DAE6C3671CC31E0400DB3429 /* MGLStyle.h in Headers */,
);
@@ -1380,6 +1394,7 @@
DAE6C38C1CC31E2A00DB3429 /* MGLOfflinePack.mm in Sources */,
35D65C5B1D65AD5500722C23 /* NSDate+MGLAdditions.mm in Sources */,
DD0902B21DB1AC6400C5BDCE /* MGLNetworkConfiguration.m in Sources */,
+ 1F7454A51ECFB00300021D39 /* MGLLight.mm in Sources */,
DAE6C3B11CC31EF300DB3429 /* MGLAnnotationImage.m in Sources */,
3508EC651D749D39009B0EE4 /* NSExpression+MGLAdditions.mm in Sources */,
DACC22151CF3D3E200D220D9 /* MGLFeature.mm in Sources */,
@@ -1446,6 +1461,7 @@
DA35A2C21CCA9F4A00E826B2 /* MGLClockDirectionFormatterTests.m in Sources */,
DAE6C3D41CC34C9900DB3429 /* MGLOfflineRegionTests.m in Sources */,
DAE6C3D61CC34C9900DB3429 /* MGLStyleTests.mm in Sources */,
+ 1F7454AB1ED1DDBD00021D39 /* MGLLightTest.mm in Sources */,
DAEDC4371D606291000224FF /* MGLAttributionButtonTests.m in Sources */,
920A3E591E6F859D00C16EFC /* MGLSourceQueryTests.m in Sources */,
DA35A2B61CCA14D700E826B2 /* MGLCompassDirectionFormatterTests.m in Sources */,
@@ -1763,7 +1779,10 @@
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_VERSION = A;
- HEADER_SEARCH_PATHS = "$(mbgl_core_INCLUDE_DIRECTORIES)";
+ HEADER_SEARCH_PATHS = (
+ "$(mbgl_core_INCLUDE_DIRECTORIES)",
+ "$(polylabel_INCLUDE_DIRECTORIES)",
+ );
INFOPLIST_FILE = "$(SRCROOT)/sdk/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
@@ -1797,7 +1816,10 @@
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_VERSION = A;
- HEADER_SEARCH_PATHS = "$(mbgl_core_INCLUDE_DIRECTORIES)";
+ HEADER_SEARCH_PATHS = (
+ "$(mbgl_core_INCLUDE_DIRECTORIES)",
+ "$(polylabel_INCLUDE_DIRECTORIES)",
+ );
INFOPLIST_FILE = "$(SRCROOT)/sdk/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
@@ -1821,7 +1843,10 @@
buildSettings = {
CLANG_ENABLE_MODULES = YES;
COMBINE_HIDPI_IMAGES = YES;
- HEADER_SEARCH_PATHS = "$(mbgl_core_INCLUDE_DIRECTORIES)";
+ HEADER_SEARCH_PATHS = (
+ "$(mbgl_core_INCLUDE_DIRECTORIES)",
+ "$(polylabel_INCLUDE_DIRECTORIES)",
+ );
INFOPLIST_FILE = test/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
LIBRARY_SEARCH_PATHS = (
@@ -1850,7 +1875,10 @@
buildSettings = {
CLANG_ENABLE_MODULES = YES;
COMBINE_HIDPI_IMAGES = YES;
- HEADER_SEARCH_PATHS = "$(mbgl_core_INCLUDE_DIRECTORIES)";
+ HEADER_SEARCH_PATHS = (
+ "$(mbgl_core_INCLUDE_DIRECTORIES)",
+ "$(polylabel_INCLUDE_DIRECTORIES)",
+ );
INFOPLIST_FILE = test/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
OTHER_CFLAGS = "-fvisibility=hidden";
diff --git a/platform/macos/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm
index 98958f045d..c7f6e59c80 100644
--- a/platform/macos/src/MGLMapView.mm
+++ b/platform/macos/src/MGLMapView.mm
@@ -1,17 +1,18 @@
#import "MGLMapView_Private.h"
-#import "MGLAnnotationImage_Private.h"
+
#import "MGLAttributionButton.h"
-#import "MGLAttributionInfo.h"
#import "MGLCompassCell.h"
#import "MGLOpenGLLayer.h"
#import "MGLStyle.h"
+#import "MGLAnnotationImage_Private.h"
+#import "MGLAttributionInfo_Private.h"
#import "MGLFeature_Private.h"
+#import "MGLFoundation_Private.h"
#import "MGLGeometry_Private.h"
#import "MGLMultiPoint_Private.h"
#import "MGLOfflineStorage_Private.h"
#import "MGLStyle_Private.h"
-#import "MGLFoundation_Private.h"
#import "MGLAccountManager.h"
#import "MGLMapCamera.h"
@@ -1735,11 +1736,15 @@ public:
}
- (IBAction)giveFeedback:(id)sender {
- CLLocationCoordinate2D centerCoordinate = self.centerCoordinate;
+ MGLMapCamera *camera = self.camera;
double zoomLevel = self.zoomLevel;
NSMutableArray *urls = [NSMutableArray array];
for (MGLAttributionInfo *info in [self.style attributionInfosWithFontSize:0 linkColor:nil]) {
- NSURL *url = [info feedbackURLAtCenterCoordinate:centerCoordinate zoomLevel:zoomLevel];
+ NSURL *url = [info feedbackURLForStyleURL:self.styleURL
+ atCenterCoordinate:camera.centerCoordinate
+ zoomLevel:zoomLevel
+ direction:camera.heading
+ pitch:camera.pitch];
if (url) {
[urls addObject:url];
}
diff --git a/platform/macos/src/Mapbox.h b/platform/macos/src/Mapbox.h
index dcb5b50b8f..0f47dace70 100644
--- a/platform/macos/src/Mapbox.h
+++ b/platform/macos/src/Mapbox.h
@@ -17,6 +17,7 @@ FOUNDATION_EXPORT MGL_EXPORT const unsigned char MapboxVersionString[];
#import "MGLDistanceFormatter.h"
#import "MGLFeature.h"
#import "MGLGeometry.h"
+#import "MGLLight.h"
#import "MGLMapCamera.h"
#import "MGLMapView.h"
#import "MGLMapView+IBAdditions.h"
diff --git a/scripts/config.xcconfig.in b/scripts/config.xcconfig.in
index eb6bc71b89..b70ff9d677 100644
--- a/scripts/config.xcconfig.in
+++ b/scripts/config.xcconfig.in
@@ -3,3 +3,4 @@
// mbgl-core
mbgl_core_INCLUDE_DIRECTORIES = "@mbgl_core_INCLUDE_DIRECTORIES@"
mbgl_core_LINK_LIBRARIES = "@mbgl_core_LINK_LIBRARIES@"
+polylabel_INCLUDE_DIRECTORIES = "@MASON_PACKAGE_polylabel_INCLUDE_DIRS@"