diff options
Diffstat (limited to 'platform/ios/src')
-rw-r--r-- | platform/ios/src/MGLAPIClient.m | 114 | ||||
-rw-r--r-- | platform/ios/src/MGLMapView.mm | 61 | ||||
-rw-r--r-- | platform/ios/src/MGLScaleBar.mm | 2 | ||||
-rw-r--r-- | platform/ios/src/MGLUserLocation.h | 2 |
4 files changed, 91 insertions, 88 deletions
diff --git a/platform/ios/src/MGLAPIClient.m b/platform/ios/src/MGLAPIClient.m index 124d436197..8a987d76d8 100644 --- a/platform/ios/src/MGLAPIClient.m +++ b/platform/ios/src/MGLAPIClient.m @@ -17,8 +17,10 @@ static NSString * const MGLAPIClientHTTPMethodPost = @"POST"; @property (nonatomic, copy) NSURLSession *session; @property (nonatomic, copy) NSURL *baseURL; -@property (nonatomic, copy) NSData *digicertCert; -@property (nonatomic, copy) NSData *geoTrustCert; +@property (nonatomic, copy) NSData *digicertCert_2016; +@property (nonatomic, copy) NSData *geoTrustCert_2016; +@property (nonatomic, copy) NSData *digicertCert_2017; +@property (nonatomic, copy) NSData *geoTrustCert_2017; @property (nonatomic, copy) NSData *testServerCert; @property (nonatomic, copy) NSString *userAgent; @property (nonatomic) BOOL usesTestServer; @@ -107,10 +109,14 @@ static NSString * const MGLAPIClientHTTPMethodPost = @"POST"; - (void)loadCertificates { NSData *certificate; - [self loadCertificate:&certificate withResource:@"api_mapbox_com-geotrust"]; - self.geoTrustCert = certificate; - [self loadCertificate:&certificate withResource:@"api_mapbox_com-digicert"]; - self.digicertCert = certificate; + [self loadCertificate:&certificate withResource:@"api_mapbox_com-geotrust_2016"]; + self.geoTrustCert_2016 = certificate; + [self loadCertificate:&certificate withResource:@"api_mapbox_com-digicert_2016"]; + self.digicertCert_2016 = certificate; + [self loadCertificate:&certificate withResource:@"api_mapbox_com-geotrust_2017"]; + self.geoTrustCert_2017 = certificate; + [self loadCertificate:&certificate withResource:@"api_mapbox_com-digicert_2017"]; + self.digicertCert_2017 = certificate; [self loadCertificate:&certificate withResource:@"api_mapbox_staging"]; self.testServerCert = certificate; } @@ -141,75 +147,53 @@ static NSString * const MGLAPIClientHTTPMethodPost = @"POST"; #pragma mark NSURLSessionDelegate +- (BOOL)evaluateCertificateWithCertificateData:(NSData *)certificateData keyCount:(CFIndex)keyCount serverTrust:(SecTrustRef)serverTrust challenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^) (NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler { + for (int lc = 0; lc < keyCount; lc++) { + SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, lc); + NSData *remoteCertificateData = CFBridgingRelease(SecCertificateCopyData(certificate)); + if ([remoteCertificateData isEqualToData:certificateData]) { + completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]); + return YES; + } + } + return NO; +} + - (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^) (NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler { + if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { - SecTrustRef serverTrust = [[challenge protectionSpace] serverTrust]; SecTrustResultType trustResult; - - // Validate the certificate chain with the device's trust store anyway - // This *might* give use revocation checking + + // Validate the certificate chain with the device's trust store anyway this *might* use revocation checking SecTrustEvaluate(serverTrust, &trustResult); - if (trustResult == kSecTrustResultUnspecified) - { + + BOOL found = NO; // For clarity; we start in a state where the challange has not been completed and no certificate has been found + + if (trustResult == kSecTrustResultUnspecified) { // Look for a pinned certificate in the server's certificate chain - long numKeys = SecTrustGetCertificateCount(serverTrust); - - BOOL found = NO; - // Try GeoTrust Cert First - for (int lc = 0; lc < numKeys; lc++) { - SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, lc); - NSData *remoteCertificateData = CFBridgingRelease(SecCertificateCopyData(certificate)); - - // Compare Remote Key With Local Version - if ([remoteCertificateData isEqualToData:_geoTrustCert]) { - // Found the certificate; continue connecting - completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]); - found = YES; - break; - } + CFIndex numKeys = SecTrustGetCertificateCount(serverTrust); + + // Check certs in the following order: digicert 2016, digicert 2017, geotrust 2016, geotrust 2017 + found = [self evaluateCertificateWithCertificateData:self.digicertCert_2016 keyCount:numKeys serverTrust:serverTrust challenge:challenge completionHandler:completionHandler]; + if (!found) { + found = [self evaluateCertificateWithCertificateData:self.digicertCert_2017 keyCount:numKeys serverTrust:serverTrust challenge:challenge completionHandler:completionHandler]; } - if (!found) { - // Fallback to Digicert Cert - for (int lc = 0; lc < numKeys; lc++) { - SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, lc); - NSData *remoteCertificateData = CFBridgingRelease(SecCertificateCopyData(certificate)); - - // Compare Remote Key With Local Version - if ([remoteCertificateData isEqualToData:_digicertCert]) { - // Found the certificate; continue connecting - completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]); - found = YES; - break; - } - } - - if (!found && _usesTestServer) { - // See if this is test server - for (int lc = 0; lc < numKeys; lc++) { - SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, lc); - NSData *remoteCertificateData = CFBridgingRelease(SecCertificateCopyData(certificate)); - - // Compare Remote Key With Local Version - if ([remoteCertificateData isEqualToData:_testServerCert]) { - // Found the certificate; continue connecting - completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]); - found = YES; - break; - } - } - } - - if (!found) { - // The certificate wasn't found in GeoTrust nor Digicert. Cancel the connection. - completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]); - } + found = [self evaluateCertificateWithCertificateData:self.geoTrustCert_2016 keyCount:numKeys serverTrust:serverTrust challenge:challenge completionHandler:completionHandler]; + } + if (!found) { + found = [self evaluateCertificateWithCertificateData:self.geoTrustCert_2017 keyCount:numKeys serverTrust:serverTrust challenge:challenge completionHandler:completionHandler]; + } + + // If challenge can't be completed with any of the above certs, then try the test server if the app is configured to use the test server + if (!found && _usesTestServer) { + found = [self evaluateCertificateWithCertificateData:self.testServerCert keyCount:numKeys serverTrust:serverTrust challenge:challenge completionHandler:completionHandler]; } } - else - { - // Certificate chain validation failed; cancel the connection + + if (!found) { + // No certificate was found so cancel the connection. completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]); } } diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index c1d257dd51..1444fc3cb0 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -85,6 +85,8 @@ typedef NS_ENUM(NSUInteger, MGLUserTrackingState) { MGLUserTrackingStatePossible = 0, /// The map view has begun to move to the first reported user location. MGLUserTrackingStateBegan, + /// The map view begins a significant transition. + MGLUserTrackingStateBeginSignificantTransition, /// The map view has finished moving to the first reported user location. MGLUserTrackingStateChanged, }; @@ -113,6 +115,9 @@ const NSUInteger MGLTargetFrameInterval = 1; // Target FPS will be 60 divided b /// Tolerance for snapping to true north, measured in degrees in either direction. const CLLocationDirection MGLToleranceForSnappingToNorth = 7; +/// Distance threshold to stop the camera while animating. +const CLLocationDistance MGLDistanceThresholdForCameraPause = 500; + /// Reuse identifier and file name of the default point annotation image. static NSString * const MGLDefaultStyleMarkerSymbolName = @"default_marker"; @@ -310,6 +315,8 @@ public: /// Center coordinate of the pinch gesture on the previous iteration of the gesture. CLLocationCoordinate2D _previousPinchCenterCoordinate; NSUInteger _previousPinchNumberOfTouches; + + CLLocationDistance _distanceFromOldUserLocation; BOOL _delegateHasAlphasForShapeAnnotations; BOOL _delegateHasStrokeColorsForShapeAnnotations; @@ -525,21 +532,21 @@ public: _singleTapGestureRecognizer.delegate = self; [self addGestureRecognizer:_singleTapGestureRecognizer]; - _twoFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTwoFingerTapGesture:)]; - _twoFingerTap.numberOfTouchesRequired = 2; - [_twoFingerTap requireGestureRecognizerToFail:_pinch]; - [_twoFingerTap requireGestureRecognizerToFail:_rotate]; - [self addGestureRecognizer:_twoFingerTap]; - _twoFingerDrag = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleTwoFingerDragGesture:)]; _twoFingerDrag.minimumNumberOfTouches = 2; _twoFingerDrag.maximumNumberOfTouches = 2; _twoFingerDrag.delegate = self; - [_twoFingerDrag requireGestureRecognizerToFail:_twoFingerTap]; [_twoFingerDrag requireGestureRecognizerToFail:_pan]; [self addGestureRecognizer:_twoFingerDrag]; _pitchEnabled = YES; + _twoFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTwoFingerTapGesture:)]; + _twoFingerTap.numberOfTouchesRequired = 2; + [_twoFingerTap requireGestureRecognizerToFail:_pinch]; + [_twoFingerTap requireGestureRecognizerToFail:_rotate]; + [_twoFingerTap requireGestureRecognizerToFail:_twoFingerDrag]; + [self addGestureRecognizer:_twoFingerTap]; + _decelerationRate = MGLMapViewDecelerationRateNormal; _quickZoom = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleQuickZoomGesture:)]; @@ -1130,6 +1137,10 @@ public: { _changeDelimiterSuppressionDepth = 0; _mbglMap->setGestureInProgress(false); + if (self.userTrackingState == MGLUserTrackingStateBegan) + { + [self setUserTrackingMode:MGLUserTrackingModeNone animated:NO]; + } _mbglMap->cancelTransitions(); } @@ -1259,16 +1270,16 @@ public: [self.delegate mapView:self shouldChangeFromCamera:oldCamera toCamera:toCamera]) { _mbglMap->setZoom(zoom, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }); - } - // The gesture recognizer only reports the gesture’s current center - // point, so use the previous center point to anchor the transition. - // If the number of touches has changed, the remembered center point is - // meaningless. - if (self.userTrackingMode == MGLUserTrackingModeNone && pinch.numberOfTouches == _previousPinchNumberOfTouches) - { - CLLocationCoordinate2D centerCoordinate = _previousPinchCenterCoordinate; - _mbglMap->setLatLng(MGLLatLngFromLocationCoordinate2D(centerCoordinate), - mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }); + // The gesture recognizer only reports the gesture’s current center + // point, so use the previous center point to anchor the transition. + // If the number of touches has changed, the remembered center point is + // meaningless. + if (self.userTrackingMode == MGLUserTrackingModeNone && pinch.numberOfTouches == _previousPinchNumberOfTouches) + { + CLLocationCoordinate2D centerCoordinate = _previousPinchCenterCoordinate; + _mbglMap->setLatLng(MGLLatLngFromLocationCoordinate2D(centerCoordinate), + mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }); + } } [self cameraIsChanging]; } @@ -1635,14 +1646,14 @@ public: if ( ! self.isPitchEnabled) return; _mbglMap->cancelTransitions(); - MGLMapCamera *oldCamera = self.camera; if (twoFingerDrag.state == UIGestureRecognizerStateBegan) { [self trackGestureEvent:MGLEventGesturePitchStart forRecognizer:twoFingerDrag]; [self notifyGestureDidBegin]; } - else if (twoFingerDrag.state == UIGestureRecognizerStateBegan || twoFingerDrag.state == UIGestureRecognizerStateChanged) + + if (twoFingerDrag.state == UIGestureRecognizerStateBegan || twoFingerDrag.state == UIGestureRecognizerStateChanged) { CGFloat gestureDistance = CGPoint([twoFingerDrag translationInView:twoFingerDrag.view]).y; CGFloat currentPitch = _mbglMap->getPitch(); @@ -1652,6 +1663,7 @@ public: CGPoint centerPoint = [self anchorPointForGesture:twoFingerDrag]; + MGLMapCamera *oldCamera = self.camera; MGLMapCamera *toCamera = [self cameraByTiltingToPitch:pitchNew]; if (![self.delegate respondsToSelector:@selector(mapView:shouldChangeFromCamera:toCamera:)] || @@ -4362,6 +4374,7 @@ public: { CLLocation *oldLocation = self.userLocation.location; CLLocation *newLocation = locations.lastObject; + _distanceFromOldUserLocation = [newLocation distanceFromLocation:oldLocation]; if ( ! _showsUserLocation || ! newLocation || ! CLLocationCoordinate2DIsValid(newLocation.coordinate)) return; @@ -4455,7 +4468,12 @@ public: /// first location update. - (void)didUpdateLocationSignificantlyAnimated:(BOOL)animated { - self.userTrackingState = MGLUserTrackingStateBegan; + + if (_distanceFromOldUserLocation >= MGLDistanceThresholdForCameraPause) { + self.userTrackingState = MGLUserTrackingStateBeginSignificantTransition; + } else { + self.userTrackingState = MGLUserTrackingStateBegan; + } MGLMapCamera *camera = self.camera; camera.centerCoordinate = self.userLocation.location.coordinate; @@ -4475,7 +4493,8 @@ public: peakAltitude:-1 completionHandler:^{ MGLMapView *strongSelf = weakSelf; - if (strongSelf.userTrackingState == MGLUserTrackingStateBegan) + if (strongSelf.userTrackingState == MGLUserTrackingStateBegan || + strongSelf.userTrackingState == MGLDistanceThresholdForCameraPause) { strongSelf.userTrackingState = MGLUserTrackingStateChanged; } diff --git a/platform/ios/src/MGLScaleBar.mm b/platform/ios/src/MGLScaleBar.mm index cd88c1e08e..410aa7d57e 100644 --- a/platform/ios/src/MGLScaleBar.mm +++ b/platform/ios/src/MGLScaleBar.mm @@ -188,9 +188,9 @@ static const CGFloat MGLFeetPerMeter = 3.28084; - (MGLRow)preferredRow { CLLocationDistance maximumDistance = [self maximumWidth] * [self unitsPerPoint]; - MGLRow row; BOOL useMetric = [self usesMetricSystem]; + MGLRow row = useMetric ? MGLMetricTable[0] : MGLImperialTable[0]; NSUInteger count = useMetric ? sizeof(MGLMetricTable) / sizeof(MGLMetricTable[0]) : sizeof(MGLImperialTable) / sizeof(MGLImperialTable[0]); diff --git a/platform/ios/src/MGLUserLocation.h b/platform/ios/src/MGLUserLocation.h index c41c3ee7fd..30bfc592ca 100644 --- a/platform/ios/src/MGLUserLocation.h +++ b/platform/ios/src/MGLUserLocation.h @@ -8,7 +8,7 @@ NS_ASSUME_NONNULL_BEGIN /** The MGLUserLocation class defines a specific type of annotation that identifies the user’s current location. You do not create instances of this class - directly. Instead, you retrieve an existing MGLUserLocation object from the + directly. Instead, you retrieve an existing `MGLUserLocation` object from the `userLocation` property of the map view displayed in your application. */ @interface MGLUserLocation : NSObject <MGLAnnotation, NSSecureCoding> |