diff options
-rw-r--r-- | CHANGELOG.md | 16 | ||||
-rw-r--r-- | include/mbgl/map/map.hpp | 4 | ||||
-rw-r--r-- | include/mbgl/map/mode.hpp | 1 | ||||
-rw-r--r-- | ios/framework/Mapbox-static.h | 3 | ||||
-rw-r--r-- | platform/ios/INSTALL.md | 10 | ||||
-rw-r--r-- | platform/ios/Mapbox-iOS-SDK.podspec | 4 | ||||
-rw-r--r-- | platform/ios/docs/doc-README.md | 2 | ||||
-rw-r--r-- | platform/ios/docs/pod-README.md | 8 | ||||
-rw-r--r-- | platform/ios/framework/framework-ios.gypi | 1 | ||||
-rwxr-xr-x | platform/ios/scripts/package.sh | 10 | ||||
-rw-r--r-- | platform/ios/src/MGLAccountManager.m | 10 | ||||
-rw-r--r-- | platform/ios/src/MGLMapView.mm | 114 | ||||
-rw-r--r-- | platform/osx/src/MGLMapView.mm | 46 | ||||
-rw-r--r-- | src/mbgl/map/map.cpp | 10 | ||||
-rw-r--r-- | src/mbgl/map/transform.cpp | 11 | ||||
-rw-r--r-- | src/mbgl/map/transform.hpp | 4 | ||||
-rw-r--r-- | src/mbgl/map/transform_state.cpp | 12 | ||||
-rw-r--r-- | src/mbgl/map/transform_state.hpp | 3 |
18 files changed, 198 insertions, 71 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index de84cdbd80..6155ea6643 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,14 +49,26 @@ Known issues: - Black Screen On Ice Cream Sandwich and Jelly Bean devices ([#2802](https://github.com/mapbox/mapbox-gl-native/issues/2802)) - Resolved in 2.2.0 -## iOS master +## iOS 3.1.2 + +- You can once again install the static framework without manually linking several framework and library dependencies. ([#4029](https://github.com/mapbox/mapbox-gl-native/pull/4029)) +- The location manager used by MGLMapView to show the user’s location is now paused when the application is sent to the background. ([#4034](https://github.com/mapbox/mapbox-gl-native/pull/4034)) + +## iOS 3.1.1 + +- Corrected the dynamic framework’s minimum deployment target to iOS 8.0. ([#3872](https://github.com/mapbox/mapbox-gl-native/pull/3872)) +- Fixed Fabric compatibility. ([#3847](https://github.com/mapbox/mapbox-gl-native/pull/3847)) +- Fixed a crash that can occur when reselecting an annotation. ([#3881](https://github.com/mapbox/mapbox-gl-native/pull/3881)) +- Fixed an issue preventing the Latitude inspectable from working when it is set before setting the Zoom Level inspectable in Interface Builder. ([#3886](https://github.com/mapbox/mapbox-gl-native/pull/3886)) +- Fixed an issue that incorrectly expanded the tappable area of an annotation and prevented the annotation’s alignment rect insets from having any effect on the tappable area. ([#3898](https://github.com/mapbox/mapbox-gl-native/pull/3898)) +- Fixed an issue preventing `-[MGLMapViewDelegate mapView:tapOnCalloutForAnnotation:]` from being called when a non-custom callout view is tapped. ([#3875](https://github.com/mapbox/mapbox-gl-native/pull/3875)) - Polygons and polylines now default to using the map view's tint color. ([#4028](https://github.com/mapbox/mapbox-gl-native/pull/4028)) - The Improve This Map tool now uses the same zoom level that is currently being shown in the map view. ([#4068](https://github.com/mapbox/mapbox-gl-native/pull/4068)) ## iOS 3.1.0 -- The SDK is now distributed as a dynamic framework instead of a static library, resulting in a simpler installation workflow and significantly reduced download size. The framework contains both simulator and device content; due to [an Xcode bug](http://www.openradar.me/radar?id=6409498411401216), you’ll need to strip out the simulator content before submitting your application to the App Store. ([#3183](https://github.com/mapbox/mapbox-gl-native/pull/3183)) +- The SDK is now distributed as a dynamic framework instead of a static library, resulting in a simpler installation workflow and significantly reduced download size. The framework contains both simulator and device content. If you install the dynamic framework manually, you’ll need to strip out the simulator content before submitting your application to the App Store due to [an Xcode bug](http://www.openradar.me/radar?id=6409498411401216); see the installation instructions included with the framework for details. ([#3183](https://github.com/mapbox/mapbox-gl-native/pull/3183)) - Fixed an issue causing the entire MGLMapView to leak. ([#3447](https://github.com/mapbox/mapbox-gl-native/pull/3447)) - `MGLMapView` methods that alter the viewport now accept optional completion handlers. ([#3090](https://github.com/mapbox/mapbox-gl-native/pull/3090)) - You can now modify an annotation’s image after adding the annotation to the map. ([#3146](https://github.com/mapbox/mapbox-gl-native/pull/3146)) diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp index 8c27b1756a..688565fecb 100644 --- a/include/mbgl/map/map.hpp +++ b/include/mbgl/map/map.hpp @@ -138,6 +138,10 @@ public: // North Orientation void setNorthOrientation(NorthOrientation); NorthOrientation getNorthOrientation() const; + + // Constrain mode + void setConstrainMode(ConstrainMode); + ConstrainMode getConstrainMode() const; // Size uint16_t getWidth() const; diff --git a/include/mbgl/map/mode.hpp b/include/mbgl/map/mode.hpp index c197b28589..7fd1a7f522 100644 --- a/include/mbgl/map/mode.hpp +++ b/include/mbgl/map/mode.hpp @@ -24,6 +24,7 @@ enum class GLContextMode : EnumType { // We can choose to constrain the map both horizontally or vertically, or only // vertically e.g. while panning. enum class ConstrainMode : EnumType { + None, HeightOnly, WidthAndHeight, }; diff --git a/ios/framework/Mapbox-static.h b/ios/framework/Mapbox-static.h new file mode 100644 index 0000000000..d3674b0b61 --- /dev/null +++ b/ios/framework/Mapbox-static.h @@ -0,0 +1,3 @@ +#import <GLKit/GLKit.h> +#import <ImageIO/ImageIO.h> +#import <MobileCoreServices/MobileCoreServices.h> diff --git a/platform/ios/INSTALL.md b/platform/ios/INSTALL.md index 9b5d306618..b4e27acdea 100644 --- a/platform/ios/INSTALL.md +++ b/platform/ios/INSTALL.md @@ -79,7 +79,7 @@ This is the recommended workflow for manually integrating the SDK into an applic 1. Build from source manually per above. -1. Open the project editor and select your application target. Drag `build/ios/pkg/dynamic/Mapbox.framework` into the “Embedded Binaries” section of the General tab. In the sheet that appears, make sure “Copy items if needed” is checked, then click Finish. +1. Open the project editor and select your application target. Drag `build/ios/pkg/dynamic/Mapbox.framework` into the “Embedded Binaries” section of the General tab. (Don’t drag it into the “Linked Frameworks and Libraries” section; Xcode will add it there automatically.) In the sheet that appears, make sure “Copy items if needed” is checked, then click Finish. 1. In the Build Phases tab, click the + button at the top and select “New Run Script Phase”. Enter the following code into the script text field: @@ -95,7 +95,7 @@ If your application targets iOS 7.x, you’ll need to install the static framewo 1. Build from source manually per above. -1. Open the project editor and select your application target. Drag `build/ios/pkg/static/Mapbox.framework` into the “Embedded Binaries” section of the General tab. In the sheet that appears, make sure “Copy items if needed” is checked, then click Finish. +1. Open the project editor and select your application target. Drag `build/ios/pkg/static/Mapbox.framework` into the “Embedded Binaries” section of the General tab. (Don’t drag it into the “Linked Frameworks and Libraries” section; Xcode will add it there automatically.) In the sheet that appears, make sure “Copy items if needed” is checked, then click Finish. 1. Add the following Cocoa Touch frameworks and libraries to the “Linked Frameworks and Libraries” section: @@ -104,9 +104,9 @@ If your application targets iOS 7.x, you’ll need to install the static framewo - `MobileCoreServices.framework` - `QuartzCore.framework` - `SystemConfiguration.framework` - - `libc++.dylib` - - `libsqlite3.dylib` - - `libz.dylib` + - `libc++.tbd` + - `libsqlite3.tbd` + - `libz.tbd` 1. In the Build Settings tab, add `-ObjC` to the “Other Linker Flags” (`OTHER_LDFLAGS`) build setting. diff --git a/platform/ios/Mapbox-iOS-SDK.podspec b/platform/ios/Mapbox-iOS-SDK.podspec index 4e759db61b..51e1a27257 100644 --- a/platform/ios/Mapbox-iOS-SDK.podspec +++ b/platform/ios/Mapbox-iOS-SDK.podspec @@ -1,14 +1,14 @@ Pod::Spec.new do |m| m.name = 'Mapbox-iOS-SDK' - m.version = '3.1.0-pre.3-symbols' + m.version = '3.1.2' m.summary = 'Open source vector map solution for iOS with full styling capabilities.' m.description = 'Open source, OpenGL-based vector map solution for iOS with full styling capabilities and Cocoa Touch APIs.' m.homepage = 'https://www.mapbox.com/ios-sdk/' m.license = { :type => 'BSD', :file => 'LICENSE.md' } m.author = { 'Mapbox' => 'mobile@mapbox.com' } - m.screenshot = 'https://raw.githubusercontent.com/mapbox/mapbox-gl-native/master/ios/screenshot.png' + m.screenshot = 'https://raw.githubusercontent.com/mapbox/mapbox-gl-native/master/platform/ios/screenshot.png' m.social_media_url = 'https://twitter.com/mapbox' m.documentation_url = 'https://www.mapbox.com/ios-sdk/' diff --git a/platform/ios/docs/doc-README.md b/platform/ios/docs/doc-README.md index 0565d65cdd..d3c4bd5e4a 100644 --- a/platform/ios/docs/doc-README.md +++ b/platform/ios/docs/doc-README.md @@ -2,7 +2,7 @@ The Mapbox iOS SDK is an open-source framework for embedding interactive map views with scalable, customizable vector maps into Cocoa Touch applications on iOS 7.0 and above using Objective-C, Swift, or Interface Builder. It takes stylesheets that conform to the [Mapbox GL Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/), applies them to vector tiles that conform to the [Mapbox Vector Tile Specification](https://www.mapbox.com/developers/vector-tiles/), and renders them using OpenGL. -[![](https://raw.githubusercontent.com/mapbox/mapbox-gl-native/master/ios/screenshot.png)]() +[![](https://raw.githubusercontent.com/mapbox/mapbox-gl-native/master/platform/ios/screenshot.png)]() For setup information, check out the [Mapbox iOS SDK homepage](https://www.mapbox.com/ios-sdk/). For detailed usage instructions, read “[First steps with the Mapbox iOS SDK](https://www.mapbox.com/help/first-steps-ios-sdk/)” and consult the [online examples](https://www.mapbox.com/ios-sdk/examples/). A [full changelog](https://github.com/mapbox/mapbox-gl-native/blob/master/CHANGELOG.md) is also available. diff --git a/platform/ios/docs/pod-README.md b/platform/ios/docs/pod-README.md index 59c1f6ec2a..e2c8ff813a 100644 --- a/platform/ios/docs/pod-README.md +++ b/platform/ios/docs/pod-README.md @@ -4,7 +4,7 @@ The Mapbox iOS SDK is an open-source framework for embedding interactive map vie For more information, check out the [Mapbox iOS SDK homepage](https://www.mapbox.com/ios-sdk/) and the [full changelog](https://github.com/mapbox/mapbox-gl-native/blob/master/CHANGELOG.md) online. -[![](https://raw.githubusercontent.com/mapbox/mapbox-gl-native/master/ios/screenshot.png)]() +[![](https://raw.githubusercontent.com/mapbox/mapbox-gl-native/master/platform/ios/screenshot.png)]() ## Installation @@ -42,9 +42,9 @@ If your application targets iOS 7.x, you’ll need to install the static framewo - `MobileCoreServices.framework` - `QuartzCore.framework` - `SystemConfiguration.framework` - - `libc++.dylib` - - `libsqlite3.dylib` - - `libz.dylib` + - `libc++.tbd` + - `libsqlite3.tbd` + - `libz.tbd` 1. In the Build Settings tab, add `-ObjC` to the “Other Linker Flags” (`OTHER_LDFLAGS`) build setting. diff --git a/platform/ios/framework/framework-ios.gypi b/platform/ios/framework/framework-ios.gypi index 1dcc2c0f9d..3d733d963a 100644 --- a/platform/ios/framework/framework-ios.gypi +++ b/platform/ios/framework/framework-ios.gypi @@ -23,6 +23,7 @@ 'DEFINES_MODULE': 'YES', 'DYLIB_INSTALL_NAME_BASE': '@rpath', 'INFOPLIST_FILE': '../platform/ios/framework/Info.plist', + 'IPHONEOS_DEPLOYMENT_TARGET': '8.0', 'LD_RUNPATH_SEARCH_PATHS': [ '$(inherited)', '@executable_path/Frameworks', diff --git a/platform/ios/scripts/package.sh b/platform/ios/scripts/package.sh index ab6db61395..4c7ce7573a 100755 --- a/platform/ios/scripts/package.sh +++ b/platform/ios/scripts/package.sh @@ -188,10 +188,13 @@ if [[ ${BUILD_STATIC} == true ]]; then step "Copying static library headers…" mkdir -p "${OUTPUT}/static/${NAME}.framework/Headers" cp -pv platform/{darwin,ios}/include/*.h "${OUTPUT}/static/${NAME}.framework/Headers" + cat platform/ios/framework/Mapbox-static.h > "${OUTPUT}/static/${NAME}.framework/Headers/Mapbox.h" + cat platform/ios/framework/Mapbox.h >> "${OUTPUT}/static/${NAME}.framework/Headers/Mapbox.h" fi step "Copying library resources…" -SHORT_VERSION=$( git describe --tags --match=ios-v*.*.* --abbrev=0 | sed 's/^ios-v//' ) +SEM_VERSION=$( git describe --tags --match=ios-v*.*.* --abbrev=0 | sed 's/^ios-v//' ) +SHORT_VERSION=${SEM_VERSION%-*} cp -pv LICENSE.md "${OUTPUT}" cp -rv platform/ios/app/Settings.bundle "${OUTPUT}" if [[ ${BUILD_STATIC} == true ]]; then @@ -202,11 +205,16 @@ if [[ ${BUILD_STATIC} == true ]]; then plutil -replace CFBundleName -string ${NAME} "${OUTPUT}/static/${NAME}.framework/Info.plist" plutil -replace CFBundleShortVersionString -string "${SHORT_VERSION}" "${OUTPUT}/static/${NAME}.framework/Info.plist" plutil -replace CFBundleVersion -string ${PROJ_VERSION} "${OUTPUT}/static/${NAME}.framework/Info.plist" + plutil -replace MGLSemanticVersionString -string "${SEM_VERSION}" "${OUTPUT}/static/${NAME}.framework/Info.plist" + plutil -replace MGLCommitHash -string "${HASH}" "${OUTPUT}/static/${NAME}.framework/Info.plist" mkdir "${OUTPUT}/static/${NAME}.framework/Modules" cp -pv platform/ios/framework/modulemap "${OUTPUT}/static/${NAME}.framework/Modules/module.modulemap" fi if [[ ${BUILD_DYNAMIC} == true ]]; then plutil -replace CFBundleShortVersionString -string "${SHORT_VERSION}" "${OUTPUT}/dynamic/${NAME}.framework/Info.plist" + plutil -replace CFBundleVersion -string "${PROJ_VERSION}" "${OUTPUT}/dynamic/${NAME}.framework/Info.plist" + plutil -replace MGLSemanticVersionString -string "${SEM_VERSION}" "${OUTPUT}/dynamic/${NAME}.framework/Info.plist" + plutil -replace MGLCommitHash -string "${HASH}" "${OUTPUT}/dynamic/${NAME}.framework/Info.plist" cp -pv platform/ios/framework/strip-frameworks.sh "${OUTPUT}/dynamic/${NAME}.framework/strip-frameworks.sh" fi sed -n -e '/^## iOS/,$p' CHANGELOG.md > "${OUTPUT}/CHANGELOG.md" diff --git a/platform/ios/src/MGLAccountManager.m b/platform/ios/src/MGLAccountManager.m index 764f9f097b..6b98d5286a 100644 --- a/platform/ios/src/MGLAccountManager.m +++ b/platform/ios/src/MGLAccountManager.m @@ -1,7 +1,9 @@ #import "MGLAccountManager_Private.h" #import "MGLMapboxEvents.h" +#import "MGLMapView.h" #import "NSBundle+MGLAdditions.h" #import "NSProcessInfo+MGLAdditions.h" +#import "NSString+MGLAdditions.h" #import "FABKitProtocol.h" #import "Fabric+FABKits.h" @@ -93,6 +95,14 @@ } else { NSLog(@"MGLAccountManager is used in a project that doesn't have Fabric."); } + + // https://github.com/mapbox/mapbox-gl-native/issues/2966 + mgl_linkBundleCategory(); + mgl_linkStringCategory(); + mgl_linkProcessInfoCategory(); + + // https://github.com/mapbox/mapbox-gl-native/issues/3113 + [MGLMapView class]; } @end diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index 4f732fb627..78ab235332 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -147,6 +147,7 @@ public: GLKViewDelegate, CLLocationManagerDelegate, UIActionSheetDelegate, + SMCalloutViewDelegate, MGLCalloutViewDelegate, UIAlertViewDelegate, MGLMultiPointDelegate, @@ -313,7 +314,7 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration) _mbglFileSource = new mbgl::DefaultFileSource([fileCachePath UTF8String], [[[[NSBundle mainBundle] resourceURL] path] UTF8String]); // setup mbgl map - _mbglMap = new mbgl::Map(*_mbglView, *_mbglFileSource, mbgl::MapMode::Continuous); + _mbglMap = new mbgl::Map(*_mbglView, *_mbglFileSource, mbgl::MapMode::Continuous, mbgl::GLContextMode::Unique, mbgl::ConstrainMode::None); // start paused if in IB if (_isTargetingInterfaceBuilder || background) { @@ -759,7 +760,7 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration) // This is the delegate of the GLKView object's display call. - (void)glkView:(__unused GLKView *)view drawInRect:(__unused CGRect)rect { - if ( ! self.isDormant) + if ( ! self.dormant) { CGFloat zoomFactor = _mbglMap->getMaxZoom() - _mbglMap->getMinZoom() + 1; CGFloat cpuFactor = (CGFloat)[[NSProcessInfo processInfo] processorCount]; @@ -905,7 +906,7 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration) { MGLAssertIsMainThread(); - if ( ! self.isDormant) + if ( ! self.dormant) { [self validateDisplayLink]; self.dormant = YES; @@ -919,6 +920,11 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration) BOOL isVisible = self.superview && self.window; if (isVisible && ! _displayLink) { + if (_mbglMap->getConstrainMode() == mbgl::ConstrainMode::None) + { + _mbglMap->setConstrainMode(mbgl::ConstrainMode::HeightOnly); + } + _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateFromDisplayLink)]; _displayLink.frameInterval = MGLTargetFrameInterval; [_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; @@ -951,6 +957,8 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration) { self.dormant = YES; + [self validateLocationServices]; + [MGLMapboxEvents flush]; _displayLink.paused = YES; @@ -1000,6 +1008,8 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration) _mbglMap->resume(); _displayLink.paused = NO; + + [self validateLocationServices]; } } @@ -1482,6 +1492,14 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration) return [self.delegate respondsToSelector:@selector(mapView:tapOnCalloutForAnnotation:)]; } +- (void)calloutViewClicked:(__unused SMCalloutView *)calloutView +{ + if ([self.delegate respondsToSelector:@selector(mapView:tapOnCalloutForAnnotation:)]) + { + [self.delegate mapView:self tapOnCalloutForAnnotation:self.selectedAnnotation]; + } +} + - (void)calloutViewTapped:(__unused MGLCompactCalloutView *)calloutView { if ([self.delegate respondsToSelector:@selector(mapView:tapOnCalloutForAnnotation:)]) @@ -2643,7 +2661,8 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration) // Filter out any annotation whose image is unselectable or for which // hit testing fails. - std::remove_if(nearbyAnnotations.begin(), nearbyAnnotations.end(), [&](const MGLAnnotationTag annotationTag) + auto end = std::remove_if(nearbyAnnotations.begin(), nearbyAnnotations.end(), + [&](const MGLAnnotationTag annotationTag) { id <MGLAnnotation> annotation = [self annotationWithTag:annotationTag]; NSAssert(annotation, @"Unknown annotation found nearby tap"); @@ -2660,6 +2679,7 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration) centeredAtCoordinate:annotation.coordinate]; return !!!CGRectIntersectsRect(annotationRect, hitRect); }); + nearbyAnnotations.resize(std::distance(nearbyAnnotations.begin(), end)); } MGLAnnotationTag hitAnnotationTag = MGLAnnotationTagNotFound; @@ -2689,19 +2709,28 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration) if (_selectedAnnotationTag == MGLAnnotationTagNotFound || _selectedAnnotationTag == _annotationsNearbyLastTap.back()) { - // Either an annotation from this set hasn’t been selected - // before or the last annotation in the set was selected. Wrap - // around to the first annotation in the set. + // Either no annotation is selected or the last annotation in + // the set was selected. Wrap around to the first annotation in + // the set. hitAnnotationTag = _annotationsNearbyLastTap.front(); } else { - // Step to the next annotation in the set. auto result = std::find(_annotationsNearbyLastTap.begin(), _annotationsNearbyLastTap.end(), _selectedAnnotationTag); - auto distance = std::distance(_annotationsNearbyLastTap.begin(), result); - hitAnnotationTag = _annotationsNearbyLastTap[distance + 1]; + if (result == _annotationsNearbyLastTap.end()) + { + // An annotation from this set hasn’t been selected before. + // Select the first (nearest) one. + hitAnnotationTag = _annotationsNearbyLastTap.front(); + } + else + { + // Step to the next annotation in the set. + auto distance = std::distance(_annotationsNearbyLastTap.begin(), result); + hitAnnotationTag = _annotationsNearbyLastTap[distance + 1]; + } } } else @@ -2997,45 +3026,31 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration) #pragma mark - User Location - -- (void)setShowsUserLocation:(BOOL)showsUserLocation +- (void)validateLocationServices { - if (showsUserLocation == _showsUserLocation || _isTargetingInterfaceBuilder) return; - - _showsUserLocation = showsUserLocation; + BOOL shouldEnableLocationServices = self.showsUserLocation && !self.dormant; - if (showsUserLocation) + if (shouldEnableLocationServices && ! self.locationManager) { - if ([self.delegate respondsToSelector:@selector(mapViewWillStartLocatingUser:)]) - { - [self.delegate mapViewWillStartLocatingUser:self]; - } - - self.userLocationAnnotationView = [[MGLUserLocationAnnotationView alloc] initInMapView:self]; - self.userLocationAnnotationView.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | - UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin); - - self.locationManager = [CLLocationManager new]; + self.locationManager = [[CLLocationManager alloc] init]; #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 - // enable iOS 8+ location authorization API - // - if ([CLLocationManager instancesRespondToSelector:@selector(requestWhenInUseAuthorization)]) + if ([CLLocationManager instancesRespondToSelector:@selector(requestWhenInUseAuthorization)] && [CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined) { - BOOL hasLocationDescription = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"] || - [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"]; + BOOL hasLocationDescription = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"] || [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"]; if (!hasLocationDescription) { [NSException raise:@"Missing Location Services usage description" format: - @"In iOS 8 and above, this app must have a value for NSLocationWhenInUseUsageDescription or NSLocationAlwaysUsageDescription in its Info.plist."]; + @"In iOS 8 and above, this app must have a value for NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription in its Info.plist."]; } - // request location permissions, if both keys exist ask for less permissive - if ([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"]) + + if ([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"]) { - [self.locationManager requestWhenInUseAuthorization]; + [self.locationManager requestAlwaysAuthorization]; } - else if ([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"]) + else if ([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"]) { - [self.locationManager requestAlwaysAuthorization]; + [self.locationManager requestWhenInUseAuthorization]; } } #endif @@ -3044,12 +3059,37 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration) self.locationManager.delegate = self; [self.locationManager startUpdatingLocation]; } - else + else if ( ! shouldEnableLocationServices && self.locationManager) { [self.locationManager stopUpdatingLocation]; [self.locationManager stopUpdatingHeading]; self.locationManager.delegate = nil; self.locationManager = nil; + } +} + +- (void)setShowsUserLocation:(BOOL)showsUserLocation +{ + if (showsUserLocation == _showsUserLocation || _isTargetingInterfaceBuilder) return; + + _showsUserLocation = showsUserLocation; + + if (showsUserLocation) + { + if ([self.delegate respondsToSelector:@selector(mapViewWillStartLocatingUser:)]) + { + [self.delegate mapViewWillStartLocatingUser:self]; + } + + self.userLocationAnnotationView = [[MGLUserLocationAnnotationView alloc] initInMapView:self]; + self.userLocationAnnotationView.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | + UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin); + + [self validateLocationServices]; + } + else + { + [self validateLocationServices]; if ([self.delegate respondsToSelector:@selector(mapViewDidStopLocatingUser:)]) { diff --git a/platform/osx/src/MGLMapView.mm b/platform/osx/src/MGLMapView.mm index ec3fb7eb35..cd8cd45265 100644 --- a/platform/osx/src/MGLMapView.mm +++ b/platform/osx/src/MGLMapView.mm @@ -249,7 +249,7 @@ public: NSString *cachePath = cacheURL ? cacheURL.path : @""; _mbglFileSource = new mbgl::DefaultFileSource(cachePath.UTF8String, [[[[NSBundle mainBundle] resourceURL] path] UTF8String]); - _mbglMap = new mbgl::Map(*_mbglView, *_mbglFileSource, mbgl::MapMode::Continuous); + _mbglMap = new mbgl::Map(*_mbglView, *_mbglFileSource, mbgl::MapMode::Continuous, mbgl::GLContextMode::Unique, mbgl::ConstrainMode::None); // Install the OpenGL layer. Interface Builder’s synchronous drawing means // we can’t display a map, so don’t even bother to have a map layer. @@ -559,19 +559,24 @@ public: } - (void)viewDidMoveToWindow { - if (self.dormant && self.window) { + NSWindow *window = self.window; + if (self.dormant && window) { _mbglMap->resume(); self.dormant = NO; } - [self.window addObserver:self - forKeyPath:@"contentLayoutRect" - options:NSKeyValueObservingOptionInitial - context:NULL]; - [self.window addObserver:self - forKeyPath:@"titlebarAppearsTransparent" - options:NSKeyValueObservingOptionInitial - context:NULL]; + if (window && _mbglMap->getConstrainMode() == mbgl::ConstrainMode::None) { + _mbglMap->setConstrainMode(mbgl::ConstrainMode::HeightOnly); + } + + [window addObserver:self + forKeyPath:@"contentLayoutRect" + options:NSKeyValueObservingOptionInitial + context:NULL]; + [window addObserver:self + forKeyPath:@"titlebarAppearsTransparent" + options:NSKeyValueObservingOptionInitial + context:NULL]; } - (BOOL)wantsLayer { @@ -1712,7 +1717,7 @@ public: // Filter out any annotation whose image is unselectable or for which // hit testing fails. - std::remove_if(nearbyAnnotations.begin(), nearbyAnnotations.end(), [&](const MGLAnnotationTag annotationTag) { + auto end = std::remove_if(nearbyAnnotations.begin(), nearbyAnnotations.end(), [&](const MGLAnnotationTag annotationTag) { NSAssert(_annotationContextsByAnnotationTag.count(annotationTag) != 0, @"Unknown annotation found nearby click"); id <MGLAnnotation> annotation = [self annotationWithTag:annotationTag]; if (!annotation) { @@ -1731,6 +1736,7 @@ public: return !!![annotationImage.image hitTestRect:hitRect withImageDestinationRect:annotationRect context:nil hints:nil flipped:NO]; }); + nearbyAnnotations.resize(std::distance(nearbyAnnotations.begin(), end)); } MGLAnnotationTag hitAnnotationTag = MGLAnnotationTagNotFound; @@ -1757,17 +1763,23 @@ public: // set of annotations as we do now. Cycle through them. if (_lastSelectedAnnotationTag == MGLAnnotationTagNotFound || _lastSelectedAnnotationTag == _annotationsNearbyLastClick.back()) { - // Either an annotation from this set hasn’t been selected - // before or the last annotation in the set was selected. Wrap - // around to the first annotation in the set. + // Either no annotation is selected or the last annotation in + // the set was selected. Wrap around to the first annotation in + // the set. hitAnnotationTag = _annotationsNearbyLastClick.front(); } else { - // Step to the next annotation in the set. auto result = std::find(_annotationsNearbyLastClick.begin(), _annotationsNearbyLastClick.end(), _lastSelectedAnnotationTag); - auto distance = std::distance(_annotationsNearbyLastClick.begin(), result); - hitAnnotationTag = _annotationsNearbyLastClick[distance + 1]; + if (result == _annotationsNearbyLastClick.end()) { + // An annotation from this set hasn’t been selected before. + // Select the first (nearest) one. + hitAnnotationTag = _annotationsNearbyLastClick.front(); + } else { + // Step to the next annotation in the set. + auto distance = std::distance(_annotationsNearbyLastClick.begin(), result); + hitAnnotationTag = _annotationsNearbyLastClick[distance + 1]; + } } } else { // Remember the nearby annotations for the next time this method is diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index cfbdbafb6e..c3123fb3be 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -395,6 +395,16 @@ NorthOrientation Map::getNorthOrientation() const { return transform->getNorthOrientation(); } +#pragma mark - Constrain mode + +void Map::setConstrainMode(mbgl::ConstrainMode mode) { + transform->setConstrainMode(mode); + update(Update::Repaint); +} + +ConstrainMode Map::getConstrainMode() const { + return transform->getConstrainMode(); +} #pragma mark - Projection diff --git a/src/mbgl/map/transform.cpp b/src/mbgl/map/transform.cpp index b8c816ddc2..0f7af8c9e9 100644 --- a/src/mbgl/map/transform.cpp +++ b/src/mbgl/map/transform.cpp @@ -560,6 +560,17 @@ NorthOrientation Transform::getNorthOrientation() const { return state.getNorthOrientation(); } +#pragma mark - Constrain mode + +void Transform::setConstrainMode(mbgl::ConstrainMode mode) { + state.constrainMode = mode; + state.constrain(state.scale, state.x, state.y); +} + +ConstrainMode Transform::getConstrainMode() const { + return state.getConstrainMode(); +} + #pragma mark - Transition void Transform::startTransition(const CameraOptions& camera, diff --git a/src/mbgl/map/transform.hpp b/src/mbgl/map/transform.hpp index 806413058d..48615421fe 100644 --- a/src/mbgl/map/transform.hpp +++ b/src/mbgl/map/transform.hpp @@ -119,6 +119,10 @@ public: // North Orientation void setNorthOrientation(NorthOrientation); NorthOrientation getNorthOrientation() const; + + // Constrain mode + void setConstrainMode(ConstrainMode); + ConstrainMode getConstrainMode() const; // Transitions bool inTransition() const; diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp index 42fbd9af87..087defabda 100644 --- a/src/mbgl/map/transform_state.cpp +++ b/src/mbgl/map/transform_state.cpp @@ -81,6 +81,12 @@ double TransformState::getNorthOrientationAngle() const { return angleOrientation; } +#pragma mark - Constrain mode + +ConstrainMode TransformState::getConstrainMode() const { + return constrainMode; +} + #pragma mark - Position LatLng TransformState::getLatLng() const { @@ -354,8 +360,10 @@ void TransformState::constrain(double& scale_, double& x_, double& y_) const { x_ = std::max(-max_x, std::min(x_, max_x)); } - double max_y = (scale_ * util::tileSize - (rotatedNorth() ? width : height)) / 2; - y_ = std::max(-max_y, std::min(y_, max_y)); + if (constrainMode != ConstrainMode::None) { + double max_y = (scale_ * util::tileSize - (rotatedNorth() ? width : height)) / 2; + y_ = std::max(-max_y, std::min(y_, max_y)); + } } void TransformState::moveLatLng(const LatLng& latLng, const PrecisionPoint& anchor) { diff --git a/src/mbgl/map/transform_state.hpp b/src/mbgl/map/transform_state.hpp index a276c08868..0fb1f2304b 100644 --- a/src/mbgl/map/transform_state.hpp +++ b/src/mbgl/map/transform_state.hpp @@ -34,6 +34,9 @@ public: // North Orientation NorthOrientation getNorthOrientation() const; double getNorthOrientationAngle() const; + + // Constrain mode + ConstrainMode getConstrainMode() const; // Position LatLng getLatLng() const; |