summaryrefslogtreecommitdiff
path: root/platform/ios/src/MGLMapView.mm
diff options
context:
space:
mode:
Diffstat (limited to 'platform/ios/src/MGLMapView.mm')
-rw-r--r--platform/ios/src/MGLMapView.mm114
1 files changed, 77 insertions, 37 deletions
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:)])
{