From 15b9f3171a1c41d5a4c2b454fcce9b92350e28f2 Mon Sep 17 00:00:00 2001 From: Jason Wray Date: Wed, 20 Jan 2016 20:04:12 -0500 Subject: [PATCH] [ios] Refactor MGLMapView's location services MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Pause location services when the app goes to sleep; address iOS 8 blue bar issue. - Only ask for location permissions if not already granted/denied. - Cleanup usage of `.isDormant` → `.dormant` Partially addresses #2945, for which a full and complete fix waits until #4030. --- platform/ios/src/MGLMapView.mm | 73 ++++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 29 deletions(-) diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index c4f6cd39a30..83904f168fa 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -760,7 +760,7 @@ - (void)setOpaque:(BOOL)opaque // 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]; @@ -906,7 +906,7 @@ - (void)willTerminate { MGLAssertIsMainThread(); - if ( ! self.isDormant) + if ( ! self.dormant) { [self validateDisplayLink]; self.dormant = YES; @@ -957,6 +957,8 @@ - (void)sleepGL:(__unused NSNotification *)notification { self.dormant = YES; + [self validateLocationServices]; + [MGLMapboxEvents flush]; _displayLink.paused = YES; @@ -1006,6 +1008,8 @@ - (void)wakeGL:(__unused NSNotification *)notification _mbglMap->resume(); _displayLink.paused = NO; + + [self validateLocationServices]; } } @@ -3022,45 +3026,31 @@ - (void)annotationImageNeedsRedisplay:(MGLAnnotationImage *)annotationImage #pragma mark - User Location - -- (void)setShowsUserLocation:(BOOL)showsUserLocation +- (void)validateLocationServices { - if (showsUserLocation == _showsUserLocation || _isTargetingInterfaceBuilder) return; + BOOL shouldEnableLocationServices = self.showsUserLocation && !self.dormant; - _showsUserLocation = showsUserLocation; - - 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 @@ -3069,12 +3059,37 @@ - (void)setShowsUserLocation:(BOOL)showsUserLocation 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:)]) {